summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore50
-rw-r--r--.travis.yml28
-rw-r--r--.ycm_extra_conf.py144
-rw-r--r--AUTHORS4
-rw-r--r--COPYING.GPL339
-rw-r--r--COPYING.LGPL502
-rw-r--r--COPYING.MPL470
-rw-r--r--Makefile.am56
-rw-r--r--NEWS108
-rw-r--r--README.md16
-rwxr-xr-xautogen.sh12
-rw-r--r--cmis-test.sh139
-rw-r--r--configure.ac224
-rw-r--r--coverage.mk22
-rw-r--r--cppcheck-suppress3
-rw-r--r--doc/cmis-client.xml.in570
-rw-r--r--inc/Makefile.am1
-rw-r--r--inc/libcmis-c/Makefile.am20
-rw-r--r--inc/libcmis-c/allowable-actions.h50
-rw-r--r--inc/libcmis-c/document.h96
-rw-r--r--inc/libcmis-c/error.h48
-rw-r--r--inc/libcmis-c/folder.h81
-rw-r--r--inc/libcmis-c/libcmis-c-api.h45
-rw-r--r--inc/libcmis-c/libcmis-c.h50
-rw-r--r--inc/libcmis-c/oauth2-data.h58
-rw-r--r--inc/libcmis-c/object-type.h114
-rw-r--r--inc/libcmis-c/object.h134
-rw-r--r--inc/libcmis-c/property-type.h86
-rw-r--r--inc/libcmis-c/property.h66
-rw-r--r--inc/libcmis-c/rendition.h59
-rw-r--r--inc/libcmis-c/repository.h107
-rw-r--r--inc/libcmis-c/session-factory.h79
-rw-r--r--inc/libcmis-c/session.h83
-rw-r--r--inc/libcmis-c/types.h228
-rw-r--r--inc/libcmis-c/vectors.h68
-rw-r--r--inc/libcmis/Makefile.am20
-rw-r--r--inc/libcmis/allowable-actions.hxx131
-rw-r--r--inc/libcmis/document.hxx147
-rw-r--r--inc/libcmis/exception.hxx62
-rw-r--r--inc/libcmis/folder.hxx84
-rw-r--r--inc/libcmis/libcmis-api.h45
-rw-r--r--inc/libcmis/libcmis.hxx49
-rw-r--r--inc/libcmis/oauth2-data.hxx78
-rw-r--r--inc/libcmis/object-type.hxx144
-rw-r--r--inc/libcmis/object.hxx218
-rw-r--r--inc/libcmis/property-type.hxx127
-rw-r--r--inc/libcmis/property.hxx89
-rw-r--r--inc/libcmis/rendition.hxx90
-rw-r--r--inc/libcmis/repository.hxx119
-rw-r--r--inc/libcmis/session-factory.hxx157
-rw-r--r--inc/libcmis/session.hxx103
-rw-r--r--inc/libcmis/xml-utils.hxx166
-rw-r--r--inc/libcmis/xmlserializable.hxx48
-rw-r--r--lgtm.yml9
-rw-r--r--libcmis-c.pc.in13
-rw-r--r--libcmis.pc.in12
-rw-r--r--m4/ax_cxx_compile_stdcxx.m4982
-rw-r--r--m4/ax_cxx_compile_stdcxx_11.m439
-rw-r--r--m4/ax_gcc_func_attribute.m4238
-rw-r--r--m4/boost.m41568
-rw-r--r--qa/Makefile.am1
-rw-r--r--qa/libcmis-c/Makefile.am48
-rw-r--r--qa/libcmis-c/test-allowable-actions.cxx82
-rw-r--r--qa/libcmis-c/test-api.cxx39
-rw-r--r--qa/libcmis-c/test-build.c36
-rw-r--r--qa/libcmis-c/test-document.cxx621
-rw-r--r--qa/libcmis-c/test-dummies.cxx633
-rw-r--r--qa/libcmis-c/test-dummies.hxx223
-rw-r--r--qa/libcmis-c/test-folder.cxx433
-rw-r--r--qa/libcmis-c/test-object-type.cxx377
-rw-r--r--qa/libcmis-c/test-object.cxx425
-rw-r--r--qa/libcmis-c/test-property-type.cxx251
-rw-r--r--qa/libcmis-c/test-property.cxx242
-rw-r--r--qa/libcmis-c/test-repository.cxx205
-rw-r--r--qa/libcmis-c/test-session.cxx88
-rw-r--r--qa/libcmis/Makefile.am190
-rw-r--r--qa/libcmis/data/atom/allowable-actions.xml32
-rw-r--r--qa/libcmis/data/atom/create-document.xml82
-rw-r--r--qa/libcmis/data/atom/create-folder-bad-type.xml60
-rw-r--r--qa/libcmis/data/atom/create-folder.xml62
-rw-r--r--qa/libcmis/data/atom/get-versions.xml230
-rw-r--r--qa/libcmis/data/atom/root-children.xml389
-rw-r--r--qa/libcmis/data/atom/root-folder.xml90
-rw-r--r--qa/libcmis/data/atom/test-document-parents.xml134
-rw-r--r--qa/libcmis/data/atom/test-document-relationships.xml179
-rw-r--r--qa/libcmis/data/atom/test-document-updated.xml137
-rw-r--r--qa/libcmis/data/atom/test-document.xml155
-rw-r--r--qa/libcmis/data/atom/type-docLevel1.xml404
-rw-r--r--qa/libcmis/data/atom/type-docLevel2.xml675
-rw-r--r--qa/libcmis/data/atom/type-document.xml402
-rw-r--r--qa/libcmis/data/atom/type-folder.xml224
-rw-r--r--qa/libcmis/data/atom/typechildren-docLevel1.xml56
-rw-r--r--qa/libcmis/data/atom/typechildren-document.xml55
-rw-r--r--qa/libcmis/data/atom/valid-object-noactions.xml66
-rw-r--r--qa/libcmis/data/atom/valid-object.xml97
-rw-r--r--qa/libcmis/data/atom/working-copy.xml98
-rw-r--r--qa/libcmis/data/atom/workspaces.xml238
-rw-r--r--qa/libcmis/data/gdrive/allVersions.json49
-rw-r--r--qa/libcmis/data/gdrive/approve.html10
-rw-r--r--qa/libcmis/data/gdrive/authcode.html6
-rw-r--r--qa/libcmis/data/gdrive/challenge.html21
-rw-r--r--qa/libcmis/data/gdrive/document-updated.json67
-rw-r--r--qa/libcmis/data/gdrive/document.json67
-rw-r--r--qa/libcmis/data/gdrive/document2.json62
-rw-r--r--qa/libcmis/data/gdrive/document_parents.json14
-rw-r--r--qa/libcmis/data/gdrive/folder.json47
-rw-r--r--qa/libcmis/data/gdrive/folder2.json47
-rw-r--r--qa/libcmis/data/gdrive/folder_children.json20
-rw-r--r--qa/libcmis/data/gdrive/gdoc-file.json58
-rw-r--r--qa/libcmis/data/gdrive/jsontest-good.json60
-rw-r--r--qa/libcmis/data/gdrive/login1.html12
-rw-r--r--qa/libcmis/data/gdrive/login2.html11
-rw-r--r--qa/libcmis/data/gdrive/refresh_response.json5
-rw-r--r--qa/libcmis/data/gdrive/root_child_missing.json4
-rw-r--r--qa/libcmis/data/gdrive/root_child_search.json13
-rw-r--r--qa/libcmis/data/gdrive/token-response.json6
-rw-r--r--qa/libcmis/data/onedrive/file.json24
-rw-r--r--qa/libcmis/data/onedrive/folder-listed.json51
-rw-r--r--qa/libcmis/data/onedrive/folder.json23
-rw-r--r--qa/libcmis/data/onedrive/folderA.json23
-rw-r--r--qa/libcmis/data/onedrive/folderB.json23
-rw-r--r--qa/libcmis/data/onedrive/folderC.json23
-rw-r--r--qa/libcmis/data/onedrive/new-file.json5
-rw-r--r--qa/libcmis/data/onedrive/parent-folder.json23
-rw-r--r--qa/libcmis/data/onedrive/refresh-response.json8
-rw-r--r--qa/libcmis/data/onedrive/search-result.json52
-rw-r--r--qa/libcmis/data/onedrive/searched-file.json24
-rw-r--r--qa/libcmis/data/onedrive/searched-wrong-file.json24
-rw-r--r--qa/libcmis/data/onedrive/token-response.json8
-rw-r--r--qa/libcmis/data/onedrive/updated-file.json24
-rw-r--r--qa/libcmis/data/sharepoint/auth-resp.json191
-rw-r--r--qa/libcmis/data/sharepoint/auth-xml-resp.xml69
-rw-r--r--qa/libcmis/data/sharepoint/author.json28
-rw-r--r--qa/libcmis/data/sharepoint/children-files.json60
-rw-r--r--qa/libcmis/data/sharepoint/children-folders.json42
-rw-r--r--qa/libcmis/data/sharepoint/file-v1.json56
-rw-r--r--qa/libcmis/data/sharepoint/file.json56
-rw-r--r--qa/libcmis/data/sharepoint/folder-properties.json35
-rw-r--r--qa/libcmis/data/sharepoint/folder.json38
-rw-r--r--qa/libcmis/data/sharepoint/new-xdigest.json20
-rw-r--r--qa/libcmis/data/sharepoint/root-folder.json38
-rw-r--r--qa/libcmis/data/sharepoint/versions.json44
-rw-r--r--qa/libcmis/data/sharepoint/xdigest.json20
-rw-r--r--qa/libcmis/data/ws/CMISWS-Service.wsdl1262
-rw-r--r--qa/libcmis/data/ws/cancel-checkout.http25
-rw-r--r--qa/libcmis/data/ws/checked-in.http144
-rw-r--r--qa/libcmis/data/ws/checkin.http27
-rw-r--r--qa/libcmis/data/ws/checkout.http28
-rw-r--r--qa/libcmis/data/ws/create-document.http25
-rw-r--r--qa/libcmis/data/ws/create-folder-bad-type.http33
-rw-r--r--qa/libcmis/data/ws/create-folder.http25
-rw-r--r--qa/libcmis/data/ws/created-document.http85
-rw-r--r--qa/libcmis/data/ws/created-folder.http64
-rw-r--r--qa/libcmis/data/ws/delete-object.http23
-rw-r--r--qa/libcmis/data/ws/delete-tree.http27
-rw-r--r--qa/libcmis/data/ws/get-content-stream.http37
-rw-r--r--qa/libcmis/data/ws/get-renditions.http41
-rw-r--r--qa/libcmis/data/ws/get-versions.http204
-rw-r--r--qa/libcmis/data/ws/getbypath-bad.http33
-rw-r--r--qa/libcmis/data/ws/move-object.http27
-rw-r--r--qa/libcmis/data/ws/repositories.http25
-rw-r--r--qa/libcmis/data/ws/repository-infos-bad.http33
-rw-r--r--qa/libcmis/data/ws/repository-infos.http207
-rw-r--r--qa/libcmis/data/ws/root-children.http292
-rw-r--r--qa/libcmis/data/ws/root-folder.http93
-rw-r--r--qa/libcmis/data/ws/secondary-type.http57
-rw-r--r--qa/libcmis/data/ws/set-content-stream.http28
-rw-r--r--qa/libcmis/data/ws/test-document-add-secondary.http148
-rw-r--r--qa/libcmis/data/ws/test-document-parents.http106
-rw-r--r--qa/libcmis/data/ws/test-document-updated.http140
-rw-r--r--qa/libcmis/data/ws/test-document.http142
-rw-r--r--qa/libcmis/data/ws/type-bad.http33
-rw-r--r--qa/libcmis/data/ws/type-docLevel1.http411
-rw-r--r--qa/libcmis/data/ws/type-docLevel2-secondary.http698
-rw-r--r--qa/libcmis/data/ws/type-docLevel2.http682
-rw-r--r--qa/libcmis/data/ws/type-document.http410
-rw-r--r--qa/libcmis/data/ws/type-folder.http232
-rw-r--r--qa/libcmis/data/ws/typechildren-document.http413
-rw-r--r--qa/libcmis/data/ws/update-properties.http26
-rw-r--r--qa/libcmis/data/ws/valid-object.http99
-rw-r--r--qa/libcmis/data/ws/working-copy.http98
-rw-r--r--qa/libcmis/test-atom.cxx1250
-rw-r--r--qa/libcmis/test-commons.cxx223
-rw-r--r--qa/libcmis/test-decoder.cxx221
-rw-r--r--qa/libcmis/test-factory.cxx336
-rw-r--r--qa/libcmis/test-gdrive.cxx1318
-rw-r--r--qa/libcmis/test-helpers.cxx187
-rw-r--r--qa/libcmis/test-helpers.hxx63
-rw-r--r--qa/libcmis/test-jsonutils.cxx182
-rw-r--r--qa/libcmis/test-main.cxx39
-rw-r--r--qa/libcmis/test-mockup-helpers.cxx50
-rw-r--r--qa/libcmis/test-mockup-helpers.hxx33
-rw-r--r--qa/libcmis/test-onedrive.cxx781
-rw-r--r--qa/libcmis/test-sharepoint.cxx733
-rw-r--r--qa/libcmis/test-soap.cxx563
-rw-r--r--qa/libcmis/test-ws.cxx1505
-rw-r--r--qa/libcmis/test-xmlutils.cxx626
-rw-r--r--qa/mockup/Makefile.am15
-rw-r--r--qa/mockup/curl-mockup.cxx504
-rw-r--r--qa/mockup/curl/curl.h153
-rw-r--r--qa/mockup/internals.hxx133
-rw-r--r--qa/mockup/mockup-config.cxx409
-rw-r--r--qa/mockup/mockup-config.h113
-rw-r--r--samples/populate.sh168
-rw-r--r--src/Makefile.am17
-rw-r--r--src/cmis-client.cxx1158
-rw-r--r--src/libcmis-c/Makefile.am39
-rw-r--r--src/libcmis-c/allowable-actions.cxx56
-rw-r--r--src/libcmis-c/document.cxx448
-rw-r--r--src/libcmis-c/error.cxx74
-rw-r--r--src/libcmis-c/folder.cxx369
-rw-r--r--src/libcmis-c/internals.hxx242
-rw-r--r--src/libcmis-c/oauth2-data.cxx110
-rw-r--r--src/libcmis-c/object-type.cxx388
-rw-r--r--src/libcmis-c/object.cxx512
-rw-r--r--src/libcmis-c/property-type.cxx201
-rw-r--r--src/libcmis-c/property.cxx200
-rw-r--r--src/libcmis-c/rendition.cxx110
-rw-r--r--src/libcmis-c/repository.cxx208
-rw-r--r--src/libcmis-c/session-factory.cxx239
-rw-r--r--src/libcmis-c/session.cxx305
-rw-r--r--src/libcmis-c/vectors.cxx139
-rw-r--r--src/libcmis/Makefile.am147
-rw-r--r--src/libcmis/allowable-actions.cxx294
-rw-r--r--src/libcmis/atom-document.cxx480
-rw-r--r--src/libcmis/atom-document.hxx66
-rw-r--r--src/libcmis/atom-folder.cxx322
-rw-r--r--src/libcmis/atom-folder.hxx56
-rw-r--r--src/libcmis/atom-object-type.cxx167
-rw-r--r--src/libcmis/atom-object-type.hxx63
-rw-r--r--src/libcmis/atom-object.cxx486
-rw-r--r--src/libcmis/atom-object.hxx106
-rw-r--r--src/libcmis/atom-session.cxx349
-rw-r--r--src/libcmis/atom-session.hxx90
-rw-r--r--src/libcmis/atom-workspace.cxx228
-rw-r--r--src/libcmis/atom-workspace.hxx91
-rw-r--r--src/libcmis/base-session.cxx146
-rw-r--r--src/libcmis/base-session.hxx104
-rw-r--r--src/libcmis/document.cxx107
-rw-r--r--src/libcmis/dummy.cxx0
-rw-r--r--src/libcmis/folder.cxx92
-rw-r--r--src/libcmis/gdrive-allowable-actions.hxx102
-rw-r--r--src/libcmis/gdrive-document.cxx250
-rw-r--r--src/libcmis/gdrive-document.hxx90
-rw-r--r--src/libcmis/gdrive-folder.cxx192
-rw-r--r--src/libcmis/gdrive-folder.hxx66
-rw-r--r--src/libcmis/gdrive-object-type.cxx141
-rw-r--r--src/libcmis/gdrive-object-type.hxx46
-rw-r--r--src/libcmis/gdrive-object.cxx276
-rw-r--r--src/libcmis/gdrive-object.hxx87
-rw-r--r--src/libcmis/gdrive-property.cxx79
-rw-r--r--src/libcmis/gdrive-property.hxx51
-rw-r--r--src/libcmis/gdrive-repository.cxx55
-rw-r--r--src/libcmis/gdrive-repository.hxx41
-rw-r--r--src/libcmis/gdrive-session.cxx254
-rw-r--r--src/libcmis/gdrive-session.hxx72
-rw-r--r--src/libcmis/gdrive-utils.cxx221
-rw-r--r--src/libcmis/gdrive-utils.hxx67
-rw-r--r--src/libcmis/http-session.cxx994
-rw-r--r--src/libcmis/http-session.hxx179
-rw-r--r--src/libcmis/json-utils.cxx306
-rw-r--r--src/libcmis/json-utils.hxx87
-rw-r--r--src/libcmis/oauth2-data.cxx95
-rw-r--r--src/libcmis/oauth2-handler.cxx196
-rw-r--r--src/libcmis/oauth2-handler.hxx97
-rw-r--r--src/libcmis/oauth2-providers.cxx246
-rw-r--r--src/libcmis/oauth2-providers.hxx63
-rw-r--r--src/libcmis/object-type.cxx368
-rw-r--r--src/libcmis/object.cxx398
-rw-r--r--src/libcmis/onedrive-allowable-actions.hxx102
-rw-r--r--src/libcmis/onedrive-document.cxx177
-rw-r--r--src/libcmis/onedrive-document.hxx75
-rw-r--r--src/libcmis/onedrive-folder.cxx167
-rw-r--r--src/libcmis/onedrive-folder.hxx64
-rw-r--r--src/libcmis/onedrive-object-type.cxx118
-rw-r--r--src/libcmis/onedrive-object-type.hxx46
-rw-r--r--src/libcmis/onedrive-object.cxx198
-rw-r--r--src/libcmis/onedrive-object.hxx76
-rw-r--r--src/libcmis/onedrive-property.cxx78
-rw-r--r--src/libcmis/onedrive-property.hxx52
-rw-r--r--src/libcmis/onedrive-repository.cxx54
-rw-r--r--src/libcmis/onedrive-repository.hxx40
-rw-r--r--src/libcmis/onedrive-session.cxx207
-rw-r--r--src/libcmis/onedrive-session.hxx75
-rw-r--r--src/libcmis/onedrive-utils.cxx131
-rw-r--r--src/libcmis/onedrive-utils.hxx60
-rw-r--r--src/libcmis/property-type.cxx254
-rw-r--r--src/libcmis/property.cxx232
-rw-r--r--src/libcmis/rendition.cxx195
-rw-r--r--src/libcmis/repository.cxx294
-rw-r--r--src/libcmis/session-factory.cxx164
-rw-r--r--src/libcmis/sharepoint-allowable-actions.hxx102
-rw-r--r--src/libcmis/sharepoint-document.cxx213
-rw-r--r--src/libcmis/sharepoint-document.hxx72
-rw-r--r--src/libcmis/sharepoint-folder.cxx205
-rw-r--r--src/libcmis/sharepoint-folder.hxx67
-rw-r--r--src/libcmis/sharepoint-object-type.cxx105
-rw-r--r--src/libcmis/sharepoint-object-type.hxx46
-rw-r--r--src/libcmis/sharepoint-object.cxx200
-rw-r--r--src/libcmis/sharepoint-object.hxx74
-rw-r--r--src/libcmis/sharepoint-property.cxx79
-rw-r--r--src/libcmis/sharepoint-property.hxx50
-rw-r--r--src/libcmis/sharepoint-repository.cxx65
-rw-r--r--src/libcmis/sharepoint-repository.hxx39
-rw-r--r--src/libcmis/sharepoint-session.cxx424
-rw-r--r--src/libcmis/sharepoint-session.hxx91
-rw-r--r--src/libcmis/sharepoint-utils.cxx133
-rw-r--r--src/libcmis/sharepoint-utils.hxx54
-rw-r--r--src/libcmis/ws-document.cxx135
-rw-r--r--src/libcmis/ws-document.hxx60
-rw-r--r--src/libcmis/ws-folder.cxx68
-rw-r--r--src/libcmis/ws-folder.hxx54
-rw-r--r--src/libcmis/ws-navigationservice.cxx101
-rw-r--r--src/libcmis/ws-navigationservice.hxx60
-rw-r--r--src/libcmis/ws-object-type.cxx90
-rw-r--r--src/libcmis/ws-object-type.hxx57
-rw-r--r--src/libcmis/ws-object.cxx130
-rw-r--r--src/libcmis/ws-object.hxx61
-rw-r--r--src/libcmis/ws-objectservice.cxx242
-rw-r--r--src/libcmis/ws-objectservice.hxx95
-rw-r--r--src/libcmis/ws-relatedmultipart.cxx353
-rw-r--r--src/libcmis/ws-relatedmultipart.hxx138
-rw-r--r--src/libcmis/ws-repositoryservice.cxx136
-rw-r--r--src/libcmis/ws-repositoryservice.hxx71
-rw-r--r--src/libcmis/ws-requests.cxx877
-rw-r--r--src/libcmis/ws-requests.hxx786
-rw-r--r--src/libcmis/ws-session.cxx417
-rw-r--r--src/libcmis/ws-session.hxx124
-rw-r--r--src/libcmis/ws-soap.cxx335
-rw-r--r--src/libcmis/ws-soap.hxx178
-rw-r--r--src/libcmis/ws-versioningservice.cxx138
-rw-r--r--src/libcmis/ws-versioningservice.hxx67
-rw-r--r--src/libcmis/xml-utils.cxx573
333 files changed, 57908 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2e01d2d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,50 @@
+aclocal.m4
+autom4te.cache
+compile
+config.*
+configure
+depcomp
+INSTALL
+install-sh
+libtool
+ltmain.sh
+m4/l*.m4
+Makefile
+Makefile.in
+missing
+*.pc
+.deps
+*.o
+*.la
+*.lo
+.libs
+tags
+ChangeLog
+libcmis-*.*.*.tar.gz
+test-utils
+test-mockup
+test-atom
+test-gdrive
+test-onedrive
+test-json
+test-sharepoint
+test-ws
+test-factory
+test-api
+test-c-build
+cmis-client
+test-server
+*.tar.gz
+*.1
+*.swp
+run-test.sh
+*.gcda
+*.gcno
+*.info
+libcmis-lcov
+*.pyc
+*.trs
+*.log
+test-driver
+qa/libcmis/libtest.a
+doc/cmis-client.xml
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2698938
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,28 @@
+language: cpp
+sudo: required
+
+addons:
+ apt:
+ update: true
+ packages:
+ - docbook-to-man
+ - libboost-date-time-dev
+ - libboost-dev
+ - libboost-program-options-dev
+ - libcppunit-dev
+ - libxml2-dev
+
+compiler:
+ - gcc
+ - clang
+arch:
+ - amd64
+ - ppc64le
+
+script:
+ - ./autogen.sh && make && make check
+
+notifications:
+ email:
+ on_success: never
+ on_failure: always
diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py
new file mode 100644
index 0000000..f312747
--- /dev/null
+++ b/.ycm_extra_conf.py
@@ -0,0 +1,144 @@
+
+#
+# Here's the license text for this file:
+#
+# This is free and unencumbered software released into the public domain.
+#
+# Anyone is free to copy, modify, publish, use, compile, sell, or
+# distribute this software, either in source code form or as a compiled
+# binary, for any purpose, commercial or non-commercial, and by any
+# means.
+#
+# In jurisdictions that recognize copyright laws, the author or authors
+# of this software dedicate any and all copyright interest in the
+# software to the public domain. We make this dedication for the benefit
+# of the public at large and to the detriment of our heirs and
+# successors. We intend this dedication to be an overt act of
+# relinquishment in perpetuity of all present and future rights to this
+# software under copyright law.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# For more information, please refer to <http://unlicense.org/>
+
+import os
+import ycm_core
+
+# These are the compilation flags that will be used in case there's no
+# compilation database set (by default, one is not set).
+# CHANGE THIS LIST OF FLAGS. YES, THIS IS THE DROID YOU HAVE BEEN LOOKING FOR.
+flags = [
+'-Werror',
+'-Wall',
+'-pedantic',
+'-Weffc++',
+'-Wshadow',
+'-Wendif-labels',
+'-Wextra',
+'-Wsign-promo',
+'-Woverloaded-virtual',
+'-Wnon-virtual-dtor',
+'-Wsign-promo',
+'-DDATA_DIR="qa/libcmis/data"',
+# THIS IS IMPORTANT! Without a "-std=<something>" flag, clang won't know which
+# language to use when compiling headers. So it will guess. Badly. So C++
+# headers will be compiled as C headers. You don't want that so ALWAYS specify
+# a "-std=<something>".
+# For a C project, you would set this to something like 'c99' instead of
+# 'c++11'.
+'-std=c++98',
+# ...and the same thing goes for the magic -x option which specifies the
+# language that the files to be compiled are written in. This is mostly
+# relevant for c++ headers.
+# For a C project, you would set this to 'c' instead of 'c++'.
+'-x',
+'c++',
+'-I',
+'src/libcmis',
+'-I',
+'src/libcmis-c',
+'-I',
+'qa/libcmis',
+'-I',
+'qa/libcmis-c',
+'-I',
+'qa/mockup',
+]
+
+# Set this to the absolute path to the folder (NOT the file!) containing the
+# compile_commands.json file to use that instead of 'flags'. See here for
+# more details: http://clang.llvm.org/docs/JSONCompilationDatabase.html
+#
+# Most projects will NOT need to set this to anything; you can just change the
+# 'flags' list of compilation flags. Notice that YCM itself uses that approach.
+compilation_database_folder = ''
+
+if compilation_database_folder:
+ database = ycm_core.CompilationDatabase( compilation_database_folder )
+else:
+ database = None
+
+
+def DirectoryOfThisScript():
+ return os.path.dirname( os.path.abspath( __file__ ) )
+
+
+def MakeRelativePathsInFlagsAbsolute( flags, working_directory ):
+ if not working_directory:
+ return list( flags )
+ new_flags = []
+ make_next_absolute = False
+ path_flags = [ '-isystem', '-I', '-iquote', '--sysroot=' ]
+ for flag in flags:
+ new_flag = flag
+
+ if make_next_absolute:
+ make_next_absolute = False
+ if not flag.startswith( '/' ):
+ new_flag = os.path.join( working_directory, flag )
+
+ for path_flag in path_flags:
+ if flag == path_flag:
+ make_next_absolute = True
+ break
+
+ if flag.startswith( path_flag ):
+ path = flag[ len( path_flag ): ]
+ new_flag = path_flag + os.path.join( working_directory, path )
+ break
+
+ if new_flag:
+ new_flags.append( new_flag )
+ return new_flags
+
+
+def FlagsForFile( filename ):
+ if database:
+ # Bear in mind that compilation_info.compiler_flags_ does NOT return a
+ # python list, but a "list-like" StringVec object
+ compilation_info = database.GetCompilationInfoForFile( filename )
+ final_flags = MakeRelativePathsInFlagsAbsolute(
+ compilation_info.compiler_flags_,
+ compilation_info.compiler_working_dir_ )
+
+ # NOTE: This is just for YouCompleteMe; it's highly likely that your project
+ # does NOT need to remove the stdlib flag. DO NOT USE THIS IN YOUR
+ # ycm_extra_conf IF YOU'RE NOT 100% YOU NEED IT.
+ try:
+ final_flags.remove( '-stdlib=libc++' )
+ except ValueError:
+ pass
+ else:
+ relative_to = DirectoryOfThisScript()
+ final_flags = MakeRelativePathsInFlagsAbsolute( flags, relative_to )
+
+ return {
+ 'flags': final_flags,
+ 'do_cache': True
+ }
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..734cc5a
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Cedric Bosdonnat <cedric.bosdonnat@free.fr>
+Mihai Varga <mihai.mv13@gmail.com>
+Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+David Tardon <dtardon@redhat.com>
diff --git a/COPYING.GPL b/COPYING.GPL
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/COPYING.GPL
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/COPYING.LGPL b/COPYING.LGPL
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/COPYING.LGPL
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/COPYING.MPL b/COPYING.MPL
new file mode 100644
index 0000000..8e6bb3e
--- /dev/null
+++ b/COPYING.MPL
@@ -0,0 +1,470 @@
+ MOZILLA PUBLIC LICENSE
+ Version 1.1
+
+ ---------------
+
+1. Definitions.
+
+ 1.0.1. "Commercial Use" means distribution or otherwise making the
+ Covered Code available to a third party.
+
+ 1.1. "Contributor" means each entity that creates or contributes to
+ the creation of Modifications.
+
+ 1.2. "Contributor Version" means the combination of the Original
+ Code, prior Modifications used by a Contributor, and the Modifications
+ made by that particular Contributor.
+
+ 1.3. "Covered Code" means the Original Code or Modifications or the
+ combination of the Original Code and Modifications, in each case
+ including portions thereof.
+
+ 1.4. "Electronic Distribution Mechanism" means a mechanism generally
+ accepted in the software development community for the electronic
+ transfer of data.
+
+ 1.5. "Executable" means Covered Code in any form other than Source
+ Code.
+
+ 1.6. "Initial Developer" means the individual or entity identified
+ as the Initial Developer in the Source Code notice required by Exhibit
+ A.
+
+ 1.7. "Larger Work" means a work which combines Covered Code or
+ portions thereof with code not governed by the terms of this License.
+
+ 1.8. "License" means this document.
+
+ 1.8.1. "Licensable" means having the right to grant, to the maximum
+ extent possible, whether at the time of the initial grant or
+ subsequently acquired, any and all of the rights conveyed herein.
+
+ 1.9. "Modifications" means any addition to or deletion from the
+ substance or structure of either the Original Code or any previous
+ Modifications. When Covered Code is released as a series of files, a
+ Modification is:
+ A. Any addition to or deletion from the contents of a file
+ containing Original Code or previous Modifications.
+
+ B. Any new file that contains any part of the Original Code or
+ previous Modifications.
+
+ 1.10. "Original Code" means Source Code of computer software code
+ which is described in the Source Code notice required by Exhibit A as
+ Original Code, and which, at the time of its release under this
+ License is not already Covered Code governed by this License.
+
+ 1.10.1. "Patent Claims" means any patent claim(s), now owned or
+ hereafter acquired, including without limitation, method, process,
+ and apparatus claims, in any patent Licensable by grantor.
+
+ 1.11. "Source Code" means the preferred form of the Covered Code for
+ making modifications to it, including all modules it contains, plus
+ any associated interface definition files, scripts used to control
+ compilation and installation of an Executable, or source code
+ differential comparisons against either the Original Code or another
+ well known, available Covered Code of the Contributor's choice. The
+ Source Code can be in a compressed or archival form, provided the
+ appropriate decompression or de-archiving software is widely available
+ for no charge.
+
+ 1.12. "You" (or "Your") means an individual or a legal entity
+ exercising rights under, and complying with all of the terms of, this
+ License or a future version of this License issued under Section 6.1.
+ For legal entities, "You" includes any entity which controls, is
+ controlled by, or is under common control with You. For purposes of
+ this definition, "control" means (a) the power, direct or indirect,
+ to cause the direction or management of such entity, whether by
+ contract or otherwise, or (b) ownership of more than fifty percent
+ (50%) of the outstanding shares or beneficial ownership of such
+ entity.
+
+2. Source Code License.
+
+ 2.1. The Initial Developer Grant.
+ The Initial Developer hereby grants You a world-wide, royalty-free,
+ non-exclusive license, subject to third party intellectual property
+ claims:
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Initial Developer to use, reproduce,
+ modify, display, perform, sublicense and distribute the Original
+ Code (or portions thereof) with or without Modifications, and/or
+ as part of a Larger Work; and
+
+ (b) under Patents Claims infringed by the making, using or
+ selling of Original Code, to make, have made, use, practice,
+ sell, and offer for sale, and/or otherwise dispose of the
+ Original Code (or portions thereof).
+
+ (c) the licenses granted in this Section 2.1(a) and (b) are
+ effective on the date Initial Developer first distributes
+ Original Code under the terms of this License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent license is
+ granted: 1) for code that You delete from the Original Code; 2)
+ separate from the Original Code; or 3) for infringements caused
+ by: i) the modification of the Original Code or ii) the
+ combination of the Original Code with other software or devices.
+
+ 2.2. Contributor Grant.
+ Subject to third party intellectual property claims, each Contributor
+ hereby grants You a world-wide, royalty-free, non-exclusive license
+
+ (a) under intellectual property rights (other than patent or
+ trademark) Licensable by Contributor, to use, reproduce, modify,
+ display, perform, sublicense and distribute the Modifications
+ created by such Contributor (or portions thereof) either on an
+ unmodified basis, with other Modifications, as Covered Code
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making, using, or
+ selling of Modifications made by that Contributor either alone
+ and/or in combination with its Contributor Version (or portions
+ of such combination), to make, use, sell, offer for sale, have
+ made, and/or otherwise dispose of: 1) Modifications made by that
+ Contributor (or portions thereof); and 2) the combination of
+ Modifications made by that Contributor with its Contributor
+ Version (or portions of such combination).
+
+ (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+ effective on the date Contributor first makes Commercial Use of
+ the Covered Code.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent license is
+ granted: 1) for any code that Contributor has deleted from the
+ Contributor Version; 2) separate from the Contributor Version;
+ 3) for infringements caused by: i) third party modifications of
+ Contributor Version or ii) the combination of Modifications made
+ by that Contributor with other software (except as part of the
+ Contributor Version) or other devices; or 4) under Patent Claims
+ infringed by Covered Code in the absence of Modifications made by
+ that Contributor.
+
+3. Distribution Obligations.
+
+ 3.1. Application of License.
+ The Modifications which You create or to which You contribute are
+ governed by the terms of this License, including without limitation
+ Section 2.2. The Source Code version of Covered Code may be
+ distributed only under the terms of this License or a future version
+ of this License released under Section 6.1, and You must include a
+ copy of this License with every copy of the Source Code You
+ distribute. You may not offer or impose any terms on any Source Code
+ version that alters or restricts the applicable version of this
+ License or the recipients' rights hereunder. However, You may include
+ an additional document offering the additional rights described in
+ Section 3.5.
+
+ 3.2. Availability of Source Code.
+ Any Modification which You create or to which You contribute must be
+ made available in Source Code form under the terms of this License
+ either on the same media as an Executable version or via an accepted
+ Electronic Distribution Mechanism to anyone to whom you made an
+ Executable version available; and if made available via Electronic
+ Distribution Mechanism, must remain available for at least twelve (12)
+ months after the date it initially became available, or at least six
+ (6) months after a subsequent version of that particular Modification
+ has been made available to such recipients. You are responsible for
+ ensuring that the Source Code version remains available even if the
+ Electronic Distribution Mechanism is maintained by a third party.
+
+ 3.3. Description of Modifications.
+ You must cause all Covered Code to which You contribute to contain a
+ file documenting the changes You made to create that Covered Code and
+ the date of any change. You must include a prominent statement that
+ the Modification is derived, directly or indirectly, from Original
+ Code provided by the Initial Developer and including the name of the
+ Initial Developer in (a) the Source Code, and (b) in any notice in an
+ Executable version or related documentation in which You describe the
+ origin or ownership of the Covered Code.
+
+ 3.4. Intellectual Property Matters
+ (a) Third Party Claims.
+ If Contributor has knowledge that a license under a third party's
+ intellectual property rights is required to exercise the rights
+ granted by such Contributor under Sections 2.1 or 2.2,
+ Contributor must include a text file with the Source Code
+ distribution titled "LEGAL" which describes the claim and the
+ party making the claim in sufficient detail that a recipient will
+ know whom to contact. If Contributor obtains such knowledge after
+ the Modification is made available as described in Section 3.2,
+ Contributor shall promptly modify the LEGAL file in all copies
+ Contributor makes available thereafter and shall take other steps
+ (such as notifying appropriate mailing lists or newsgroups)
+ reasonably calculated to inform those who received the Covered
+ Code that new knowledge has been obtained.
+
+ (b) Contributor APIs.
+ If Contributor's Modifications include an application programming
+ interface and Contributor has knowledge of patent licenses which
+ are reasonably necessary to implement that API, Contributor must
+ also include this information in the LEGAL file.
+
+ (c) Representations.
+ Contributor represents that, except as disclosed pursuant to
+ Section 3.4(a) above, Contributor believes that Contributor's
+ Modifications are Contributor's original creation(s) and/or
+ Contributor has sufficient rights to grant the rights conveyed by
+ this License.
+
+ 3.5. Required Notices.
+ You must duplicate the notice in Exhibit A in each file of the Source
+ Code. If it is not possible to put such notice in a particular Source
+ Code file due to its structure, then You must include such notice in a
+ location (such as a relevant directory) where a user would be likely
+ to look for such a notice. If You created one or more Modification(s)
+ You may add your name as a Contributor to the notice described in
+ Exhibit A. You must also duplicate this License in any documentation
+ for the Source Code where You describe recipients' rights or ownership
+ rights relating to Covered Code. You may choose to offer, and to
+ charge a fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Code. However, You
+ may do so only on Your own behalf, and not on behalf of the Initial
+ Developer or any Contributor. You must make it absolutely clear than
+ any such warranty, support, indemnity or liability obligation is
+ offered by You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred by the
+ Initial Developer or such Contributor as a result of warranty,
+ support, indemnity or liability terms You offer.
+
+ 3.6. Distribution of Executable Versions.
+ You may distribute Covered Code in Executable form only if the
+ requirements of Section 3.1-3.5 have been met for that Covered Code,
+ and if You include a notice stating that the Source Code version of
+ the Covered Code is available under the terms of this License,
+ including a description of how and where You have fulfilled the
+ obligations of Section 3.2. The notice must be conspicuously included
+ in any notice in an Executable version, related documentation or
+ collateral in which You describe recipients' rights relating to the
+ Covered Code. You may distribute the Executable version of Covered
+ Code or ownership rights under a license of Your choice, which may
+ contain terms different from this License, provided that You are in
+ compliance with the terms of this License and that the license for the
+ Executable version does not attempt to limit or alter the recipient's
+ rights in the Source Code version from the rights set forth in this
+ License. If You distribute the Executable version under a different
+ license You must make it absolutely clear that any terms which differ
+ from this License are offered by You alone, not by the Initial
+ Developer or any Contributor. You hereby agree to indemnify the
+ Initial Developer and every Contributor for any liability incurred by
+ the Initial Developer or such Contributor as a result of any such
+ terms You offer.
+
+ 3.7. Larger Works.
+ You may create a Larger Work by combining Covered Code with other code
+ not governed by the terms of this License and distribute the Larger
+ Work as a single product. In such a case, You must make sure the
+ requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+ If it is impossible for You to comply with any of the terms of this
+ License with respect to some or all of the Covered Code due to
+ statute, judicial order, or regulation then You must: (a) comply with
+ the terms of this License to the maximum extent possible; and (b)
+ describe the limitations and the code they affect. Such description
+ must be included in the LEGAL file described in Section 3.4 and must
+ be included with all distributions of the Source Code. Except to the
+ extent prohibited by statute or regulation, such description must be
+ sufficiently detailed for a recipient of ordinary skill to be able to
+ understand it.
+
+5. Application of this License.
+
+ This License applies to code to which the Initial Developer has
+ attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+ 6.1. New Versions.
+ BBC Communications Corporation ("Netscape") may publish revised
+ and/or new versions of the License from time to time. Each version
+ will be given a distinguishing version number.
+
+ 6.2. Effect of New Versions.
+ Once Covered Code has been published under a particular version of the
+ License, You may always continue to use it under the terms of that
+ version. You may also choose to use such Covered Code under the terms
+ of any subsequent version of the License published by BBC. No one
+ other than BBC has the right to modify the terms applicable to
+ Covered Code created under this License.
+
+ 6.3. Derivative Works.
+ If You create or use a modified version of this License (which you may
+ only do in order to apply it to code which is not already Covered Code
+ governed by this License), You must (a) rename Your license so that
+ the phrases "Mozilla", "MOZILLAPL", "MOZPL", "BBC",
+ "MPL", "NPL" or any confusingly similar phrase do not appear in your
+ license (except to note that your license differs from this License)
+ and (b) otherwise make it clear that Your version of the license
+ contains terms which differ from the Mozilla Public License and
+ BBC Public License. (Filling in the name of the Initial
+ Developer, Original Code or Contributor in the notice described in
+ Exhibit A shall not of themselves be deemed to be modifications of
+ this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+ COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+ DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+ THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+ IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+ YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+ COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+ OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+ 8.1. This License and the rights granted hereunder will terminate
+ automatically if You fail to comply with terms herein and fail to cure
+ such breach within 30 days of becoming aware of the breach. All
+ sublicenses to the Covered Code which are properly granted shall
+ survive any termination of this License. Provisions which, by their
+ nature, must remain in effect beyond the termination of this License
+ shall survive.
+
+ 8.2. If You initiate litigation by asserting a patent infringement
+ claim (excluding declatory judgment actions) against Initial Developer
+ or a Contributor (the Initial Developer or Contributor against whom
+ You file such action is referred to as "Participant") alleging that:
+
+ (a) such Participant's Contributor Version directly or indirectly
+ infringes any patent, then any and all rights granted by such
+ Participant to You under Sections 2.1 and/or 2.2 of this License
+ shall, upon 60 days notice from Participant terminate prospectively,
+ unless if within 60 days after receipt of notice You either: (i)
+ agree in writing to pay Participant a mutually agreeable reasonable
+ royalty for Your past and future use of Modifications made by such
+ Participant, or (ii) withdraw Your litigation claim with respect to
+ the Contributor Version against such Participant. If within 60 days
+ of notice, a reasonable royalty and payment arrangement are not
+ mutually agreed upon in writing by the parties or the litigation claim
+ is not withdrawn, the rights granted by Participant to You under
+ Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+ the 60 day notice period specified above.
+
+ (b) any software, hardware, or device, other than such Participant's
+ Contributor Version, directly or indirectly infringes any patent, then
+ any rights granted to You by such Participant under Sections 2.1(b)
+ and 2.2(b) are revoked effective as of the date You first made, used,
+ sold, distributed, or had made, Modifications made by that
+ Participant.
+
+ 8.3. If You assert a patent infringement claim against Participant
+ alleging that such Participant's Contributor Version directly or
+ indirectly infringes any patent where such claim is resolved (such as
+ by license or settlement) prior to the initiation of patent
+ infringement litigation, then the reasonable value of the licenses
+ granted by such Participant under Sections 2.1 or 2.2 shall be taken
+ into account in determining the amount or value of any payment or
+ license.
+
+ 8.4. In the event of termination under Sections 8.1 or 8.2 above,
+ all end user license agreements (excluding distributors and resellers)
+ which have been validly granted by You or any distributor hereunder
+ prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+ DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+ OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+ ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+ CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+ WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+ RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+ PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+ EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+ THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+ The Covered Code is a "commercial item," as that term is defined in
+ 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+ software" and "commercial computer software documentation," as such
+ terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+ C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+ all U.S. Government End Users acquire Covered Code with only those
+ rights set forth herein.
+
+11. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the extent
+ necessary to make it enforceable. This License shall be governed by
+ California law provisions (except to the extent applicable law, if
+ any, provides otherwise), excluding its conflict-of-law provisions.
+ With respect to disputes in which at least one party is a citizen of,
+ or an entity chartered or registered to do business in the United
+ States of America, any litigation relating to this License shall be
+ subject to the jurisdiction of the Federal Courts of the Northern
+ District of California, with venue lying in Santa Clara County,
+ California, with the losing party responsible for costs, including
+ without limitation, court costs and reasonable attorneys' fees and
+ expenses. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly excluded.
+ Any law or regulation which provides that the language of a contract
+ shall be construed against the drafter shall not apply to this
+ License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or indirectly,
+ out of its utilization of rights under this License and You agree to
+ work with Initial Developer and Contributors to distribute such
+ responsibility on an equitable basis. Nothing herein is intended or
+ shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+ Initial Developer may designate portions of the Covered Code as
+ "Multiple-Licensed". "Multiple-Licensed" means that the Initial
+ Developer permits you to utilize portions of the Covered Code under
+ Your choice of the GPL, LGPL, MIT or the alternative licenses, if
+ any, specified by the Initial Developer in the file described in
+ Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+ ``The contents of this file are subject to the Mozilla Public License
+ Version 1.1 (the "License"); you may not use this file except in
+ compliance with the License. You may obtain a copy of the License at
+ http://www.mozilla.org/MPL/
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ License for the specific language governing rights and limitations
+ under the License.
+
+ The Original Code is ______________________________________.
+
+ The Initial Developer of the Original Code is ________________________.
+ Portions created by ______________________ are Copyright (C) ______
+ _______________________. All Rights Reserved.
+
+ Contributor(s): ______________________________________.
+
+ Alternatively, the contents of this file may be used under the terms
+ of the _____ license (the "[___] License"), in which case the
+ provisions of [______] License are applicable instead of those
+ above. If you wish to allow use of your version of this file only
+ under the terms of the [____] License and not to allow others to use
+ your version of this file under the MPL, indicate your decision by
+ deleting the provisions above and replace them with the notice and
+ other provisions required by the [___] License. If you do not delete
+ the provisions above, a recipient may use your version of this file
+ under either the MPL or the [___] License."
+
+ [NOTE: The text of this Exhibit A may differ slightly from the text of
+ the notices in the Source Code files of the Original Code. You should
+ use the text of this Exhibit A rather than the text found in the
+ Original Code Source Code for Your Modifications.]
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..3c1de92
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,56 @@
+include $(top_srcdir)/coverage.mk
+
+SUBDIRS = inc src
+
+if ENABLE_TESTS
+SUBDIRS += qa
+endif
+
+ACLOCAL_AMFLAGS = -I m4
+
+pkgconfig_DATA = \
+ libcmis-@LIBCMIS_API_VERSION@.pc \
+ libcmis-c-@LIBCMIS_API_VERSION@.pc
+pkgconfigdir = $(libdir)/pkgconfig
+
+if ENABLE_MAN
+cmis-client.1: doc/cmis-client.xml
+ $(DOCBOOK2MAN) $<
+
+man_MANS = cmis-client.1
+endif
+
+EXTRA_DIST = \
+ libcmis.pc.in \
+ libcmis-c.pc.in \
+ COPYING.MPL \
+ COPYING.GPL \
+ COPYING.LGPL \
+ doc/cmis-client.xml.in \
+ cppcheck-suppress \
+ qa/libcmis/data
+
+DISTCLEANFILES = \
+ cmis-client.1 \
+ libcmis-@LIBCMIS_API_VERSION@.pc \
+ libcmis-c-@LIBCMIS_API_VERSION@.pc
+
+dist-hook:
+ @if test -d "$(srcdir)/.git"; \
+ then \
+ echo Creating ChangeLog && \
+ ( cd "$(top_srcdir)" && \
+ echo '# Generated by Makefile. Do not edit.'; echo; \
+ $(top_srcdir)/missing --run git log --pretty=medium ) > ChangeLog.tmp \
+ && mv -f ChangeLog.tmp $(top_distdir)/ChangeLog \
+ || ( rm -f ChangeLog.tmp ; \
+ echo Failed to generate ChangeLog >&2 ); \
+ else \
+ echo A git clone is required to generate a ChangeLog >&2; \
+ fi
+
+cppcheck:
+ @CPPCHECK@ -q --enable=style,performance,portability \
+ -j @CPPCHECK_PARALLELISM@ \
+ --suppressions-list=@SRCDIR@/cppcheck-suppress \
+ --error-exitcode=1 @SRCDIR@
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..9fb74aa
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,108 @@
+0.1.0
+
+ * Generic
+ * Anonymous connection
+ * AtomPub binding
+ * Get the content hierarchy using the down relations
+ * Get the content of a document
+ * Query nodes by ID
+
+0.2.0
+
+ * Generic
+ * Support for authentication in the API
+ * Callback for providing interactive authentication
+ * Added API to create documents and folders
+ * Added API to delete documents and folders
+ * AtomPub binding
+ * Handle all the authentication methods that can be handled by
+ libcurl like Basic, NTLM...
+ * Decode base64 encoded content sent by SharePoint
+ * Set the content of a document
+ * Query nodes by path
+ * Get the allowable actions for a node
+ * Object properties can be updated
+ * Query object types
+ * Creation of folders and documents
+ * Deletion of folders and documents
+
+0.2.1
+
+ * Fixed documentation distribution
+
+0.2.2
+
+ * Fixed soname for the library
+ * Allow building against libcurl 7.13.1
+
+0.2.3
+
+ * Fixed SharePoint support
+ * Conditional build of man page
+
+0.3.0
+
+ * Added Document::checkOut(), Document::cancelCheckout() and Document::checkIn()
+ * Added Object::move( ) -- Grau Data
+ * Fixes for xcmis and cloudoku.com -- Grau Data
+ * Added Document::getAllVersions( )
+ * WebService binding implementation
+ * Session factory automatically detects which binding to use
+ * C wrapper API
+ * Unit tests are now split between quick ones and the ones needing a CMIS server
+
+0.4.0
+
+ * Support for Google Drive protocol as a binding
+ * Support for Alfresco in the cloud
+ * Added OAuth2 authentication support
+ * Added API to configure HTTP proxy
+ * Handle invalid SSL certificate problems
+ * Added API for renditions
+ * Moved the CMIS Atom binding unit tests to use libcurl mockup
+ * Added repository capabilities support (still missing
+ capabilityCreatablePropertyTypes and capabilityNewTypeSettableAttributes)
+
+0.5.0
+
+ * Completely removed the dependency on InMemory server for unit tests
+ * Minimized the number of HTTP requests sent by SessionFactory::createSession
+ * Added Session::getBaseTypes()
+
+0.5.1
+
+ * Fixed a crash when server response did not contain cmis:baseTypeId
+ property (tdf#90351)
+ * Removed the requirement for non-empty password when using HTTP
+ authentication credentials
+ * Fixed build with boost 1.60 and gcc 5
+ * Fixed a few problems found by Coverity
+ * Fixed a busload of memory leaks
+
+0.5.2
+
+ * Fixed Google Drive login, broken by Google's new 2-page login sequence
+ * Added support for Google Drive two-factor authentication
+ * Fixed access to SharePoint root folder (tdf#101385)
+ * Limited the maximal number of redirections to 20 (rhbz#1410197)
+ * Switched library implementation to C++11 (the API remains
+ C++98-compatible)
+ * Fixed build with boost >= 1.68.0 (#19)
+ * Fixed encoding of OAuth2 credentials
+ * Dropped cppcheck run from "make check". A new "make cppcheck" target
+ was created for it
+ * Added proper API symbol exporting
+ * Speeded up building of tests a bit
+ * Fixed a few issues found by coverity and cppcheck
+
+0.6.0
+
+ * Merged outstanding LibreOffice, etc. modifications
+
+0.6.1
+
+ * add a callback that can be used to configure libcurl
+
+0.6.2
+
+ * fix up version-info
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4e8e4e3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,16 @@
+[![Build Status](https://travis-ci.org/tdf/libcmis.svg?branch=master)](https://travis-ci.org/tdf/libcmis)
+[![Total alerts](https://img.shields.io/lgtm/alerts/g/tdf/libcmis.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/tdf/libcmis/alerts/)
+[![Coverity Scan](https://scan.coverity.com/projects/17516/badge.svg)](https://scan.coverity.com/projects/tdf-libcmis)
+
+Objective
+---------
+
+Libcmis aims at providing a C/C++ client library for the CMIS protocol.
+A cmis-client tool is maintained to help testing and showing libcmis features.
+
+Dependencies
+------------
+
+ * libxml2
+ * libcurl
+ * boost
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..84165ae
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+touch ChangeLog
+
+if [ ! -e ltmain.sh ]; then
+ libtoolize
+fi
+
+aclocal -I m4
+automake -a -c --foreign
+autoconf
+test x$NOCONFIGURE = x && ./configure $@
diff --git a/cmis-test.sh b/cmis-test.sh
new file mode 100644
index 0000000..de315ab
--- /dev/null
+++ b/cmis-test.sh
@@ -0,0 +1,139 @@
+#!/bin/sh
+# libcmis
+# Version: MPL 1.1 / GPLv2+ / LGPLv2+
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License or as specified alternatively below. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# Major Contributor(s):
+# Copyright (C) 2012 SUSE <cbosdonnat@suse.com>
+#
+#
+# All Rights Reserved.
+#
+# For minor contributions see the git repository.
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+# the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+# in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+# instead of those above.
+
+while [[ $# > 1 ]]
+do
+ key="$1"
+ shift
+
+ case $key in
+ --url)
+ BINDING_URL="$1"
+ shift;;
+ -u)
+ USER="$1"
+ shift;;
+ -p)
+ PASS="$1"
+ shift;;
+ -r)
+ REPO="$1"
+ shift;;
+ --oauth2-client-id)
+ OAUTH2_CLIENT_ID="$1"
+ shift;;
+ --oauth2-client-secret)
+ OAUTH2_CLIENT_SECRET="$1"
+ shift;;
+ --oauth2-scope)
+ OAUTH2_SCOPE="$1"
+ shift;;
+ --oauth2-auth-url)
+ OAUTH2_AUTH_URL="$1"
+ shift;;
+ --oauth2-token-url)
+ OAUTH2_TOKEN_URL="$1"
+ shift;;
+ --oauth2-redirect-uri)
+ OAUTH2_REDIRECT_URI="$1"
+ shift;;
+ --base-folder)
+ BASE_FOLDER="$1"
+ shift;;
+ *)
+ ;;
+ esac
+done
+
+function cmis_client ( )
+{
+ repo_opt=
+ if test "z$REPO" != "z"; then
+ repo_opt=" -r \"$REPO\""
+ fi
+
+ args="--url "$BINDING_URL" -u "$USER" -p "$PASS"$repo_opt"
+ if test "z$OAUTH2_CLIENT_ID" != "z"; then
+ args="$args --oauth2-client-id "$OAUTH2_CLIENT_ID"
+ --oauth2-client-secret "$OAUTH2_CLIENT_SECRET"
+ --oauth2-scope "$OAUTH2_SCOPE"
+ --oauth2-auth-url "$OAUTH2_AUTH_URL"
+ --oauth2-token-url "$OAUTH2_TOKEN_URL"
+ --oauth2-redirect-uri "$OAUTH2_REDIRECT_URI""
+ fi
+
+ args="$args "$@""
+ src/cmis-client $args
+}
+
+function get_versionable_type ( )
+{
+ versionable_type=
+ test_type=$1
+
+ # Is test_type versionable?
+ versionable=`cmis_client type-by-id $test_type | grep ^Versionable: | cut -d ' ' -f 2`
+ if test "z$versionable" == "z1"; then
+ versionable_type=$test_type
+ else
+ # Otherwise, loop over its children
+ children=`cmis_client type-by-id $test_type | sed -n -e '/Children type/,/^[^ ]/ p' | grep -e '^\ ' | tr '()' '\t' | cut -f 2`
+ for type_id in $children; do
+ versionable_type=`get_versionable_type $type_id`
+ if test "z$versionable_type" != "z"; then
+ break
+ fi
+ done
+ fi
+
+ echo -n $versionable_type
+}
+
+#First get the Root Id
+ROOT_ID=`cmis_client show-root | grep '^Id:' | cut -d ' ' -f 2`
+
+# Create a test folder
+test_folder_name=$BASE_FOLDER"/test-$$"
+test_folder_id=`cmis_client create-folder $ROOT_ID $test_folder_name | grep '^Id:' | cut -d ' ' -f 2`
+
+# Get a Versionable document type, not alway cmis:document for all servers
+versionable_type=`get_versionable_type "cmis:document"`
+
+# Create a versionable document
+file_path=NEWS
+file_mime=`file --mime-type $file_path | cut -d ' ' -f 2`
+doc1_id=`cmis_client --object-type $versionable_type --input-file $file_path --input-type $file_mime create-document $test_folder_id doc_1 | grep '^Id:' | cut -d ' ' -f 2`
+
+# Checkout the document
+doc1_pwc=`cmis_client checkout $doc1_id | grep '^Id:' | cut -d ' ' -f 2`
+
+# TODO Checkin the document
+doc1_checkIn=`cmis_client --input-file $file_path --input-type $file_mime --message checkin_message checkin $doc1_id | grep '^Id:' | cut -d ' ' -f 2`
+
+# Cleanup the test folder to remove all traces of the tests
+cmis_client delete $test_folder_id
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..218cf9f
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,224 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+m4_define([libcmis_major_version], [0])
+m4_define([libcmis_minor_version], [6])
+m4_define([libcmis_micro_version], [2])
+m4_define([libcmis_api_version], [libcmis_major_version.libcmis_minor_version])
+m4_define([libcmis_version],[libcmis_api_version.libcmis_micro_version])
+
+
+AC_PREREQ([2.63])
+AC_INIT([libcmis], [libcmis_version])
+AM_INIT_AUTOMAKE([1.10 foreign dist-xz])
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
+# Checks for programs.
+AC_PROG_CC
+AC_PROG_CPP
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_MAKE_SET
+AC_PROG_LIBTOOL
+LT_INIT([win32-dll disable-static pic-only])
+AC_CANONICAL_HOST
+
+AX_CXX_COMPILE_STDCXX_11
+
+# Check the options
+AC_ARG_ENABLE(client,
+ AC_HELP_STRING([--disable-client],[Compile only the library, not the client tool]),
+ enable_client=$enableval, enable_client=yes)
+AM_CONDITIONAL(ENABLE_CLIENT, test "x$enable_client" != "xno")
+
+AC_ARG_ENABLE([tests],
+ [AS_HELP_STRING([--disable-tests], [Do not build the unit tests])],
+ [enable_tests="$enableval"],
+ [enable_tests=yes]
+)
+AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" != "xno")
+
+AC_ARG_ENABLE([coverage],
+ [AS_HELP_STRING([--enable-coverage], [Extract test coverage data])],
+ [enable_coverage="$enableval"],
+ [enable_coverage=no]
+)
+AM_CONDITIONAL(ENABLE_COVERAGE, test "x$enable_coverage" != "xno")
+
+AS_IF([test "x$enable_coverage" != "xno"], [
+ enable_tests=yes
+
+ # Make sure we have gcc
+ if test "x$GCC" != "xyes"; then
+ AC_MSG_ERROR([GCC is required for --enable-coverage])
+ fi
+
+ AC_CHECK_PROG(LCOV, lcov, lcov)
+ AC_CHECK_PROG(GENHTML, genhtml, genhtml)
+
+ AS_IF([test "x$ac_cv_prog_LCOV" = "x"], [
+ AC_MSG_ERROR([lcov is required for --enable-coverage])
+ ])
+ AS_IF([test "x$ac_cv_prog_GENHTML" = "x"], [
+ AC_MSG_ERROR([genhtml is required for --enable-coverage])
+ ])
+
+ CFLAGS="-g -O0 --coverage"
+ CXXFLAGS="-g -O0 --coverage"
+ LDFLAGS+="--coverage"
+])
+
+
+LIBCMIS_API_VERSION=libcmis_api_version
+AC_SUBST(LIBCMIS_API_VERSION)
+
+AC_CONFIG_MACRO_DIR([m4])
+
+for top_builddir in . .. ../.. $ac_auxdir $ac_auxdir/..; do
+ test -f $top_builddir/configure && break
+done
+
+SRCDIR=$srcdir
+AC_SUBST(SRCDIR)
+
+AC_LANG([C++])
+
+# ==========================
+# Platform check for windows
+# ==========================
+AC_MSG_CHECKING([for native Win32])
+AS_CASE([$host], [*-*-mingw*], [native_win32=yes], [native_win32=no])
+AC_MSG_RESULT([$native_win32])
+AM_CONDITIONAL(OS_WIN32, [test "x$native_win32" = "xyes"])
+
+# ====================
+# Check for visibility
+# ====================
+AC_MSG_CHECKING([for -fvisibility=hidden compiler flag])
+saved_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS -fvisibility=hidden"
+AC_TRY_COMPILE([], [], [have_visibility=yes], [have_visibility=no])
+AC_MSG_RESULT([$have_visibility])
+CPPFLAGS="$saved_CPPFLAGS"
+AX_GCC_FUNC_ATTRIBUTE([visibility])
+AM_CONDITIONAL([ENABLE_VISIBILITY], [
+ test "x$have_visibility" = "xyes" && test "x$ax_cv_have_func_attribute_visibility" = "xyes"])
+
+# =============
+# Documentation
+# =============
+AC_ARG_WITH(man,
+ [AS_HELP_STRING([--without-man], [Do not build manpage])],
+ [with_man="$withval"],
+ [with_man=yes]
+)
+AS_IF([test "x$with_man" != "xno"], [
+ build_man=yes
+ AS_IF([test -z "$DOCBOOK2MAN"], [
+ AC_PATH_PROGS([DOCBOOK2MAN], [docbook2x-man docbook-to-man docbook2man.pl docbook2man])
+ AS_IF([test -z "$DOCBOOK2MAN"], [
+ AC_MSG_ERROR([docbook-to-man is missing. Install docbook2X package.])
+ ])
+ ])
+], [build_man=no])
+AC_SUBST(DOCBOOK2MAN)
+AM_CONDITIONAL([ENABLE_MAN], [test "x$build_man" != "xno"])
+
+# ========
+# Cppcheck
+# ========
+AC_PATH_PROG(CPPCHECK,[cppcheck],[])
+AS_IF([test "x$ac_cv_path_CPPCHECK" != "x"], [enable_cppcheck=yes], [enable_cppcheck=no])
+AC_SUBST(CPPCHECK)
+AC_PATH_PROG([NPROC], [nproc], [])
+AS_IF([test "x$NPROC" != "x"], [CPPCHECK_PARALLELISM=`$NPROC`], [CPPCHECK_PARALLELISM=1])
+AC_SUBST([CPPCHECK_PARALLELISM])
+
+AC_ARG_ENABLE([werror],
+ [AS_HELP_STRING([--disable-werror], [Treat all warnings as errors, usefull for development])],
+ [enable_werror="$enableval"],
+ [enable_werror=yes]
+)
+AS_IF([test x"$enable_werror" != "xno"], [
+ CFLAGS="$CFLAGS -Werror"
+ CXXFLAGS="$CXXFLAGS -Werror"
+])
+AS_IF([test x"$GCC" = xyes], [
+ # Be tough with warnings and produce less careless code
+ CFLAGS="$CFLAGS -Wall -pedantic -Wshadow -Wendif-labels -Wextra"
+ CXXFLAGS="$CXXFLAGS -Wall -pedantic -Weffc++ -Wshadow -Wendif-labels -Wextra -Wsign-promo -Woverloaded-virtual -Wnon-virtual-dtor -Wsign-promo"
+])
+
+# Check for curl
+PKG_CHECK_MODULES(CURL, [libcurl])
+AC_SUBST(CURL_CFLAGS)
+AC_SUBST(CURL_LIBS)
+
+# Check for lixml2
+PKG_CHECK_MODULES(XML2, [libxml-2.0])
+AC_SUBST(XML2_CFLAGS)
+AC_SUBST(XML2_LIBS)
+
+# Check for cppunit
+AS_IF([test "x$enable_tests" != "xno"], [
+ PKG_CHECK_MODULES(CPPUNIT, cppunit >= 1.12 )
+ AC_SUBST(CPPUNIT_CFLAGS)
+ AC_SUBST(CPPUNIT_LIBS)
+])
+
+# Check for boost
+m4_pattern_allow([^BOOST_])
+
+BOOST_REQUIRE([1.36])
+BOOST_DATE_TIME
+BOOST_SMART_PTR
+BOOST_STRING_ALGO
+BOOST_UUID
+
+AS_IF([test "x$enable_client" != "xno"], [
+ BOOST_PROGRAM_OPTIONS
+])
+AC_SUBST(BOOST_CPPFLAGS)
+
+# Checks for header files.
+AC_CHECK_HEADERS([stdlib.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_STDBOOL
+AC_C_INLINE
+AC_TYPE_MODE_T
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+
+AC_CONFIG_FILES([
+ Makefile
+ doc/cmis-client.xml
+ inc/Makefile
+ inc/libcmis-c/Makefile
+ inc/libcmis/Makefile
+ libcmis-c-$LIBCMIS_API_VERSION.pc:libcmis-c.pc.in
+ libcmis-$LIBCMIS_API_VERSION.pc:libcmis.pc.in
+ qa/Makefile
+ qa/libcmis-c/Makefile
+ qa/libcmis/Makefile
+ qa/mockup/Makefile
+ src/Makefile
+ src/libcmis-c/Makefile
+ src/libcmis/Makefile
+])
+AC_OUTPUT
+
+AC_MSG_NOTICE([
+
+libcmis $VERSION:
+ Prefix: ${prefix}
+ Compiler: ${CXX}
+ Compiler flags: ${CXXFLAGS}
+ client: ${enable_client}
+ werror: ${enable_werror}
+ tests: ${enable_tests}
+ test coverage: ${enable_coverage}
+ mans: ${build_man}
+])
diff --git a/coverage.mk b/coverage.mk
new file mode 100644
index 0000000..01cbadd
--- /dev/null
+++ b/coverage.mk
@@ -0,0 +1,22 @@
+.PHONY: coverage genlcov coverage-clean
+
+coverage:
+ -$(MAKE) $(AM_MAKEFLAGS) -k check
+ $(MAKE) $(AM_MAKEFLAGS) genlcov
+
+infos = libcmis-lcov.info libcmis-c-lcov.info
+$(infos): %-lcov.info:
+ $(LCOV) --directory $(top_builddir)/src/$* \
+ --base-directory $(top_builddir)/src/$* \
+ --capture \
+ --output-file $@ \
+ --no-external \
+ --compat-libtool
+genlcov: $(infos)
+ LANG=C $(GENHTML) --output-directory libcmis-lcov --title "Libcmis Code Coverage" --legend --show-details $^
+ @echo "file://$(abs_top_builddir)/libcmis-lcov/index.html"
+
+coverage-clean:
+ -$(LCOV) --directory $(top_builddir) -z
+ -rm -rf $(infos) libcmis-lcov
+ -find $(top_builddir) -type f -name "*.gcda" -o -name "*.gcno" -o -name "*.gcov" -exec rm "{}" \;
diff --git a/cppcheck-suppress b/cppcheck-suppress
new file mode 100644
index 0000000..9ef8482
--- /dev/null
+++ b/cppcheck-suppress
@@ -0,0 +1,3 @@
+publicAllocationError:qa/libcmis/test-decoder.cxx
+noExplicitConstructor
+noExplicitCopyMoveConstructor
diff --git a/doc/cmis-client.xml.in b/doc/cmis-client.xml.in
new file mode 100644
index 0000000..a1b8c9f
--- /dev/null
+++ b/doc/cmis-client.xml.in
@@ -0,0 +1,570 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+<refentry>
+ <refentryinfo>
+ <date>2018-12-23</date>
+ </refentryinfo>
+ <refmeta>
+ <refentrytitle>cmis-client</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo>@PACKAGE_STRING@</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>
+ <application>cmis-client</application>
+ </refname>
+ <refpurpose>
+ command line CMIS client tool.
+ </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <refsynopsisdivinfo>
+ <date>2012-01-27</date>
+ </refsynopsisdivinfo>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="plain">help</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">list-repos</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="plain">repo-infos</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="plain">show-root</arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="plain">get-content <replaceable>id</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="plain">--input-file <replaceable>path/to/file</replaceable></arg>
+ <arg choice="plain">--input-type <replaceable>mime/type</replaceable></arg>
+ <arg choice="opt">--input-name <replaceable>name.ext</replaceable></arg>
+ <arg choice="plain">set-content <replaceable>id</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="opt">--object-type <replaceable>some:cmistype</replaceable></arg>
+ <arg choice="opt" rep="repeat">--object-property <replaceable>prop-id=prop-value</replaceable></arg>
+ <arg choice="plain">create-folder <replaceable>parent-id name</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="plain">--input-file <replaceable>path/to/file</replaceable></arg>
+ <arg choice="plain">--input-type <replaceable>mime/type</replaceable></arg>
+ <arg choice="opt">--input-name <replaceable>name.ext</replaceable></arg>
+ <arg choice="opt">--object-type <replaceable>some:cmistype</replaceable></arg>
+ <arg choice="opt" rep="repeat">--object-property <replaceable>prop-id=prop-value</replaceable></arg>
+ <arg choice="plain">create-document <replaceable>parent-id name</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="opt" rep="repeat">--object-property <replaceable>prop-id=prop-value</replaceable></arg>
+ <arg choice="plain">update-object <replaceable>object-id</replaceable></arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <group choice="plain">
+ <arg>type-by-id</arg>
+ <arg>show-by-id</arg>
+ <arg>show-by-path</arg>
+ <arg>delete</arg>
+ </group>
+ <arg rep="repeat" choice="plain">
+ <replaceable>arg</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <group choice="plain">
+ <arg>checkout</arg>
+ <arg>cancel-checkout</arg>
+ <arg>get-versions</arg>
+ </group>
+ <arg choice="plain">
+ <replaceable>arg</replaceable>
+ </arg>
+ </cmdsynopsis>
+ <cmdsynopsis>
+ <command>cmis-client</command>
+ <arg choice="opt">-v</arg>
+ <arg choice="opt">-u <replaceable>login</replaceable></arg>
+ <arg choice="opt">-p <replaceable>secret</replaceable></arg>
+ <arg choice="plain">--url <replaceable>url://to/binding</replaceable></arg>
+ <arg choice="plain">-r <replaceable>repo-id</replaceable></arg>
+ <arg choice="opt">--input-file <replaceable>path/to/file</replaceable></arg>
+ <arg choice="opt">--input-type <replaceable>mime/type</replaceable></arg>
+ <arg choice="opt">--input-name <replaceable>name.ext</replaceable></arg>
+ <arg choice="opt" rep="repeat">--object-property <replaceable>prop-id=prop-value</replaceable></arg>
+ <arg choice="opt">--major</arg>
+ <arg choice="opt">--message</arg>
+ <arg choice="plain">checkin <replaceable>pwc id</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <refsect1info>
+ <date>2012-01-27</date>
+ </refsect1info>
+ <title>DESCRIPTION</title>
+ <para>
+ The <command>cmis-client</command> tool sends queries over the net to a CMIS-enabled server
+ to access or modify its content. It is originally demonstrating what libcmis is capable of.
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>OPTIONS</title>
+ <refsect2>
+ <title>GLOBAL OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>-v, --verbose</term>
+ <listitem>
+ <para>
+ Shows a lot of information to monitor what is happening behind the scene.
+ This helps a lot to debug libcmis.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--help</term>
+ <listitem>
+ <para>
+ Show the help and exit. This is equivalent to use the help command.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--url <replaceable class="parameter">url://to/binding</replaceable></term>
+ <listitem>
+ <para><replaceable class="parameter">url://to/binding</replaceable> needs to point to the service document of
+ either AtomPub or WebService binding.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-r,--repository <replaceable class="parameter">repo-id</replaceable></term>
+ <listitem>
+ <para>
+ Operate on the <replaceable class="parameter">repo-id</replaceable> CMIS repository.
+ If there is only one repository on the server, this parameter is not needed and that
+ repository will be automatically selected. Use this parameter if there are several
+ repositories on the server.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-u,--username <replaceable class="parameter">login</replaceable></term>
+ <listitem>
+ <para>
+ Connect as <replaceable class="parameter">login</replaceable> to the CMIS server.
+ If not provided connect anonymously.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-p,--password <replaceable class="parameter">secret</replaceable></term>
+ <listitem>
+ <para>
+ Use <replaceable class="parameter">secret</replaceable> to authenticate on the CMIS server.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--no-ssl-check</term>
+ <listitem>
+ <para>
+ Disables the SSL certificate verifications. Lowers the security, but may be handy
+ to work around bad certificates like expired or self-signed ones.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--proxy <replaceable class="parameter">url</replaceable></term>
+ <listitem>
+ <para>
+ Use <replaceable class="parameter">url</replaceable> as the HTTP proxy.
+ Setting this value will override the system proxy settings.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--proxy-username <replaceable class="parameter">login</replaceable></term>
+ <listitem>
+ <para>
+ Use <replaceable class="parameter">login</replaceable> to authenticate on the HTTP proxy.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--proxy-password <replaceable class="parameter">secret</replaceable></term>
+ <listitem>
+ <para>
+ Use <replaceable class="parameter">secret</replaceable> to authenticate on the HTTP proxy.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--noproxy <replaceable class="parameter">list</replaceable></term>
+ <listitem>
+ <para>
+ Proxy settings won't apply to hostnames and domain names listed
+ in <replaceable class="parameter">list</replaceable>.
+ This value is a coma separated list.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--oauth2-client-id <replaceable class="parameter">client_id</replaceable></term>
+ <listitem>
+ <para>
+ Application client id to use in the OAuth2 authentication flow.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--oauth2-client-secret <replaceable class="parameter">client_secret</replaceable></term>
+ <listitem>
+ <para>
+ Application client secret to use in the OAuth2 authentication flow.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--oauth2-auth-url <replaceable class="parameter">url</replaceable></term>
+ <listitem>
+ <para>
+ URL to authenticate the user in the OAuth2 authentication flow.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--oauth2-token-url <replaceable class="parameter">url</replaceable></term>
+ <listitem>
+ <para>
+ URL to authenticate the application in the OAuth2 authentication flow.
+ The access and refresh tokens are provided by this URL.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--oauth2-redirect-uri <replaceable class="parameter">uri</replaceable></term>
+ <listitem>
+ <para>
+ URI where the OAuth2 authentication flow will redirect after a sucessful
+ authentication.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--oauth2-scope <replaceable class="parameter">scope</replaceable></term>
+ <listitem>
+ <para>
+ Requested scope to access in the OAuth2 authentication flow.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ <refsect2>
+ <title>MODIFICATION OPERATIONS OPTIONS</title>
+ <variablelist>
+ <varlistentry>
+ <term>--input-file <replaceable class="parameter">path/to/file</replaceable></term>
+ <listitem>
+ <para>
+ Upload <replaceable class="parameter">path/to/file</replaceable> as the new content stream
+ of the object.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--input-type <replaceable class="parameter">mime/type</replaceable></term>
+ <listitem>
+ <para>
+ Set the mime type of the new content stream of the object to <replaceable class="parameter">mime/type</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--input-name <replaceable class="parameter">name.ext</replaceable></term>
+ <listitem>
+ <para>
+ Set the remote content stream filename of the new content stream of the object to <replaceable class="parameter">name.ext</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--object-type <replaceable class="parameter">some:cmistype</replaceable></term>
+ <listitem>
+ <para>
+ Set the object type of the CMIS object to be created to <replaceable class="parameter">some:cmistype</replaceable>.
+ This is the equivalent of --object-property cmis:objectTypeId=some:cmistype.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--object-property <replaceable class="parameter">prop-id=prop-value</replaceable></term>
+ <listitem>
+ <para>
+ Set a property to be updated or added to the CMIS object. <replaceable class="parameter">prop-id</replaceable> is
+ the property definition id and <replaceable class="parameter">prop-value</replaceable> is the value to set on it.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>--major</term>
+ <listitem>
+ <para>
+ Create a major version when performing a checkin.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-m, --message <replaceable class="parameter">message</replaceable></term>
+ <listitem>
+ <para>
+ Set the checking message.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ <refsect2>
+ <title>COMMANDS</title>
+ <variablelist>
+ <varlistentry>
+ <term>help</term>
+ <listitem>
+ <para>
+ Show the help and exit.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>list-repos</term>
+ <listitem>
+ <para>
+ List the repositories available on the server.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>repo-infos</term>
+ <listitem>
+ <para>
+ Displays the informations and capabilities of the selected repository
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>show-root</term>
+ <listitem>
+ <para>
+ Displays the root node infos and children.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>get-content <replaceable class="parameter">id</replaceable></term>
+ <listitem>
+ <para>
+ Download the content of the CMIS object corresponding to
+ <replaceable class="parameter">id</replaceable> in the current directory.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>set-content <replaceable class="parameter">id</replaceable></term>
+ <listitem>
+ <para>
+ Upload a file as the content stream of the CMIS object corresponding to
+ <replaceable class="parameter">id</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>create-folder <replaceable class="parameter">parent-id name</replaceable></term>
+ <listitem>
+ <para>
+ Create a sub folder in folder <replaceable class="parameter">parent-id</replaceable>
+ named <replaceable class="parameter">name</replaceable>. The default type of the folder
+ to create is cmis:folder, but this can be changed using --object-type option.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>create-document <replaceable class="parameter">parent-id name</replaceable></term>
+ <listitem>
+ <para>
+ Create a document in folder <replaceable class="parameter">parent-id</replaceable>
+ named <replaceable class="parameter">name</replaceable>. The default type of the document
+ to create is cmis:document, but this can be changed using --object-type option.
+ </para>
+ <para>
+ Note that the --input-file and --input-type may be mandatory, depending on the type of
+ the document to create and its constraints.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>update-object <replaceable class="parameter">object-id</replaceable></term>
+ <listitem>
+ <para>
+ Replace the writeable properties given with --object-property option on the object
+ matching id <replaceable class="parameter">object-id</replaceable>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>type-by-id <replaceable class="parameter">arg...</replaceable></term>
+ <listitem>
+ <para>
+ Displays the infos and children (if any) of all the CMIS types corresponding
+ to the listed ids.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>show-by-id <replaceable class="parameter">arg...</replaceable></term>
+ <listitem>
+ <para>
+ Displays the infos and children (if any) of all the CMIS objects corresponding
+ to the listed ids.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>show-by-path <replaceable class="parameter">arg...</replaceable></term>
+ <listitem>
+ <para>
+ Displays the infos and children (if any) of all the CMIS objects corresponding
+ to the listed paths.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>delete <replaceable class="parameter">arg...</replaceable></term>
+ <listitem>
+ <para>
+ Deletes the CMIS objects corresponding to the listed ids. If the node
+ is a folder, its content will be removed as well.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>checkout <replaceable class="parameter">arg</replaceable></term>
+ <listitem>
+ <para>
+ Checkout the document corresponding to the provided id and display
+ the infos of the created private working copy.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>cancel-checkout <replaceable class="parameter">arg</replaceable></term>
+ <listitem>
+ <para>
+ Cancel the Private Working Copy corresponding to the node id.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>get-versions <replaceable class="parameter">arg</replaceable></term>
+ <listitem>
+ <para>
+ Display the versions (if any) of all the CMIS object corresponding
+ to the provided id.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>checkin <replaceable class="parameter">arg</replaceable></term>
+ <listitem>
+ <para>
+ Check in the private working copy corresponding to the provided id and display
+ the infos of the resulting document. Use the --major and --message options to
+ define the version to create and the commit to associate to it.
+
+ Note that repositories without the ability to update the private working copies
+ will need the --input-file, --input-type and --object-property options.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+ <refsect1>
+ <title>USAGE</title>
+ <para>Displays the root node of repository A1:</para>
+ <para><command>cmis-client</command> -r A1 --url http://localhost/atom show-root</para>
+ <para>Displays the nodes with id 133 and 116 of repository A1:</para>
+ <para><command>cmis-client</command> -r A1 --url http://localhost/atom show-by id 133 116</para>
+ </refsect1>
+ <refsect1>
+ <title>AUTHOR</title>
+ <para>
+ <author>
+ <firstname>Cédric</firstname>
+ <surname>Bosdonnat</surname>
+ <contrib>Original author</contrib>
+ </author>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>REPORTING BUGS</title>
+ <para>Report bugs to &lt;<ulink url="https://github.com/tdf/libcmis/issues">https://github.com/tdf/libcmis/issues</ulink>&gt;.</para>
+ </refsect1>
+</refentry>
diff --git a/inc/Makefile.am b/inc/Makefile.am
new file mode 100644
index 0000000..f088d50
--- /dev/null
+++ b/inc/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libcmis libcmis-c
diff --git a/inc/libcmis-c/Makefile.am b/inc/libcmis-c/Makefile.am
new file mode 100644
index 0000000..eefbde2
--- /dev/null
+++ b/inc/libcmis-c/Makefile.am
@@ -0,0 +1,20 @@
+libcmis_cdir = $(includedir)/libcmis-c-@LIBCMIS_API_VERSION@/libcmis-c
+
+dist_libcmis_c_HEADERS = \
+ allowable-actions.h \
+ document.h \
+ error.h \
+ folder.h \
+ libcmis-c-api.h \
+ libcmis-c.h \
+ oauth2-data.h \
+ object-type.h \
+ object.h \
+ property-type.h \
+ property.h \
+ rendition.h \
+ repository.h \
+ session-factory.h \
+ session.h \
+ types.h \
+ vectors.h
diff --git a/inc/libcmis-c/allowable-actions.h b/inc/libcmis-c/allowable-actions.h
new file mode 100644
index 0000000..c2764d3
--- /dev/null
+++ b/inc/libcmis-c/allowable-actions.h
@@ -0,0 +1,50 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_ALLOWABLE_ACTIONS_H_
+#define _LIBCMIS_ALLOWABLE_ACTIONS_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_allowable_actions_free( libcmis_AllowableActionsPtr allowable );
+
+LIBCMIS_C_API bool libcmis_allowable_actions_isAllowed( libcmis_AllowableActionsPtr allowable,
+ libcmis_allowable_actions_Type action );
+
+LIBCMIS_C_API bool libcmis_allowable_actions_isDefined( libcmis_AllowableActionsPtr allowable,
+ libcmis_allowable_actions_Type action );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/document.h b/inc/libcmis-c/document.h
new file mode 100644
index 0000000..5436956
--- /dev/null
+++ b/inc/libcmis-c/document.h
@@ -0,0 +1,96 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_DOCUMENT_H_
+#define _LIBCMIS_DOCUMENT_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_vector_document_free( libcmis_vector_document_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_document_size( libcmis_vector_document_Ptr vector );
+LIBCMIS_C_API libcmis_DocumentPtr libcmis_vector_document_get( libcmis_vector_document_Ptr vector, size_t i );
+
+LIBCMIS_C_API bool libcmis_is_document( libcmis_ObjectPtr object );
+LIBCMIS_C_API libcmis_DocumentPtr libcmis_document_cast( libcmis_ObjectPtr object );
+
+LIBCMIS_C_API void libcmis_document_free( libcmis_DocumentPtr document );
+
+LIBCMIS_C_API libcmis_vector_folder_Ptr libcmis_document_getParents( libcmis_DocumentPtr document, libcmis_ErrorPtr error );
+
+LIBCMIS_C_API void libcmis_document_getContentStream(
+ libcmis_DocumentPtr document,
+ libcmis_writeFn writeFn,
+ void* userData,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API void libcmis_document_setContentStream(
+ libcmis_DocumentPtr document,
+ libcmis_readFn readFn,
+ void* userData,
+ const char* contentType,
+ const char* filename,
+ bool overwrite,
+ libcmis_ErrorPtr );
+
+/** The resulting value needs to be free'd
+ */
+LIBCMIS_C_API char* libcmis_document_getContentType( libcmis_DocumentPtr document );
+
+/** The resulting value needs to be free'd
+ */
+LIBCMIS_C_API char* libcmis_document_getContentFilename( libcmis_DocumentPtr document );
+
+LIBCMIS_C_API long libcmis_document_getContentLength( libcmis_DocumentPtr document );
+
+LIBCMIS_C_API libcmis_DocumentPtr libcmis_document_checkOut( libcmis_DocumentPtr document, libcmis_ErrorPtr error );
+LIBCMIS_C_API void libcmis_document_cancelCheckout( libcmis_DocumentPtr document, libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_DocumentPtr libcmis_document_checkIn(
+ libcmis_DocumentPtr document,
+ bool isMajor,
+ const char* comment,
+ libcmis_vector_property_Ptr properties,
+ libcmis_readFn readFn,
+ void* userData,
+ const char* contentType,
+ const char* filename,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_vector_document_Ptr libcmis_document_getAllVersions(
+ libcmis_DocumentPtr document,
+ libcmis_ErrorPtr error );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/error.h b/inc/libcmis-c/error.h
new file mode 100644
index 0000000..8a63bfa
--- /dev/null
+++ b/inc/libcmis-c/error.h
@@ -0,0 +1,48 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_ERROR_H_
+#define _LIBCMIS_ERROR_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API libcmis_ErrorPtr libcmis_error_create( );
+LIBCMIS_C_API void libcmis_error_free( libcmis_ErrorPtr e );
+
+LIBCMIS_C_API const char* libcmis_error_getMessage( libcmis_ErrorPtr e );
+LIBCMIS_C_API const char* libcmis_error_getType( libcmis_ErrorPtr e );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/folder.h b/inc/libcmis-c/folder.h
new file mode 100644
index 0000000..e741e71
--- /dev/null
+++ b/inc/libcmis-c/folder.h
@@ -0,0 +1,81 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_FOLDER_H_
+#define _LIBCMIS_FOLDER_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_vector_folder_free( libcmis_vector_folder_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_folder_size( libcmis_vector_folder_Ptr vector );
+LIBCMIS_C_API libcmis_FolderPtr libcmis_vector_folder_get( libcmis_vector_folder_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API bool libcmis_is_folder( libcmis_ObjectPtr object );
+LIBCMIS_C_API libcmis_FolderPtr libcmis_folder_cast( libcmis_ObjectPtr object );
+
+LIBCMIS_C_API void libcmis_folder_free( libcmis_FolderPtr folder );
+
+LIBCMIS_C_API libcmis_FolderPtr libcmis_folder_getParent( libcmis_FolderPtr folder, libcmis_ErrorPtr error );
+LIBCMIS_C_API libcmis_vector_object_Ptr libcmis_folder_getChildren( libcmis_FolderPtr folder, libcmis_ErrorPtr error );
+
+/** Get the path of the folder. The returned string needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_folder_getPath( libcmis_FolderPtr folder );
+
+LIBCMIS_C_API bool libcmis_folder_isRootFolder( libcmis_FolderPtr folder );
+
+LIBCMIS_C_API libcmis_FolderPtr libcmis_folder_createFolder(
+ libcmis_FolderPtr folder,
+ libcmis_vector_property_Ptr properties,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_DocumentPtr libcmis_folder_createDocument(
+ libcmis_FolderPtr folder,
+ libcmis_vector_property_Ptr properties,
+ libcmis_readFn readFn,
+ void* userData,
+ const char* contentType,
+ const char* filename,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_vector_string_Ptr libcmis_folder_removeTree( libcmis_FolderPtr folder,
+ bool allVersion,
+ libcmis_folder_UnfileObjects unfile,
+ bool continueOnError,
+ libcmis_ErrorPtr error );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/libcmis-c-api.h b/inc/libcmis-c/libcmis-c-api.h
new file mode 100644
index 0000000..3fe7986
--- /dev/null
+++ b/inc/libcmis-c/libcmis-c-api.h
@@ -0,0 +1,45 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_C_API_H_
+#define _LIBCMIS_C_API_H_
+
+#ifdef DLL_EXPORT
+#ifdef LIBCMIS_C_BUILD
+#define LIBCMIS_C_API __declspec(dllexport)
+#else
+#define LIBCMIS_C_API __declspec(dllimport)
+#endif
+#else /* !DLL_EXPORT */
+#ifdef LIBCMIS_C_VISIBILITY
+#define LIBCMIS_C_API __attribute__((visibility("default")))
+#else
+#define LIBCMIS_C_API
+#endif
+#endif
+
+#endif
diff --git a/inc/libcmis-c/libcmis-c.h b/inc/libcmis-c/libcmis-c.h
new file mode 100644
index 0000000..d9f6e4e
--- /dev/null
+++ b/inc/libcmis-c/libcmis-c.h
@@ -0,0 +1,50 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_C_H_
+#define _LIBCMIS_C_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#include "libcmis-c/allowable-actions.h"
+#include "libcmis-c/document.h"
+#include "libcmis-c/error.h"
+#include "libcmis-c/folder.h"
+#include "libcmis-c/object.h"
+#include "libcmis-c/object-type.h"
+#include "libcmis-c/property.h"
+#include "libcmis-c/property-type.h"
+#include "libcmis-c/oauth2-data.h"
+#include "libcmis-c/rendition.h"
+#include "libcmis-c/repository.h"
+#include "libcmis-c/types.h"
+#include "libcmis-c/session.h"
+#include "libcmis-c/session-factory.h"
+#include "libcmis-c/vectors.h"
+
+#endif
diff --git a/inc/libcmis-c/oauth2-data.h b/inc/libcmis-c/oauth2-data.h
new file mode 100644
index 0000000..ec4a9d3
--- /dev/null
+++ b/inc/libcmis-c/oauth2-data.h
@@ -0,0 +1,58 @@
+
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_OAUTH2_DATA_H_
+#define _LIBCMIS_OAUTH2_DATA_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API libcmis_OAuth2DataPtr libcmis_oauth2data_create(
+ char* authUrl, char* tokenUrl, char* scopes, char* redirectUri,
+ char* clientId, char* clientSecret );
+
+LIBCMIS_C_API void libcmis_oauth2data_free( libcmis_OAuth2DataPtr oauth2 );
+
+LIBCMIS_C_API bool libcmis_oauth2data_isComplete( libcmis_OAuth2DataPtr oauth2 );
+
+LIBCMIS_C_API const char* libcmis_oauth2data_getAuthUrl( libcmis_OAuth2DataPtr oauth2 );
+LIBCMIS_C_API const char* libcmis_oauth2data_getTokenUrl( libcmis_OAuth2DataPtr oauth2 );
+LIBCMIS_C_API const char* libcmis_oauth2data_getClientId( libcmis_OAuth2DataPtr oauth2 );
+LIBCMIS_C_API const char* libcmis_oauth2data_getClientSecret( libcmis_OAuth2DataPtr oauth2 );
+LIBCMIS_C_API const char* libcmis_oauth2data_getScope( libcmis_OAuth2DataPtr oauth2 );
+LIBCMIS_C_API const char* libcmis_oauth2data_getRedirectUri( libcmis_OAuth2DataPtr oauth2 );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/object-type.h b/inc/libcmis-c/object-type.h
new file mode 100644
index 0000000..0e0317c
--- /dev/null
+++ b/inc/libcmis-c/object-type.h
@@ -0,0 +1,114 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_OBJECT_TYPE_H_
+#define _LIBCMIS_OBJECT_TYPE_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+LIBCMIS_C_API void libcmis_vector_object_type_free( libcmis_vector_object_type_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_object_type_size( libcmis_vector_object_type_Ptr vector );
+LIBCMIS_C_API libcmis_ObjectTypePtr libcmis_vector_object_type_get( libcmis_vector_object_type_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API void libcmis_object_type_free( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_getId( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_getLocalName( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_getLocalNamespace( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_getQueryName( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_getDisplayName( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_getDescription( libcmis_ObjectTypePtr type );
+
+LIBCMIS_C_API libcmis_ObjectTypePtr libcmis_object_type_getParentType(
+ libcmis_ObjectTypePtr type,
+ libcmis_ErrorPtr error );
+LIBCMIS_C_API libcmis_ObjectTypePtr libcmis_object_type_getBaseType(
+ libcmis_ObjectTypePtr type,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_vector_object_type_Ptr libcmis_object_type_getChildren(
+ libcmis_ObjectTypePtr type,
+ libcmis_ErrorPtr error );
+
+/** The resulting value needs to be freed
+ \since libcmis 0.4
+ */
+LIBCMIS_C_API char* libcmis_object_type_getParentTypeId( libcmis_ObjectTypePtr type );
+
+/** The resulting value needs to be freed
+ \since libcmis 0.4
+ */
+LIBCMIS_C_API char* libcmis_object_type_getBaseTypeId( libcmis_ObjectTypePtr type );
+
+LIBCMIS_C_API bool libcmis_object_type_isCreatable( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isFileable( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isQueryable( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isFulltextIndexed( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isIncludedInSupertypeQuery( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isControllablePolicy( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isControllableACL( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API bool libcmis_object_type_isVersionable( libcmis_ObjectTypePtr type );
+
+LIBCMIS_C_API libcmis_object_type_ContentStreamAllowed libcmis_object_type_getContentStreamAllowed( libcmis_ObjectTypePtr type );
+
+LIBCMIS_C_API libcmis_vector_property_type_Ptr libcmis_object_type_getPropertiesTypes( libcmis_ObjectTypePtr type );
+LIBCMIS_C_API libcmis_PropertyTypePtr libcmis_object_type_getPropertyType( libcmis_ObjectTypePtr type, const char* id );
+
+
+/** The resulting value needs to be freed
+ */
+LIBCMIS_C_API char* libcmis_object_type_toString( libcmis_ObjectTypePtr type );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/object.h b/inc/libcmis-c/object.h
new file mode 100644
index 0000000..8739cff
--- /dev/null
+++ b/inc/libcmis-c/object.h
@@ -0,0 +1,134 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_OBJECT_H_
+#define _LIBCMIS_OBJECT_H_
+
+#include <time.h>
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_vector_object_free( libcmis_vector_object_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_object_size( libcmis_vector_object_Ptr vector );
+LIBCMIS_C_API libcmis_ObjectPtr libcmis_vector_object_get( libcmis_vector_object_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API void libcmis_object_free( libcmis_ObjectPtr object );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getId( libcmis_ObjectPtr object );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getName( libcmis_ObjectPtr object );
+
+LIBCMIS_C_API libcmis_vector_string_Ptr libcmis_object_getPaths( libcmis_ObjectPtr object );
+
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getBaseType( libcmis_ObjectPtr object );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getType( libcmis_ObjectPtr object );
+
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getCreatedBy( libcmis_ObjectPtr object );
+LIBCMIS_C_API time_t libcmis_object_getCreationDate( libcmis_ObjectPtr object );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getLastModifiedBy( libcmis_ObjectPtr object );
+LIBCMIS_C_API time_t libcmis_object_getLastModificationDate( libcmis_ObjectPtr object );
+
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getChangeToken( libcmis_ObjectPtr object );
+LIBCMIS_C_API bool libcmis_object_isImmutable( libcmis_ObjectPtr object );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API libcmis_vector_string_Ptr libcmis_object_getSecondaryTypes( libcmis_ObjectPtr object );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_getThumbnailUrl( libcmis_ObjectPtr object );
+
+LIBCMIS_C_API libcmis_vector_rendition_Ptr libcmis_object_getRenditions( libcmis_ObjectPtr object, libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_ObjectPtr
+LIBCMIS_C_API libcmis_object_addSecondaryType( libcmis_ObjectPtr object,
+ const char* id,
+ libcmis_vector_property_Ptr properties,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_ObjectPtr
+LIBCMIS_C_API libcmis_object_removeSecondaryType( libcmis_ObjectPtr object,
+ const char* id,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_vector_property_Ptr libcmis_object_getProperties( libcmis_ObjectPtr object );
+LIBCMIS_C_API libcmis_PropertyPtr libcmis_object_getProperty( libcmis_ObjectPtr object, const char* name );
+LIBCMIS_C_API void libcmis_object_setProperty( libcmis_ObjectPtr object, libcmis_PropertyPtr property );
+LIBCMIS_C_API libcmis_ObjectPtr libcmis_object_updateProperties(
+ libcmis_ObjectPtr object,
+ libcmis_vector_property_Ptr properties,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_ObjectTypePtr libcmis_object_getTypeDescription( libcmis_ObjectPtr object );
+LIBCMIS_C_API libcmis_AllowableActionsPtr libcmis_object_getAllowableActions( libcmis_ObjectPtr object );
+
+LIBCMIS_C_API void libcmis_object_refresh( libcmis_ObjectPtr object, libcmis_ErrorPtr error );
+LIBCMIS_C_API time_t libcmis_object_getRefreshTimestamp( libcmis_ObjectPtr object );
+
+LIBCMIS_C_API void libcmis_object_remove( libcmis_ObjectPtr object, bool allVersions, libcmis_ErrorPtr error );
+
+LIBCMIS_C_API void libcmis_object_move( libcmis_ObjectPtr object,
+ libcmis_FolderPtr source,
+ libcmis_FolderPtr dest,
+ libcmis_ErrorPtr error );
+
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_object_toString( libcmis_ObjectPtr object );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/property-type.h b/inc/libcmis-c/property-type.h
new file mode 100644
index 0000000..f0faa90
--- /dev/null
+++ b/inc/libcmis-c/property-type.h
@@ -0,0 +1,86 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_PROPERTY_TYPE_H_
+#define _LIBCMIS_PROPERTY_TYPE_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+LIBCMIS_C_API void libcmis_vector_property_type_free( libcmis_vector_property_type_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_property_type_size( libcmis_vector_property_type_Ptr vector );
+LIBCMIS_C_API libcmis_PropertyTypePtr libcmis_vector_property_type_get( libcmis_vector_property_type_Ptr vector, size_t i );
+
+LIBCMIS_C_API void libcmis_property_type_free( libcmis_PropertyTypePtr type );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_property_type_getId( libcmis_PropertyTypePtr type );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_property_type_getLocalName( libcmis_PropertyTypePtr type );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_property_type_getLocalNamespace( libcmis_PropertyTypePtr type );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_property_type_getDisplayName( libcmis_PropertyTypePtr type );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_property_type_getQueryName( libcmis_PropertyTypePtr type );
+
+LIBCMIS_C_API libcmis_property_type_Type libcmis_property_type_getType( libcmis_PropertyTypePtr type );
+
+/** The resulting value needs to be free'd.
+ */
+LIBCMIS_C_API char* libcmis_property_type_getXmlType( libcmis_PropertyTypePtr type );
+
+LIBCMIS_C_API bool libcmis_property_type_isMultiValued( libcmis_PropertyTypePtr type );
+LIBCMIS_C_API bool libcmis_property_type_isUpdatable( libcmis_PropertyTypePtr type );
+LIBCMIS_C_API bool libcmis_property_type_isInherited( libcmis_PropertyTypePtr type );
+LIBCMIS_C_API bool libcmis_property_type_isRequired( libcmis_PropertyTypePtr type );
+LIBCMIS_C_API bool libcmis_property_type_isQueryable( libcmis_PropertyTypePtr type );
+LIBCMIS_C_API bool libcmis_property_type_isOrderable( libcmis_PropertyTypePtr type );
+LIBCMIS_C_API bool libcmis_property_type_isOpenChoice( libcmis_PropertyTypePtr type );
+
+LIBCMIS_C_API void libcmis_property_type_update( libcmis_PropertyTypePtr propDef,
+ libcmis_vector_object_type_Ptr types );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/property.h b/inc/libcmis-c/property.h
new file mode 100644
index 0000000..7d06418
--- /dev/null
+++ b/inc/libcmis-c/property.h
@@ -0,0 +1,66 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_PROPERTY_HXX_
+#define _LIBCMIS_PROPERTY_HXX_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API libcmis_vector_property_Ptr libcmis_vector_property_create( );
+LIBCMIS_C_API void libcmis_vector_property_free( libcmis_vector_property_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_property_size( libcmis_vector_property_Ptr vector );
+LIBCMIS_C_API libcmis_PropertyPtr libcmis_vector_property_get( libcmis_vector_property_Ptr vector, size_t i );
+
+/** The item object can be deleted after this call safely.
+ */
+LIBCMIS_C_API void libcmis_vector_property_append( libcmis_vector_property_Ptr vector, libcmis_PropertyPtr item );
+
+
+LIBCMIS_C_API libcmis_PropertyPtr libcmis_property_create( libcmis_PropertyTypePtr type, const char** strValues, size_t size );
+LIBCMIS_C_API void libcmis_property_free( libcmis_PropertyPtr property );
+
+LIBCMIS_C_API libcmis_PropertyTypePtr libcmis_property_getPropertyType( libcmis_PropertyPtr property );
+
+LIBCMIS_C_API libcmis_vector_time_Ptr libcmis_property_getDateTimes( libcmis_PropertyPtr property );
+LIBCMIS_C_API libcmis_vector_bool_Ptr libcmis_property_getBools( libcmis_PropertyPtr property );
+LIBCMIS_C_API libcmis_vector_string_Ptr libcmis_property_getStrings( libcmis_PropertyPtr property );
+LIBCMIS_C_API libcmis_vector_long_Ptr libcmis_property_getLongs( libcmis_PropertyPtr property );
+LIBCMIS_C_API libcmis_vector_double_Ptr libcmis_property_getDoubles( libcmis_PropertyPtr property );
+
+LIBCMIS_C_API void libcmis_property_setValues( libcmis_PropertyPtr property, const char** strValues, size_t size );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/inc/libcmis-c/rendition.h b/inc/libcmis-c/rendition.h
new file mode 100644
index 0000000..927fd28
--- /dev/null
+++ b/inc/libcmis-c/rendition.h
@@ -0,0 +1,59 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _LIBCMIS_RENDITION_H_
+#define _LIBCMIS_RENDITION_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_rendition_free( libcmis_RenditionPtr rendition );
+
+LIBCMIS_C_API bool libcmis_rendition_isThumbnail( libcmis_RenditionPtr rendition );
+
+LIBCMIS_C_API const char* libcmis_rendition_getStreamId( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API const char* libcmis_rendition_getMimeType( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API const char* libcmis_rendition_getKind( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API const char* libcmis_rendition_getUrl( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API const char* libcmis_rendition_getTitle( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API long libcmis_rendition_getLength( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API long libcmis_rendition_getWidth( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API long libcmis_rendition_getHeight( libcmis_RenditionPtr rendition );
+LIBCMIS_C_API const char* libcmis_rendition_getRenditionDocumentId( libcmis_RenditionPtr rendition );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/inc/libcmis-c/repository.h b/inc/libcmis-c/repository.h
new file mode 100644
index 0000000..651a881
--- /dev/null
+++ b/inc/libcmis-c/repository.h
@@ -0,0 +1,107 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _REPOSITORY_H_
+#define _REPOSITORY_H_
+
+#include <libxml/tree.h>
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_vector_repository_free( libcmis_vector_Repository_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_repository_size( libcmis_vector_Repository_Ptr vector );
+LIBCMIS_C_API libcmis_RepositoryPtr libcmis_vector_repository_get( libcmis_vector_Repository_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API libcmis_RepositoryPtr libcmis_repository_create( xmlNodePtr node );
+
+LIBCMIS_C_API void libcmis_repository_free( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getId( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getName( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getDescription( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getVendorName( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getProductName( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getProductVersion( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getRootId( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getCmisVersionSupported( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getThinClientUri( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getPrincipalAnonymous( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getPrincipalAnyone( libcmis_RepositoryPtr repository );
+
+/** The resulting value needs to be freed.
+ */
+LIBCMIS_C_API char* libcmis_repository_getCapability(
+ libcmis_RepositoryPtr repository,
+ libcmis_repository_capability_Type capability );
+
+LIBCMIS_C_API bool libcmis_repository_getCapabilityAsBool(
+ libcmis_RepositoryPtr repository,
+ libcmis_repository_capability_Type capability );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/session-factory.h b/inc/libcmis-c/session-factory.h
new file mode 100644
index 0000000..f10ddd2
--- /dev/null
+++ b/inc/libcmis-c/session-factory.h
@@ -0,0 +1,79 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SESSION_FACTORY_H_
+#define _SESSION_FACTORY_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_setAuthenticationCallback( libcmis_authenticationCallback callback );
+LIBCMIS_C_API void libcmis_setCertValidationCallback( libcmis_certValidationCallback callback );
+LIBCMIS_C_API void libcmis_setOAuth2AuthCodeProvider( libcmis_oauth2AuthCodeProvider callback );
+LIBCMIS_C_API libcmis_oauth2AuthCodeProvider libcmis_getOAuth2AuthCodeProvider( );
+
+LIBCMIS_C_API void libcmis_setProxySettings(
+ char* proxy,
+ char* noProxy,
+ char* proxyUser,
+ char* proxyPass );
+
+LIBCMIS_C_API const char* libcmis_getProxy( );
+LIBCMIS_C_API const char* libcmis_getNoProxy( );
+LIBCMIS_C_API const char* libcmis_getProxyUser( );
+LIBCMIS_C_API const char* libcmis_getProxyPass( );
+
+LIBCMIS_C_API libcmis_SessionPtr libcmis_createSession(
+ char* bindingUrl,
+ char* repositoryId,
+ char* username,
+ char* password,
+ bool noSslCheck,
+ libcmis_OAuth2DataPtr oauth2,
+ bool verbose,
+ libcmis_ErrorPtr error );
+
+/**
+ \deprecated
+ use libcmis_createSession and libcmis_session_getRepositories instead
+ */
+LIBCMIS_C_API libcmis_vector_Repository_Ptr libcmis_getRepositories(
+ char* bindingUrl,
+ char* username,
+ char* password,
+ bool verbose,
+ libcmis_ErrorPtr error );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/session.h b/inc/libcmis-c/session.h
new file mode 100644
index 0000000..77c0d90
--- /dev/null
+++ b/inc/libcmis-c/session.h
@@ -0,0 +1,83 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_SESSION_H_
+#define _LIBCMIS_SESSION_H_
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_session_free( libcmis_SessionPtr session );
+
+LIBCMIS_C_API libcmis_RepositoryPtr libcmis_session_getRepository(
+ libcmis_SessionPtr session,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_vector_Repository_Ptr libcmis_session_getRepositories(
+ libcmis_SessionPtr session );
+
+LIBCMIS_C_API bool libcmis_session_setRepository(
+ libcmis_SessionPtr session,
+ const char* repositoryId );
+
+LIBCMIS_C_API libcmis_FolderPtr libcmis_session_getRootFolder(
+ libcmis_SessionPtr session,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_ObjectPtr libcmis_session_getObject(
+ libcmis_SessionPtr session,
+ const char* id,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_ObjectPtr libcmis_session_getObjectByPath(
+ libcmis_SessionPtr session,
+ const char* path,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_FolderPtr libcmis_session_getFolder(
+ libcmis_SessionPtr session,
+ const char* id,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_ObjectTypePtr libcmis_session_getType(
+ libcmis_SessionPtr session,
+ const char* id,
+ libcmis_ErrorPtr error );
+
+LIBCMIS_C_API libcmis_vector_object_type_Ptr libcmis_session_getBaseTypes(
+ libcmis_SessionPtr session,
+ libcmis_ErrorPtr error );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/types.h b/inc/libcmis-c/types.h
new file mode 100644
index 0000000..c3e784c
--- /dev/null
+++ b/inc/libcmis-c/types.h
@@ -0,0 +1,228 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_TYPES_H_
+#define _LIBCMIS_TYPES_H_
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Vectors of simple types */
+
+
+typedef struct libcmis_vector_bool* libcmis_vector_bool_Ptr;
+
+typedef struct libcmis_vector_string* libcmis_vector_string_Ptr;
+
+typedef struct libcmis_vector_long* libcmis_vector_long_Ptr;
+
+typedef struct libcmis_vector_double* libcmis_vector_double_Ptr;
+
+typedef struct libcmis_vector_time* libcmis_vector_time_Ptr;
+
+typedef struct libcmis_vector_repository* libcmis_vector_Repository_Ptr;
+
+
+/* AllowableActions */
+
+
+typedef struct libcmis_allowable_actions* libcmis_AllowableActionsPtr;
+
+typedef enum
+{
+ libcmis_DeleteObject,
+ libcmis_UpdateProperties,
+ libcmis_GetFolderTree,
+ libcmis_GetProperties,
+ libcmis_GetObjectRelationships,
+ libcmis_GetObjectParents,
+ libcmis_GetFolderParent,
+ libcmis_GetDescendants,
+ libcmis_MoveObject,
+ libcmis_DeleteContentStream,
+ libcmis_CheckOut,
+ libcmis_CancelCheckOut,
+ libcmis_CheckIn,
+ libcmis_SetContentStream,
+ libcmis_GetAllVersions,
+ libcmis_AddObjectToFolder,
+ libcmis_RemoveObjectFromFolder,
+ libcmis_GetContentStream,
+ libcmis_ApplyPolicy,
+ libcmis_GetAppliedPolicies,
+ libcmis_RemovePolicy,
+ libcmis_GetChildren,
+ libcmis_CreateDocument,
+ libcmis_CreateFolder,
+ libcmis_CreateRelationship,
+ libcmis_DeleteTree,
+ libcmis_GetRenditions,
+ libcmis_GetACL,
+ libcmis_ApplyACL
+} libcmis_allowable_actions_Type;
+
+
+/* Document */
+
+
+typedef struct libcmis_document* libcmis_DocumentPtr;
+typedef size_t ( *libcmis_writeFn )( const void*, size_t, size_t, void* );
+typedef size_t ( *libcmis_readFn )( void*, size_t, size_t, void* );
+
+typedef struct libcmis_vector_document* libcmis_vector_document_Ptr;
+
+/* Error */
+
+
+typedef struct libcmis_error* libcmis_ErrorPtr;
+
+
+/* Folder */
+
+
+typedef struct libcmis_folder* libcmis_FolderPtr;
+
+
+typedef struct libcmis_vector_folder* libcmis_vector_folder_Ptr;
+
+typedef enum
+{
+ libcmis_Unfile,
+ libcmis_DeleteSingleFiled,
+ libcmis_Delete
+} libcmis_folder_UnfileObjects;
+
+
+/* ObjectType */
+
+
+typedef struct libcmis_object_type* libcmis_ObjectTypePtr;
+
+typedef struct libcmis_vector_object_type* libcmis_vector_object_type_Ptr;
+
+typedef enum
+{
+ libcmis_NotAllowed,
+ libcmis_Allowed,
+ libcmis_Required
+} libcmis_object_type_ContentStreamAllowed;
+
+
+/* Object */
+
+
+typedef struct libcmis_object* libcmis_ObjectPtr;
+
+typedef struct libcmis_vector_object* libcmis_vector_object_Ptr;
+
+
+/* Property */
+
+
+typedef struct libcmis_property* libcmis_PropertyPtr;
+
+typedef struct libcmis_vector_property* libcmis_vector_property_Ptr;
+
+
+/* PropertyType */
+
+
+typedef struct libcmis_property_type* libcmis_PropertyTypePtr;
+
+typedef struct libcmis_vector_property_type* libcmis_vector_property_type_Ptr;
+
+typedef enum
+{
+ libcmis_String,
+ libcmis_Integer,
+ libcmis_Decimal,
+ libcmis_Bool,
+ libcmis_DateTime
+} libcmis_property_type_Type;
+
+
+/* Repository */
+
+typedef enum
+{
+ libcmis_capability_ACL,
+ libcmis_capability_AllVersionsSearchable,
+ libcmis_capability_Changes,
+ libcmis_capability_ContentStreamUpdatability,
+ libcmis_capability_GetDescendants,
+ libcmis_capability_GetFolderTree,
+ libcmis_capability_OrderBy,
+ libcmis_capability_Multifiling,
+ libcmis_capability_PWCSearchable,
+ libcmis_capability_PWCUpdatable,
+ libcmis_capability_Query,
+ libcmis_capability_Renditions,
+ libcmis_capability_Unfiling,
+ libcmis_capability_VersionSpecificFiling,
+ libcmis_capability_Join
+} libcmis_repository_capability_Type;
+
+typedef struct libcmis_repository* libcmis_RepositoryPtr;
+
+
+/* Session */
+
+
+typedef struct libcmis_session* libcmis_SessionPtr;
+
+typedef bool ( *libcmis_authenticationCallback )( char* username, char* password );
+typedef bool ( *libcmis_certValidationCallback )( libcmis_vector_string_Ptr certificatesChain );
+typedef char * ( *libcmis_oauth2AuthCodeProvider ) ( const char* authUrl, const char* username, const char* password );
+
+
+/* OAuth2Data */
+
+
+typedef struct libcmis_oauth2data* libcmis_OAuth2DataPtr;
+
+typedef char* ( *libcmis_OAuth2AuthCodeProvider )( const char* authUrl,
+ const char* username, const char* password );
+
+
+/* Rendition */
+
+
+typedef struct libcmis_rendition* libcmis_RenditionPtr;
+typedef struct libcmis_vector_rendition* libcmis_vector_rendition_Ptr;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis-c/vectors.h b/inc/libcmis-c/vectors.h
new file mode 100644
index 0000000..2c791c7
--- /dev/null
+++ b/inc/libcmis-c/vectors.h
@@ -0,0 +1,68 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_VECTORS_HXX_
+#define _LIBCMIS_VECTORS_HXX_
+
+#include <time.h>
+
+#include "libcmis-c/libcmis-c-api.h"
+#include "libcmis-c/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+LIBCMIS_C_API void libcmis_vector_bool_free( libcmis_vector_bool_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_bool_size( libcmis_vector_bool_Ptr vector );
+LIBCMIS_C_API bool libcmis_vector_bool_get( libcmis_vector_bool_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API void libcmis_vector_string_free( libcmis_vector_string_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_string_size( libcmis_vector_string_Ptr vector );
+LIBCMIS_C_API const char* libcmis_vector_string_get( libcmis_vector_string_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API void libcmis_vector_long_free( libcmis_vector_long_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_long_size( libcmis_vector_long_Ptr vector );
+LIBCMIS_C_API long libcmis_vector_long_get( libcmis_vector_long_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API void libcmis_vector_double_free( libcmis_vector_double_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_double_size( libcmis_vector_double_Ptr vector );
+LIBCMIS_C_API double libcmis_vector_double_get( libcmis_vector_double_Ptr vector, size_t i );
+
+
+LIBCMIS_C_API void libcmis_vector_time_free( libcmis_vector_time_Ptr vector );
+LIBCMIS_C_API size_t libcmis_vector_time_size( libcmis_vector_time_Ptr vector );
+LIBCMIS_C_API time_t libcmis_vector_time_get( libcmis_vector_time_Ptr vector, size_t i );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/libcmis/Makefile.am b/inc/libcmis/Makefile.am
new file mode 100644
index 0000000..93b139b
--- /dev/null
+++ b/inc/libcmis/Makefile.am
@@ -0,0 +1,20 @@
+libcmisdir = $(includedir)/libcmis-@LIBCMIS_API_VERSION@/libcmis
+
+dist_libcmis_HEADERS = \
+ allowable-actions.hxx \
+ document.hxx \
+ exception.hxx \
+ folder.hxx \
+ libcmis-api.h \
+ libcmis.hxx \
+ oauth2-data.hxx \
+ object-type.hxx \
+ object.hxx \
+ property-type.hxx \
+ property.hxx \
+ rendition.hxx \
+ repository.hxx \
+ session-factory.hxx \
+ session.hxx \
+ xml-utils.hxx \
+ xmlserializable.hxx
diff --git a/inc/libcmis/allowable-actions.hxx b/inc/libcmis/allowable-actions.hxx
new file mode 100644
index 0000000..50e9402
--- /dev/null
+++ b/inc/libcmis/allowable-actions.hxx
@@ -0,0 +1,131 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ALLOWABLE_ACTIONS_HXX_
+#define _ALLOWABLE_ACTIONS_HXX_
+
+#include <map>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+ class Object;
+
+ class LIBCMIS_API ObjectAction
+ {
+ public:
+ enum Type
+ {
+ DeleteObject,
+ UpdateProperties,
+ GetFolderTree,
+ GetProperties,
+ GetObjectRelationships,
+ GetObjectParents,
+ GetFolderParent,
+ GetDescendants,
+ MoveObject,
+ DeleteContentStream,
+ CheckOut,
+ CancelCheckOut,
+ CheckIn,
+ SetContentStream,
+ GetAllVersions,
+ AddObjectToFolder,
+ RemoveObjectFromFolder,
+ GetContentStream,
+ ApplyPolicy,
+ GetAppliedPolicies,
+ RemovePolicy,
+ GetChildren,
+ CreateDocument,
+ CreateFolder,
+ CreateRelationship,
+ DeleteTree,
+ GetRenditions,
+ GetACL,
+ ApplyACL
+ };
+
+ private:
+ Type m_type;
+ bool m_enabled;
+ bool m_valid;
+
+ public:
+ ObjectAction( xmlNodePtr node );
+ virtual ~ObjectAction( ){ }
+
+ Type getType( ) { return m_type; }
+ bool isEnabled( ) { return m_enabled; }
+ bool isValid( ) { return m_valid; }
+
+ /** Parses the permission name into one of the enum values or throws
+ an exception for invalid input strings.
+ */
+ static Type parseType( std::string type );
+
+ };
+
+ /** Class providing access to the allowed actions on an object.
+ */
+ class LIBCMIS_API AllowableActions
+ {
+ protected:
+ std::map< ObjectAction::Type, bool > m_states;
+
+ public:
+ /** Default constructor for testing purpose
+ */
+ AllowableActions( );
+ AllowableActions( xmlNodePtr node );
+ AllowableActions( const AllowableActions& copy );
+ virtual ~AllowableActions( );
+
+ AllowableActions& operator=( const AllowableActions& copy );
+
+ /** Returns the permissions for the corresponding actions.
+ */
+ bool isAllowed( ObjectAction::Type action );
+
+ /** Returns true if the action was defined, false if the default
+ value is used.
+ */
+ bool isDefined( ObjectAction::Type action );
+
+ std::string toString( );
+ };
+ typedef boost::shared_ptr< AllowableActions > AllowableActionsPtr;
+}
+
+#endif
diff --git a/inc/libcmis/document.hxx b/inc/libcmis/document.hxx
new file mode 100644
index 0000000..8f44313
--- /dev/null
+++ b/inc/libcmis/document.hxx
@@ -0,0 +1,147 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _DOCUMENT_HXX_
+#define _DOCUMENT_HXX_
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+#include "libcmis/object.hxx"
+
+namespace libcmis
+{
+ class Folder;
+ class Session;
+
+ /** Interface for a CMIS Document object.
+ */
+ class LIBCMIS_API Document : public virtual Object
+ {
+ public:
+ Document( Session* session ) : Object( session ) { }
+ virtual ~Document( ) { }
+
+ /** Get the folder parents for the document.
+
+ Note that an unfiled document will have no parent folder.
+
+ @return the parents folder if any.
+ */
+ virtual std::vector< boost::shared_ptr< Folder > > getParents( ) = 0;
+
+ /** Get the content stream without using a temporary file.
+
+ <p>The stream may not contain anything if there is
+ no content or if something wrong happened during the
+ download.</p>
+
+ @param streamId of the rendition
+ @return
+ An input stream to read the data from.
+
+ @throws Exception
+ if anything wrong happened during the file transfer.
+ In such a case, the content of the stream can't be
+ guaranteed.
+ */
+ virtual boost::shared_ptr< std::istream > getContentStream( std::string streamId = std::string( ) )
+ = 0;
+
+ /** Set or replace the content stream of the document.
+
+ @param is the output stream containing the new data for the content stream
+ @param contentType the mime-type of the new content stream
+ @param filename the filename to set for the file
+ @param overwrite if set to false, don't overwrite the content stream if one is already set.
+
+ @throw Exception if anything happens during the upload like a wrong authentication,
+ no rights to set the stream, server doesn't have the ContentStreamUpdatability
+ capability.
+ */
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os, std::string contentType,
+ std::string filename, bool overwrite = true ) = 0;
+
+ /** Get the content mime type.
+ */
+ virtual std::string getContentType( );
+
+ /** Get the content stream filename.
+ */
+ virtual std::string getContentFilename( );
+
+ /** Get the content length in bytes.
+ */
+ virtual long getContentLength( );
+
+ /** Checks out the document and returns the object corresponding to the
+ created Private Working Copy.
+
+ \return the Private Working Copy document
+ */
+ virtual boost::shared_ptr< Document > checkOut( ) = 0;
+
+ /** Cancels the checkout if the document is a private working copy, or
+ throws an exception.
+ */
+ virtual void cancelCheckout( ) = 0;
+
+ /** Check in the private working copy and create a new version or throw
+ an exception.
+
+ The current object will be updated to reflect the changes performed
+ on the server side.
+
+ \param isMajor defines it the version to create is a major or minor one
+ \param comment contains the checkin comment
+ \param properties the properties to set the new version
+ \param stream the content stream to set for the new version
+ \param contentType the mime type of the stream to set
+
+ \return the document with the new version
+ */
+ virtual boost::shared_ptr< Document > checkIn( bool isMajor, std::string comment,
+ const std::map< std::string, PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType, std::string fileName ) = 0;
+
+ virtual std::vector< boost::shared_ptr< Document > > getAllVersions( ) = 0;
+
+ // virtual methods form Object
+ virtual std::vector< std::string > getPaths( );
+
+ virtual std::string toString( );
+ };
+ typedef boost::shared_ptr< Document > DocumentPtr;
+}
+
+#endif
diff --git a/inc/libcmis/exception.hxx b/inc/libcmis/exception.hxx
new file mode 100644
index 0000000..aa42ae7
--- /dev/null
+++ b/inc/libcmis/exception.hxx
@@ -0,0 +1,62 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _EXCEPTION_HXX_
+#define _EXCEPTION_HXX_
+
+#include <exception>
+#include <string>
+
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+ class LIBCMIS_API Exception : public std::exception
+ {
+ private:
+ std::string m_message;
+ std::string m_type;
+
+ public:
+ Exception( std::string message, std::string type = "runtime" ) :
+ exception( ),
+ m_message( message ),
+ m_type( type )
+ {
+ }
+
+ ~Exception( ) noexcept { }
+ virtual const char* what() const noexcept
+ {
+ return m_message.c_str( );
+ }
+
+ std::string getType( ) const { return m_type; }
+ };
+}
+
+#endif
diff --git a/inc/libcmis/folder.hxx b/inc/libcmis/folder.hxx
new file mode 100644
index 0000000..0010dbd
--- /dev/null
+++ b/inc/libcmis/folder.hxx
@@ -0,0 +1,84 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _FOLDER_HXX_
+#define _FOLDER_HXX_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+#include "libcmis/object.hxx"
+
+namespace libcmis
+{
+ class Document;
+ class Session;
+
+ struct LIBCMIS_API UnfileObjects {
+ enum Type
+ {
+ Unfile,
+ DeleteSingleFiled,
+ Delete
+ };
+ };
+
+ /** Class representing a CMIS folder.
+ */
+ class LIBCMIS_API Folder : public virtual Object
+ {
+ public:
+ Folder( Session* session ) : Object( session ) { }
+ virtual ~Folder() { }
+
+ virtual std::vector< std::string > getPaths( );
+
+ virtual boost::shared_ptr< Folder > getFolderParent( );
+ virtual std::vector< ObjectPtr > getChildren( ) = 0;
+ virtual std::string getParentId( );
+ virtual std::string getPath( );
+
+ virtual bool isRootFolder( );
+
+ virtual boost::shared_ptr< Folder > createFolder( const std::map< std::string, PropertyPtr >& properties )
+ = 0;
+ virtual boost::shared_ptr< Document > createDocument( const std::map< std::string, PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > os, std::string contentType, std::string fileName ) = 0;
+
+ virtual std::vector< std::string > removeTree( bool allVersion = true, UnfileObjects::Type unfile = UnfileObjects::Delete,
+ bool continueOnError = false ) = 0;
+
+ virtual std::string toString( );
+ };
+ typedef boost::shared_ptr< Folder > FolderPtr;
+
+}
+
+#endif
diff --git a/inc/libcmis/libcmis-api.h b/inc/libcmis/libcmis-api.h
new file mode 100644
index 0000000..983ff4f
--- /dev/null
+++ b/inc/libcmis/libcmis-api.h
@@ -0,0 +1,45 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_API_H_
+#define _LIBCMIS_API_H_
+
+#ifdef DLL_EXPORT
+#ifdef LIBCMIS_BUILD
+#define LIBCMIS_API __declspec(dllexport)
+#else
+#define LIBCMIS_API __declspec(dllimport)
+#endif
+#else // !DLL_EXPORT
+#ifdef LIBCMIS_VISIBILITY
+#define LIBCMIS_API __attribute__((visibility("default")))
+#else
+#define LIBCMIS_API
+#endif
+#endif
+
+#endif
diff --git a/inc/libcmis/libcmis.hxx b/inc/libcmis/libcmis.hxx
new file mode 100644
index 0000000..411850d
--- /dev/null
+++ b/inc/libcmis/libcmis.hxx
@@ -0,0 +1,49 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_HXX_
+#define _LIBCMIS_HXX_
+
+#include "libcmis/libcmis-api.h"
+
+#include "libcmis/allowable-actions.hxx"
+#include "libcmis/document.hxx"
+#include "libcmis/exception.hxx"
+#include "libcmis/folder.hxx"
+#include "libcmis/oauth2-data.hxx"
+#include "libcmis/object-type.hxx"
+#include "libcmis/object.hxx"
+#include "libcmis/property-type.hxx"
+#include "libcmis/property.hxx"
+#include "libcmis/rendition.hxx"
+#include "libcmis/repository.hxx"
+#include "libcmis/session-factory.hxx"
+#include "libcmis/session.hxx"
+#include "libcmis/xml-utils.hxx"
+#include "libcmis/xmlserializable.hxx"
+
+#endif
diff --git a/inc/libcmis/oauth2-data.hxx b/inc/libcmis/oauth2-data.hxx
new file mode 100644
index 0000000..5321652
--- /dev/null
+++ b/inc/libcmis/oauth2-data.hxx
@@ -0,0 +1,78 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_OAUTH2_DATA_HXX_
+#define _LIBCMIS_OAUTH2_DATA_HXX_
+
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+ /** Class storing the data needed for OAuth2 authentication.
+ */
+ class LIBCMIS_API OAuth2Data
+ {
+ private:
+
+ std::string m_authUrl;
+ std::string m_tokenUrl;
+ std::string m_clientId;
+ std::string m_clientSecret;
+ std::string m_scope;
+ std::string m_redirectUri;
+ public:
+
+ OAuth2Data( );
+ OAuth2Data( const std::string& authUrl,
+ const std::string& tokenUrl,
+ const std::string& scope,
+ const std::string& redirectUri,
+ const std::string& clientId,
+ const std::string& clientSecret );
+
+ OAuth2Data( const OAuth2Data& copy );
+ ~OAuth2Data( );
+
+ OAuth2Data& operator=( const OAuth2Data& copy );
+
+ bool isComplete();
+
+ const std::string& getAuthUrl() { return m_authUrl; }
+ const std::string& getTokenUrl() { return m_tokenUrl; }
+ const std::string& getClientId() { return m_clientId; }
+ const std::string& getClientSecret() { return m_clientSecret; }
+ const std::string& getScope() { return m_scope; }
+ const std::string& getRedirectUri() { return m_redirectUri; }
+ };
+ typedef boost::shared_ptr< OAuth2Data > OAuth2DataPtr;
+}
+
+#endif //_LIBCMIS_OAUTH2_DATA_HXX_
+
diff --git a/inc/libcmis/object-type.hxx b/inc/libcmis/object-type.hxx
new file mode 100644
index 0000000..7fbf3e9
--- /dev/null
+++ b/inc/libcmis/object-type.hxx
@@ -0,0 +1,144 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _OBJECT_TYPE_HXX_
+#define _OBJECT_TYPE_HXX_
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include <string>
+#include <vector>
+
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+#include "libcmis/property-type.hxx"
+
+namespace libcmis
+{
+ /** Class representing a CMIS object type definition.
+ */
+ class LIBCMIS_API ObjectType
+ {
+ public:
+
+ enum ContentStreamAllowed
+ {
+ NotAllowed,
+ Allowed,
+ Required
+ };
+
+ protected:
+ time_t m_refreshTimestamp;
+
+ std::string m_id;
+ std::string m_localName;
+ std::string m_localNamespace;
+ std::string m_displayName;
+ std::string m_queryName;
+ std::string m_description;
+
+ std::string m_parentTypeId;
+ std::string m_baseTypeId;
+
+ bool m_creatable;
+ bool m_fileable;
+ bool m_queryable;
+ bool m_fulltextIndexed;
+ bool m_includedInSupertypeQuery;
+ bool m_controllablePolicy;
+ bool m_controllableAcl;
+ bool m_versionable;
+ libcmis::ObjectType::ContentStreamAllowed m_contentStreamAllowed;
+
+ std::map< std::string, libcmis::PropertyTypePtr > m_propertiesTypes;
+
+ ObjectType( );
+ void initializeFromNode( xmlNodePtr node );
+
+ public:
+
+ ObjectType( xmlNodePtr node );
+ ObjectType( const ObjectType& copy );
+ virtual ~ObjectType() { }
+
+ ObjectType& operator=( const ObjectType& copy );
+
+ /** Reload the data from the server.
+
+ \attention
+ This method needs to be implemented in subclasses or it will
+ do nothing
+ */
+ virtual void refresh( );
+ virtual time_t getRefreshTimestamp( ) const;
+
+ std::string getId( ) const;
+ std::string getLocalName( ) const;
+ std::string getLocalNamespace( ) const;
+ std::string getDisplayName( ) const;
+ std::string getQueryName( ) const;
+ std::string getDescription( ) const;
+
+ virtual boost::shared_ptr< ObjectType > getParentType( );
+ virtual boost::shared_ptr< ObjectType > getBaseType( );
+ virtual std::vector< boost::shared_ptr< ObjectType > > getChildren( );
+
+ /** Get the parent type id without extracting the complete parent type from
+ the repository. This is mainly provided for performance reasons.
+
+ \since libcmis 0.4
+ */
+ std::string getParentTypeId( ) const;
+
+ /** Get the base type id without extracting the complete base type from
+ the repository. This is mainly provided for performance reasons.
+
+ \since libcmis 0.4
+ */
+ std::string getBaseTypeId( ) const;
+
+ bool isCreatable( ) const;
+ bool isFileable( ) const;
+ bool isQueryable( ) const;
+ bool isFulltextIndexed( ) const;
+ bool isIncludedInSupertypeQuery( ) const;
+ bool isControllablePolicy( ) const;
+ bool isControllableACL( ) const;
+ bool isVersionable( ) const;
+ ContentStreamAllowed getContentStreamAllowed( ) const;
+
+ std::map< std::string, PropertyTypePtr >& getPropertiesTypes( );
+
+ virtual std::string toString( );
+ };
+
+ typedef boost::shared_ptr< ObjectType > ObjectTypePtr;
+}
+
+#endif
diff --git a/inc/libcmis/object.hxx b/inc/libcmis/object.hxx
new file mode 100644
index 0000000..5e5b3b5
--- /dev/null
+++ b/inc/libcmis/object.hxx
@@ -0,0 +1,218 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _OBJECT_HXX_
+#define _OBJECT_HXX_
+
+#include <ctime>
+#include <map>
+#include <string>
+#include <vector>
+
+#ifndef __cplusplus
+#include <stdbool.h>
+#endif
+
+#include <boost/date_time.hpp>
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include "libcmis/allowable-actions.hxx"
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+#include "libcmis/object-type.hxx"
+#include "libcmis/property.hxx"
+#include "libcmis/xmlserializable.hxx"
+#include "libcmis/rendition.hxx"
+
+namespace libcmis
+{
+ class Folder;
+ class Session;
+
+ /** Class representing any CMIS object.
+ */
+ class LIBCMIS_API Object : public XmlSerializable
+ {
+ protected:
+ Session* m_session;
+
+ ObjectTypePtr m_typeDescription;
+ time_t m_refreshTimestamp;
+
+ /** Type id used as cache before we get it as a property
+ */
+ std::string m_typeId;
+
+ std::map< std::string, PropertyPtr > m_properties;
+ boost::shared_ptr< AllowableActions > m_allowableActions;
+ std::vector< RenditionPtr > m_renditions;
+ void initializeFromNode( xmlNodePtr node );
+
+ public:
+
+ Object( Session* session );
+ Object( Session* session, xmlNodePtr node );
+ Object( const Object& copy );
+ virtual ~Object( ) { }
+
+ Object& operator=( const Object& copy );
+
+ virtual std::string getId( );
+ virtual std::string getName( );
+ virtual std::string getStringProperty( const std::string& propertyName );
+
+ /** Computes the paths for the objects.
+
+ Note that folders will have only path, documents may have
+ several ones and there may be cases where there is no path
+ at all (unfilled objects);
+ */
+ virtual std::vector< std::string > getPaths( );
+
+ virtual std::string getBaseType( );
+ virtual std::string getType( );
+
+ virtual std::string getCreatedBy( );
+ virtual boost::posix_time::ptime getCreationDate( );
+ virtual std::string getLastModifiedBy( );
+ virtual boost::posix_time::ptime getLastModificationDate( );
+
+ virtual std::string getChangeToken( );
+ virtual bool isImmutable( );
+
+ virtual std::vector< std::string > getSecondaryTypes();
+
+ /** Convenience function adding a secondary type to the object.
+
+ Behind the scene this function is basically computing the
+ properties and sets them for you to avoid reading the CMIS
+ 1.1 specification, section 2.1.9.
+
+ \param id
+ the identifier of the secondary type to add
+ \param properties
+ the properties coming with the secondary type
+
+ \return
+ the updated object. Note that it may represent the same
+ object on the server but it still is a different object
+ instance (see updateProperties method).
+
+ \throw Exception
+ if anything wrong happens. Note that the server is likely
+ to throw a constraint exception if it doesn't allow the
+ operation.
+ */
+ virtual boost::shared_ptr< Object > addSecondaryType(
+ std::string id,
+ PropertyPtrMap properties );
+
+ /** Convenience function removing a secondary type from the object.
+
+ Behind the scene this function is basically computing the
+ correct property and sets it for you to avoid reading the
+ CMIS 1.1 specification, section 2.1.9.
+
+ The server should remove the related properties, there is
+ normally no need to worry about them.
+
+ \param id
+ the identifier of the secondary type to remove
+
+ \return
+ the updated object. Note that it may represent the same
+ object on the server but it still is a different object
+ instance (see updateProperties method).
+
+ \throw Exception
+ if anything wrong happens. Note that the server is likely
+ to throw a constraint exception if it doesn't allow the
+ operation.
+ */
+ virtual boost::shared_ptr< Object > removeSecondaryType( std::string id );
+
+ /** Gives access to the properties of the object.
+
+ \attention
+ API users should consider this method as read-only as the
+ changed properties won't be updated to the server. Updating
+ the returned map may lead to changes loss when calling
+ updateProperties.
+
+ \sa updateProperties to change properties on the server
+ */
+ virtual libcmis::PropertyPtrMap& getProperties( );
+
+
+ /** Get the renditions of the object.
+
+ \param filter is defined by the CMIS spec section 2.2.1.2.4.1.
+ By default, this value is just ignored, but some bindings and servers
+ may use it.
+
+ \attention
+ The streamId of the rendition is used in getContentStream( )
+ */
+ virtual std::vector< RenditionPtr> getRenditions( std::string filter = std::string( ) );
+ virtual AllowableActionsPtr getAllowableActions( ) { return m_allowableActions; }
+
+ /** Update the object properties and return the updated object.
+
+ \attention
+ even if the returned object may have the same Id than 'this'
+ and thus representing the same object on the server, those
+ are still two different instances to ease memory handling.
+ */
+ virtual boost::shared_ptr< Object > updateProperties(
+ const PropertyPtrMap& properties ) = 0;
+
+ virtual ObjectTypePtr getTypeDescription( );
+
+ /** Reload the data from the server.
+ */
+ virtual void refresh( ) = 0;
+ virtual time_t getRefreshTimestamp( ) { return m_refreshTimestamp; }
+
+ virtual void remove( bool allVersions = true ) = 0;
+
+ virtual void move( boost::shared_ptr< Folder > source, boost::shared_ptr< Folder > destination ) = 0;
+
+
+ virtual std::string getThumbnailUrl( );
+
+ /** Dump the object as a string for debugging or display purpose.
+ */
+ virtual std::string toString( );
+
+ void toXml( xmlTextWriterPtr writer );
+ };
+
+ typedef boost::shared_ptr< Object > ObjectPtr;
+}
+
+#endif
diff --git a/inc/libcmis/property-type.hxx b/inc/libcmis/property-type.hxx
new file mode 100644
index 0000000..350a7b2
--- /dev/null
+++ b/inc/libcmis/property-type.hxx
@@ -0,0 +1,127 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _PROPERTY_TYPE_HXX_
+#define _PROPERTY_TYPE_HXX_
+
+#include <boost/date_time.hpp>
+#include <libxml/tree.h>
+
+#include <string>
+
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+ class ObjectType;
+ typedef boost::shared_ptr< ObjectType > ObjectTypePtr;
+
+ class LIBCMIS_API PropertyType
+ {
+ public:
+
+ enum Type
+ {
+ String,
+ Integer,
+ Decimal,
+ Bool,
+ DateTime
+ };
+
+ private:
+
+ std::string m_id;
+ std::string m_localName;
+ std::string m_localNamespace;
+ std::string m_displayName;
+ std::string m_queryName;
+ Type m_type;
+ std::string m_xmlType;
+ bool m_multiValued;
+ bool m_updatable;
+ bool m_inherited;
+ bool m_required;
+ bool m_queryable;
+ bool m_orderable;
+ bool m_openChoice;
+ bool m_temporary;
+
+ public:
+
+ /// Default constructor, mostly present for testing.
+ PropertyType( );
+ PropertyType( xmlNodePtr node );
+ PropertyType( const PropertyType& copy );
+ /// constructor for temporary type definitions
+ PropertyType( std::string type,
+ std::string id,
+ std::string localName,
+ std::string displayName,
+ std::string queryName );
+ virtual ~PropertyType( ) { };
+
+ PropertyType& operator=( const PropertyType& copy );
+
+ std::string getId( ) { return m_id; }
+ std::string getLocalName( ) { return m_localName; }
+ std::string getLocalNamespace( ) { return m_localNamespace; }
+ std::string getDisplayName( ) { return m_displayName; }
+ std::string getQueryName( ) { return m_queryName; }
+ Type getType( ) { return m_type; }
+ std::string getXmlType( ) { return m_xmlType; }
+ bool isMultiValued( ) { return m_multiValued; }
+ bool isUpdatable( ) { return m_updatable; }
+ bool isInherited( ) { return m_inherited; }
+ bool isRequired( ) { return m_required; }
+ bool isQueryable( ) { return m_queryable; }
+ bool isOrderable( ) { return m_orderable; }
+ bool isOpenChoice( ) { return m_openChoice; }
+
+ void setId( std::string id ) { m_id = id; }
+ void setLocalName( std::string localName ) { m_localName = localName; }
+ void setLocalNamespace( std::string localNamespace ) { m_localNamespace = localNamespace; }
+ void setDisplayName( std::string displayName ) { m_displayName = displayName; }
+ void setQueryName( std::string queryName ) { m_queryName = queryName; }
+ void setType( Type type ) { m_type = type; }
+ void setMultiValued( bool multivalued ) { m_multiValued = multivalued; }
+ void setUpdatable( bool updatable ) { m_updatable = updatable; }
+ void setInherited( bool inherited ) { m_inherited = inherited; }
+ void setRequired( bool required ) { m_required = required; }
+ void setQueryable( bool queryable ) { m_queryable = queryable; }
+ void setOrderable( bool orderable ) { m_orderable = orderable; }
+ void setOpenChoice( bool openChoice ) { m_openChoice = openChoice; }
+
+ void setTypeFromXml( std::string typeStr );
+ void setTypeFromJsonType( std::string jsonType );
+
+ void update( std::vector< ObjectTypePtr > typesDefs );
+ };
+ typedef boost::shared_ptr< PropertyType > PropertyTypePtr;
+}
+
+#endif
diff --git a/inc/libcmis/property.hxx b/inc/libcmis/property.hxx
new file mode 100644
index 0000000..9f67b55
--- /dev/null
+++ b/inc/libcmis/property.hxx
@@ -0,0 +1,89 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _PROPERTY_HXX_
+#define _PROPERTY_HXX_
+
+#include <libxml/tree.h>
+#include <libxml/xmlwriter.h>
+
+#include <boost/date_time.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <string>
+#include <vector>
+
+#include "libcmis/libcmis-api.h"
+#include "libcmis/property-type.hxx"
+#include "libcmis/xmlserializable.hxx"
+
+namespace libcmis
+{
+ class ObjectType;
+
+ class LIBCMIS_API Property : public XmlSerializable
+ {
+ private:
+ PropertyTypePtr m_propertyType;
+ std::vector< std::string > m_strValues;
+ std::vector< bool > m_boolValues;
+ std::vector< long > m_longValues;
+ std::vector< double > m_doubleValues;
+ std::vector< boost::posix_time::ptime > m_dateTimeValues;
+
+ protected:
+ Property( );
+
+ public:
+ /** Property constructor allowing to use different values for the id and names.
+ */
+ Property( PropertyTypePtr propertyType, std::vector< std::string > strValues );
+
+ ~Property( ){ }
+
+ PropertyTypePtr getPropertyType( ) { return m_propertyType; }
+
+ std::vector< boost::posix_time::ptime > getDateTimes( ) { return m_dateTimeValues; }
+ std::vector< bool > getBools( ) { return m_boolValues; }
+ std::vector< std::string > getStrings( ) { return m_strValues; }
+ std::vector< long > getLongs( ) { return m_longValues; }
+ std::vector< double > getDoubles( ) { return m_doubleValues; }
+
+ void setPropertyType( PropertyTypePtr propertyType);
+ void setValues( std::vector< std::string > strValues );
+
+ void toXml( xmlTextWriterPtr writer );
+
+ std::string toString( );
+ };
+ typedef boost::shared_ptr< Property > PropertyPtr;
+ typedef std::map< std::string, libcmis::PropertyPtr > PropertyPtrMap;
+
+ PropertyPtr parseProperty( xmlNodePtr node, boost::shared_ptr< ObjectType > objectType );
+}
+
+#endif
diff --git a/inc/libcmis/rendition.hxx b/inc/libcmis/rendition.hxx
new file mode 100644
index 0000000..62dc59c
--- /dev/null
+++ b/inc/libcmis/rendition.hxx
@@ -0,0 +1,90 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _RENDITION_HXX_
+#define _RENDITION_HXX_
+
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+ class LIBCMIS_API Rendition
+ {
+ private:
+ Rendition( );
+
+ std::string m_streamId;
+ std::string m_mimeType;
+ std::string m_kind;
+ std::string m_href;
+ std::string m_title;
+ long m_length;
+ long m_width;
+ long m_height;
+ std::string m_renditionDocumentId;
+
+ public:
+ Rendition( std::string streamId, std::string mimeType,
+ std::string kind, std::string href,
+ std::string title = std::string( ),
+ long length = -1, long width = -1, long height = -1,
+ std::string renditionDocumentId = std::string( ) );
+
+ /** Parse an XML node of type cmisRenditionType
+ */
+ Rendition( xmlNodePtr node );
+ ~Rendition( );
+
+ bool isThumbnail( );
+
+ const std::string& getStreamId( ) const;
+ const std::string& getMimeType( ) const;
+ const std::string& getKind( ) const;
+ const std::string& getUrl( ) const;
+ const std::string& getTitle( ) const;
+
+ /** Provides the stream length in bytes or a negative value if missing.
+ */
+ long getLength( ) const;
+ long getWidth( ) const;
+ long getHeight( ) const;
+ const std::string& getRenditionDocumentId( );
+
+ std::string toString( );
+ };
+
+ typedef boost::shared_ptr< Rendition > RenditionPtr;
+}
+
+#endif
+
diff --git a/inc/libcmis/repository.hxx b/inc/libcmis/repository.hxx
new file mode 100644
index 0000000..3c0f67c
--- /dev/null
+++ b/inc/libcmis/repository.hxx
@@ -0,0 +1,119 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Cédric Bosdonnat <cbosdo@users.sourceforge.net>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _REPOSITORY_HXX_
+#define _REPOSITORY_HXX_
+
+#include <map>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+ /** Class representing a repository and its infos.
+
+ \sa 2.2.2.2 section of the CMIS specifications
+ */
+ class LIBCMIS_API Repository
+ {
+ public:
+
+ enum Capability
+ {
+ ACL,
+ AllVersionsSearchable,
+ Changes,
+ ContentStreamUpdatability,
+ GetDescendants,
+ GetFolderTree,
+ OrderBy,
+ Multifiling,
+ PWCSearchable,
+ PWCUpdatable,
+ Query,
+ Renditions,
+ Unfiling,
+ VersionSpecificFiling,
+ Join
+ };
+
+ protected:
+ std::string m_id;
+ std::string m_name;
+ std::string m_description;
+ std::string m_vendorName;
+ std::string m_productName;
+ std::string m_productVersion;
+ std::string m_rootId;
+ std::string m_cmisVersionSupported;
+ boost::shared_ptr< std::string > m_thinClientUri;
+ boost::shared_ptr< std::string > m_principalAnonymous;
+ boost::shared_ptr< std::string > m_principalAnyone;
+
+ std::map< Capability, std::string > m_capabilities ;
+
+ Repository( );
+ void initializeFromNode( xmlNodePtr node );
+
+ public:
+ Repository( xmlNodePtr node );
+ virtual ~Repository( ) { };
+
+ std::string getId( ) const;
+ std::string getName( ) const;
+ std::string getDescription( ) const;
+ std::string getVendorName( ) const;
+ std::string getProductName( ) const;
+ std::string getProductVersion( ) const;
+ std::string getRootId( ) const;
+ std::string getCmisVersionSupported( ) const;
+ boost::shared_ptr< std::string > getThinClientUri( ) const;
+ boost::shared_ptr< std::string > getPrincipalAnonymous( ) const;
+ boost::shared_ptr< std::string > getPrincipalAnyone( ) const;
+
+ std::string getCapability( Capability capability ) const;
+
+ /** Wrapper function providing the capability as a boolean value.
+ If the capability value is not a boolean, returns false.
+ */
+ bool getCapabilityAsBool( Capability capability ) const;
+
+ std::string toString( ) const;
+
+ private:
+
+ static std::map< Capability, std::string > parseCapabilities( xmlNodePtr node );
+ };
+
+ typedef boost::shared_ptr< Repository > RepositoryPtr;
+}
+
+#endif
diff --git a/inc/libcmis/session-factory.hxx b/inc/libcmis/session-factory.hxx
new file mode 100644
index 0000000..227ac4d
--- /dev/null
+++ b/inc/libcmis/session-factory.hxx
@@ -0,0 +1,157 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SESSION_FACTORY_HXX_
+#define _SESSION_FACTORY_HXX_
+
+#include <vector>
+#include <map>
+#include <string>
+
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+#include "libcmis/oauth2-data.hxx"
+#include "libcmis/repository.hxx"
+#include "libcmis/session.hxx"
+
+// needed for a callback type
+typedef void CURL;
+
+namespace libcmis
+{
+ /** This callback provides the OAuth2 code or NULL.
+
+ The returned string must be free()d by the caller.
+ */
+ typedef char* ( *OAuth2AuthCodeProvider )( const char* authUrl,
+ const char* username, const char* password );
+
+ class LIBCMIS_API AuthProvider
+ {
+ public:
+ virtual ~AuthProvider() { };
+
+ /** The function implementing it needs to fill the username and password parameters
+ and return true. Returning false means that the user cancelled the authentication
+ and will fail the query.
+ */
+ virtual bool authenticationQuery( std::string& username, std::string& password ) = 0;
+ };
+ typedef boost::shared_ptr< AuthProvider > AuthProviderPtr;
+
+ /** Handler class used to request user input when an invalid SSL certificate is encountered.
+ */
+ class LIBCMIS_API CertValidationHandler
+ {
+ public:
+ virtual ~CertValidationHandler( ){ };
+
+ /** This function is provided a vector of X509 certificates encoded in base64, with
+ the first certificate being the one to validate, and the others are the issuers
+ chain.
+
+ The result will be stored in the session object to avoid asking several times
+ to validate the same certificate.
+
+ \result true if the certificate should be ignored, false to fail the request.
+ */
+ virtual bool validateCertificate( std::vector< std::string > certificatesChain ) = 0;
+ };
+ typedef boost::shared_ptr< CertValidationHandler > CertValidationHandlerPtr;
+
+ typedef void(*CurlInitProtocolsFunction)(CURL *);
+
+ class LIBCMIS_API SessionFactory
+ {
+ private:
+
+ static AuthProviderPtr s_authProvider;
+
+ static std::string s_proxy;
+ static std::string s_noProxy;
+ static std::string s_proxyUser;
+ static std::string s_proxyPass;
+
+ static OAuth2AuthCodeProvider s_oauth2AuthCodeProvider;
+
+ static CertValidationHandlerPtr s_certValidationHandler;
+
+ public:
+
+ static void setAuthenticationProvider( AuthProviderPtr provider ) { s_authProvider = provider; }
+ static AuthProviderPtr getAuthenticationProvider( ) { return s_authProvider; }
+
+ static void setOAuth2AuthCodeProvider( OAuth2AuthCodeProvider provider ) { s_oauth2AuthCodeProvider = provider; }
+ static OAuth2AuthCodeProvider getOAuth2AuthCodeProvider( ) { return s_oauth2AuthCodeProvider; }
+
+ /** Set the handler to ask the user what to do with invalid SSL certificates. If not set,
+ every invalid certificate will raise an exception.
+ */
+ static void setCertificateValidationHandler( CertValidationHandlerPtr handler ) { s_certValidationHandler = handler; }
+ static CertValidationHandlerPtr getCertificateValidationHandler( ) { return s_certValidationHandler; }
+
+ static void setCurlInitProtocolsFunction(CurlInitProtocolsFunction);
+
+ static void setProxySettings( std::string proxy,
+ std::string noProxy,
+ std::string proxyUser,
+ std::string proxyPass );
+
+ static const std::string& getProxy() { return s_proxy; }
+ static const std::string& getNoProxy() { return s_noProxy; }
+ static const std::string& getProxyUser() { return s_proxyUser; }
+ static const std::string& getProxyPass() { return s_proxyPass; }
+
+ /** Create a session from the given parameters. The binding type is automatically
+ detected based on the provided URL.
+
+ The resulting pointer should be deleted by the caller.
+ */
+ static Session* createSession( std::string bindingUrl,
+ std::string username = std::string( ),
+ std::string password = std::string( ),
+ std::string repositoryId = std::string( ),
+ bool noSslCheck = false,
+ OAuth2DataPtr oauth2 = OAuth2DataPtr(), bool verbose = false );
+
+ /**
+ Gets the informations of the repositories on the server.
+
+ \deprecated
+ Since libcmis 0.4.0, this helper function simply creates a session
+ using the createSession function with no repository and then calls
+ getRepositories on the resulting session.
+ Kept only for backward API compatibility.
+ */
+ static std::vector< RepositoryPtr > getRepositories( std::string bindingUrl,
+ std::string username = std::string( ),
+ std::string password = std::string( ),
+ bool verbose = false );
+ };
+}
+
+#endif
diff --git a/inc/libcmis/session.hxx b/inc/libcmis/session.hxx
new file mode 100644
index 0000000..ec95ab4
--- /dev/null
+++ b/inc/libcmis/session.hxx
@@ -0,0 +1,103 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SESSION_HXX_
+#define _SESSION_HXX_
+
+#include <vector>
+#include <string>
+#include <boost/shared_ptr.hpp>
+
+#include "libcmis/libcmis-api.h"
+#include "libcmis/object-type.hxx"
+#include "libcmis/object.hxx"
+#include "libcmis/folder.hxx"
+#include "libcmis/repository.hxx"
+
+namespace libcmis
+{
+ class LIBCMIS_API Session
+ {
+ public:
+
+ virtual ~Session() { };
+
+ /** Get the current repository.
+ */
+ virtual RepositoryPtr getRepository( ) = 0;
+
+ virtual std::vector< RepositoryPtr > getRepositories( ) = 0;
+
+ /** Change the current repository.
+
+ \return
+ false if no repository with the provided id can be found on the server,
+ true otherwise
+ */
+ virtual bool setRepository( std::string repositoryId ) = 0;
+
+ /** Get the Root folder of the repository
+ */
+ virtual FolderPtr getRootFolder()= 0;
+
+ /** Get a CMIS object from its ID.
+ */
+ virtual ObjectPtr getObject( std::string id ) = 0;
+
+ /** Get a CMIS object from one of its path.
+ */
+ virtual ObjectPtr getObjectByPath( std::string path ) = 0;
+
+ /** Get a CMIS folder from its ID.
+ */
+ virtual libcmis::FolderPtr getFolder( std::string id ) = 0;
+
+ /** Get a CMIS object type from its ID.
+ */
+ virtual ObjectTypePtr getType( std::string id ) = 0;
+
+ /** Get all the CMIS base object types known by the server.
+ */
+ virtual std::vector< ObjectTypePtr > getBaseTypes( ) = 0;
+
+ /** Enable or disable the SSL certificate verification.
+
+ By default, SSL certificates are verified and errors are thrown in case of
+ one is invalid. The user may decide to ignore the checks for this CMIS session
+ to workaround self-signed certificates or other similar problems.
+
+ As each session only handles the connection to one CMIS server, it should
+ concern only one SSL certificate and should provide the same feature as the
+ certificate exception feature available on common web browser.
+ */
+ virtual void setNoSSLCertificateCheck( bool noCheck ) = 0;
+
+ virtual std::string getRefreshToken() { return ""; };
+ };
+}
+
+#endif
diff --git a/inc/libcmis/xml-utils.hxx b/inc/libcmis/xml-utils.hxx
new file mode 100644
index 0000000..929385e
--- /dev/null
+++ b/inc/libcmis/xml-utils.hxx
@@ -0,0 +1,166 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _XML_UTILS_HXX_
+#define _XML_UTILS_HXX_
+
+#include <map>
+#include <ostream>
+#include <sstream>
+#include <string>
+
+#include <boost/date_time.hpp>
+#include <libxml/tree.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/xmlwriter.h>
+
+#include "libcmis/exception.hxx"
+#include "libcmis/libcmis-api.h"
+
+#define NS_CMIS_PREFIX "cmis"
+#define NS_CMISRA_PREFIX "cmisra"
+#define NS_SOAP_ENV_PREFIX "soap-env"
+#define NS_CMIS_URL "http://docs.oasis-open.org/ns/cmis/core/200908/"
+#define NS_CMISRA_URL "http://docs.oasis-open.org/ns/cmis/restatom/200908/"
+#define NS_CMISM_URL "http://docs.oasis-open.org/ns/cmis/messaging/200908/"
+#define NS_CMISW_URL "http://docs.oasis-open.org/ns/cmis/ws/200908/"
+#define NS_APP_URL "http://www.w3.org/2007/app"
+#define NS_ATOM_URL "http://www.w3.org/2005/Atom"
+#define NS_SOAP_URL "http://schemas.xmlsoap.org/wsdl/soap/"
+#define NS_SOAP_ENV_URL "http://schemas.xmlsoap.org/soap/envelope/"
+
+#define LIBCURL_VERSION_VALUE ( \
+ ( LIBCURL_VERSION_MAJOR << 16 ) | ( LIBCURL_VERSION_MINOR << 8 ) | ( LIBCURL_VERSION_PATCH ) \
+)
+
+namespace libcmis
+{
+ /** Class used to decode a stream.
+
+ An instance of this class can hold remaining un-decoded data to use
+ for a future decode call.
+ */
+ class LIBCMIS_API EncodedData
+ {
+ private:
+ xmlTextWriterPtr m_writer;
+ FILE* m_stream;
+ std::ostream* m_outStream;
+
+ std::string m_encoding;
+ bool m_decode;
+ unsigned long m_pendingValue;
+ int m_pendingRank;
+ size_t m_missingBytes;
+
+ public:
+ EncodedData( FILE* stream );
+ EncodedData( std::ostream* stream );
+ EncodedData( const EncodedData& rCopy );
+ EncodedData( xmlTextWriterPtr writer );
+
+ EncodedData& operator=( const EncodedData& rCopy );
+
+ void setEncoding( std::string encoding ) { m_encoding = encoding; }
+ void decode( void* buf, size_t size, size_t nmemb );
+ void encode( void* buf, size_t size, size_t nmemb );
+ void finish( );
+
+ private:
+ void write( void* buf, size_t size, size_t nmemb );
+ void decodeBase64( const char* buf, size_t len );
+ void encodeBase64( const char* buf, size_t len );
+ };
+
+ class LIBCMIS_API HttpResponse
+ {
+ private:
+ std::map< std::string, std::string > m_headers;
+ boost::shared_ptr< std::stringstream > m_stream;
+ boost::shared_ptr< EncodedData > m_data;
+
+ public:
+ HttpResponse( );
+ ~HttpResponse( ) { };
+
+ std::map< std::string, std::string >& getHeaders( ) { return m_headers; }
+ boost::shared_ptr< EncodedData > getData( ) { return m_data; }
+ boost::shared_ptr< std::stringstream > getStream( ) { return m_stream; }
+ };
+ typedef boost::shared_ptr< HttpResponse > HttpResponsePtr;
+
+ LIBCMIS_API void registerNamespaces( xmlXPathContextPtr xpathCtx );
+
+ /** Register the CMIS and WSDL / SOAP namespaces
+ */
+ LIBCMIS_API void registerCmisWSNamespaces( xmlXPathContextPtr xpathCtx );
+
+ /** Register only the WSD / SOAP namespaces.
+ */
+ LIBCMIS_API void registerSoapNamespaces( xmlXPathContextPtr xpathCtx );
+
+ LIBCMIS_API std::string getXPathValue( xmlXPathContextPtr xpathCtx, std::string req );
+
+ LIBCMIS_API xmlDocPtr wrapInDoc( xmlNodePtr entryNode );
+
+ /** Utility extracting an attribute value from an Xml Node,
+ based on the attribute name. If the defaultValue is NULL and
+ the attribute can't be found then throw an exception.
+ */
+ LIBCMIS_API std::string getXmlNodeAttributeValue( xmlNodePtr node,
+ const char* attributeName,
+ const char* defaultValue = NULL );
+
+ /** Parse a xsd:dateTime string and return the corresponding UTC posix time.
+ */
+ LIBCMIS_API boost::posix_time::ptime parseDateTime( std::string dateTimeStr );
+
+ /// Write a UTC time object to an xsd:dateTime string
+ LIBCMIS_API std::string writeDateTime( boost::posix_time::ptime time );
+
+ LIBCMIS_API bool parseBool( std::string str );
+
+ LIBCMIS_API long parseInteger( std::string str );
+
+ LIBCMIS_API double parseDouble( std::string str );
+
+ /** Trim spaces on the left and right of a string.
+ */
+ LIBCMIS_API std::string trim( const std::string& str );
+
+ LIBCMIS_API std::string base64encode( const std::string& str );
+
+ LIBCMIS_API std::string sha1( const std::string& str );
+
+ LIBCMIS_API int stringstream_write_callback(void * context, const char * s, int len);
+
+ LIBCMIS_API std::string escape( std::string str );
+
+ LIBCMIS_API std::string unescape( std::string str );
+}
+
+#endif
diff --git a/inc/libcmis/xmlserializable.hxx b/inc/libcmis/xmlserializable.hxx
new file mode 100644
index 0000000..bd7c7c2
--- /dev/null
+++ b/inc/libcmis/xmlserializable.hxx
@@ -0,0 +1,48 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _XMLSERIALIZABLE_HXX_
+#define _XMLSERIALIZABLE_HXX_
+
+#include <libxml/xmlwriter.h>
+
+#include "libcmis/libcmis-api.h"
+
+namespace libcmis
+{
+
+ /// Interface for objects dumpable as XML
+ class LIBCMIS_API XmlSerializable
+ {
+ public:
+ virtual ~XmlSerializable( ) { }
+
+ virtual void toXml( xmlTextWriterPtr writer ) = 0;
+ };
+}
+
+#endif
diff --git a/lgtm.yml b/lgtm.yml
new file mode 100644
index 0000000..998c2dd
--- /dev/null
+++ b/lgtm.yml
@@ -0,0 +1,9 @@
+path_classifiers:
+ library:
+ - src/inc
+ - src/libcmis
+ - src/libcmis-c
+ test:
+ - qa
+ tool:
+ - src/cmis-client.cxx
diff --git a/libcmis-c.pc.in b/libcmis-c.pc.in
new file mode 100644
index 0000000..9590d12
--- /dev/null
+++ b/libcmis-c.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libcmis
+Description: CMIS protocol C client library
+Version: @VERSION@
+Requires: libcmis-@LIBCMIS_API_VERSION@ libxml-2.0
+Requires.private: libcurl
+Libs: -L${libdir} -lcmis-c-@LIBCMIS_API_VERSION@
+Cflags: -I${includedir}/libcmis-c-@LIBCMIS_API_VERSION@
+
diff --git a/libcmis.pc.in b/libcmis.pc.in
new file mode 100644
index 0000000..c9307f1
--- /dev/null
+++ b/libcmis.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libcmis
+Description: CMIS protocol client library
+Version: @VERSION@
+Requires: libcurl libxml-2.0
+Libs: -L${libdir} -lcmis-@LIBCMIS_API_VERSION@
+Cflags: -I${includedir}/libcmis-@LIBCMIS_API_VERSION@
+
diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000..acc0db2
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,982 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the specified
+# version of the C++ standard. If necessary, add switches to CXX and
+# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
+# or '14' (for the C++14 standard).
+#
+# The second argument, if specified, indicates whether you insist on an
+# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+# -std=c++11). If neither is specified, you get whatever works, with
+# preference for an extended mode.
+#
+# The third argument, if specified 'mandatory' or if left unspecified,
+# indicates that baseline support for the specified C++ standard is
+# required and that the macro should error out if no mode with that
+# support is found. If specified 'optional', then configuration proceeds
+# regardless, after defining HAVE_CXX${VERSION} if and only if a
+# supporting mode is found.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+# Copyright (c) 2015 Paul Norman <penorman@mac.com>
+# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+# Copyright (c) 2016 Krzesimir Nowak <qdlacz@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 7
+
+dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl (serial version number 13).
+
+AX_REQUIRE_DEFINED([AC_MSG_WARN])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+ m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
+ [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
+ [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
+ [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$2], [], [],
+ [$2], [ext], [],
+ [$2], [noext], [],
+ [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+ m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+ [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+ [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+ AC_LANG_PUSH([C++])dnl
+ ac_success=no
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+ ax_cv_cxx_compile_cxx$1,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [ax_cv_cxx_compile_cxx$1=yes],
+ [ax_cv_cxx_compile_cxx$1=no])])
+ if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+ ac_success=yes
+ fi
+
+ m4_if([$2], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ switch="-std=gnu++${alternative}"
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$2], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ dnl HP's aCC needs +std=c++11 according to:
+ dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+ dnl Cray's crayCC needs "-h std=c++11"
+ for alternative in ${ax_cxx_compile_alternatives}; do
+ for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+ $cachevar,
+ [ac_save_CXX="$CXX"
+ CXX="$CXX $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXX="$ac_save_CXX"])
+ if eval test x\$$cachevar = xyes; then
+ CXX="$CXX $switch"
+ if test -n "$CXXCPP" ; then
+ CXXCPP="$CXXCPP $switch"
+ fi
+ ac_success=yes
+ break
+ fi
+ done
+ if test x$ac_success = xyes; then
+ break
+ fi
+ done
+ fi])
+ AC_LANG_POP([C++])
+ if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+ if test x$ac_success = xno; then
+ AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+ fi
+ fi
+ if test x$ac_success = xno; then
+ HAVE_CXX$1=0
+ AC_MSG_NOTICE([No compiler with C++$1 support was found])
+ else
+ HAVE_CXX$1=1
+ AC_DEFINE(HAVE_CXX$1,1,
+ [define if the compiler supports basic C++$1 syntax])
+ fi
+ AC_SUBST(HAVE_CXX$1)
+ m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the checks may change in incompatible ways anytime])])
+])
+
+
+dnl Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+ _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
+)
+
+dnl Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L && !(defined _MSC_VER)
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+ namespace test_static_assert
+ {
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ }
+
+ namespace test_final_override
+ {
+
+ struct Base
+ {
+ virtual void f() {}
+ };
+
+ struct Derived : public Base
+ {
+ virtual void f() override {}
+ };
+
+ }
+
+ namespace test_double_right_angle_brackets
+ {
+
+ template < typename T >
+ struct check {};
+
+ typedef check<void> single_type;
+ typedef check<check<void>> double_type;
+ typedef check<check<check<void>>> triple_type;
+ typedef check<check<check<check<void>>>> quadruple_type;
+
+ }
+
+ namespace test_decltype
+ {
+
+ int
+ f()
+ {
+ int a = 1;
+ decltype(a) b = 2;
+ return a + b;
+ }
+
+ }
+
+ namespace test_type_deduction
+ {
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static const bool value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static const bool value = true;
+ };
+
+ template < typename T1, typename T2 >
+ auto
+ add(T1 a1, T2 a2) -> decltype(a1 + a2)
+ {
+ return a1 + a2;
+ }
+
+ int
+ test(const int c, volatile int v)
+ {
+ static_assert(is_same<int, decltype(0)>::value == true, "");
+ static_assert(is_same<int, decltype(c)>::value == false, "");
+ static_assert(is_same<int, decltype(v)>::value == false, "");
+ auto ac = c;
+ auto av = v;
+ auto sumi = ac + av + 'x';
+ auto sumf = ac + av + 1.0;
+ static_assert(is_same<int, decltype(ac)>::value == true, "");
+ static_assert(is_same<int, decltype(av)>::value == true, "");
+ static_assert(is_same<int, decltype(sumi)>::value == true, "");
+ static_assert(is_same<int, decltype(sumf)>::value == false, "");
+ static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+ return (sumf > 0.0) ? sumi : add(c, v);
+ }
+
+ }
+
+ namespace test_noexcept
+ {
+
+ int f() { return 0; }
+ int g() noexcept { return 0; }
+
+ static_assert(noexcept(f()) == false, "");
+ static_assert(noexcept(g()) == true, "");
+
+ }
+
+ namespace test_constexpr
+ {
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+ {
+ return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+ }
+
+ template < typename CharT >
+ unsigned long constexpr
+ strlen_c(const CharT *const s) noexcept
+ {
+ return strlen_c_r(s, 0UL);
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("1") == 1UL, "");
+ static_assert(strlen_c("example") == 7UL, "");
+ static_assert(strlen_c("another\0example") == 7UL, "");
+
+ }
+
+ namespace test_rvalue_references
+ {
+
+ template < int N >
+ struct answer
+ {
+ static constexpr int value = N;
+ };
+
+ answer<1> f(int&) { return answer<1>(); }
+ answer<2> f(const int&) { return answer<2>(); }
+ answer<3> f(int&&) { return answer<3>(); }
+
+ void
+ test()
+ {
+ int i = 0;
+ const int c = 0;
+ static_assert(decltype(f(i))::value == 1, "");
+ static_assert(decltype(f(c))::value == 2, "");
+ static_assert(decltype(f(0))::value == 3, "");
+ }
+
+ }
+
+ namespace test_uniform_initialization
+ {
+
+ struct test
+ {
+ static const int zero {};
+ static const int one {1};
+ };
+
+ static_assert(test::zero == 0, "");
+ static_assert(test::one == 1, "");
+
+ }
+
+ namespace test_lambdas
+ {
+
+ void
+ test1()
+ {
+ auto lambda1 = [](){};
+ auto lambda2 = lambda1;
+ lambda1();
+ lambda2();
+ }
+
+ int
+ test2()
+ {
+ auto a = [](int i, int j){ return i + j; }(1, 2);
+ auto b = []() -> int { return '0'; }();
+ auto c = [=](){ return a + b; }();
+ auto d = [&](){ return c; }();
+ auto e = [a, &b](int x) mutable {
+ const auto identity = [](int y){ return y; };
+ for (auto i = 0; i < a; ++i)
+ a += b--;
+ return x + identity(a + b);
+ }(0);
+ return a + b + c + d + e;
+ }
+
+ int
+ test3()
+ {
+ const auto nullary = [](){ return 0; };
+ const auto unary = [](int x){ return x; };
+ using nullary_t = decltype(nullary);
+ using unary_t = decltype(unary);
+ const auto higher1st = [](nullary_t f){ return f(); };
+ const auto higher2nd = [unary](nullary_t f1){
+ return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+ };
+ return higher1st(nullary) + higher2nd(nullary)(unary);
+ }
+
+ }
+
+ namespace test_variadic_templates
+ {
+
+ template <int...>
+ struct sum;
+
+ template <int N0, int... N1toN>
+ struct sum<N0, N1toN...>
+ {
+ static constexpr auto value = N0 + sum<N1toN...>::value;
+ };
+
+ template <>
+ struct sum<>
+ {
+ static constexpr auto value = 0;
+ };
+
+ static_assert(sum<>::value == 0, "");
+ static_assert(sum<1>::value == 1, "");
+ static_assert(sum<23>::value == 23, "");
+ static_assert(sum<1, 2>::value == 3, "");
+ static_assert(sum<5, 5, 11>::value == 21, "");
+ static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+ }
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+ // because of this.
+ namespace test_template_alias_sfinae
+ {
+
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() { func<foo>(0); }
+
+ }
+
+} // namespace cxx11
+
+#endif // __cplusplus >= 201103L
+
+]])
+
+
+dnl Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+ namespace test_polymorphic_lambdas
+ {
+
+ int
+ test()
+ {
+ const auto lambda = [](auto&&... args){
+ const auto istiny = [](auto x){
+ return (sizeof(x) == 1UL) ? 1 : 0;
+ };
+ const int aretiny[] = { istiny(args)... };
+ return aretiny[0];
+ };
+ return lambda(1, 1L, 1.0f, '1');
+ }
+
+ }
+
+ namespace test_binary_literals
+ {
+
+ constexpr auto ivii = 0b0000000000101010;
+ static_assert(ivii == 42, "wrong value");
+
+ }
+
+ namespace test_generalized_constexpr
+ {
+
+ template < typename CharT >
+ constexpr unsigned long
+ strlen_c(const CharT *const s) noexcept
+ {
+ auto length = 0UL;
+ for (auto p = s; *p; ++p)
+ ++length;
+ return length;
+ }
+
+ static_assert(strlen_c("") == 0UL, "");
+ static_assert(strlen_c("x") == 1UL, "");
+ static_assert(strlen_c("test") == 4UL, "");
+ static_assert(strlen_c("another\0test") == 7UL, "");
+
+ }
+
+ namespace test_lambda_init_capture
+ {
+
+ int
+ test()
+ {
+ auto x = 0;
+ const auto lambda1 = [a = x](int b){ return a + b; };
+ const auto lambda2 = [a = lambda1(x)](){ return a; };
+ return lambda2();
+ }
+
+ }
+
+ namespace test_digit_separators
+ {
+
+ constexpr auto ten_million = 100'000'000;
+ static_assert(ten_million == 100000000, "");
+
+ }
+
+ namespace test_return_type_deduction
+ {
+
+ auto f(int& x) { return x; }
+ decltype(auto) g(int& x) { return x; }
+
+ template < typename T1, typename T2 >
+ struct is_same
+ {
+ static constexpr auto value = false;
+ };
+
+ template < typename T >
+ struct is_same<T, T>
+ {
+ static constexpr auto value = true;
+ };
+
+ int
+ test()
+ {
+ auto x = 0;
+ static_assert(is_same<int, decltype(f(x))>::value, "");
+ static_assert(is_same<int&, decltype(g(x))>::value, "");
+ return x;
+ }
+
+ }
+
+} // namespace cxx14
+
+#endif // __cplusplus >= 201402L
+
+]])
+
+
+dnl Tests for new features in C++17
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
+
+// If the compiler admits that it is not ready for C++17, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus <= 201402L
+
+#error "This is not a C++17 compiler"
+
+#else
+
+#if defined(__clang__)
+ #define REALLY_CLANG
+#else
+ #if defined(__GNUC__)
+ #define REALLY_GCC
+ #endif
+#endif
+
+#include <initializer_list>
+#include <utility>
+#include <type_traits>
+
+namespace cxx17
+{
+
+#if !defined(REALLY_CLANG)
+ namespace test_constexpr_lambdas
+ {
+
+ // TODO: test it with clang++ from git
+
+ constexpr int foo = [](){return 42;}();
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+ namespace test::nested_namespace::definitions
+ {
+
+ }
+
+ namespace test_fold_expression
+ {
+
+ template<typename... Args>
+ int multiply(Args... args)
+ {
+ return (args * ... * 1);
+ }
+
+ template<typename... Args>
+ bool all(Args... args)
+ {
+ return (args && ...);
+ }
+
+ }
+
+ namespace test_extended_static_assert
+ {
+
+ static_assert (true);
+
+ }
+
+ namespace test_auto_brace_init_list
+ {
+
+ auto foo = {5};
+ auto bar {5};
+
+ static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
+ static_assert(std::is_same<int, decltype(bar)>::value);
+ }
+
+ namespace test_typename_in_template_template_parameter
+ {
+
+ template<template<typename> typename X> struct D;
+
+ }
+
+ namespace test_fallthrough_nodiscard_maybe_unused_attributes
+ {
+
+ int f1()
+ {
+ return 42;
+ }
+
+ [[nodiscard]] int f2()
+ {
+ [[maybe_unused]] auto unused = f1();
+
+ switch (f1())
+ {
+ case 17:
+ f1();
+ [[fallthrough]];
+ case 42:
+ f1();
+ }
+ return f1();
+ }
+
+ }
+
+ namespace test_extended_aggregate_initialization
+ {
+
+ struct base1
+ {
+ int b1, b2 = 42;
+ };
+
+ struct base2
+ {
+ base2() {
+ b3 = 42;
+ }
+ int b3;
+ };
+
+ struct derived : base1, base2
+ {
+ int d;
+ };
+
+ derived d1 {{1, 2}, {}, 4}; // full initialization
+ derived d2 {{}, {}, 4}; // value-initialized bases
+
+ }
+
+ namespace test_general_range_based_for_loop
+ {
+
+ struct iter
+ {
+ int i;
+
+ int& operator* ()
+ {
+ return i;
+ }
+
+ const int& operator* () const
+ {
+ return i;
+ }
+
+ iter& operator++()
+ {
+ ++i;
+ return *this;
+ }
+ };
+
+ struct sentinel
+ {
+ int i;
+ };
+
+ bool operator== (const iter& i, const sentinel& s)
+ {
+ return i.i == s.i;
+ }
+
+ bool operator!= (const iter& i, const sentinel& s)
+ {
+ return !(i == s);
+ }
+
+ struct range
+ {
+ iter begin() const
+ {
+ return {0};
+ }
+
+ sentinel end() const
+ {
+ return {5};
+ }
+ };
+
+ void f()
+ {
+ range r {};
+
+ for (auto i : r)
+ {
+ [[maybe_unused]] auto v = i;
+ }
+ }
+
+ }
+
+ namespace test_lambda_capture_asterisk_this_by_value
+ {
+
+ struct t
+ {
+ int i;
+ int foo()
+ {
+ return [*this]()
+ {
+ return i;
+ }();
+ }
+ };
+
+ }
+
+ namespace test_enum_class_construction
+ {
+
+ enum class byte : unsigned char
+ {};
+
+ byte foo {42};
+
+ }
+
+ namespace test_constexpr_if
+ {
+
+ template <bool cond>
+ int f ()
+ {
+ if constexpr(cond)
+ {
+ return 13;
+ }
+ else
+ {
+ return 42;
+ }
+ }
+
+ }
+
+ namespace test_selection_statement_with_initializer
+ {
+
+ int f()
+ {
+ return 13;
+ }
+
+ int f2()
+ {
+ if (auto i = f(); i > 0)
+ {
+ return 3;
+ }
+
+ switch (auto i = f(); i + 4)
+ {
+ case 17:
+ return 2;
+
+ default:
+ return 1;
+ }
+ }
+
+ }
+
+#if !defined(REALLY_CLANG)
+ namespace test_template_argument_deduction_for_class_templates
+ {
+
+ // TODO: test it with clang++ from git
+
+ template <typename T1, typename T2>
+ struct pair
+ {
+ pair (T1 p1, T2 p2)
+ : m1 {p1},
+ m2 {p2}
+ {}
+
+ T1 m1;
+ T2 m2;
+ };
+
+ void f()
+ {
+ [[maybe_unused]] auto p = pair{13, 42u};
+ }
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+ namespace test_non_type_auto_template_parameters
+ {
+
+ template <auto n>
+ struct B
+ {};
+
+ B<5> b1;
+ B<'a'> b2;
+
+ }
+
+#if !defined(REALLY_CLANG)
+ namespace test_structured_bindings
+ {
+
+ // TODO: test it with clang++ from git
+
+ int arr[2] = { 1, 2 };
+ std::pair<int, int> pr = { 1, 2 };
+
+ auto f1() -> int(&)[2]
+ {
+ return arr;
+ }
+
+ auto f2() -> std::pair<int, int>&
+ {
+ return pr;
+ }
+
+ struct S
+ {
+ int x1 : 2;
+ volatile double y1;
+ };
+
+ S f3()
+ {
+ return {};
+ }
+
+ auto [ x1, y1 ] = f1();
+ auto& [ xr1, yr1 ] = f1();
+ auto [ x2, y2 ] = f2();
+ auto& [ xr2, yr2 ] = f2();
+ const auto [ x3, y3 ] = f3();
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+#if !defined(REALLY_CLANG)
+ namespace test_exception_spec_type_system
+ {
+
+ // TODO: test it with clang++ from git
+
+ struct Good {};
+ struct Bad {};
+
+ void g1() noexcept;
+ void g2();
+
+ template<typename T>
+ Bad
+ f(T*, T*);
+
+ template<typename T1, typename T2>
+ Good
+ f(T1*, T2*);
+
+ static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
+
+ }
+#endif // !defined(REALLY_CLANG)
+
+ namespace test_inline_variables
+ {
+
+ template<class T> void f(T)
+ {}
+
+ template<class T> inline T g(T)
+ {
+ return T{};
+ }
+
+ template<> inline void f<>(int)
+ {}
+
+ template<> int g<>(int)
+ {
+ return 5;
+ }
+
+ }
+
+} // namespace cxx17
+
+#endif // __cplusplus <= 201402L
+
+]])
diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4
new file mode 100644
index 0000000..1733fd8
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx_11.m4
@@ -0,0 +1,39 @@
+# =============================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# =============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the C++11
+# standard; if necessary, add switches to CXX and CXXCPP to enable
+# support.
+#
+# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
+# macro with the version set to C++11. The two optional arguments are
+# forwarded literally as the second and third argument respectively.
+# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
+# more information. If you want to use this macro, you also need to
+# download the ax_cxx_compile_stdcxx.m4 file.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+# Copyright (c) 2015 Paul Norman <penorman@mac.com>
+# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 18
+
+AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])
diff --git a/m4/ax_gcc_func_attribute.m4 b/m4/ax_gcc_func_attribute.m4
new file mode 100644
index 0000000..098c9aa
--- /dev/null
+++ b/m4/ax_gcc_func_attribute.m4
@@ -0,0 +1,238 @@
+# ===========================================================================
+# https://www.gnu.org/software/autoconf-archive/ax_gcc_func_attribute.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_GCC_FUNC_ATTRIBUTE(ATTRIBUTE)
+#
+# DESCRIPTION
+#
+# This macro checks if the compiler supports one of GCC's function
+# attributes; many other compilers also provide function attributes with
+# the same syntax. Compiler warnings are used to detect supported
+# attributes as unsupported ones are ignored by default so quieting
+# warnings when using this macro will yield false positives.
+#
+# The ATTRIBUTE parameter holds the name of the attribute to be checked.
+#
+# If ATTRIBUTE is supported define HAVE_FUNC_ATTRIBUTE_<ATTRIBUTE>.
+#
+# The macro caches its result in the ax_cv_have_func_attribute_<attribute>
+# variable.
+#
+# The macro currently supports the following function attributes:
+#
+# alias
+# aligned
+# alloc_size
+# always_inline
+# artificial
+# cold
+# const
+# constructor
+# constructor_priority for constructor attribute with priority
+# deprecated
+# destructor
+# dllexport
+# dllimport
+# error
+# externally_visible
+# fallthrough
+# flatten
+# format
+# format_arg
+# gnu_inline
+# hot
+# ifunc
+# leaf
+# malloc
+# noclone
+# noinline
+# nonnull
+# noreturn
+# nothrow
+# optimize
+# pure
+# sentinel
+# sentinel_position
+# unused
+# used
+# visibility
+# warning
+# warn_unused_result
+# weak
+# weakref
+#
+# Unsupported function attributes will be tested with a prototype
+# returning an int and not accepting any arguments and the result of the
+# check might be wrong or meaningless so use with care.
+#
+# LICENSE
+#
+# Copyright (c) 2013 Gabriele Svelto <gabriele.svelto@gmail.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 9
+
+AC_DEFUN([AX_GCC_FUNC_ATTRIBUTE], [
+ AS_VAR_PUSHDEF([ac_var], [ax_cv_have_func_attribute_$1])
+
+ AC_CACHE_CHECK([for __attribute__(($1))], [ac_var], [
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([
+ m4_case([$1],
+ [alias], [
+ int foo( void ) { return 0; }
+ int bar( void ) __attribute__(($1("foo")));
+ ],
+ [aligned], [
+ int foo( void ) __attribute__(($1(32)));
+ ],
+ [alloc_size], [
+ void *foo(int a) __attribute__(($1(1)));
+ ],
+ [always_inline], [
+ inline __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [artificial], [
+ inline __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [cold], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [const], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [constructor_priority], [
+ int foo( void ) __attribute__((__constructor__(65535/2)));
+ ],
+ [constructor], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [deprecated], [
+ int foo( void ) __attribute__(($1("")));
+ ],
+ [destructor], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [dllexport], [
+ __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [dllimport], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [error], [
+ int foo( void ) __attribute__(($1("")));
+ ],
+ [externally_visible], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [fallthrough], [
+ int foo( void ) {switch (0) { case 1: __attribute__(($1)); case 2: break ; }};
+ ],
+ [flatten], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [format], [
+ int foo(const char *p, ...) __attribute__(($1(printf, 1, 2)));
+ ],
+ [format_arg], [
+ char *foo(const char *p) __attribute__(($1(1)));
+ ],
+ [gnu_inline], [
+ inline __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [hot], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [ifunc], [
+ int my_foo( void ) { return 0; }
+ static int (*resolve_foo(void))(void) { return my_foo; }
+ int foo( void ) __attribute__(($1("resolve_foo")));
+ ],
+ [leaf], [
+ __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [malloc], [
+ void *foo( void ) __attribute__(($1));
+ ],
+ [noclone], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [noinline], [
+ __attribute__(($1)) int foo( void ) { return 0; }
+ ],
+ [nonnull], [
+ int foo(char *p) __attribute__(($1(1)));
+ ],
+ [noreturn], [
+ void foo( void ) __attribute__(($1));
+ ],
+ [nothrow], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [optimize], [
+ __attribute__(($1(3))) int foo( void ) { return 0; }
+ ],
+ [pure], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [sentinel], [
+ int foo(void *p, ...) __attribute__(($1));
+ ],
+ [sentinel_position], [
+ int foo(void *p, ...) __attribute__(($1(1)));
+ ],
+ [returns_nonnull], [
+ void *foo( void ) __attribute__(($1));
+ ],
+ [unused], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [used], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [visibility], [
+ int foo_def( void ) __attribute__(($1("default")));
+ int foo_hid( void ) __attribute__(($1("hidden")));
+ int foo_int( void ) __attribute__(($1("internal")));
+ int foo_pro( void ) __attribute__(($1("protected")));
+ ],
+ [warning], [
+ int foo( void ) __attribute__(($1("")));
+ ],
+ [warn_unused_result], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [weak], [
+ int foo( void ) __attribute__(($1));
+ ],
+ [weakref], [
+ static int foo( void ) { return 0; }
+ static int bar( void ) __attribute__(($1("foo")));
+ ],
+ [
+ m4_warn([syntax], [Unsupported attribute $1, the test may fail])
+ int foo( void ) __attribute__(($1));
+ ]
+ )], [])
+ ],
+ dnl GCC doesn't exit with an error if an unknown attribute is
+ dnl provided but only outputs a warning, so accept the attribute
+ dnl only if no warning were issued.
+ [AS_IF([test -s conftest.err],
+ [AS_VAR_SET([ac_var], [no])],
+ [AS_VAR_SET([ac_var], [yes])])],
+ [AS_VAR_SET([ac_var], [no])])
+ ])
+
+ AS_IF([test yes = AS_VAR_GET([ac_var])],
+ [AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_FUNC_ATTRIBUTE_$1), 1,
+ [Define to 1 if the system has the `$1' function attribute])], [])
+
+ AS_VAR_POPDEF([ac_var])
+])
diff --git a/m4/boost.m4 b/m4/boost.m4
new file mode 100644
index 0000000..2c1df68
--- /dev/null
+++ b/m4/boost.m4
@@ -0,0 +1,1568 @@
+# boost.m4: Locate Boost headers and libraries for autoconf-based projects.
+# Copyright (C) 2007-2011, 2014 Benoit Sigoure <tsuna@lrde.epita.fr>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Additional permission under section 7 of the GNU General Public
+# License, version 3 ("GPLv3"):
+#
+# If you convey this file as part of a work that contains a
+# configuration script generated by Autoconf, you may do so under
+# terms of your choice.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+m4_define([_BOOST_SERIAL], [m4_translit([
+# serial 26
+], [#
+], [])])
+
+# Original sources can be found at http://github.com/tsuna/boost.m4
+# You can fetch the latest version of the script by doing:
+# wget http://github.com/tsuna/boost.m4/raw/master/build-aux/boost.m4
+
+# ------ #
+# README #
+# ------ #
+
+# This file provides several macros to use the various Boost libraries.
+# The first macro is BOOST_REQUIRE. It will simply check if it's possible to
+# find the Boost headers of a given (optional) minimum version and it will
+# define BOOST_CPPFLAGS accordingly. It will add an option --with-boost to
+# your configure so that users can specify non standard locations.
+# If the user's environment contains BOOST_ROOT and --with-boost was not
+# specified, --with-boost=$BOOST_ROOT is implicitly used.
+# For more README and documentation, go to http://github.com/tsuna/boost.m4
+# Note: THESE MACROS ASSUME THAT YOU USE LIBTOOL. If you don't, don't worry,
+# simply read the README, it will show you what to do step by step.
+
+m4_pattern_forbid([^_?(BOOST|Boost)_])
+
+
+# _BOOST_SED_CPP(SED-PROGRAM, PROGRAM,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# --------------------------------------------------------
+# Same as AC_EGREP_CPP, but leave the result in conftest.i.
+#
+# SED-PROGRAM is *not* overquoted, as in AC_EGREP_CPP. It is expanded
+# in double-quotes, so escape your double quotes.
+#
+# It could be useful to turn this into a macro which extracts the
+# value of any macro.
+m4_define([_BOOST_SED_CPP],
+[AC_LANG_PUSH([C++])dnl
+AC_LANG_PREPROC_REQUIRE()dnl
+AC_REQUIRE([AC_PROG_SED])dnl
+AC_LANG_CONFTEST([AC_LANG_SOURCE([[$2]])])
+AS_IF([dnl eval is necessary to expand ac_cpp.
+dnl Ultrix and Pyramid sh refuse to redirect output of eval, so use subshell.
+dnl Beware of Windows end-of-lines, for instance if we are running
+dnl some Windows programs under Wine. In that case, boost/version.hpp
+dnl is certainly using "\r\n", but the regular Unix shell will only
+dnl strip `\n' with backquotes, not the `\r'. This results in
+dnl boost_cv_lib_version='1_37\r' for instance, which breaks
+dnl everything else.
+dnl Cannot use 'dnl' after [$4] because a trailing dnl may break AC_CACHE_CHECK
+dnl
+dnl Beware that GCC 5, when expanding macros, may embed # line directives
+dnl a within single line:
+dnl
+dnl # 1 "conftest.cc"
+dnl # 1 "<built-in>"
+dnl # 1 "<command-line>"
+dnl # 1 "conftest.cc"
+dnl # 1 "/opt/local/include/boost/version.hpp" 1 3
+dnl # 2 "conftest.cc" 2
+dnl boost-lib-version =
+dnl # 2 "conftest.cc" 3
+dnl "1_56"
+dnl
+dnl So get rid of the # and empty lines, and glue the remaining ones together.
+(eval "$ac_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD |
+ grep -v '#' |
+ grep -v '^[[[:space:]]]*$' |
+ tr -d '\r' |
+ tr -s '\n' ' ' |
+ $SED -n -e "$1" >conftest.i 2>&1],
+ [$3],
+ [$4])
+rm -rf conftest*
+AC_LANG_POP([C++])dnl
+])# _BOOST_SED_CPP
+
+
+
+# BOOST_REQUIRE([VERSION], [ACTION-IF-NOT-FOUND])
+# -----------------------------------------------
+# Look for Boost. If version is given, it must either be a literal of the form
+# "X.Y.Z" where X, Y and Z are integers (the ".Z" part being optional) or a
+# variable "$var".
+# Defines the value BOOST_CPPFLAGS. This macro only checks for headers with
+# the required version, it does not check for any of the Boost libraries.
+# On # success, defines HAVE_BOOST. On failure, calls the optional
+# ACTION-IF-NOT-FOUND action if one was supplied.
+# Otherwise aborts with an error message.
+AC_DEFUN_ONCE([BOOST_REQUIRE],
+[AC_REQUIRE([AC_PROG_CXX])dnl
+AC_REQUIRE([AC_PROG_GREP])dnl
+echo "$as_me: this is boost.m4[]_BOOST_SERIAL" >&AS_MESSAGE_LOG_FD
+boost_save_IFS=$IFS
+boost_version_req=$1
+IFS=.
+set x $boost_version_req 0 0 0
+IFS=$boost_save_IFS
+shift
+boost_version_req=`expr "$[1]" '*' 100000 + "$[2]" '*' 100 + "$[3]"`
+boost_version_req_string=$[1].$[2].$[3]
+AC_ARG_WITH([boost],
+ [AS_HELP_STRING([--with-boost=DIR],
+ [prefix of Boost $1 @<:@guess@:>@])])dnl
+AC_ARG_VAR([BOOST_ROOT],[Location of Boost installation])dnl
+# If BOOST_ROOT is set and the user has not provided a value to
+# --with-boost, then treat BOOST_ROOT as if it the user supplied it.
+if test x"$BOOST_ROOT" != x; then
+ if test x"$with_boost" = x; then
+ AC_MSG_NOTICE([Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT])
+ with_boost=$BOOST_ROOT
+ else
+ AC_MSG_NOTICE([Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost])
+ fi
+fi
+AC_SUBST([DISTCHECK_CONFIGURE_FLAGS],
+ ["$DISTCHECK_CONFIGURE_FLAGS '--with-boost=$with_boost'"])dnl
+boost_save_CPPFLAGS=$CPPFLAGS
+ AC_CACHE_CHECK([for Boost headers version >= $boost_version_req_string],
+ [boost_cv_inc_path],
+ [boost_cv_inc_path=no
+AC_LANG_PUSH([C++])dnl
+m4_pattern_allow([^BOOST_VERSION$])dnl
+ AC_LANG_CONFTEST([AC_LANG_PROGRAM([[#include <boost/version.hpp>
+#if !defined BOOST_VERSION
+# error BOOST_VERSION is not defined
+#elif BOOST_VERSION < $boost_version_req
+# error Boost headers version < $boost_version_req
+#endif
+]])])
+ # If the user provided a value to --with-boost, use it and only it.
+ case $with_boost in #(
+ ''|yes) set x '' /opt/local/include /usr/local/include /opt/include \
+ /usr/include C:/Boost/include;; #(
+ *) set x "$with_boost/include" "$with_boost";;
+ esac
+ shift
+ for boost_dir
+ do
+ # Without --layout=system, Boost (or at least some versions) installs
+ # itself in <prefix>/include/boost-<version>. This inner loop helps to
+ # find headers in such directories.
+ #
+ # Any ${boost_dir}/boost-x_xx directories are searched in reverse version
+ # order followed by ${boost_dir}. The final '.' is a sentinel for
+ # searching $boost_dir" itself. Entries are whitespace separated.
+ #
+ # I didn't indent this loop on purpose (to avoid over-indented code)
+ boost_layout_system_search_list=`cd "$boost_dir" 2>/dev/null \
+ && ls -1 | "${GREP}" '^boost-' | sort -rn -t- -k2 \
+ && echo .`
+ for boost_inc in $boost_layout_system_search_list
+ do
+ if test x"$boost_inc" != x.; then
+ boost_inc="$boost_dir/$boost_inc"
+ else
+ boost_inc="$boost_dir" # Uses sentinel in boost_layout_system_search_list
+ fi
+ if test x"$boost_inc" != x; then
+ # We are going to check whether the version of Boost installed
+ # in $boost_inc is usable by running a compilation that
+ # #includes it. But if we pass a -I/some/path in which Boost
+ # is not installed, the compiler will just skip this -I and
+ # use other locations (either from CPPFLAGS, or from its list
+ # of system include directories). As a result we would use
+ # header installed on the machine instead of the /some/path
+ # specified by the user. So in that precise case (trying
+ # $boost_inc), make sure the version.hpp exists.
+ #
+ # Use test -e as there can be symlinks.
+ test -e "$boost_inc/boost/version.hpp" || continue
+ CPPFLAGS="$CPPFLAGS -I$boost_inc"
+ fi
+ AC_COMPILE_IFELSE([], [boost_cv_inc_path=yes], [boost_cv_version=no])
+ if test x"$boost_cv_inc_path" = xyes; then
+ if test x"$boost_inc" != x; then
+ boost_cv_inc_path=$boost_inc
+ fi
+ break 2
+ fi
+ done
+ done
+AC_LANG_POP([C++])dnl
+ ])
+ case $boost_cv_inc_path in #(
+ no)
+ boost_errmsg="cannot find Boost headers version >= $boost_version_req_string"
+ m4_if([$2], [], [AC_MSG_ERROR([$boost_errmsg])],
+ [AC_MSG_NOTICE([$boost_errmsg])])
+ $2
+ ;;#(
+ yes)
+ BOOST_CPPFLAGS=
+ ;;#(
+ *)
+ AC_SUBST([BOOST_CPPFLAGS], ["-I$boost_cv_inc_path"])dnl
+ ;;
+ esac
+ if test x"$boost_cv_inc_path" != xno; then
+ AC_DEFINE([HAVE_BOOST], [1],
+ [Defined if the requested minimum BOOST version is satisfied])
+ AC_CACHE_CHECK([for Boost's header version],
+ [boost_cv_lib_version],
+ [m4_pattern_allow([^BOOST_LIB_VERSION$])dnl
+ _BOOST_SED_CPP([[/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}]],
+ [#include <boost/version.hpp>
+boost-lib-version = BOOST_LIB_VERSION],
+ [boost_cv_lib_version=`cat conftest.i`])])
+ # e.g. "134" for 1_34_1 or "135" for 1_35
+ boost_major_version=`echo "$boost_cv_lib_version" | sed 's/_//;s/_.*//'`
+ case $boost_major_version in #(
+ '' | *[[!0-9]]*)
+ AC_MSG_ERROR([invalid value: boost_major_version='$boost_major_version'])
+ ;;
+ esac
+fi
+CPPFLAGS=$boost_save_CPPFLAGS
+])# BOOST_REQUIRE
+
+
+# BOOST_STATIC()
+# --------------
+# Add the "--enable-static-boost" configure argument. If this argument is given
+# on the command line, static versions of the libraries will be looked up.
+AC_DEFUN([BOOST_STATIC],
+ [AC_ARG_ENABLE([static-boost],
+ [AS_HELP_STRING([--enable-static-boost],
+ [Prefer the static boost libraries over the shared ones [no]])],
+ [enable_static_boost=yes],
+ [enable_static_boost=no])])# BOOST_STATIC
+
+
+# BOOST_FIND_HEADER([HEADER-NAME], [ACTION-IF-NOT-FOUND], [ACTION-IF-FOUND])
+# --------------------------------------------------------------------------
+# Wrapper around AC_CHECK_HEADER for Boost headers. Useful to check for
+# some parts of the Boost library which are only made of headers and don't
+# require linking (such as Boost.Foreach).
+#
+# Default ACTION-IF-NOT-FOUND: Fail with a fatal error unless Boost couldn't be
+# found in the first place, in which case by default a notice is issued to the
+# user. Presumably if we haven't died already it's because it's OK to not have
+# Boost, which is why only a notice is issued instead of a hard error.
+#
+# Default ACTION-IF-FOUND: define the preprocessor symbol HAVE_<HEADER-NAME> in
+# case of success # (where HEADER-NAME is written LIKE_THIS, e.g.,
+# HAVE_BOOST_FOREACH_HPP).
+AC_DEFUN([BOOST_FIND_HEADER],
+[AC_REQUIRE([BOOST_REQUIRE])dnl
+if test x"$boost_cv_inc_path" = xno; then
+ m4_default([$2], [AC_MSG_NOTICE([Boost not available, not searching for $1])])
+else
+AC_LANG_PUSH([C++])dnl
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+AC_CHECK_HEADER([$1],
+ [m4_default([$3], [AC_DEFINE(AS_TR_CPP([HAVE_$1]), [1],
+ [Define to 1 if you have <$1>])])],
+ [m4_default([$2], [AC_MSG_ERROR([cannot find $1])])])
+CPPFLAGS=$boost_save_CPPFLAGS
+AC_LANG_POP([C++])dnl
+fi
+])# BOOST_FIND_HEADER
+
+
+# BOOST_FIND_LIBS([COMPONENT-NAME], [CANDIDATE-LIB-NAMES],
+# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
+# [CXX-PROLOGUE])
+# --------------------------------------------------------------
+# Look for the Boost library COMPONENT-NAME (e.g., `thread', for
+# libboost_thread) under the possible CANDIDATE-LIB-NAMES (e.g.,
+# "thread_win32 thread"). Check that HEADER-NAME works and check that
+# libboost_LIB-NAME can link with the code CXX-TEST. The optional
+# argument CXX-PROLOGUE can be used to include some C++ code before
+# the `main' function.
+#
+# Invokes BOOST_FIND_HEADER([HEADER-NAME]) (see above).
+#
+# Boost libraries typically come compiled with several flavors (with different
+# runtime options) so PREFERRED-RT-OPT is the preferred suffix. A suffix is one
+# or more of the following letters: sgdpn (in that order). s = static
+# runtime, d = debug build, g = debug/diagnostic runtime, p = STLPort build,
+# n = (unsure) STLPort build without iostreams from STLPort (it looks like `n'
+# must always be used along with `p'). Additionally, PREFERRED-RT-OPT can
+# start with `mt-' to indicate that there is a preference for multi-thread
+# builds. Some sample values for PREFERRED-RT-OPT: (nothing), mt, d, mt-d, gdp
+# ... If you want to make sure you have a specific version of Boost
+# (eg, >= 1.33) you *must* invoke BOOST_REQUIRE before this macro.
+AC_DEFUN([BOOST_FIND_LIBS],
+[AC_REQUIRE([BOOST_REQUIRE])dnl
+AC_REQUIRE([_BOOST_FIND_COMPILER_TAG])dnl
+AC_REQUIRE([BOOST_STATIC])dnl
+AC_REQUIRE([_BOOST_GUESS_WHETHER_TO_USE_MT])dnl
+if test x"$boost_cv_inc_path" = xno; then
+ AC_MSG_NOTICE([Boost not available, not searching for the Boost $1 library])
+else
+dnl The else branch is huge and wasn't intended on purpose.
+AC_LANG_PUSH([C++])dnl
+AS_VAR_PUSHDEF([Boost_lib], [boost_cv_lib_$1])dnl
+AS_VAR_PUSHDEF([Boost_lib_LDFLAGS], [boost_cv_lib_$1_LDFLAGS])dnl
+AS_VAR_PUSHDEF([Boost_lib_LDPATH], [boost_cv_lib_$1_LDPATH])dnl
+AS_VAR_PUSHDEF([Boost_lib_LIBS], [boost_cv_lib_$1_LIBS])dnl
+BOOST_FIND_HEADER([$4])
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+AC_CACHE_CHECK([for the Boost $1 library], [Boost_lib],
+ [_BOOST_FIND_LIBS($@)])
+case $Boost_lib in #(
+ (no) _AC_MSG_LOG_CONFTEST
+ AC_MSG_ERROR([cannot find the flags to link with Boost $1])
+ ;;
+esac
+AC_SUBST(AS_TR_CPP([BOOST_$1_LDFLAGS]), [$Boost_lib_LDFLAGS])dnl
+AC_SUBST(AS_TR_CPP([BOOST_$1_LDPATH]), [$Boost_lib_LDPATH])dnl
+AC_SUBST([BOOST_LDPATH], [$Boost_lib_LDPATH])dnl
+AC_SUBST(AS_TR_CPP([BOOST_$1_LIBS]), [$Boost_lib_LIBS])dnl
+CPPFLAGS=$boost_save_CPPFLAGS
+AS_VAR_POPDEF([Boost_lib])dnl
+AS_VAR_POPDEF([Boost_lib_LDFLAGS])dnl
+AS_VAR_POPDEF([Boost_lib_LDPATH])dnl
+AS_VAR_POPDEF([Boost_lib_LIBS])dnl
+AC_LANG_POP([C++])dnl
+fi
+])
+
+
+# BOOST_FIND_LIB([LIB-NAME],
+# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
+# [CXX-PROLOGUE])
+# --------------------------------------------------------------
+# Backward compatibility wrapper for BOOST_FIND_LIBS.
+AC_DEFUN([BOOST_FIND_LIB],
+[BOOST_FIND_LIBS([$1], $@)])
+
+
+# _BOOST_FIND_LIBS([LIB-NAME], [CANDIDATE-LIB-NAMES],
+# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
+# [CXX-PROLOGUE])
+# --------------------------------------------------------------
+# Real implementation of BOOST_FIND_LIBS: rely on these local macros:
+# Boost_lib, Boost_lib_LDFLAGS, Boost_lib_LDPATH, Boost_lib_LIBS
+#
+# The algorithm is as follows: first look for a given library name
+# according to the user's PREFERRED-RT-OPT. For each library name, we
+# prefer to use the ones that carry the tag (toolset name). Each
+# library is searched through the various standard paths were Boost is
+# usually installed. If we can't find the standard variants, we try
+# to enforce -mt (for instance on MacOSX, libboost_thread.dylib
+# doesn't exist but there's -obviously- libboost_thread-mt.dylib).
+AC_DEFUN([_BOOST_FIND_LIBS],
+[Boost_lib=no
+ case "$3" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X$3" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=$3;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[[sgpn]]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ AC_MSG_ERROR([the libext variable is empty, did you invoke Libtool?])
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <$4>
+$6], [$5])])
+dnl Optimization hacks: compiling C++ is slow, especially with Boost. What
+dnl we're trying to do here is guess the right combination of link flags
+dnl (LIBS / LDFLAGS) to use a given library. This can take several
+dnl iterations before it succeeds and is thus *very* slow. So what we do
+dnl instead is that we compile the code first (and thus get an object file,
+dnl typically conftest.o). Then we try various combinations of link flags
+dnl until we succeed to link conftest.o in an executable. The problem is
+dnl that the various TRY_LINK / COMPILE_IFELSE macros of Autoconf always
+dnl remove all the temporary files including conftest.o. So the trick here
+dnl is to temporarily change the value of ac_objext so that conftest.o is
+dnl preserved accross tests. This is obviously fragile and I will burn in
+dnl hell for not respecting Autoconf's documented interfaces, but in the
+dnl mean time, it optimizes the macro by a factor of 5 to 30.
+dnl Another small optimization: the first argument of AC_COMPILE_IFELSE left
+dnl empty because the test file is generated only once above (before we
+dnl start the for loops).
+ AC_COMPILE_IFELSE([],
+ [ac_objext=do_not_rm_me_plz],
+ [AC_MSG_ERROR([cannot compile a test that uses Boost $1])])
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in $2; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ Boost_lib_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$Boost_lib_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ Boost_lib_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$Boost_lib_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+dnl First argument of AC_LINK_IFELSE left empty because the test file is
+dnl generated only once above (before we start the for loops).
+ _BOOST_AC_LINK_IFELSE([],
+ [Boost_lib=yes], [Boost_lib=no])
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$Boost_lib" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ AC_CACHE_VAL([boost_cv_rpath_link_ldflag],
+ [case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $Boost_lib_LIBS"
+ _BOOST_AC_LINK_IFELSE([],
+ [boost_rpath_link_ldflag_found=yes
+ break],
+ [boost_rpath_link_ldflag_found=no])
+ done
+ ;;
+ esac
+ AS_IF([test "x$boost_rpath_link_ldflag_found" != "xyes"],
+ [AC_MSG_ERROR([Unable to determine whether to use -R or -rpath])])
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ ])
+ test x"$boost_ldpath" != x &&
+ Boost_lib_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ Boost_lib_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+])
+
+
+
+# --------------------------------------- #
+# Checks for the various Boost libraries. #
+# --------------------------------------- #
+
+# List of boost libraries: http://www.boost.org/libs/libraries.htm
+# The page http://beta.boost.org/doc/libs is useful: it gives the first release
+# version of each library (among other things).
+
+# BOOST_DEFUN(LIBRARY, CODE)
+# --------------------------
+# Define BOOST_<LIBRARY-UPPERCASE> as a macro that runs CODE.
+#
+# Use indir to avoid the warning on underquoted macro name given to AC_DEFUN.
+m4_define([BOOST_DEFUN],
+[m4_indir([AC_DEFUN],
+ m4_toupper([BOOST_$1]),
+[m4_pushdef([BOOST_Library], [$1])dnl
+$2
+m4_popdef([BOOST_Library])dnl
+])
+])
+
+# BOOST_ARRAY()
+# -------------
+# Look for Boost.Array
+BOOST_DEFUN([Array],
+[BOOST_FIND_HEADER([boost/array.hpp])])
+
+
+# BOOST_ASIO()
+# ------------
+# Look for Boost.Asio (new in Boost 1.35).
+BOOST_DEFUN([Asio],
+[AC_REQUIRE([BOOST_SYSTEM])dnl
+BOOST_FIND_HEADER([boost/asio.hpp])])
+
+
+# BOOST_ASSIGN()
+# -------------
+# Look for Boost.Assign
+BOOST_DEFUN([Assign],
+[BOOST_FIND_HEADER([boost/assign.hpp])])
+
+
+# BOOST_BIND()
+# ------------
+# Look for Boost.Bind.
+BOOST_DEFUN([Bind],
+[BOOST_FIND_HEADER([boost/bind.hpp])])
+
+
+# BOOST_CHRONO()
+# --------------
+# Look for Boost.Chrono.
+BOOST_DEFUN([Chrono],
+[# Do we have to check for Boost.System? This link-time dependency was
+# added as of 1.35.0. If we have a version <1.35, we must not attempt to
+# find Boost.System as it didn't exist by then.
+if test $boost_major_version -ge 135; then
+ BOOST_SYSTEM([$1])
+fi # end of the Boost.System check.
+boost_filesystem_save_LIBS=$LIBS
+boost_filesystem_save_LDFLAGS=$LDFLAGS
+m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+BOOST_FIND_LIB([chrono], [$1],
+ [boost/chrono.hpp],
+ [boost::chrono::thread_clock d;])
+if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
+ BOOST_CHRONO_LIBS="$BOOST_CHRONO_LIBS $BOOST_SYSTEM_LIBS"
+fi
+LIBS=$boost_filesystem_save_LIBS
+LDFLAGS=$boost_filesystem_save_LDFLAGS
+])# BOOST_CHRONO
+
+
+# BOOST_CONTEXT([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Context. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+#
+# * This library was introduced in Boost 1.51.0
+# * The signatures of make_fcontext() and jump_fcontext were changed in 1.56.0
+# * A dependency on boost_thread appears in 1.57.0
+BOOST_DEFUN([Context],
+[boost_context_save_LIBS=$LIBS
+ boost_context_save_LDFLAGS=$LDFLAGS
+if test $boost_major_version -ge 157; then
+ BOOST_THREAD([$1])
+ m4_pattern_allow([^BOOST_THREAD_(LIBS|LDFLAGS)$])dnl
+ LIBS="$LIBS $BOOST_THREAD_LIBS"
+ LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS"
+fi
+BOOST_FIND_LIB([context], [$1],
+ [boost/context/all.hpp],[[
+
+// creates a stack
+void * stack_pointer = new void*[4096];
+std::size_t const size = sizeof(void*[4096]);
+
+#if BOOST_VERSION <= 105100
+ctx::make_fcontext(&fc, f);
+return ctx::jump_fcontext(&fcm, &fc, 3) == 6;
+
+#else
+
+fc = ctx::make_fcontext(stack_pointer, size, f);
+return ctx::jump_fcontext(&fcm, fc, 3) == 6;
+
+#endif
+
+
+]],[dnl
+
+#include <boost/version.hpp>
+#if BOOST_VERSION <= 105100
+
+namespace ctx = boost::ctx;
+
+static ctx::fcontext_t fcm, fc;
+
+static void f(intptr_t i) {
+ ctx::jump_fcontext(&fc, &fcm, i * 2);
+}
+
+#elif BOOST_VERSION <= 105500
+
+namespace ctx = boost::context;
+
+// context
+static ctx::fcontext_t fcm, *fc;
+
+// context-function
+static void f(intptr_t i) {
+ ctx::jump_fcontext(fc, &fcm, i * 2);
+}
+
+#else
+
+namespace ctx = boost::context;
+
+// context
+static ctx::fcontext_t fcm, fc;
+
+// context-function
+static void f(intptr_t i) {
+ ctx::jump_fcontext(&fc, fcm, i * 2);
+}
+#endif
+])
+LIBS=$boost_context_save_LIBS
+LDFLAGS=$boost_context_save_LDFLAGS
+])# BOOST_CONTEXT
+
+
+# BOOST_CONVERSION()
+# ------------------
+# Look for Boost.Conversion (cast / lexical_cast)
+BOOST_DEFUN([Conversion],
+[BOOST_FIND_HEADER([boost/cast.hpp])
+BOOST_FIND_HEADER([boost/lexical_cast.hpp])
+])# BOOST_CONVERSION
+
+
+# BOOST_COROUTINE([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Coroutine. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
+# 1.53.0
+BOOST_DEFUN([Coroutine],
+[
+boost_coroutine_save_LIBS=$LIBS
+boost_coroutine_save_LDFLAGS=$LDFLAGS
+# Link-time dependency from coroutine to context
+BOOST_CONTEXT([$1])
+# Starting from Boost 1.55 a dependency on Boost.System is added
+if test $boost_major_version -ge 155; then
+ BOOST_SYSTEM([$1])
+fi
+m4_pattern_allow([^BOOST_(CONTEXT|SYSTEM)_(LIBS|LDFLAGS)])
+LIBS="$LIBS $BOOST_CONTEXT_LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_CONTEXT_LDFLAGS"
+
+# in 1.53 coroutine was a header only library
+if test $boost_major_version -eq 153; then
+ BOOST_FIND_HEADER([boost/coroutine/coroutine.hpp])
+else
+ BOOST_FIND_LIB([coroutine], [$1],
+ [boost/coroutine/coroutine.hpp],
+ [
+ #include <boost/version.hpp>
+ #if BOOST_VERSION <= 105500
+ boost::coroutines::coroutine<int(int)> coro; coro.get();
+ #else
+ boost::coroutines::asymmetric_coroutine<int>::pull_type coro; coro.get();
+ #endif
+ ])
+fi
+# Link-time dependency from coroutine to context, existed only in 1.53, in 1.54
+# coroutine doesn't use context from its headers but from its library.
+if test $boost_major_version -eq 153 || test $enable_static_boost = yes && test $boost_major_version -ge 154; then
+ BOOST_COROUTINE_LIBS="$BOOST_COROUTINE_LIBS $BOOST_CONTEXT_LIBS"
+ BOOST_COROUTINE_LDFLAGS="$BOOST_COROUTINE_LDFLAGS $BOOST_CONTEXT_LDFLAGS"
+fi
+if test $enable_static_boost = yes && test $boost_major_version -ge 155; then
+ BOOST_COROUTINE_LIBS="$BOOST_COROUTINE_LIBS $BOOST_SYSTEM_LIBS"
+ BOOST_COROUTINE_LDFLAGS="$BOOST_COROUTINE_LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+fi
+LIBS=$boost_coroutine_save_LIBS
+LDFLAGS=$boost_coroutine_save_LDFLAGS
+])# BOOST_COROUTINE
+
+
+# BOOST_CRC()
+# -----------
+# Look for Boost.CRC
+BOOST_DEFUN([CRC],
+[BOOST_FIND_HEADER([boost/crc.hpp])
+])# BOOST_CRC
+
+
+# BOOST_DATE_TIME([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Date_Time. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Date_Time],
+[BOOST_FIND_LIB([date_time], [$1],
+ [boost/date_time/posix_time/posix_time.hpp],
+ [boost::posix_time::ptime t;])
+])# BOOST_DATE_TIME
+
+
+# BOOST_FILESYSTEM([PREFERRED-RT-OPT])
+# ------------------------------------
+# Look for Boost.Filesystem. For the documentation of PREFERRED-RT-OPT, see
+# the documentation of BOOST_FIND_LIB above.
+# Do not check for boost/filesystem.hpp because this file was introduced in
+# 1.34.
+BOOST_DEFUN([Filesystem],
+[# Do we have to check for Boost.System? This link-time dependency was
+# added as of 1.35.0. If we have a version <1.35, we must not attempt to
+# find Boost.System as it didn't exist by then.
+if test $boost_major_version -ge 135; then
+ BOOST_SYSTEM([$1])
+fi # end of the Boost.System check.
+boost_filesystem_save_LIBS=$LIBS
+boost_filesystem_save_LDFLAGS=$LDFLAGS
+m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+BOOST_FIND_LIB([filesystem], [$1],
+ [boost/filesystem/path.hpp], [boost::filesystem::path p;])
+if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
+ BOOST_FILESYSTEM_LIBS="$BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
+fi
+LIBS=$boost_filesystem_save_LIBS
+LDFLAGS=$boost_filesystem_save_LDFLAGS
+])# BOOST_FILESYSTEM
+
+
+# BOOST_FLYWEIGHT()
+# -----------------
+# Look for Boost.Flyweight.
+BOOST_DEFUN([Flyweight],
+[dnl There's a hidden dependency on pthreads.
+AC_REQUIRE([_BOOST_PTHREAD_FLAG])dnl
+BOOST_FIND_HEADER([boost/flyweight.hpp])
+AC_SUBST([BOOST_FLYWEIGHT_LIBS], [$boost_cv_pthread_flag])
+])
+
+
+# BOOST_FOREACH()
+# ---------------
+# Look for Boost.Foreach.
+BOOST_DEFUN([Foreach],
+[BOOST_FIND_HEADER([boost/foreach.hpp])])
+
+
+# BOOST_FORMAT()
+# --------------
+# Look for Boost.Format.
+# Note: we can't check for boost/format/format_fwd.hpp because the header isn't
+# standalone. It can't be compiled because it triggers the following error:
+# boost/format/detail/config_macros.hpp:88: error: 'locale' in namespace 'std'
+# does not name a type
+BOOST_DEFUN([Format],
+[BOOST_FIND_HEADER([boost/format.hpp])])
+
+
+# BOOST_FUNCTION()
+# ----------------
+# Look for Boost.Function
+BOOST_DEFUN([Function],
+[BOOST_FIND_HEADER([boost/function.hpp])])
+
+
+# BOOST_GEOMETRY()
+# ----------------
+# Look for Boost.Geometry (new since 1.47.0).
+BOOST_DEFUN([Geometry],
+[BOOST_FIND_HEADER([boost/geometry.hpp])
+])# BOOST_GEOMETRY
+
+
+# BOOST_GRAPH([PREFERRED-RT-OPT])
+# -------------------------------
+# Look for Boost.Graphs. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Graph],
+[boost_graph_save_LIBS=$LIBS
+boost_graph_save_LDFLAGS=$LDFLAGS
+# Link-time dependency from graph to regex was added as of 1.40.0.
+if test $boost_major_version -ge 140; then
+ BOOST_REGEX([$1])
+ m4_pattern_allow([^BOOST_REGEX_(LIBS|LDFLAGS)$])dnl
+ LIBS="$LIBS $BOOST_REGEX_LIBS"
+ LDFLAGS="$LDFLAGS $BOOST_REGEX_LDFLAGS"
+fi
+BOOST_FIND_LIB([graph], [$1],
+ [boost/graph/adjacency_list.hpp], [boost::adjacency_list<> g;])
+LIBS=$boost_graph_save_LIBS
+LDFLAGS=$boost_graph_save_LDFLAGS
+])# BOOST_GRAPH
+
+
+# BOOST_IOSTREAMS([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.IOStreams. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([IOStreams],
+[BOOST_FIND_LIB([iostreams], [$1],
+ [boost/iostreams/device/file_descriptor.hpp],
+ [boost::iostreams::file_descriptor fd; fd.close();])
+])# BOOST_IOSTREAMS
+
+
+# BOOST_HASH()
+# ------------
+# Look for Boost.Functional/Hash
+BOOST_DEFUN([Hash],
+[BOOST_FIND_HEADER([boost/functional/hash.hpp])])
+
+
+# BOOST_LAMBDA()
+# --------------
+# Look for Boost.Lambda
+BOOST_DEFUN([Lambda],
+[BOOST_FIND_HEADER([boost/lambda/lambda.hpp])])
+
+
+# BOOST_LOCALE()
+# --------------
+# Look for Boost.Locale
+BOOST_DEFUN([Locale],
+[
+boost_locale_save_LIBS=$LIBS
+boost_locale_save_LDFLAGS=$LDFLAGS
+# require SYSTEM for boost-1.50.0 and up
+if test $boost_major_version -ge 150; then
+ BOOST_SYSTEM([$1])
+ m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+ LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+ LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+fi # end of the Boost.System check.
+BOOST_FIND_LIB([locale], [$1],
+ [boost/locale.hpp],
+ [[boost::locale::generator gen; std::locale::global(gen(""));]])
+LIBS=$boost_locale_save_LIBS
+LDFLAGS=$boost_locale_save_LDFLAGS
+])# BOOST_LOCALE
+
+# BOOST_LOG([PREFERRED-RT-OPT])
+# -----------------------------
+# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Log],
+[boost_log_save_LIBS=$LIBS
+boost_log_save_LDFLAGS=$LDFLAGS
+BOOST_SYSTEM([$1])
+BOOST_FILESYSTEM([$1])
+BOOST_DATE_TIME([$1])
+m4_pattern_allow([^BOOST_(SYSTEM|FILESYSTEM|DATE_TIME)_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_DATE_TIME_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_DATE_TIME_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+BOOST_FIND_LIB([log], [$1],
+ [boost/log/core/core.hpp],
+ [boost::log::attribute a; a.get_value();])
+LIBS=$boost_log_save_LIBS
+LDFLAGS=$boost_log_save_LDFLAGS
+])# BOOST_LOG
+
+
+# BOOST_LOG_SETUP([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Log_Setup],
+[boost_log_setup_save_LIBS=$LIBS
+boost_log_setup_save_LDFLAGS=$LDFLAGS
+BOOST_LOG([$1])
+m4_pattern_allow([^BOOST_LOG_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_LOG_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_LOG_LDFLAGS"
+BOOST_FIND_LIB([log_setup], [$1],
+ [boost/log/utility/setup/from_settings.hpp],
+ [boost::log::basic_settings<char> bs; bs.empty();])
+LIBS=$boost_log_setup_save_LIBS
+LDFLAGS=$boost_log_setup_save_LDFLAGS
+])# BOOST_LOG_SETUP
+
+
+# BOOST_MATH()
+# ------------
+# Look for Boost.Math
+# TODO: This library isn't header-only but it comes in multiple different
+# flavors that don't play well with BOOST_FIND_LIB (e.g, libboost_math_c99,
+# libboost_math_c99f, libboost_math_c99l, libboost_math_tr1,
+# libboost_math_tr1f, libboost_math_tr1l). This macro must be fixed to do the
+# right thing anyway.
+BOOST_DEFUN([Math],
+[BOOST_FIND_HEADER([boost/math/special_functions.hpp])])
+
+
+# BOOST_MPI([PREFERRED-RT-OPT])
+# -------------------------------
+# Look for Boost MPI. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above. Uses MPICXX variable if it is
+# set, otherwise tries CXX
+#
+BOOST_DEFUN([MPI],
+[boost_save_CXX=${CXX}
+boost_save_CXXCPP=${CXXCPP}
+if test x"${MPICXX}" != x; then
+ CXX=${MPICXX}
+ CXXCPP="${MPICXX} -E"
+fi
+BOOST_FIND_LIB([mpi], [$1],
+ [boost/mpi.hpp],
+ [int argc = 0;
+ char **argv = 0;
+ boost::mpi::environment env(argc,argv);])
+CXX=${boost_save_CXX}
+CXXCPP=${boost_save_CXXCPP}
+])# BOOST_MPI
+
+
+# BOOST_MULTIARRAY()
+# ------------------
+# Look for Boost.MultiArray
+BOOST_DEFUN([MultiArray],
+[BOOST_FIND_HEADER([boost/multi_array.hpp])])
+
+
+# BOOST_NUMERIC_UBLAS()
+# --------------------------
+# Look for Boost.NumericUblas (Basic Linear Algebra)
+BOOST_DEFUN([Numeric_Ublas],
+[BOOST_FIND_HEADER([boost/numeric/ublas/vector.hpp])
+])# BOOST_NUMERIC_UBLAS
+
+
+# BOOST_NUMERIC_CONVERSION()
+# --------------------------
+# Look for Boost.NumericConversion (policy-based numeric conversion)
+BOOST_DEFUN([Numeric_Conversion],
+[BOOST_FIND_HEADER([boost/numeric/conversion/converter.hpp])
+])# BOOST_NUMERIC_CONVERSION
+
+
+# BOOST_OPTIONAL()
+# ----------------
+# Look for Boost.Optional
+BOOST_DEFUN([Optional],
+[BOOST_FIND_HEADER([boost/optional.hpp])])
+
+
+# BOOST_PREPROCESSOR()
+# --------------------
+# Look for Boost.Preprocessor
+BOOST_DEFUN([Preprocessor],
+[BOOST_FIND_HEADER([boost/preprocessor/repeat.hpp])])
+
+
+# BOOST_RANGE()
+# --------------------
+# Look for Boost.Range
+BOOST_DEFUN([Range],
+[BOOST_FIND_HEADER([boost/range/adaptors.hpp])])
+
+# BOOST_UNORDERED()
+# -----------------
+# Look for Boost.Unordered
+BOOST_DEFUN([Unordered],
+[BOOST_FIND_HEADER([boost/unordered_map.hpp])])
+
+
+# BOOST_UUID()
+# ------------
+# Look for Boost.Uuid
+BOOST_DEFUN([Uuid],
+[BOOST_FIND_HEADER([boost/uuid/uuid.hpp])])
+
+
+# BOOST_PROGRAM_OPTIONS([PREFERRED-RT-OPT])
+# -----------------------------------------
+# Look for Boost.Program_options. For the documentation of PREFERRED-RT-OPT,
+# see the documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Program_Options],
+[BOOST_FIND_LIB([program_options], [$1],
+ [boost/program_options.hpp],
+ [boost::program_options::options_description d("test");])
+])# BOOST_PROGRAM_OPTIONS
+
+
+
+# _BOOST_PYTHON_CONFIG(VARIABLE, FLAG)
+# ------------------------------------
+# Save VARIABLE, and define it via `python-config --FLAG`.
+# Substitute BOOST_PYTHON_VARIABLE.
+m4_define([_BOOST_PYTHON_CONFIG],
+[AC_SUBST([BOOST_PYTHON_$1],
+ [`python-config --$2 2>/dev/null`])dnl
+boost_python_save_$1=$$1
+$1="$$1 $BOOST_PYTHON_$1"])
+
+
+# BOOST_PYTHON([PREFERRED-RT-OPT])
+# --------------------------------
+# Look for Boost.Python. For the documentation of PREFERRED-RT-OPT,
+# see the documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Python],
+[_BOOST_PYTHON_CONFIG([CPPFLAGS], [includes])
+_BOOST_PYTHON_CONFIG([LDFLAGS], [ldflags])
+_BOOST_PYTHON_CONFIG([LIBS], [libs])
+m4_pattern_allow([^BOOST_PYTHON_MODULE$])dnl
+BOOST_FIND_LIBS([python], [python python3], [$1],
+ [boost/python.hpp],
+ [], [BOOST_PYTHON_MODULE(empty) {}])
+CPPFLAGS=$boost_python_save_CPPFLAGS
+LDFLAGS=$boost_python_save_LDFLAGS
+LIBS=$boost_python_save_LIBS
+])# BOOST_PYTHON
+
+
+# BOOST_REF()
+# -----------
+# Look for Boost.Ref
+BOOST_DEFUN([Ref],
+[BOOST_FIND_HEADER([boost/ref.hpp])])
+
+
+# BOOST_REGEX([PREFERRED-RT-OPT])
+# -------------------------------
+# Look for Boost.Regex. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Regex],
+[BOOST_FIND_LIB([regex], [$1],
+ [boost/regex.hpp],
+ [boost::regex exp("*"); boost::regex_match("foo", exp);])
+])# BOOST_REGEX
+
+
+# BOOST_SERIALIZATION([PREFERRED-RT-OPT])
+# ---------------------------------------
+# Look for Boost.Serialization. For the documentation of PREFERRED-RT-OPT, see
+# the documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Serialization],
+[BOOST_FIND_LIB([serialization], [$1],
+ [boost/archive/text_oarchive.hpp],
+ [std::ostream* o = 0; // Cheap way to get an ostream...
+ boost::archive::text_oarchive t(*o);])
+])# BOOST_SERIALIZATION
+
+
+# BOOST_SIGNALS([PREFERRED-RT-OPT])
+# ---------------------------------
+# Look for Boost.Signals. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Signals],
+[BOOST_FIND_LIB([signals], [$1],
+ [boost/signal.hpp],
+ [boost::signal<void ()> s;])
+])# BOOST_SIGNALS
+
+
+# BOOST_SIGNALS2()
+# ----------------
+# Look for Boost.Signals2 (new since 1.39.0).
+BOOST_DEFUN([Signals2],
+[BOOST_FIND_HEADER([boost/signals2.hpp])
+])# BOOST_SIGNALS2
+
+
+# BOOST_SMART_PTR()
+# -----------------
+# Look for Boost.SmartPtr
+BOOST_DEFUN([Smart_Ptr],
+[BOOST_FIND_HEADER([boost/scoped_ptr.hpp])
+BOOST_FIND_HEADER([boost/shared_ptr.hpp])
+])
+
+
+# BOOST_STATICASSERT()
+# --------------------
+# Look for Boost.StaticAssert
+BOOST_DEFUN([StaticAssert],
+[BOOST_FIND_HEADER([boost/static_assert.hpp])])
+
+
+# BOOST_STRING_ALGO()
+# -------------------
+# Look for Boost.StringAlgo
+BOOST_DEFUN([String_Algo],
+[BOOST_FIND_HEADER([boost/algorithm/string.hpp])
+])
+
+
+# BOOST_SYSTEM([PREFERRED-RT-OPT])
+# --------------------------------
+# Look for Boost.System. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
+# 1.35.0.
+BOOST_DEFUN([System],
+[BOOST_FIND_LIB([system], [$1],
+ [boost/system/error_code.hpp],
+ [boost::system::error_code e; e.clear();])
+])# BOOST_SYSTEM
+
+
+# BOOST_TEST([PREFERRED-RT-OPT])
+# ------------------------------
+# Look for Boost.Test. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Test],
+[m4_pattern_allow([^BOOST_CHECK$])dnl
+BOOST_FIND_LIB([unit_test_framework], [$1],
+ [boost/test/unit_test.hpp], [BOOST_CHECK(2 == 2);],
+ [using boost::unit_test::test_suite;
+ test_suite* init_unit_test_suite(int argc, char ** argv)
+ { return NULL; }])
+])# BOOST_TEST
+
+
+# BOOST_THREAD([PREFERRED-RT-OPT])
+# ---------------------------------
+# Look for Boost.Thread. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Thread],
+[dnl Having the pthread flag is required at least on GCC3 where
+dnl boost/thread.hpp would complain if we try to compile without
+dnl -pthread on GNU/Linux.
+AC_REQUIRE([_BOOST_PTHREAD_FLAG])dnl
+boost_thread_save_LIBS=$LIBS
+boost_thread_save_LDFLAGS=$LDFLAGS
+boost_thread_save_CPPFLAGS=$CPPFLAGS
+# Link-time dependency from thread to system was added as of 1.49.0.
+if test $boost_major_version -ge 149; then
+BOOST_SYSTEM([$1])
+fi # end of the Boost.System check.
+m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+CPPFLAGS="$CPPFLAGS $boost_cv_pthread_flag"
+
+# When compiling for the Windows platform, the threads library is named
+# differently. This suffix doesn't exist in new versions of Boost, or
+# possibly new versions of GCC on mingw I am assuming it's Boost's change for
+# now and I am setting version to 1.48, for lack of knowledge as to when this
+# change occurred.
+if test $boost_major_version -lt 148; then
+ case $host_os in
+ (*mingw*) boost_thread_lib_ext=_win32;;
+ esac
+fi
+BOOST_FIND_LIBS([thread], [thread$boost_thread_lib_ext],
+ [$1],
+ [boost/thread.hpp], [boost::thread t; boost::mutex m;])
+
+case $host_os in
+ (*mingw*) boost_thread_w32_socket_link=-lws2_32;;
+esac
+
+BOOST_THREAD_LIBS="$BOOST_THREAD_LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag $boost_thread_w32_socket_link"
+BOOST_THREAD_LDFLAGS="$BOOST_SYSTEM_LDFLAGS"
+BOOST_CPPFLAGS="$BOOST_CPPFLAGS $boost_cv_pthread_flag"
+LIBS=$boost_thread_save_LIBS
+LDFLAGS=$boost_thread_save_LDFLAGS
+CPPFLAGS=$boost_thread_save_CPPFLAGS
+])# BOOST_THREAD
+
+AU_ALIAS([BOOST_THREADS], [BOOST_THREAD])
+
+
+# BOOST_TOKENIZER()
+# -----------------
+# Look for Boost.Tokenizer
+BOOST_DEFUN([Tokenizer],
+[BOOST_FIND_HEADER([boost/tokenizer.hpp])])
+
+
+# BOOST_TRIBOOL()
+# ---------------
+# Look for Boost.Tribool
+BOOST_DEFUN([Tribool],
+[BOOST_FIND_HEADER([boost/logic/tribool_fwd.hpp])
+BOOST_FIND_HEADER([boost/logic/tribool.hpp])
+])
+
+
+# BOOST_TUPLE()
+# -------------
+# Look for Boost.Tuple
+BOOST_DEFUN([Tuple],
+[BOOST_FIND_HEADER([boost/tuple/tuple.hpp])])
+
+
+# BOOST_TYPETRAITS()
+# --------------------
+# Look for Boost.TypeTraits
+BOOST_DEFUN([TypeTraits],
+[BOOST_FIND_HEADER([boost/type_traits.hpp])])
+
+
+# BOOST_UTILITY()
+# ---------------
+# Look for Boost.Utility (noncopyable, result_of, base-from-member idiom,
+# etc.)
+BOOST_DEFUN([Utility],
+[BOOST_FIND_HEADER([boost/utility.hpp])])
+
+
+# BOOST_VARIANT()
+# ---------------
+# Look for Boost.Variant.
+BOOST_DEFUN([Variant],
+[BOOST_FIND_HEADER([boost/variant/variant_fwd.hpp])
+BOOST_FIND_HEADER([boost/variant.hpp])])
+
+
+# BOOST_POINTER_CONTAINER()
+# ------------------------
+# Look for Boost.PointerContainer
+BOOST_DEFUN([Pointer_Container],
+[BOOST_FIND_HEADER([boost/ptr_container/ptr_deque.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_list.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_vector.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_array.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_set.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_map.hpp])
+])# BOOST_POINTER_CONTAINER
+
+
+# BOOST_WAVE([PREFERRED-RT-OPT])
+# ------------------------------
+# NOTE: If you intend to use Wave/Spirit with thread support, make sure you
+# call BOOST_THREAD first.
+# Look for Boost.Wave. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Wave],
+[AC_REQUIRE([BOOST_FILESYSTEM])dnl
+AC_REQUIRE([BOOST_DATE_TIME])dnl
+boost_wave_save_LIBS=$LIBS
+boost_wave_save_LDFLAGS=$LDFLAGS
+m4_pattern_allow([^BOOST_((FILE)?SYSTEM|DATE_TIME|THREAD)_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_DATE_TIME_LIBS \
+$BOOST_THREAD_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS \
+$BOOST_DATE_TIME_LDFLAGS $BOOST_THREAD_LDFLAGS"
+BOOST_FIND_LIB([wave], [$1],
+ [boost/wave.hpp],
+ [boost::wave::token_id id; get_token_name(id);])
+LIBS=$boost_wave_save_LIBS
+LDFLAGS=$boost_wave_save_LDFLAGS
+])# BOOST_WAVE
+
+
+# BOOST_XPRESSIVE()
+# -----------------
+# Look for Boost.Xpressive (new since 1.36.0).
+BOOST_DEFUN([Xpressive],
+[BOOST_FIND_HEADER([boost/xpressive/xpressive.hpp])])
+
+
+# ----------------- #
+# Internal helpers. #
+# ----------------- #
+
+
+# _BOOST_PTHREAD_FLAG()
+# ---------------------
+# Internal helper for BOOST_THREAD. Computes boost_cv_pthread_flag
+# which must be used in CPPFLAGS and LIBS.
+#
+# Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3,
+# boost/thread.hpp will trigger a #error if -pthread isn't used:
+# boost/config/requires_threads.hpp:47:5: #error "Compiler threading support
+# is not turned on. Please set the correct command line options for
+# threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)"
+#
+# Based on ACX_PTHREAD: http://autoconf-archive.cryp.to/acx_pthread.html
+AC_DEFUN([_BOOST_PTHREAD_FLAG],
+[AC_REQUIRE([AC_PROG_CXX])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_LANG_PUSH([C++])dnl
+AC_CACHE_CHECK([for the flags needed to use pthreads], [boost_cv_pthread_flag],
+[ boost_cv_pthread_flag=
+ # The ordering *is* (sometimes) important. Some notes on the
+ # individual items follow:
+ # (none): in case threads are in libc; should be tried before -Kthread and
+ # other compiler flags to prevent continual compiler warnings
+ # -lpthreads: AIX (must check this before -lpthread)
+ # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+ # -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads)
+ # -pthreads: Solaris/GCC
+ # -mthreads: MinGW32/GCC, Lynx/GCC
+ # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+ # doesn't hurt to check since this sometimes defines pthreads too;
+ # also defines -D_REENTRANT)
+ # ... -mt is also the pthreads flag for HP/aCC
+ # -lpthread: GNU Linux, etc.
+ # --thread-safe: KAI C++
+ case $host_os in #(
+ *solaris*)
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+ boost_pthread_flags="-pthreads -lpthread -mt -pthread";; #(
+ *)
+ boost_pthread_flags="-lpthreads -Kthread -kthread -llthread -pthread \
+ -pthreads -mthreads -lpthread --thread-safe -mt";;
+ esac
+ # Generate the test file.
+ AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0);])])
+ for boost_pthread_flag in '' $boost_pthread_flags; do
+ boost_pthread_ok=false
+dnl Re-use the test file already generated.
+ boost_pthreads__save_LIBS=$LIBS
+ LIBS="$LIBS $boost_pthread_flag"
+ AC_LINK_IFELSE([],
+ [if grep ".*$boost_pthread_flag" conftest.err; then
+ echo "This flag seems to have triggered warnings" >&AS_MESSAGE_LOG_FD
+ else
+ boost_pthread_ok=:; boost_cv_pthread_flag=$boost_pthread_flag
+ fi])
+ LIBS=$boost_pthreads__save_LIBS
+ $boost_pthread_ok && break
+ done
+])
+AC_LANG_POP([C++])dnl
+])# _BOOST_PTHREAD_FLAG
+
+
+# _BOOST_gcc_test(MAJOR, MINOR)
+# -----------------------------
+# Internal helper for _BOOST_FIND_COMPILER_TAG.
+m4_define([_BOOST_gcc_test],
+["defined __GNUC__ && __GNUC__ == $1 && __GNUC_MINOR__ == $2 && !defined __ICC @ gcc$1$2"])dnl
+
+# _BOOST_mingw_test(MAJOR, MINOR)
+# -----------------------------
+# Internal helper for _BOOST_FIND_COMPILER_TAG.
+m4_define([_BOOST_mingw_test],
+["defined __GNUC__ && __GNUC__ == $1 && __GNUC_MINOR__ == $2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw$1$2"])dnl
+
+
+# _BOOST_FIND_COMPILER_TAG()
+# --------------------------
+# Internal. When Boost is installed without --layout=system, each library
+# filename will hold a suffix that encodes the compiler used during the
+# build. The Boost build system seems to call this a `tag'.
+AC_DEFUN([_BOOST_FIND_COMPILER_TAG],
+[AC_REQUIRE([AC_PROG_CXX])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_CACHE_CHECK([for the toolset name used by Boost for $CXX],
+ [boost_cv_lib_tag],
+[boost_cv_lib_tag=unknown
+if test x$boost_cv_inc_path != xno; then
+ AC_LANG_PUSH([C++])dnl
+ # The following tests are mostly inspired by boost/config/auto_link.hpp
+ # The list is sorted to most recent/common to oldest compiler (in order
+ # to increase the likelihood of finding the right compiler with the
+ # least number of compilation attempt).
+ # Beware that some tests are sensible to the order (for instance, we must
+ # look for MinGW before looking for GCC3).
+ # I used one compilation test per compiler with a #error to recognize
+ # each compiler so that it works even when cross-compiling (let me know
+ # if you know a better approach).
+ # Known missing tags (known from Boost's tools/build/v2/tools/common.jam):
+ # como, edg, kcc, bck, mp, sw, tru, xlc
+ # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
+ # the same defines as GCC's).
+ for i in \
+ _BOOST_mingw_test(5, 3) \
+ _BOOST_gcc_test(5, 3) \
+ _BOOST_mingw_test(5, 2) \
+ _BOOST_gcc_test(5, 2) \
+ _BOOST_mingw_test(5, 1) \
+ _BOOST_gcc_test(5, 1) \
+ _BOOST_mingw_test(5, 0) \
+ _BOOST_gcc_test(5, 0) \
+ _BOOST_mingw_test(4, 10) \
+ _BOOST_gcc_test(4, 10) \
+ _BOOST_mingw_test(4, 9) \
+ _BOOST_gcc_test(4, 9) \
+ _BOOST_mingw_test(4, 8) \
+ _BOOST_gcc_test(4, 8) \
+ _BOOST_mingw_test(4, 7) \
+ _BOOST_gcc_test(4, 7) \
+ _BOOST_mingw_test(4, 6) \
+ _BOOST_gcc_test(4, 6) \
+ _BOOST_mingw_test(4, 5) \
+ _BOOST_gcc_test(4, 5) \
+ _BOOST_mingw_test(4, 4) \
+ _BOOST_gcc_test(4, 4) \
+ _BOOST_mingw_test(4, 3) \
+ _BOOST_gcc_test(4, 3) \
+ _BOOST_mingw_test(4, 2) \
+ _BOOST_gcc_test(4, 2) \
+ _BOOST_mingw_test(4, 1) \
+ _BOOST_gcc_test(4, 1) \
+ _BOOST_mingw_test(4, 0) \
+ _BOOST_gcc_test(4, 0) \
+ "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \
+ && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \
+ _BOOST_gcc_test(3, 4) \
+ _BOOST_gcc_test(3, 3) \
+ "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \
+ "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \
+ _BOOST_gcc_test(3, 2) \
+ "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \
+ _BOOST_gcc_test(3, 1) \
+ _BOOST_gcc_test(3, 0) \
+ "defined __BORLANDC__ @ bcb" \
+ "defined __ICC && (defined __unix || defined __unix__) @ il" \
+ "defined __ICL @ iw" \
+ "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \
+ _BOOST_gcc_test(2, 95) \
+ "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \
+ "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \
+ "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \
+ "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8"
+ do
+ boost_tag_test=`expr "X$i" : 'X\([[^@]]*\) @ '`
+ boost_tag=`expr "X$i" : 'X[[^@]]* @ \(.*\)'`
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if $boost_tag_test
+/* OK */
+#else
+# error $boost_tag_test
+#endif
+]])], [boost_cv_lib_tag=$boost_tag; break], [])
+ done
+AC_LANG_POP([C++])dnl
+ case $boost_cv_lib_tag in #(
+ # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed
+ # to "gcc41" for instance.
+ *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there.
+ gcc*)
+ boost_tag_x=
+ case $host_os in #(
+ darwin*)
+ if test $boost_major_version -ge 136; then
+ # The `x' added in r46793 of Boost.
+ boost_tag_x=x
+ fi;;
+ esac
+ # We can specify multiple tags in this variable because it's used by
+ # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ...
+ boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc"
+ ;; #(
+ unknown)
+ AC_MSG_WARN([[could not figure out which toolset name to use for $CXX]])
+ boost_cv_lib_tag=
+ ;;
+ esac
+fi])dnl end of AC_CACHE_CHECK
+])# _BOOST_FIND_COMPILER_TAG
+
+
+# _BOOST_GUESS_WHETHER_TO_USE_MT()
+# --------------------------------
+# Compile a small test to try to guess whether we should favor MT (Multi
+# Thread) flavors of Boost. Sets boost_guess_use_mt accordingly.
+AC_DEFUN([_BOOST_GUESS_WHETHER_TO_USE_MT],
+[# Check whether we do better use `mt' even though we weren't ask to.
+AC_LANG_PUSH([C++])dnl
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if defined _REENTRANT || defined _MT || defined __MT__
+/* use -mt */
+#else
+# error MT not needed
+#endif
+]])], [boost_guess_use_mt=:], [boost_guess_use_mt=false])
+AC_LANG_POP([C++])dnl
+])
+
+# _BOOST_AC_LINK_IFELSE(PROGRAM, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+# -------------------------------------------------------------------
+# Fork of _AC_LINK_IFELSE that preserves conftest.o across calls. Fragile,
+# will break when Autoconf changes its internals. Requires that you manually
+# rm -f conftest.$ac_objext in between to really different tests, otherwise
+# you will try to link a conftest.o left behind by a previous test.
+# Used to aggressively optimize BOOST_FIND_LIB (see the big comment in this
+# macro).
+#
+# Don't use "break" in the actions, as it would short-circuit some code
+# this macro runs after the actions.
+m4_define([_BOOST_AC_LINK_IFELSE],
+[m4_ifvaln([$1], [AC_LANG_CONFTEST([$1])])dnl
+rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ _AS_ECHO_LOG([re-using the existing conftest.$ac_objext])
+AS_IF([_AC_DO_STDERR($ac_link) && {
+ test -z "$ac_[]_AC_LANG_ABBREV[]_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+dnl FIXME: use AS_TEST_X instead when 2.61 is widespread enough.
+ }],
+ [$2],
+ [if $boost_use_source; then
+ _AC_MSG_LOG_CONFTEST
+ fi
+ $3])
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+dnl Delete also the IPA/IPO (Inter Procedural Analysis/Optimization)
+dnl information created by the PGI compiler (conftest_ipa8_conftest.oo),
+dnl as it would interfere with the next link command.
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext m4_ifval([$1], [conftest.$ac_ext])[]dnl
+])# _BOOST_AC_LINK_IFELSE
+
+# Local Variables:
+# mode: autoconf
+# End:
diff --git a/qa/Makefile.am b/qa/Makefile.am
new file mode 100644
index 0000000..1752412
--- /dev/null
+++ b/qa/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = mockup libcmis libcmis-c
diff --git a/qa/libcmis-c/Makefile.am b/qa/libcmis-c/Makefile.am
new file mode 100644
index 0000000..c0de5ad
--- /dev/null
+++ b/qa/libcmis-c/Makefile.am
@@ -0,0 +1,48 @@
+check_PROGRAMS = \
+ test-api \
+ test-c-build
+
+test_api_SOURCES = \
+ test-allowable-actions.cxx \
+ test-api.cxx \
+ test-document.cxx \
+ test-dummies.cxx \
+ test-dummies.hxx \
+ test-folder.cxx \
+ test-object-type.cxx \
+ test-object.cxx \
+ test-property-type.cxx \
+ test-property.cxx \
+ test-repository.cxx \
+ test-session.cxx
+
+test_api_CXXFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis-c/ \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+test_api_LDADD = \
+ $(top_builddir)/src/libcmis-c/libcmis-c-@LIBCMIS_API_VERSION@.la \
+ $(top_builddir)/src/libcmis/libcmis-@LIBCMIS_API_VERSION@.la \
+ $(XML2_LIBS) \
+ $(CURL_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+test_c_build_SOURCES = \
+ test-build.c
+
+test_c_build_CFLAGS = \
+ -I$(top_srcdir)/inc \
+ $(XML2_CFLAGS)
+
+test_c_build_LDADD = \
+ $(top_builddir)/src/libcmis-c/libcmis-c-@LIBCMIS_API_VERSION@.la \
+ $(top_builddir)/src/libcmis/libcmis-@LIBCMIS_API_VERSION@.la \
+ $(XML2_LIBS) \
+ $(CURL_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+TESTS = test-api
diff --git a/qa/libcmis-c/test-allowable-actions.cxx b/qa/libcmis-c/test-allowable-actions.cxx
new file mode 100644
index 0000000..19332d4
--- /dev/null
+++ b/qa/libcmis-c/test-allowable-actions.cxx
@@ -0,0 +1,82 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/allowable-actions.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class AllowableActionsTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_AllowableActionsPtr getTested( );
+
+ public:
+ void isDefinedTest( );
+ void isAllowedTest( );
+
+ CPPUNIT_TEST_SUITE( AllowableActionsTest );
+ CPPUNIT_TEST( isDefinedTest );
+ CPPUNIT_TEST( isAllowedTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( AllowableActionsTest );
+
+libcmis_AllowableActionsPtr AllowableActionsTest::getTested( )
+{
+ libcmis_AllowableActionsPtr result = new libcmis_allowable_actions( );
+ libcmis::AllowableActionsPtr handle( new dummies::AllowableActions( ) );
+ result->handle = handle;
+
+ return result;
+}
+
+void AllowableActionsTest::isDefinedTest( )
+{
+ libcmis_AllowableActionsPtr allowableActions = getTested( );
+ CPPUNIT_ASSERT( !libcmis_allowable_actions_isDefined( allowableActions, libcmis_DeleteObject ) );
+ CPPUNIT_ASSERT( libcmis_allowable_actions_isDefined( allowableActions, libcmis_GetFolderParent ) );
+
+ libcmis_allowable_actions_free( allowableActions );
+}
+
+void AllowableActionsTest::isAllowedTest( )
+{
+ libcmis_AllowableActionsPtr allowableActions = getTested( );
+ CPPUNIT_ASSERT( libcmis_allowable_actions_isAllowed( allowableActions, libcmis_GetProperties ) );
+ CPPUNIT_ASSERT( !libcmis_allowable_actions_isAllowed( allowableActions, libcmis_GetFolderParent ) );
+
+ libcmis_allowable_actions_free( allowableActions );
+}
diff --git a/qa/libcmis-c/test-api.cxx b/qa/libcmis-c/test-api.cxx
new file mode 100644
index 0000000..45b2daf
--- /dev/null
+++ b/qa/libcmis-c/test-api.cxx
@@ -0,0 +1,39 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+int main( int, char** )
+{
+ CppUnit::TextUi::TestRunner runner;
+ CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ runner.addTest( registry.makeTest() );
+ bool wasSuccess = runner.run( "", false );
+ return !wasSuccess;
+}
diff --git a/qa/libcmis-c/test-build.c b/qa/libcmis-c/test-build.c
new file mode 100644
index 0000000..52ac44d
--- /dev/null
+++ b/qa/libcmis-c/test-build.c
@@ -0,0 +1,36 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/libcmis-c.h>
+
+int main ( int argc, char ** argv )
+{
+ ( void )argc;
+ ( void )argv;
+ return 0;
+}
diff --git a/qa/libcmis-c/test-document.cxx b/qa/libcmis-c/test-document.cxx
new file mode 100644
index 0000000..525cbaa
--- /dev/null
+++ b/qa/libcmis-c/test-document.cxx
@@ -0,0 +1,621 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/error.h>
+#include <libcmis-c/folder.h>
+#include <libcmis-c/document.h>
+#include <libcmis-c/object.h>
+#include <libcmis-c/object-type.h>
+#include <libcmis-c/property.h>
+#include <libcmis-c/property-type.h>
+#include <libcmis-c/vectors.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+extern bool isOutOfMemory;
+
+namespace
+{
+ string lcl_readFile( FILE* file )
+ {
+ // Get the size
+ fseek( file, 0, SEEK_END );
+ long size = ftell( file );
+ rewind( file );
+
+ char* buf = new char[size + 1];
+ size_t readbytes = fread( buf, 1, size, file );
+ buf[ readbytes ] = '\0';
+
+ string result( buf );
+ delete[] buf;
+
+ return result;
+ }
+}
+
+class DocumentTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_DocumentPtr getTested( bool isFiled, bool triggersFaults );
+ dummies::Document* getTestedImplementation( libcmis_DocumentPtr document );
+
+ public:
+ void objectCastTest( );
+ void objectCastFailureTest( );
+ void objectFunctionsTest( );
+ void getParentsTest( );
+ void getParentsUnfiledTest( );
+ void getParentsErrorTest( );
+ void getContentStreamTest( );
+ void getContentStreamErrorTest( );
+ void getContentStreamBadAllocTest( );
+ void setContentStreamTest( );
+ void setContentStreamErrorTest( );
+ void getContentTypeTest( );
+ void getContentFilenameTest( );
+ void getContentLengthTest( );
+ void checkOutTest( );
+ void checkOutErrorTest( );
+ void cancelCheckoutTest( );
+ void cancelCheckoutErrorTest( );
+ void checkInTest( );
+ void checkInErrorTest( );
+ void getAllVersionsTest( );
+ void getAllVersionsErrorTest( );
+
+ CPPUNIT_TEST_SUITE( DocumentTest );
+ CPPUNIT_TEST( objectCastTest );
+ CPPUNIT_TEST( objectCastFailureTest );
+ CPPUNIT_TEST( objectFunctionsTest );
+ CPPUNIT_TEST( getParentsTest );
+ CPPUNIT_TEST( getParentsUnfiledTest );
+ CPPUNIT_TEST( getParentsErrorTest );
+ CPPUNIT_TEST( getContentStreamTest );
+ CPPUNIT_TEST( getContentStreamErrorTest );
+ CPPUNIT_TEST( getContentStreamBadAllocTest );
+ CPPUNIT_TEST( setContentStreamTest );
+ CPPUNIT_TEST( setContentStreamErrorTest );
+ CPPUNIT_TEST( getContentTypeTest );
+ CPPUNIT_TEST( getContentFilenameTest );
+ CPPUNIT_TEST( getContentLengthTest );
+ CPPUNIT_TEST( checkOutTest );
+ CPPUNIT_TEST( checkOutErrorTest );
+ CPPUNIT_TEST( cancelCheckoutTest );
+ CPPUNIT_TEST( cancelCheckoutErrorTest );
+ CPPUNIT_TEST( checkInTest );
+ CPPUNIT_TEST( checkInErrorTest );
+ CPPUNIT_TEST( getAllVersionsTest );
+ CPPUNIT_TEST( getAllVersionsErrorTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( DocumentTest );
+
+libcmis_DocumentPtr DocumentTest::getTested( bool isFiled, bool triggersFaults )
+{
+ // Create the document
+ libcmis_DocumentPtr result = new libcmis_document( );
+ libcmis::DocumentPtr handle( new dummies::Document( isFiled, triggersFaults ) );
+ result->handle = handle;
+
+ return result;
+}
+
+dummies::Document* DocumentTest::getTestedImplementation( libcmis_DocumentPtr document )
+{
+ dummies::Document* impl = dynamic_cast< dummies::Document* >( document->handle.get( ) );
+ return impl;
+}
+
+void DocumentTest::objectCastTest( )
+{
+ // Create the test object to cast
+ libcmis_ObjectPtr tested = new libcmis_object( );
+ libcmis::DocumentPtr handle( new dummies::Document( true, false ) );
+ tested->handle = handle;
+
+ // Test libcmis_is_document
+ CPPUNIT_ASSERT( libcmis_is_document( tested ) );
+
+ // Actually cast to a document
+ libcmis_DocumentPtr actual = libcmis_document_cast( tested );
+
+ // Check the result
+ CPPUNIT_ASSERT( NULL != actual );
+
+ // Check that the libcmis_object-* functions are working with the cast result
+ char* actualId = libcmis_object_getId( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Document::Id" ), string( actualId ) );
+ free( actualId );
+
+ // Free it all
+ libcmis_document_free( actual );
+ libcmis_object_free( tested );
+}
+
+void DocumentTest::objectCastFailureTest( )
+{
+ // Create the test object to cast
+ libcmis_ObjectPtr tested = new libcmis_object( );
+ libcmis::FolderPtr handle( new dummies::Folder( false, false ) );
+ tested->handle = handle;
+
+ // Test libcmis_is_document
+ CPPUNIT_ASSERT( !libcmis_is_document( tested ) );
+
+ // Actually cast to a document
+ libcmis_DocumentPtr actual = libcmis_document_cast( tested );
+
+ // Check the result
+ CPPUNIT_ASSERT( NULL == actual );
+
+ libcmis_object_free( tested );
+}
+
+void DocumentTest::objectFunctionsTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ char* actual = libcmis_object_getId( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Document::Id" ), string( actual ) );
+ free( actual );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getParentsTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get the parent folders (tested method)
+ libcmis_vector_folder_Ptr actual = libcmis_document_getParents( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), libcmis_vector_folder_size( actual ) );
+
+ // Free it all
+ libcmis_vector_folder_free( actual );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getParentsUnfiledTest( )
+{
+ libcmis_DocumentPtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get the parent folders (tested method)
+ libcmis_vector_folder_Ptr actual = libcmis_document_getParents( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT_EQUAL( size_t( 0 ), libcmis_vector_folder_size( actual ) );
+
+ // Free it all
+ libcmis_vector_folder_free( actual );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getParentsErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get the parent folders (tested method)
+ libcmis_vector_folder_Ptr actual = libcmis_document_getParents( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT( NULL == actual );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+
+ // Free it all
+ libcmis_vector_folder_free( actual );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getContentStreamTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get the content into a temporary file (tested method)
+ FILE* tmp = tmpfile( );
+ libcmis_document_getContentStream( tested,
+ ( libcmis_writeFn )fwrite, tmp, error );
+
+ // Check
+ string expected = getTestedImplementation( tested )->getContentString( );
+
+ string actual = lcl_readFile( tmp );
+ fclose( tmp );
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT_EQUAL( expected, actual );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getContentStreamErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get the content into a temporary file (tested method)
+ FILE* tmp = tmpfile( );
+ libcmis_document_getContentStream( tested,
+ ( libcmis_writeFn )fwrite, tmp, error );
+
+ // Check
+ string actual = lcl_readFile( tmp );
+ fclose( tmp );
+ CPPUNIT_ASSERT_EQUAL( string( ), actual );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getContentStreamBadAllocTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get the content into a temporary file (tested method)
+ FILE* tmp = tmpfile( );
+
+ isOutOfMemory= true;
+ libcmis_document_getContentStream( tested,
+ ( libcmis_writeFn )fwrite, tmp, error );
+ isOutOfMemory = false;
+
+ // Check
+ string actual = lcl_readFile( tmp );
+ fclose( tmp );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty() );
+ CPPUNIT_ASSERT_EQUAL( string( ), actual );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::setContentStreamTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Prepare the content to set
+ FILE* tmp = tmpfile( );
+ string expected( "New Content Stream" );
+ fwrite( expected.c_str( ), 1, expected.size( ), tmp );
+ rewind( tmp );
+
+ // get the content into a temporary file (tested method)
+ const char* contentType = "content/type";
+ const char* filename = "name.txt";
+ libcmis_document_setContentStream( tested,
+ ( libcmis_readFn )fread, tmp, contentType, filename, true, error );
+ fclose( tmp );
+
+ // Check
+ string actual = getTestedImplementation( tested )->getContentString( );
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT_EQUAL( expected, actual );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::setContentStreamErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ string expected = getTestedImplementation( tested )->getContentString( );
+
+ // Prepare the content to set
+ FILE* tmp = tmpfile( );
+ string newContent( "New Content Stream" );
+ fwrite( newContent.c_str( ), 1, newContent.size( ), tmp );
+ rewind( tmp );
+
+ // get the content into a temporary file (tested method)
+ const char* contentType = "content/type";
+ const char* filename = "name.txt";
+ libcmis_document_setContentStream( tested,
+ ( libcmis_readFn )fread, tmp, contentType, filename, true, error );
+ fclose( tmp );
+
+ // Check
+ string actual = getTestedImplementation( tested )->getContentString( );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+ CPPUNIT_ASSERT_EQUAL( expected, actual );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getContentTypeTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ char* actual = libcmis_document_getContentType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Document::ContentType" ), string( actual ) );
+ free( actual );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getContentFilenameTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ char* actual = libcmis_document_getContentFilename( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Document::ContentFilename" ), string( actual ) );
+ free( actual );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getContentLengthTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ long actual = libcmis_document_getContentLength( tested );
+ CPPUNIT_ASSERT( 0 != actual );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::checkOutTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // checkout a private working copy (tested method)
+ libcmis_DocumentPtr actual = libcmis_document_checkOut( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT( NULL != actual );
+
+ // Free it all
+ libcmis_document_free( actual );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::checkOutErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // checkout a private working copy (tested method)
+ libcmis_DocumentPtr actual = libcmis_document_checkOut( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT( NULL == actual );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+
+ // Free it all
+ libcmis_document_free( actual );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::cancelCheckoutTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // checkout a private working copy (tested method)
+ libcmis_document_cancelCheckout( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT( 0 != libcmis_object_getRefreshTimestamp( tested ) );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::cancelCheckoutErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // checkout a private working copy (tested method)
+ libcmis_document_cancelCheckout( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT( 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+
+ // Free it all
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::checkInTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Prepare the content to set
+ FILE* tmp = tmpfile( );
+ string expected( "New Content Stream" );
+ fwrite( expected.c_str( ), 1, expected.size( ), tmp );
+ rewind( tmp );
+
+ // Create the properties for the new version
+ libcmis_vector_property_Ptr properties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ const char* id = "Property1";
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, id );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr property = libcmis_property_create( propertyType, values, size );
+ delete[] values;
+ libcmis_vector_property_append( properties, property );
+
+ // get the content into a temporary file (tested method)
+ const char* contentType = "content/type";
+ const char* comment = "Version comment";
+ const char* filename = "filename.txt";
+ libcmis_DocumentPtr newVersion = libcmis_document_checkIn(
+ tested, true, comment, properties,
+ ( libcmis_readFn )fread, tmp, contentType, filename, error );
+ fclose( tmp );
+
+ // Check
+ CPPUNIT_ASSERT( NULL != newVersion );
+
+ string actual = getTestedImplementation( tested )->getContentString( );
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT_EQUAL( expected, actual );
+
+ libcmis_PropertyPtr checkedProperty = libcmis_object_getProperty( tested, "Property1" );
+ libcmis_vector_string_Ptr newValues = libcmis_property_getStrings( checkedProperty );
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), libcmis_vector_string_size( newValues ) );
+
+ // Free it all
+ libcmis_vector_string_free( newValues );
+ libcmis_property_free( checkedProperty );
+ libcmis_document_free( newVersion );
+ libcmis_property_free( property );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( properties );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::checkInErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ string expected = getTestedImplementation( tested )->getContentString( );
+
+ // Prepare the content to set
+ FILE* tmp = tmpfile( );
+ string newContent( "New Content Stream" );
+ fwrite( newContent.c_str( ), 1, newContent.size( ), tmp );
+ rewind( tmp );
+
+ // Create the properties for the new version
+ libcmis_vector_property_Ptr properties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ const char* id = "Property1";
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, id );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr property = libcmis_property_create( propertyType, values, size );
+ delete[] values;
+ libcmis_vector_property_append( properties, property );
+
+ // get the content into a temporary file (tested method)
+ const char* contentType = "content/type";
+ const char* comment = "Version comment";
+ const char* filename = "filename.txt";
+ libcmis_DocumentPtr newVersion = libcmis_document_checkIn(
+ tested, true, comment, properties,
+ ( libcmis_readFn )fread, tmp, contentType, filename, error );
+ fclose( tmp );
+
+ // Check
+ CPPUNIT_ASSERT( NULL == newVersion );
+
+ string actual = getTestedImplementation( tested )->getContentString( );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+ CPPUNIT_ASSERT_EQUAL( expected, actual );
+
+ libcmis_PropertyPtr checkedProperty = libcmis_object_getProperty( tested, "Property1" );
+ libcmis_vector_string_Ptr newValues = libcmis_property_getStrings( checkedProperty );
+ CPPUNIT_ASSERT_EQUAL( size_t( 1 ), libcmis_vector_string_size( newValues ) );
+
+ // Free it all
+ libcmis_vector_string_free( newValues );
+ libcmis_property_free( checkedProperty );
+ libcmis_document_free( newVersion );
+ libcmis_property_free( property );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( properties );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getAllVersionsTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get all versions (tested method)
+ libcmis_vector_document_Ptr versions = libcmis_document_getAllVersions( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), libcmis_vector_document_size( versions ) );
+ libcmis_DocumentPtr actualVersion = libcmis_vector_document_get( versions, 0 );
+ char* actualId = libcmis_object_getId( actualVersion );
+ CPPUNIT_ASSERT( actualId != NULL );
+ free( actualId );
+
+ // Free it all
+ libcmis_document_free( actualVersion );
+ libcmis_vector_document_free( versions );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
+
+void DocumentTest::getAllVersionsErrorTest( )
+{
+ libcmis_DocumentPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // get all versions (tested method)
+ libcmis_vector_document_Ptr versions = libcmis_document_getAllVersions( tested, error );
+
+ // Check
+ CPPUNIT_ASSERT( NULL == versions );
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+
+ // Free it all
+ libcmis_vector_document_free( versions );
+ libcmis_error_free( error );
+ libcmis_document_free( tested );
+}
diff --git a/qa/libcmis-c/test-dummies.cxx b/qa/libcmis-c/test-dummies.cxx
new file mode 100644
index 0000000..5056bcf
--- /dev/null
+++ b/qa/libcmis-c/test-dummies.cxx
@@ -0,0 +1,633 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "test-dummies.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+bool isOutOfMemory = false;
+
+/// Ignore all tests results depending on this when running in valgrind
+void * operator new ( size_t requestedSize )
+{
+ if ( isOutOfMemory )
+ {
+ throw bad_alloc( );
+ }
+
+ return malloc( requestedSize );
+}
+
+void operator delete ( void* ptr ) throw ( )
+{
+ free( ptr );
+}
+
+#if __cplusplus > 201103L
+void operator delete ( void* ptr, std::size_t ) throw ( )
+{
+ free( ptr );
+}
+#endif
+
+namespace dummies
+{
+ Session::Session( )
+ {
+ }
+
+ Session::~Session( )
+ {
+ }
+
+ libcmis::RepositoryPtr Session::getRepository( )
+ {
+ libcmis::RepositoryPtr repo( new Repository( ) );
+ return repo;
+ }
+
+
+ bool Session::setRepository( std::string )
+ {
+ return true;
+ }
+
+ vector< libcmis::RepositoryPtr > Session::getRepositories( )
+ {
+ vector< libcmis::RepositoryPtr > repos;
+ libcmis::RepositoryPtr repo1( new Repository( ) );
+ libcmis::RepositoryPtr repo2( new Repository( ) );
+ repos.push_back( repo1 );
+ repos.push_back( repo2 );
+ return repos;
+ }
+
+ libcmis::FolderPtr Session::getRootFolder()
+ {
+ libcmis::FolderPtr root( new Folder( true, false ) );
+ return root;
+ }
+
+ libcmis::ObjectPtr Session::getObject( string id )
+ {
+ return getFolder( id );
+ }
+
+ libcmis::ObjectPtr Session::getObjectByPath( string path )
+ {
+ return getFolder( path );
+ }
+
+ libcmis::FolderPtr Session::getFolder( string )
+ {
+ libcmis::FolderPtr result( new Folder( false, false ) );
+ return result;
+ }
+
+ libcmis::ObjectTypePtr Session::getType( string )
+ {
+ libcmis::ObjectTypePtr type( new ObjectType( true, false ) );
+ return type;
+ }
+
+ vector< libcmis::ObjectTypePtr > Session::getBaseTypes( )
+ {
+ vector< libcmis::ObjectTypePtr > types;
+ libcmis::ObjectTypePtr type( new ObjectType( true, false ) );
+ types.push_back( type );
+ return types;
+ }
+
+ std::string Session::getRefreshToken( )
+ {
+ return string( );
+ }
+
+ Repository::Repository( ) :
+ libcmis::Repository( )
+ {
+ m_id = string( "Repository::Id" );
+ m_name = string( "Repository::Name" );
+ m_description = string( "Repository::Description" );
+ m_vendorName = string( "Repository::VendorName" );
+ m_productName = string( "Repository::ProductName" );
+ m_productVersion = string( "Repository::ProductVersion" );
+ m_rootId = string( "Repository::RootId" );
+ m_cmisVersionSupported = string( "Repository::CmisVersionSupported" );
+ m_thinClientUri.reset( new string( "Repository::ThinClientUri" ) );
+ m_principalAnonymous.reset( new string( "Repository::PrincipalAnonymous" ) );
+ m_principalAnyone.reset( new string( "Repository::PrincipalAnyone" ) );
+ }
+
+ Repository::~Repository( )
+ {
+ }
+
+ PropertyType::PropertyType( string id, string xmlType ) :
+ libcmis::PropertyType( )
+ {
+ setId( id );
+ setLocalName( string( "PropertyType::LocalName" ) );
+ setLocalNamespace( string( "PropertyType::LocalNamespace" ) );
+ setDisplayName( string( "PropertyType::DisplayName" ) );
+ setQueryName( string( "PropertyType::QueryName" ) );
+ setTypeFromXml( xmlType );
+
+ // Setting true for the tests to see a difference with
+ // the default false result of the tested functions
+ setMultiValued( true );
+ setUpdatable( true );
+ setInherited( true );
+ setRequired( true );
+ setQueryable( true );
+ setOrderable( true );
+ setOpenChoice( true );
+ }
+
+ PropertyType::~PropertyType( )
+ {
+ }
+
+ AllowableActions::AllowableActions( ) :
+ libcmis::AllowableActions( )
+ {
+ m_states.insert( pair< libcmis::ObjectAction::Type, bool >( libcmis::ObjectAction::GetProperties, true ) );
+ m_states.insert( pair< libcmis::ObjectAction::Type, bool >( libcmis::ObjectAction::GetFolderParent, false ) );
+ }
+
+ AllowableActions::~AllowableActions( )
+ {
+ }
+
+ ObjectType::ObjectType( ) :
+ libcmis::ObjectType( ),
+ m_typeId( ),
+ m_childrenIds( ),
+ m_triggersFaults( false )
+ {
+ }
+
+ ObjectType::ObjectType( bool rootType, bool triggersFaults ) :
+ libcmis::ObjectType( ),
+ m_typeId( ),
+ m_childrenIds( ),
+ m_triggersFaults( triggersFaults )
+ {
+ if ( rootType )
+ m_typeId = "RootType";
+ else
+ {
+ m_typeId = "ObjectType";
+ m_parentTypeId = "ParentType";
+ m_childrenIds.push_back( "ChildType1" );
+ m_childrenIds.push_back( "ChildType2" );
+ }
+
+ m_baseTypeId = "RootType";
+ libcmis::PropertyTypePtr propType1( new PropertyType( "Property1", "string" ) );
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( propType1->getId( ), propType1 ) );
+ libcmis::PropertyTypePtr propType2( new PropertyType( "Property2", "string" ) );
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( propType2->getId( ), propType2 ) );
+ libcmis::PropertyTypePtr propType3( new PropertyType( "Property3", "string" ) );
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( propType3->getId( ), propType3 ) );
+
+ initMembers( );
+ }
+
+ void ObjectType::initMembers( )
+ {
+
+ m_id = m_typeId + "::Id";
+ m_localName = m_typeId + "::LocalName";
+ m_localNamespace = m_typeId + "::LocalNamespace";
+ m_displayName = m_typeId + "::DisplayName";
+ m_queryName = m_typeId + "::QueryName";
+ m_description = m_typeId + "::Description";
+
+ m_creatable = true;
+ m_fileable = true;
+ m_queryable = true;
+ m_fulltextIndexed = true;
+ m_includedInSupertypeQuery = true;
+ m_controllablePolicy = true;
+ m_controllableAcl = true;
+ m_versionable = true;
+ m_contentStreamAllowed = libcmis::ObjectType::Allowed;
+ }
+
+ ObjectType::~ObjectType( )
+ {
+ }
+
+ libcmis::ObjectTypePtr ObjectType::getParentType( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ ObjectType* parent = NULL;
+ if ( !m_parentTypeId.empty( ) )
+ {
+ parent = new ObjectType( );
+ parent->m_typeId = m_parentTypeId;
+ parent->m_parentTypeId = m_baseTypeId;
+ parent->m_baseTypeId = m_baseTypeId;
+ parent->m_childrenIds.push_back( m_id );
+ parent->m_triggersFaults = m_triggersFaults;
+ parent->m_propertiesTypes = m_propertiesTypes;
+
+ parent->initMembers( );
+ }
+
+ libcmis::ObjectTypePtr result( parent );
+ return result;
+ }
+
+ libcmis::ObjectTypePtr ObjectType::getBaseType( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ ObjectType* base = this;
+ if ( m_typeId != m_baseTypeId )
+ {
+ base = new ObjectType( );
+ base->m_typeId = m_baseTypeId;
+ base->m_baseTypeId = m_baseTypeId;
+ base->m_childrenIds.push_back( m_id );
+ base->m_triggersFaults = m_triggersFaults;
+ base->m_propertiesTypes = m_propertiesTypes;
+
+ base->initMembers( );
+ }
+
+ libcmis::ObjectTypePtr result( base );
+ return result;
+ }
+
+ vector< libcmis::ObjectTypePtr > ObjectType::getChildren( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ vector< libcmis::ObjectTypePtr > children;
+
+ for ( vector< string >::iterator it = m_childrenIds.begin( ); it != m_childrenIds.end( ); ++it )
+ {
+ ObjectType* child = new ObjectType( );
+ child->m_typeId = *it;
+ child->m_parentTypeId = m_typeId;
+ child->m_baseTypeId = m_baseTypeId;
+ child->m_triggersFaults = m_triggersFaults;
+ child->m_propertiesTypes = m_propertiesTypes;
+
+ child->initMembers( );
+
+ libcmis::ObjectTypePtr result( child );
+ children.push_back( result );
+ }
+
+ return children;
+ }
+
+ string ObjectType::toString( )
+ {
+ return m_typeId + "::toString";
+ }
+
+ Object::Object( bool triggersFaults, string type ):
+ libcmis::Object( NULL ),
+ m_type( type ),
+ m_triggersFaults( triggersFaults )
+ {
+ libcmis::PropertyTypePtr propertyType( new PropertyType( "Property1", "string" ) );
+ vector< string > values;
+ values.push_back( "Value1" );
+ libcmis::PropertyPtr property( new libcmis::Property( propertyType, values ) );
+ m_properties.insert( pair< string, libcmis::PropertyPtr >( propertyType->getId( ), property ) );
+ }
+
+ string Object::getId( )
+ {
+ return m_type + "::Id";
+ }
+
+ string Object::getName( )
+ {
+ return m_type + "::Name";
+ }
+
+ vector< string > Object::getPaths( )
+ {
+ vector< string > paths;
+ paths.push_back( string( "/Path1/" ) );
+ paths.push_back( string( "/Path2/" ) );
+
+ return paths;
+ }
+
+ string Object::getBaseType( )
+ {
+ return m_type + "::BaseType";
+ }
+
+ string Object::getType( )
+ {
+ return m_type + "::Type";
+ }
+
+ boost::posix_time::ptime Object::getCreationDate( )
+ {
+ boost::posix_time::ptime now( boost::posix_time::second_clock::local_time( ) );
+ return now;
+ }
+
+ boost::posix_time::ptime Object::getLastModificationDate( )
+ {
+ boost::posix_time::ptime now( boost::posix_time::second_clock::local_time( ) );
+ return now;
+ }
+
+ libcmis::ObjectPtr Object::updateProperties(
+ const PropertyPtrMap& )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+ libcmis::ObjectPtr result( new Object( false ) );
+ return result;
+ }
+
+ libcmis::ObjectTypePtr Object::getTypeDescription( )
+ {
+ libcmis::ObjectTypePtr type( new ObjectType( false, m_triggersFaults ) );
+ return type;
+ }
+
+ libcmis::AllowableActionsPtr Object::getAllowableActions( )
+ {
+ libcmis::AllowableActionsPtr allowableActions( new AllowableActions( ) );
+ return allowableActions;
+ }
+
+ void Object::refresh( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+ }
+
+ void Object::remove( bool )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+ }
+
+ void Object::move( libcmis::FolderPtr, libcmis::FolderPtr )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+ }
+
+ void Object::toXml( xmlTextWriterPtr )
+ {
+ }
+
+ Folder::Folder( bool isRoot, bool triggersFaults ) :
+ libcmis::Object( NULL ),
+ libcmis::Folder( NULL ),
+ dummies::Object( triggersFaults, "Folder" ),
+ m_isRoot( isRoot )
+ {
+ }
+
+ libcmis::FolderPtr Folder::getFolderParent( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ libcmis::FolderPtr parent;
+
+ if ( !m_isRoot )
+ parent.reset( new Folder( true, m_triggersFaults ) );
+
+ return parent;
+ }
+
+ vector< libcmis::ObjectPtr > Folder::getChildren( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ vector< libcmis::ObjectPtr > children;
+
+ libcmis::ObjectPtr child1( new Object( m_triggersFaults ) );
+ children.push_back( child1 );
+ libcmis::ObjectPtr child2( new Object( m_triggersFaults ) );
+ children.push_back( child2 );
+
+ return children;
+ }
+
+ string Folder::getPath( )
+ {
+ return string( "/Path/" );
+ }
+
+ bool Folder::isRootFolder( )
+ {
+ return m_isRoot;
+ }
+
+ libcmis::FolderPtr Folder::createFolder( const PropertyPtrMap& )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ libcmis::FolderPtr created( new Folder( true, m_triggersFaults ) );
+ return created;
+ }
+
+ libcmis::DocumentPtr Folder::createDocument( const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os, string contentType, string filename )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ dummies::Document* document = new dummies::Document( true, false );
+
+ PropertyPtrMap propertiesCopy( properties );
+ document->getProperties( ).swap( propertiesCopy );
+ document->setContentStream( os, contentType, filename );
+
+ libcmis::DocumentPtr created( document );
+ return created;
+ }
+
+ vector< string > Folder::removeTree( bool, libcmis::UnfileObjects::Type,
+ bool )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+
+ vector< string > failed;
+ failed.push_back( "failed 1" );
+ return failed;
+ }
+
+ Document::Document( bool isFiled, bool triggersFaults ) :
+ libcmis::Object( NULL ),
+ libcmis::Document( NULL ),
+ dummies::Object( triggersFaults, "Document" ),
+ m_isFiled( isFiled ),
+ m_contentString( "Document::ContentStream" )
+ {
+ }
+
+ vector< libcmis::FolderPtr > Document::getParents( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ vector< libcmis::FolderPtr > parents;
+ if ( m_isFiled )
+ {
+ libcmis::FolderPtr parent1( new Folder( true, m_triggersFaults ) );
+ parents.push_back( parent1 );
+ libcmis::FolderPtr parent2( new Folder( false, m_triggersFaults ) );
+ parents.push_back( parent2 );
+ }
+
+ return parents;
+ }
+
+ boost::shared_ptr< istream > Document::getContentStream( string /*streamId*/ )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ bool oldOutOfMem = isOutOfMemory;
+ isOutOfMemory = false;
+ boost::shared_ptr< istream > stream( new stringstream( m_contentString ) );
+ isOutOfMemory = oldOutOfMem;
+ return stream;
+ }
+
+ void Document::setContentStream( boost::shared_ptr< ostream > os, string, string, bool )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ istream is( os->rdbuf( ) );
+ stringstream out;
+ is.seekg( 0 );
+ int bufSize = 2048;
+ char* buf = new char[ bufSize ];
+ while ( !is.eof( ) )
+ {
+ is.read( buf, bufSize );
+ size_t read = is.gcount( );
+ out.write( buf, read );
+ }
+ delete[] buf;
+
+ m_contentString = out.str( );
+
+ time( &m_refreshTimestamp );
+ }
+
+ string Document::getContentType( )
+ {
+ return "Document::ContentType";
+ }
+
+ string Document::getContentFilename( )
+ {
+ return "Document::ContentFilename";
+ }
+
+ long Document::getContentLength( )
+ {
+ return long( 12345 );
+ }
+
+ libcmis::DocumentPtr Document::checkOut( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+
+ libcmis::DocumentPtr result( new Document( true, m_triggersFaults ) );
+ return result;
+ }
+
+ void Document::cancelCheckout( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ time( &m_refreshTimestamp );
+ }
+
+ libcmis::DocumentPtr Document::checkIn( bool, string, const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os, string contentType, string filename )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ m_properties = properties;
+ setContentStream( os, contentType, filename );
+ time( &m_refreshTimestamp );
+
+ return libcmis::DocumentPtr( new Document( true, false ) );
+ }
+
+ vector< libcmis::DocumentPtr > Document::getAllVersions( )
+ {
+ if ( m_triggersFaults )
+ throw libcmis::Exception( "Fault triggered" );
+
+ vector< libcmis::DocumentPtr > versions;
+
+ libcmis::DocumentPtr version1( new Document( true, false ) );
+ versions.push_back( version1 );
+ libcmis::DocumentPtr version2( new Document( true, false ) );
+ versions.push_back( version2 );
+
+ return versions;
+ }
+}
diff --git a/qa/libcmis-c/test-dummies.hxx b/qa/libcmis-c/test-dummies.hxx
new file mode 100644
index 0000000..161c813
--- /dev/null
+++ b/qa/libcmis-c/test-dummies.hxx
@@ -0,0 +1,223 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_TEST_DUMMIES_HXX_
+#define _LIBCMIS_TEST_DUMMIES_HXX_
+
+
+#include <libcmis/allowable-actions.hxx>
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+#include <libcmis/object.hxx>
+#include <libcmis/object-type.hxx>
+#include <libcmis/property-type.hxx>
+#include <libcmis/repository.hxx>
+#include <libcmis/session.hxx>
+
+/** This namespace contains dummy classes to simulate the libcmis layer
+ in the libcmis-c unit tests.
+ */
+namespace dummies
+{
+ class Session : public libcmis::Session
+ {
+ public:
+ Session( );
+ ~Session( );
+
+ virtual libcmis::RepositoryPtr getRepository( );
+ virtual bool setRepository( std::string repositoryId );
+ virtual std::vector< libcmis::RepositoryPtr > getRepositories( );
+ virtual libcmis::FolderPtr getRootFolder();
+ virtual libcmis::ObjectPtr getObject( std::string id );
+ virtual libcmis::ObjectPtr getObjectByPath( std::string path );
+ virtual libcmis::FolderPtr getFolder( std::string id );
+ virtual libcmis::ObjectTypePtr getType( std::string id );
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+ virtual std::string getRefreshToken( );
+ virtual void setNoSSLCertificateCheck( bool /*noCheck*/ ) { }
+ };
+
+ class Repository : public libcmis::Repository
+ {
+ public:
+ Repository( );
+ ~Repository( );
+ };
+
+ class PropertyType : public libcmis::PropertyType
+ {
+ public:
+ PropertyType( std::string id, std::string xmlType );
+ ~PropertyType( );
+ };
+
+ /** Dummy for testing the C API for allowable actions. The dummy has only the
+ following actions defined:
+ \li \c GetProperties, defined to \c true
+ \li \c GetFolderParent, defined to \c false
+ */
+ class AllowableActions : public libcmis::AllowableActions
+ {
+ public:
+ AllowableActions( );
+ ~AllowableActions( );
+ };
+
+ class ObjectType : public libcmis::ObjectType
+ {
+ private:
+ std::string m_typeId;
+ std::vector< std::string > m_childrenIds;
+ bool m_triggersFaults;
+
+ ObjectType( );
+ void initMembers( );
+
+ public:
+ ObjectType( bool rootType, bool triggersFaults );
+ ~ObjectType( );
+
+ virtual boost::shared_ptr< libcmis::ObjectType > getParentType( );
+ virtual boost::shared_ptr< libcmis::ObjectType > getBaseType( );
+ virtual std::vector< boost::shared_ptr< libcmis::ObjectType > > getChildren( );
+
+ virtual std::string toString( );
+ };
+
+ class Object : public virtual libcmis::Object
+ {
+ public:
+ std::string m_type;
+ bool m_triggersFaults;
+
+ public:
+ Object( bool triggersFaults, std::string m_type = "Object" );
+ ~Object( ) { }
+
+ virtual std::string getId( );
+ virtual std::string getName( );
+
+ virtual std::vector< std::string > getPaths( );
+
+ virtual std::string getBaseType( );
+ virtual std::string getType( );
+
+ virtual std::string getCreatedBy( ) { return m_type + "::CreatedBy"; }
+ virtual boost::posix_time::ptime getCreationDate( );
+ virtual std::string getLastModifiedBy( ) { return m_type + "::LastModifiedBy"; }
+ virtual boost::posix_time::ptime getLastModificationDate( );
+
+ virtual std::string getChangeToken( ) { return m_type + "::ChangeToken"; }
+ virtual bool isImmutable( ) { return true; };
+
+ virtual libcmis::ObjectPtr updateProperties(
+ const std::map< std::string, libcmis::PropertyPtr >& properties );
+
+ virtual libcmis::ObjectTypePtr getTypeDescription( );
+ virtual libcmis::AllowableActionsPtr getAllowableActions( );
+
+ virtual void refresh( );
+
+ virtual void remove( bool allVersions = true );
+
+ virtual void move( libcmis::FolderPtr source, libcmis::FolderPtr destination );
+
+ virtual std::string toString( ) { return m_type + "::toString"; }
+
+ virtual void toXml( xmlTextWriterPtr writer );
+ };
+
+ class Folder : public libcmis::Folder, public Object
+ {
+ private:
+ bool m_isRoot;
+
+ public:
+ Folder( bool isRoot, bool triggersFaults );
+ ~Folder( ) { }
+
+ virtual libcmis::FolderPtr getFolderParent( );
+ virtual std::vector< libcmis::ObjectPtr > getChildren( );
+ virtual std::string getPath( );
+
+ virtual bool isRootFolder( );
+
+ virtual libcmis::FolderPtr createFolder( const std::map< std::string, libcmis::PropertyPtr >& properties );
+ virtual libcmis::DocumentPtr createDocument( const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > os, std::string contentType, std::string filename );
+
+ virtual std::vector< std::string > removeTree( bool allVersion = true,
+ libcmis::UnfileObjects::Type unfile = libcmis::UnfileObjects::Delete,
+ bool continueOnError = false );
+
+ virtual std::vector< std::string > getPaths( ) { return dummies::Object::getPaths( ); }
+ virtual std::string toString( ) { return dummies::Object::toString( ); }
+ };
+
+ class Document : public libcmis::Document, public Object
+ {
+ private:
+ bool m_isFiled;
+ std::string m_contentString;
+
+ public:
+ Document( bool isFiled, bool triggersFaults );
+ ~Document( ) { }
+
+ std::string getContentString( ) { return m_contentString; }
+
+ virtual std::vector< libcmis::FolderPtr > getParents( );
+
+ virtual boost::shared_ptr< std::istream > getContentStream( std::string streamId = std::string( ) );
+
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os, std::string contentType,
+ std::string fileName, bool overwrite = true );
+
+ virtual std::string getContentType( );
+
+ virtual std::string getContentFilename( );
+
+ virtual long getContentLength( );
+
+ virtual libcmis::DocumentPtr checkOut( );
+
+ virtual void cancelCheckout( );
+
+ virtual libcmis::DocumentPtr checkIn( bool isMajor, std::string comment,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType, std::string filename );
+
+ virtual std::vector< libcmis::DocumentPtr > getAllVersions( );
+
+ virtual std::vector< std::string > getPaths( ) { return dummies::Object::getPaths( ); }
+ virtual std::string toString( ) { return dummies::Object::toString( ); }
+ };
+}
+
+#endif
diff --git a/qa/libcmis-c/test-folder.cxx b/qa/libcmis-c/test-folder.cxx
new file mode 100644
index 0000000..171c57d
--- /dev/null
+++ b/qa/libcmis-c/test-folder.cxx
@@ -0,0 +1,433 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/document.h>
+#include <libcmis-c/error.h>
+#include <libcmis-c/folder.h>
+#include <libcmis-c/object.h>
+#include <libcmis-c/object-type.h>
+#include <libcmis-c/property.h>
+#include <libcmis-c/property-type.h>
+#include <libcmis-c/vectors.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class FolderTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_FolderPtr getTested( bool isRoot, bool triggersFaults );
+ dummies::Document* getDocumentImplementation( libcmis_DocumentPtr document );
+
+ public:
+ void objectCastTest( );
+ void objectCastFailureTest( );
+ void objectFunctionsTest( );
+ void getParentTest( );
+ void getParentRootTest( );
+ void getParentErrorTest( );
+ void getChildrenTest( );
+ void getChildrenErrorTest( );
+ void getPathTest( );
+ void createFolderTest( );
+ void createFolderErrorTest( );
+ void createDocumentTest( );
+ void createDocumentErrorTest( );
+ void removeTreeTest( );
+ void removeTreeErrorTest( );
+
+ CPPUNIT_TEST_SUITE( FolderTest );
+ CPPUNIT_TEST( objectCastTest );
+ CPPUNIT_TEST( objectCastFailureTest );
+ CPPUNIT_TEST( objectFunctionsTest );
+ CPPUNIT_TEST( getParentTest );
+ CPPUNIT_TEST( getParentRootTest );
+ CPPUNIT_TEST( getParentErrorTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( getChildrenErrorTest );
+ CPPUNIT_TEST( getPathTest );
+ CPPUNIT_TEST( createFolderTest );
+ CPPUNIT_TEST( createFolderErrorTest );
+ CPPUNIT_TEST( createDocumentTest );
+ CPPUNIT_TEST( createDocumentErrorTest );
+ CPPUNIT_TEST( removeTreeTest );
+ CPPUNIT_TEST( removeTreeErrorTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( FolderTest );
+
+libcmis_FolderPtr FolderTest::getTested( bool isRoot, bool triggersFaults )
+{
+ libcmis_FolderPtr result = new libcmis_folder( );
+ libcmis::FolderPtr handle( new dummies::Folder( isRoot, triggersFaults ) );
+ result->handle = handle;
+
+ return result;
+}
+
+dummies::Document* FolderTest::getDocumentImplementation( libcmis_DocumentPtr document )
+{
+ dummies::Document* impl = dynamic_cast< dummies::Document* >( document->handle.get( ) );
+ return impl;
+}
+
+void FolderTest::objectCastTest( )
+{
+ // Create the test object to cast
+ libcmis_ObjectPtr tested = new libcmis_object( );
+ libcmis::FolderPtr handle( new dummies::Folder( false, false ) );
+ tested->handle = handle;
+
+ // Test libcmis_is_folder
+ CPPUNIT_ASSERT( libcmis_is_folder( tested ) );
+
+ // Actually cast to a folder
+ libcmis_FolderPtr actual = libcmis_folder_cast( tested );
+
+ // Check the result
+ CPPUNIT_ASSERT( NULL != actual );
+
+ // Check that the libcmis_object-* functions are working with the cast result
+ char* actualId = libcmis_object_getId( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Folder::Id" ), string( actualId ) );
+ free( actualId );
+
+ // Free it all
+ libcmis_folder_free( actual );
+ libcmis_object_free( tested );
+}
+
+void FolderTest::objectCastFailureTest( )
+{
+ // Create the test object to cast
+ libcmis_ObjectPtr tested = new libcmis_object( );
+ libcmis::DocumentPtr handle( new dummies::Document( true, false ) );
+ tested->handle = handle;
+
+ // Test libcmis_is_folder
+ CPPUNIT_ASSERT( !libcmis_is_folder( tested ) );
+
+ // Actually cast to a folder
+ libcmis_FolderPtr actual = libcmis_folder_cast( tested );
+
+ // Check the result
+ CPPUNIT_ASSERT( NULL == actual );
+
+ libcmis_object_free( tested );
+}
+
+void FolderTest::objectFunctionsTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, false );
+ char* actual = libcmis_object_getId( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Folder::Id" ), string( actual ) );
+ free( actual );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::getParentTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_FolderPtr parent = libcmis_folder_getParent( tested, error );
+ CPPUNIT_ASSERT( NULL != parent );
+ CPPUNIT_ASSERT( !libcmis_folder_isRootFolder( tested ) );
+ libcmis_folder_free( parent );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::getParentRootTest( )
+{
+ libcmis_FolderPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_FolderPtr parent = libcmis_folder_getParent( tested, error );
+ CPPUNIT_ASSERT( NULL == parent );
+ CPPUNIT_ASSERT( libcmis_folder_isRootFolder( tested ) );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::getParentErrorTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_FolderPtr parent = libcmis_folder_getParent( tested, error );
+ CPPUNIT_ASSERT( NULL == parent );
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::getChildrenTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ libcmis_vector_object_Ptr children = libcmis_folder_getChildren( tested, error );
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), libcmis_vector_object_size( children ) );
+ libcmis_vector_object_free( children );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::getChildrenErrorTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ libcmis_vector_object_Ptr children = libcmis_folder_getChildren( tested, error );
+ CPPUNIT_ASSERT( NULL == children );
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::getPathTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, false );
+ char* actual = libcmis_folder_getPath( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "/Path/" ), string( actual ) );
+ free( actual );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::createFolderTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Create the properties for the new folder
+ libcmis_vector_property_Ptr properties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ const char* id = "Property1";
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, id );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr property = libcmis_property_create( propertyType, values, size );
+ delete[] values;
+ libcmis_vector_property_append( properties, property );
+
+ // Create the new folder (method to test)
+ libcmis_FolderPtr created = libcmis_folder_createFolder( tested, properties, error );
+
+ // Check
+ CPPUNIT_ASSERT( NULL != created );
+
+ // Free everything
+ libcmis_folder_free( created );
+ libcmis_property_free( property );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( properties );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::createFolderErrorTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Create the properties for the new folder
+ libcmis_vector_property_Ptr properties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ const char* id = "Property1";
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, id );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr property = libcmis_property_create( propertyType, values, size );
+ delete[] values;
+ libcmis_vector_property_append( properties, property );
+
+ // Create the new folder (method to test)
+ libcmis_FolderPtr created = libcmis_folder_createFolder( tested, properties, error );
+
+ // Check
+ CPPUNIT_ASSERT( NULL == created );
+
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+
+ // Free everything
+ libcmis_folder_free( created );
+ libcmis_property_free( property );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( properties );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::createDocumentTest( )
+{
+ libcmis_FolderPtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Prepare the content to set
+ FILE* tmp = tmpfile( );
+ string expectedStream( "New Content Stream" );
+ fwrite( expectedStream.c_str( ), 1, expectedStream.size( ), tmp );
+ rewind( tmp );
+
+ // Create the properties for the new version
+ libcmis_vector_property_Ptr properties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ const char* id = "Property1";
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, id );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr property = libcmis_property_create( propertyType, values, size );
+ delete[] values;
+ libcmis_vector_property_append( properties, property );
+
+ // get the content into a temporary file (tested method)
+ const char* contentType = "content/type";
+ const char* filename = "name.txt";
+ libcmis_DocumentPtr actual = libcmis_folder_createDocument( tested, properties,
+ ( libcmis_readFn )fread, tmp, contentType, filename, error );
+ fclose( tmp );
+
+ // Check
+ string actualStream = getDocumentImplementation( actual )->getContentString( );
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT_EQUAL( expectedStream, actualStream );
+
+ libcmis_PropertyPtr checkedProperty = libcmis_object_getProperty( actual, "Property1" );
+ libcmis_vector_string_Ptr newValues = libcmis_property_getStrings( checkedProperty );
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), libcmis_vector_string_size( newValues ) );
+
+ // Free it all
+ libcmis_vector_string_free( newValues );
+ libcmis_property_free( checkedProperty );
+ libcmis_document_free( actual );
+ libcmis_property_free( property );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( properties );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::createDocumentErrorTest( )
+{
+ libcmis_FolderPtr tested = getTested( true, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Prepare the content to set
+ FILE* tmp = tmpfile( );
+ string newStream( "New Content Stream" );
+ fwrite( newStream.c_str( ), 1, newStream.size( ), tmp );
+ rewind( tmp );
+
+ // Create the properties for the new version
+ libcmis_vector_property_Ptr properties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ const char* id = "Property1";
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, id );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr property = libcmis_property_create( propertyType, values, size );
+ delete[] values;
+ libcmis_vector_property_append( properties, property );
+
+ // get the content into a temporary file (tested method)
+ const char* contentType = "content/type";
+ const char* filename = "name.txt";
+ libcmis_DocumentPtr actual = libcmis_folder_createDocument( tested, properties,
+ ( libcmis_readFn )fread, tmp, contentType, filename, error );
+ fclose( tmp );
+
+ // Check
+ CPPUNIT_ASSERT( !string( libcmis_error_getMessage( error ) ).empty( ) );
+ CPPUNIT_ASSERT( NULL == actual );
+
+ // Free it all
+ libcmis_property_free( property );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( properties );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::removeTreeTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+
+ // Remove the tree (method to test)
+ libcmis_vector_string_Ptr failed = libcmis_folder_removeTree( tested, true, libcmis_Delete, true, error );
+
+ // Check
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not updated", 0 != libcmis_object_getRefreshTimestamp( tested ) );
+ CPPUNIT_ASSERT_EQUAL( size_t( 1 ), libcmis_vector_string_size( failed ) );
+ CPPUNIT_ASSERT_EQUAL( string( "failed 1" ), string( libcmis_vector_string_get( failed, 0 ) ) );
+
+ // Free everything
+ libcmis_vector_string_free( failed );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
+
+void FolderTest::removeTreeErrorTest( )
+{
+ libcmis_FolderPtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Remove the tree (method to test)
+ libcmis_vector_string_Ptr failed = libcmis_folder_removeTree(
+ tested, true, libcmis_Delete, true, error );
+
+ // Check
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+
+ // Free everything
+ libcmis_vector_string_free( failed );
+ libcmis_error_free( error );
+ libcmis_folder_free( tested );
+}
diff --git a/qa/libcmis-c/test-object-type.cxx b/qa/libcmis-c/test-object-type.cxx
new file mode 100644
index 0000000..99a0768
--- /dev/null
+++ b/qa/libcmis-c/test-object-type.cxx
@@ -0,0 +1,377 @@
+
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/error.h>
+#include <libcmis-c/object-type.h>
+#include <libcmis-c/property-type.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class ObjectTypeTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_ObjectTypePtr getTested( bool rootType, bool triggersFaults );
+
+ public:
+ void getIdTest( );
+ void getLocalNameTest( );
+ void getLocalNamespaceTest( );
+ void getQueryNameTest( );
+ void getDisplayNameTest( );
+ void getDescriptionTest( );
+ void getParentTypeTest( );
+ void getParentTypeRootTest( );
+ void getParentTypeErrorTest( );
+ void getBaseTypeTest( );
+ void getBaseTypeErrorTest( );
+ void getChildrenTest( );
+ void getChildrenErrorTest( );
+ void isCreatableTest( );
+ void isFileableTest( );
+ void isQueryableTest( );
+ void isFulltextIndexedTest( );
+ void isIncludedInSupertypeQueryTest( );
+ void isControllablePolicyTest( );
+ void isControllableACLTest( );
+ void isVersionableTest( );
+ void getContentStreamAllowedTest( );
+ void getPropertiesTypesTest( );
+ void getPropertyTypeTest( );
+ void toStringTest( );
+
+ // TODO Add more tests
+
+ CPPUNIT_TEST_SUITE( ObjectTypeTest );
+ CPPUNIT_TEST( getIdTest );
+ CPPUNIT_TEST( getLocalNameTest );
+ CPPUNIT_TEST( getLocalNamespaceTest );
+ CPPUNIT_TEST( getQueryNameTest );
+ CPPUNIT_TEST( getDisplayNameTest );
+ CPPUNIT_TEST( getDescriptionTest );
+ CPPUNIT_TEST( getParentTypeTest );
+ CPPUNIT_TEST( getParentTypeRootTest );
+ CPPUNIT_TEST( getParentTypeErrorTest );
+ CPPUNIT_TEST( getBaseTypeTest );
+ CPPUNIT_TEST( getBaseTypeErrorTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( getChildrenErrorTest );
+ CPPUNIT_TEST( isCreatableTest );
+ CPPUNIT_TEST( isFileableTest );
+ CPPUNIT_TEST( isQueryableTest );
+ CPPUNIT_TEST( isFulltextIndexedTest );
+ CPPUNIT_TEST( isIncludedInSupertypeQueryTest );
+ CPPUNIT_TEST( isControllablePolicyTest );
+ CPPUNIT_TEST( isControllableACLTest );
+ CPPUNIT_TEST( isVersionableTest );
+ CPPUNIT_TEST( getContentStreamAllowedTest );
+ CPPUNIT_TEST( getPropertiesTypesTest );
+ CPPUNIT_TEST( getPropertyTypeTest );
+ CPPUNIT_TEST( toStringTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( ObjectTypeTest );
+
+libcmis_ObjectTypePtr ObjectTypeTest::getTested( bool rootType, bool triggersFaults )
+{
+ libcmis_ObjectTypePtr result = new libcmis_object_type( );
+ libcmis::ObjectTypePtr handle( new dummies::ObjectType( rootType, triggersFaults ) );
+ result->handle = handle;
+
+ return result;
+}
+
+void ObjectTypeTest::getIdTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* id = libcmis_object_type_getId( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::Id" ),
+ string( id ) );
+ free( id );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getLocalNameTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* actual = libcmis_object_type_getLocalName( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::LocalName" ),
+ string( actual ) );
+ free( actual );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getLocalNamespaceTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* actual = libcmis_object_type_getLocalNamespace( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::LocalNamespace" ),
+ string( actual ) );
+ free( actual );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getQueryNameTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* actual = libcmis_object_type_getQueryName( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::QueryName" ),
+ string( actual ) );
+ free( actual );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getDisplayNameTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* actual = libcmis_object_type_getDisplayName( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::DisplayName" ),
+ string( actual ) );
+ free( actual );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getDescriptionTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* actual = libcmis_object_type_getDescription( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::Description" ),
+ string( actual ) );
+ free( actual );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getParentTypeTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_ObjectTypePtr parent = libcmis_object_type_getParentType( tested, error );
+
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ char* id = libcmis_object_type_getId( parent );
+ CPPUNIT_ASSERT_EQUAL( string( "ParentType::Id" ), string( id ) );
+ free( id );
+
+ libcmis_error_free( error );
+ libcmis_object_type_free( parent );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getParentTypeRootTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( true, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_ObjectTypePtr parent = libcmis_object_type_getParentType( tested, error );
+
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT( NULL == parent );
+
+ libcmis_error_free( error );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getParentTypeErrorTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_ObjectTypePtr parent = libcmis_object_type_getParentType( tested, error );
+
+ CPPUNIT_ASSERT( NULL != libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT( NULL == parent );
+
+ libcmis_error_free( error );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getBaseTypeTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_ObjectTypePtr base = libcmis_object_type_getBaseType( tested, error );
+
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ char* id = libcmis_object_type_getId( base );
+ CPPUNIT_ASSERT_EQUAL( string( "RootType::Id" ), string( id ) );
+ free( id );
+
+ libcmis_error_free( error );
+ libcmis_object_type_free( base );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getBaseTypeErrorTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_ObjectTypePtr base = libcmis_object_type_getBaseType( tested, error );
+
+ CPPUNIT_ASSERT( NULL != libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT( NULL == base );
+
+ libcmis_error_free( error );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getChildrenTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_vector_object_type_Ptr children = libcmis_object_type_getChildren( tested, error );
+
+ CPPUNIT_ASSERT( NULL == libcmis_error_getMessage( error ) );
+ size_t size = libcmis_vector_object_type_size( children );
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), size );
+
+ libcmis_error_free( error );
+ libcmis_vector_object_type_free( children );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getChildrenErrorTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, true );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_vector_object_type_Ptr children = libcmis_object_type_getChildren( tested, error );
+
+ CPPUNIT_ASSERT( NULL != libcmis_error_getMessage( error ) );
+ CPPUNIT_ASSERT( NULL == children );
+
+ libcmis_error_free( error );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isCreatableTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isCreatable( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isFileableTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isFileable( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isQueryableTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isQueryable( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isFulltextIndexedTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isFulltextIndexed( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isIncludedInSupertypeQueryTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isIncludedInSupertypeQuery( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isControllablePolicyTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isControllablePolicy( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isControllableACLTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isControllableACL( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::isVersionableTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT( libcmis_object_type_isVersionable( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getContentStreamAllowedTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ CPPUNIT_ASSERT_EQUAL(
+ libcmis_Allowed,
+ libcmis_object_type_getContentStreamAllowed( tested ) );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getPropertiesTypesTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ libcmis_vector_property_type_Ptr propertiesTypes = libcmis_object_type_getPropertiesTypes( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 3 ), libcmis_vector_property_type_size( propertiesTypes ) );
+ libcmis_vector_property_type_free( propertiesTypes );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::getPropertyTypeTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ string id( "Property2" );
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( tested, id.c_str( ) );
+ char* propertyId = libcmis_property_type_getId( propertyType );
+ CPPUNIT_ASSERT_EQUAL( id, string( propertyId ) );
+ free( propertyId );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( tested );
+}
+
+void ObjectTypeTest::toStringTest( )
+{
+ libcmis_ObjectTypePtr tested = getTested( false, false );
+ char* actual = libcmis_object_type_toString( tested );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "ObjectType::toString" ),
+ string( actual ) );
+ free( actual );
+ libcmis_object_type_free( tested );
+}
diff --git a/qa/libcmis-c/test-object.cxx b/qa/libcmis-c/test-object.cxx
new file mode 100644
index 0000000..1b7324b
--- /dev/null
+++ b/qa/libcmis-c/test-object.cxx
@@ -0,0 +1,425 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/allowable-actions.h>
+#include <libcmis-c/error.h>
+#include <libcmis-c/folder.h>
+#include <libcmis-c/object.h>
+#include <libcmis-c/object-type.h>
+#include <libcmis-c/property.h>
+#include <libcmis-c/property-type.h>
+#include <libcmis-c/vectors.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class ObjectTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_ObjectPtr getTested( bool triggersFaults );
+ libcmis_FolderPtr getTestFolder( );
+
+ public:
+ void getIdTest( );
+ void getNameTest( );
+ void getPathsTest( );
+ void getBaseTypeTest( );
+ void getTypeTest( );
+ void getCreatedByTest( );
+ void getCreationDateTest( );
+ void getLastModifiedByTest( );
+ void getLastModificationDateTest( );
+ void getChangeTokenTest( );
+ void isImmutableTest( );
+ void getPropertiesTest( );
+ void getPropertyTest( );
+ void getPropertyMissingTest( );
+ void updatePropertiesTest( );
+ void updatePropertiesErrorTest( );
+ void getTypeDescriptionTest( );
+ void getAllowableActionsTest( );
+ void refreshTest( );
+ void refreshErrorTest( );
+ void removeTest( );
+ void removeErrorTest( );
+ void moveTest( );
+ void moveErrorTest( );
+ void toStringTest( );
+
+ CPPUNIT_TEST_SUITE( ObjectTest );
+ CPPUNIT_TEST( getIdTest );
+ CPPUNIT_TEST( getNameTest );
+ CPPUNIT_TEST( getPathsTest );
+ CPPUNIT_TEST( getBaseTypeTest );
+ CPPUNIT_TEST( getTypeTest );
+ CPPUNIT_TEST( getCreatedByTest );
+ CPPUNIT_TEST( getCreationDateTest );
+ CPPUNIT_TEST( getLastModifiedByTest );
+ CPPUNIT_TEST( getLastModificationDateTest );
+ CPPUNIT_TEST( getChangeTokenTest );
+ CPPUNIT_TEST( isImmutableTest );
+ CPPUNIT_TEST( getPropertiesTest );
+ CPPUNIT_TEST( getPropertyTest );
+ CPPUNIT_TEST( getPropertyMissingTest );
+ CPPUNIT_TEST( updatePropertiesTest );
+ CPPUNIT_TEST( updatePropertiesErrorTest );
+ CPPUNIT_TEST( getTypeDescriptionTest );
+ CPPUNIT_TEST( getAllowableActionsTest );
+ CPPUNIT_TEST( refreshTest );
+ CPPUNIT_TEST( refreshErrorTest );
+ CPPUNIT_TEST( removeTest );
+ CPPUNIT_TEST( removeErrorTest );
+ CPPUNIT_TEST( moveTest );
+ CPPUNIT_TEST( moveErrorTest );
+ CPPUNIT_TEST( toStringTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( ObjectTest );
+
+libcmis_ObjectPtr ObjectTest::getTested( bool triggersFaults )
+{
+ libcmis_ObjectPtr result = new libcmis_object( );
+ libcmis::ObjectPtr handle( new dummies::Object( triggersFaults ) );
+ result->handle = handle;
+
+ return result;
+}
+
+libcmis_FolderPtr ObjectTest::getTestFolder( )
+{
+ libcmis_FolderPtr result = new libcmis_folder( );
+ libcmis::FolderPtr handle( new dummies::Folder( false, false ) );
+ result->handle = handle;
+
+ return result;
+}
+
+void ObjectTest::getIdTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getId( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::Id" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getNameTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getName( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::Name" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getPathsTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ libcmis_vector_string_Ptr actual = libcmis_object_getPaths( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), libcmis_vector_string_size( actual ) );
+ CPPUNIT_ASSERT_EQUAL(
+ string( "/Path1/" ),
+ string( libcmis_vector_string_get( actual, 0 ) ) );
+ libcmis_vector_string_free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getBaseTypeTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getBaseType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::BaseType" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getTypeTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::Type" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getCreatedByTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getCreatedBy( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::CreatedBy" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getCreationDateTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ time_t actual = libcmis_object_getCreationDate( tested );
+ CPPUNIT_ASSERT( 0 != actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getLastModifiedByTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getLastModifiedBy( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::LastModifiedBy" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getLastModificationDateTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ time_t actual = libcmis_object_getLastModificationDate( tested );
+ CPPUNIT_ASSERT( 0 != actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getChangeTokenTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_getChangeToken( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::ChangeToken" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::isImmutableTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ CPPUNIT_ASSERT( libcmis_object_isImmutable( tested ) );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getPropertiesTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ libcmis_vector_property_Ptr actual = libcmis_object_getProperties( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 1 ), libcmis_vector_property_size( actual ) );
+ libcmis_vector_property_free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getPropertyTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ const char* id = "Property1";
+ libcmis_PropertyPtr actual = libcmis_object_getProperty( tested, id );
+ CPPUNIT_ASSERT( NULL != actual );
+ libcmis_property_free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getPropertyMissingTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ const char* id = "MissingProperty";
+ libcmis_PropertyPtr actual = libcmis_object_getProperty( tested, id );
+ CPPUNIT_ASSERT( NULL == actual );
+ libcmis_property_free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::updatePropertiesTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Create the changed properties map
+ libcmis_vector_property_Ptr newProperties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, "cmis:Property2" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr newProperty = libcmis_property_create( propertyType, values, size );
+ delete[ ] values;
+ libcmis_vector_property_append( newProperties, newProperty );
+
+ // Update the properties (method under test)
+ libcmis_ObjectPtr updated = libcmis_object_updateProperties( tested, newProperties, error );
+
+ // Checks
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not updated", 0 != libcmis_object_getRefreshTimestamp( tested ) );
+ CPPUNIT_ASSERT( updated != NULL );
+
+ // Free it all
+ libcmis_object_free( updated );
+ libcmis_property_free( newProperty );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( newProperties );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::updatePropertiesErrorTest( )
+{
+ libcmis_ObjectPtr tested = getTested( true );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Create the changed properties map
+ libcmis_vector_property_Ptr newProperties = libcmis_vector_property_create( );
+ libcmis_ObjectTypePtr objectType = libcmis_object_getTypeDescription( tested );
+ libcmis_PropertyTypePtr propertyType = libcmis_object_type_getPropertyType( objectType, "cmis:Property2" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "Value 1";
+ values[1] = "Value 2";
+ libcmis_PropertyPtr newProperty = libcmis_property_create( propertyType, values, size );
+ delete[ ] values;
+ libcmis_vector_property_append( newProperties, newProperty );
+
+ // Update the properties (method under test)
+ libcmis_ObjectPtr updated = libcmis_object_updateProperties( tested, newProperties, error );
+
+ // Checks
+ CPPUNIT_ASSERT( updated == NULL );
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+
+ // Free it all
+ libcmis_object_free( updated );
+ libcmis_property_free( newProperty );
+ libcmis_property_type_free( propertyType );
+ libcmis_object_type_free( objectType );
+ libcmis_vector_property_free( newProperties );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getTypeDescriptionTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ libcmis_ObjectTypePtr actual = libcmis_object_getTypeDescription( tested );
+ char* actualId = libcmis_object_type_getId( actual );
+ CPPUNIT_ASSERT( !string( actualId ).empty( ) );
+ free( actualId );
+ libcmis_object_type_free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::getAllowableActionsTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ libcmis_AllowableActionsPtr actual = libcmis_object_getAllowableActions( tested );
+ CPPUNIT_ASSERT( libcmis_allowable_actions_isDefined( actual, libcmis_GetFolderParent ) );
+ libcmis_allowable_actions_free( actual );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::refreshTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_object_refresh( tested, error );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not updated", 0 != libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::refreshErrorTest( )
+{
+ libcmis_ObjectPtr tested = getTested( true );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_object_refresh( tested, error );
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::removeTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_object_remove( tested, true, error );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not updated", 0 != libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::removeErrorTest( )
+{
+ libcmis_ObjectPtr tested = getTested( true );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+ libcmis_object_remove( tested, true, error );
+ const char* actualMessage = libcmis_error_getMessage( error );
+ CPPUNIT_ASSERT( !string( actualMessage ).empty( ) );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::moveTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not set to 0 initially", 0 == libcmis_object_getRefreshTimestamp( tested ) );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ // Move the object from source to dest (tested method)
+ libcmis_FolderPtr source = getTestFolder( );
+ libcmis_FolderPtr dest = getTestFolder( );
+ libcmis_object_move( tested, source, dest, error );
+
+ // Check
+ CPPUNIT_ASSERT_MESSAGE( "Timestamp not updated", 0 != libcmis_object_getRefreshTimestamp( tested ) );
+
+ // Free it all
+ libcmis_folder_free( dest );
+ libcmis_folder_free( source );
+ libcmis_error_free( error );
+ libcmis_object_free( tested );
+}
+
+void ObjectTest::moveErrorTest( )
+{
+}
+
+void ObjectTest::toStringTest( )
+{
+ libcmis_ObjectPtr tested = getTested( false );
+ char* actual = libcmis_object_toString( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Object::toString" ), string( actual ) );
+ free( actual );
+ libcmis_object_free( tested );
+}
diff --git a/qa/libcmis-c/test-property-type.cxx b/qa/libcmis-c/test-property-type.cxx
new file mode 100644
index 0000000..c8832f6
--- /dev/null
+++ b/qa/libcmis-c/test-property-type.cxx
@@ -0,0 +1,251 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/property-type.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class PropertyTypeTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_PropertyTypePtr getTested( string id, string xmlType );
+
+ public:
+ void getIdTest( );
+ void getLocalNameTest( );
+ void getLocalNamespaceTest( );
+ void getDisplayNameTest( );
+ void getQueryNameTest( );
+ void getTypeTest( );
+ void isMultiValuedTest( );
+ void isUpdatableTest( );
+ void isInheritedTest( );
+ void isRequiredTest( );
+ void isQueryableTest( );
+ void isOrderableTest( );
+ void isOpenChoiceTest( );
+
+ CPPUNIT_TEST_SUITE( PropertyTypeTest );
+ CPPUNIT_TEST( getIdTest );
+ CPPUNIT_TEST( getLocalNameTest );
+ CPPUNIT_TEST( getLocalNamespaceTest );
+ CPPUNIT_TEST( getDisplayNameTest );
+ CPPUNIT_TEST( getQueryNameTest );
+ CPPUNIT_TEST( getTypeTest );
+ CPPUNIT_TEST( isMultiValuedTest );
+ CPPUNIT_TEST( isUpdatableTest );
+ CPPUNIT_TEST( isInheritedTest );
+ CPPUNIT_TEST( isRequiredTest );
+ CPPUNIT_TEST( isQueryableTest );
+ CPPUNIT_TEST( isOrderableTest );
+ CPPUNIT_TEST( isOpenChoiceTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( PropertyTypeTest );
+
+libcmis_PropertyTypePtr PropertyTypeTest::getTested( string id, string xmlType )
+{
+ libcmis_PropertyTypePtr result = new libcmis_property_type( );
+ libcmis::PropertyTypePtr handle( new dummies::PropertyType( id, xmlType ) );
+ result->handle = handle;
+
+ return result;
+}
+
+void PropertyTypeTest::getIdTest( )
+{
+ string id( "Id" );
+ libcmis_PropertyTypePtr tested = getTested( id, "string" );
+ char* actual = libcmis_property_type_getId( tested );
+ CPPUNIT_ASSERT_EQUAL( id, string( actual ) );
+
+ free( actual );
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::getLocalNameTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ char* actual = libcmis_property_type_getLocalName( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "PropertyType::LocalName" ), string( actual ) );
+
+ free( actual );
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::getLocalNamespaceTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ char* actual = libcmis_property_type_getLocalNamespace( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "PropertyType::LocalNamespace" ), string( actual ) );
+
+ free( actual );
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::getDisplayNameTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ char* actual = libcmis_property_type_getDisplayName( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "PropertyType::DisplayName" ), string( actual ) );
+
+ free( actual );
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::getQueryNameTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ char* actual = libcmis_property_type_getQueryName( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "PropertyType::QueryName" ), string( actual ) );
+
+ free( actual );
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::getTypeTest( )
+{
+ // String
+ {
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ libcmis_property_type_Type actualType = libcmis_property_type_getType( tested );
+ CPPUNIT_ASSERT_EQUAL( libcmis_String, actualType );
+ char* actualXml = libcmis_property_type_getXmlType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "String" ), string( actualXml ) );
+
+ free( actualXml );
+ libcmis_property_type_free( tested );
+ }
+
+ // DateTime
+ {
+ libcmis_PropertyTypePtr tested = getTested( "id", "datetime" );
+ libcmis_property_type_Type actualType = libcmis_property_type_getType( tested );
+ CPPUNIT_ASSERT_EQUAL( libcmis_DateTime, actualType );
+ char* actualXml = libcmis_property_type_getXmlType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "DateTime" ), string( actualXml ) );
+
+ free( actualXml );
+ libcmis_property_type_free( tested );
+ }
+
+ // Integer
+ {
+ libcmis_PropertyTypePtr tested = getTested( "id", "integer" );
+ libcmis_property_type_Type actualType = libcmis_property_type_getType( tested );
+ CPPUNIT_ASSERT_EQUAL( libcmis_Integer, actualType );
+ char* actualXml = libcmis_property_type_getXmlType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Integer" ), string( actualXml ) );
+
+ free( actualXml );
+ libcmis_property_type_free( tested );
+ }
+
+ // Html
+ {
+ libcmis_PropertyTypePtr tested = getTested( "id", "html" );
+ libcmis_property_type_Type actualType = libcmis_property_type_getType( tested );
+ CPPUNIT_ASSERT_EQUAL( libcmis_String, actualType );
+ char* actualXml = libcmis_property_type_getXmlType( tested );
+ CPPUNIT_ASSERT_EQUAL( string( "Html" ), string( actualXml ) );
+
+ free( actualXml );
+ libcmis_property_type_free( tested );
+ }
+}
+
+void PropertyTypeTest::isMultiValuedTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isMultiValued( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::isUpdatableTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isUpdatable( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::isInheritedTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isInherited( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::isRequiredTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isRequired( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::isQueryableTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isQueryable( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::isOrderableTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isOrderable( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
+
+void PropertyTypeTest::isOpenChoiceTest( )
+{
+ libcmis_PropertyTypePtr tested = getTested( "id", "string" );
+ bool actual = libcmis_property_type_isOpenChoice( tested );
+ CPPUNIT_ASSERT_EQUAL( true , actual );
+
+ libcmis_property_type_free( tested );
+}
diff --git a/qa/libcmis-c/test-property.cxx b/qa/libcmis-c/test-property.cxx
new file mode 100644
index 0000000..99c9b2c
--- /dev/null
+++ b/qa/libcmis-c/test-property.cxx
@@ -0,0 +1,242 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/property.h>
+#include <libcmis-c/property-type.h>
+#include <libcmis-c/vectors.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class PropertyTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_PropertyTypePtr getTestType( string xmlType );
+
+ public:
+ void getDateTimesTest( );
+ void getBoolsTest( );
+ void getStringsTest( );
+ void getLongsTest( );
+ void getDoublesTest( );
+ void setValuesTest( );
+
+ CPPUNIT_TEST_SUITE( PropertyTest );
+ CPPUNIT_TEST( getDateTimesTest );
+ CPPUNIT_TEST( getBoolsTest );
+ CPPUNIT_TEST( getStringsTest );
+ CPPUNIT_TEST( getLongsTest );
+ CPPUNIT_TEST( getDoublesTest );
+ CPPUNIT_TEST( setValuesTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( PropertyTest );
+
+libcmis_PropertyTypePtr PropertyTest::getTestType( string xmlType )
+{
+ libcmis_PropertyTypePtr result = new libcmis_property_type( );
+ libcmis::PropertyTypePtr handle( new dummies::PropertyType( "Id", xmlType ) );
+ result->handle = handle;
+
+ return result;
+}
+
+void PropertyTest::getDateTimesTest( )
+{
+ libcmis_PropertyTypePtr type = getTestType( "datetime" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "2012-01-19T09:06:57.388Z";
+ values[1] = "2012-02-19T09:06:57.388Z";
+ libcmis_PropertyPtr tested = libcmis_property_create( type, values, size );
+
+ libcmis_vector_time_Ptr times = libcmis_property_getDateTimes( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_time_size( times ) );
+ libcmis_vector_time_free( times );
+
+ libcmis_vector_string_Ptr strings = libcmis_property_getStrings( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_string_size( strings ) );
+ CPPUNIT_ASSERT_EQUAL( string( values[1] ), string( libcmis_vector_string_get( strings, 1 ) ) );
+ libcmis_vector_string_free( strings );
+ delete[] values;
+
+ libcmis_vector_bool_Ptr bools = libcmis_property_getBools( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 0 ), libcmis_vector_bool_size( bools ) );
+ libcmis_vector_bool_free( bools );
+
+ libcmis_property_free( tested );
+ libcmis_property_type_free( type );
+}
+
+void PropertyTest::getBoolsTest( )
+{
+ libcmis_PropertyTypePtr type = getTestType( "boolean" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "true";
+ values[1] = "false";
+ libcmis_PropertyPtr tested = libcmis_property_create( type, values, size );
+
+ libcmis_vector_bool_Ptr bools = libcmis_property_getBools( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_bool_size( bools ) );
+ CPPUNIT_ASSERT_EQUAL( true, libcmis_vector_bool_get( bools, 0 ) );
+ CPPUNIT_ASSERT_EQUAL( false, libcmis_vector_bool_get( bools, 1 ) );
+ libcmis_vector_bool_free( bools );
+
+ libcmis_vector_string_Ptr strings = libcmis_property_getStrings( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_string_size( strings ) );
+ CPPUNIT_ASSERT_EQUAL( string( values[1] ), string( libcmis_vector_string_get( strings, 1 ) ) );
+ libcmis_vector_string_free( strings );
+ delete[] values;
+
+ libcmis_vector_long_Ptr longs = libcmis_property_getLongs( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 0 ), libcmis_vector_long_size( longs ) );
+ libcmis_vector_long_free( longs );
+
+ libcmis_property_free( tested );
+ libcmis_property_type_free( type );
+}
+
+
+void PropertyTest::getStringsTest( )
+{
+ libcmis_PropertyTypePtr type = getTestType( "string" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "string 1";
+ values[1] = "string 2";
+ libcmis_PropertyPtr tested = libcmis_property_create( type, values, size );
+
+ libcmis_vector_string_Ptr strings = libcmis_property_getStrings( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_string_size( strings ) );
+ CPPUNIT_ASSERT_EQUAL( string( values[0] ), string( libcmis_vector_string_get( strings, 0 ) ) );
+ CPPUNIT_ASSERT_EQUAL( string( values[1] ), string( libcmis_vector_string_get( strings, 1 ) ) );
+ libcmis_vector_string_free( strings );
+ delete[] values;
+
+ libcmis_vector_double_Ptr doubles = libcmis_property_getDoubles( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 0 ), libcmis_vector_double_size( doubles ) );
+ libcmis_vector_double_free( doubles );
+
+ libcmis_property_free( tested );
+ libcmis_property_type_free( type );
+}
+
+
+void PropertyTest::getLongsTest( )
+{
+ libcmis_PropertyTypePtr type = getTestType( "integer" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "123456";
+ values[1] = "789";
+ libcmis_PropertyPtr tested = libcmis_property_create( type, values, size );
+
+ libcmis_vector_long_Ptr longs = libcmis_property_getLongs( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_long_size( longs ) );
+ CPPUNIT_ASSERT_EQUAL( long( 123456 ), libcmis_vector_long_get( longs, 0 ) );
+ CPPUNIT_ASSERT_EQUAL( long( 789 ), libcmis_vector_long_get( longs, 1 ) );
+ libcmis_vector_long_free( longs );
+
+ libcmis_vector_string_Ptr strings = libcmis_property_getStrings( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_string_size( strings ) );
+ CPPUNIT_ASSERT_EQUAL( string( values[1] ), string( libcmis_vector_string_get( strings, 1 ) ) );
+ libcmis_vector_string_free( strings );
+ delete[] values;
+
+ libcmis_vector_time_Ptr times = libcmis_property_getDateTimes( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 0 ), libcmis_vector_time_size( times ) );
+ libcmis_vector_time_free( times );
+
+ libcmis_property_free( tested );
+ libcmis_property_type_free( type );
+}
+
+
+void PropertyTest::getDoublesTest( )
+{
+ libcmis_PropertyTypePtr type = getTestType( "decimal" );
+ size_t size = 2;
+ const char** values = new const char*[size];
+ values[0] = "123.456";
+ values[1] = "7.89";
+ libcmis_PropertyPtr tested = libcmis_property_create( type, values, size );
+
+ libcmis_vector_double_Ptr doubles = libcmis_property_getDoubles( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_double_size( doubles ) );
+ CPPUNIT_ASSERT_EQUAL( 123.456, libcmis_vector_double_get( doubles, 0 ) );
+ CPPUNIT_ASSERT_EQUAL( 7.89, libcmis_vector_double_get( doubles, 1 ) );
+ libcmis_vector_double_free( doubles );
+
+ libcmis_vector_string_Ptr strings = libcmis_property_getStrings( tested );
+ CPPUNIT_ASSERT_EQUAL( size, libcmis_vector_string_size( strings ) );
+ CPPUNIT_ASSERT_EQUAL( string( values[1] ), string( libcmis_vector_string_get( strings, 1 ) ) );
+ libcmis_vector_string_free( strings );
+ delete[] values;
+
+ libcmis_vector_long_Ptr longs = libcmis_property_getLongs( tested );
+ CPPUNIT_ASSERT_EQUAL( size_t( 0 ), libcmis_vector_long_size( longs ) );
+ libcmis_vector_long_free( longs );
+
+ libcmis_property_free( tested );
+ libcmis_property_type_free( type );
+}
+
+
+void PropertyTest::setValuesTest( )
+{
+ libcmis_PropertyTypePtr type = getTestType( "string" );
+ size_t size = 1;
+ const char** values = new const char*[size];
+ values[0] = "string 1";
+ libcmis_PropertyPtr tested = libcmis_property_create( type, values, size );
+ delete[] values;
+
+ size_t newSize = 2;
+ const char** newValues = new const char*[newSize];
+ newValues[0] = "new string 1";
+ newValues[1] = "new string 2";
+ libcmis_property_setValues( tested, newValues, newSize );
+
+ libcmis_vector_string_Ptr newStrings = libcmis_property_getStrings( tested );
+ CPPUNIT_ASSERT_EQUAL( newSize, libcmis_vector_string_size( newStrings ) );
+ CPPUNIT_ASSERT_EQUAL( string( newValues[0] ), string( libcmis_vector_string_get( newStrings, 0 ) ) );
+ CPPUNIT_ASSERT_EQUAL( string( newValues[1] ), string( libcmis_vector_string_get( newStrings, 1 ) ) );
+ libcmis_vector_string_free( newStrings );
+ delete[] newValues;
+
+ libcmis_property_free( tested );
+ libcmis_property_type_free( type );
+}
diff --git a/qa/libcmis-c/test-repository.cxx b/qa/libcmis-c/test-repository.cxx
new file mode 100644
index 0000000..63e7363
--- /dev/null
+++ b/qa/libcmis-c/test-repository.cxx
@@ -0,0 +1,205 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/repository.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class RepositoryTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_RepositoryPtr getTested( );
+
+ public:
+ void getIdTest( );
+ void getNameTest( );
+ void getDescriptionTest( );
+ void getVendorNameTest( );
+ void getProductNameTest( );
+ void getProductVersionTest( );
+ void getRootIdTest( );
+ void getCmisVersionSupportedTest( );
+ void getThinClientUriTest( );
+ void getPrincipalAnonymousTest( );
+ void getPrincipalAnyoneTest( );
+
+ CPPUNIT_TEST_SUITE( RepositoryTest );
+ CPPUNIT_TEST( getIdTest );
+ CPPUNIT_TEST( getNameTest );
+ CPPUNIT_TEST( getDescriptionTest );
+ CPPUNIT_TEST( getVendorNameTest );
+ CPPUNIT_TEST( getProductNameTest );
+ CPPUNIT_TEST( getProductVersionTest );
+ CPPUNIT_TEST( getRootIdTest );
+ CPPUNIT_TEST( getCmisVersionSupportedTest );
+ CPPUNIT_TEST( getThinClientUriTest );
+ CPPUNIT_TEST( getPrincipalAnonymousTest );
+ CPPUNIT_TEST( getPrincipalAnyoneTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( RepositoryTest );
+
+libcmis_RepositoryPtr RepositoryTest::getTested( )
+{
+ libcmis_RepositoryPtr result = new libcmis_repository( );
+
+ libcmis::RepositoryPtr handle( new dummies::Repository( ) );
+ result->handle = handle;
+
+ return result;
+}
+
+void RepositoryTest::getIdTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getId( tested );
+ string expected( "Repository::Id" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getNameTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getName( tested );
+ string expected( "Repository::Name" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getDescriptionTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getDescription( tested );
+ string expected( "Repository::Description" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getVendorNameTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getVendorName( tested );
+ string expected( "Repository::VendorName" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getProductNameTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getProductName( tested );
+ string expected( "Repository::ProductName" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getProductVersionTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getProductVersion( tested );
+ string expected( "Repository::ProductVersion" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getRootIdTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getRootId( tested );
+ string expected( "Repository::RootId" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getCmisVersionSupportedTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getCmisVersionSupported( tested );
+ string expected( "Repository::CmisVersionSupported" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getThinClientUriTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getThinClientUri( tested );
+ string expected( "Repository::ThinClientUri" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getPrincipalAnonymousTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getPrincipalAnonymous( tested );
+ string expected( "Repository::PrincipalAnonymous" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
+void RepositoryTest::getPrincipalAnyoneTest( )
+{
+ libcmis_RepositoryPtr tested = getTested( );
+ char* actual = libcmis_repository_getPrincipalAnyone( tested );
+ string expected( "Repository::PrincipalAnyone" );
+ CPPUNIT_ASSERT_EQUAL( expected, string( actual ) );
+
+ free( actual );
+ libcmis_repository_free( tested );
+}
+
diff --git a/qa/libcmis-c/test-session.cxx b/qa/libcmis-c/test-session.cxx
new file mode 100644
index 0000000..b236bc5
--- /dev/null
+++ b/qa/libcmis-c/test-session.cxx
@@ -0,0 +1,88 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <libcmis-c/libcmis-c.h>
+
+#include "internals.hxx"
+#include "test-dummies.hxx"
+
+using namespace std;
+
+class SessionTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis_SessionPtr getTested( );
+
+ public:
+ void getRepositoriesTest( );
+ void getBaseTypesTest( );
+
+ CPPUNIT_TEST_SUITE( SessionTest );
+ CPPUNIT_TEST( getRepositoriesTest );
+ CPPUNIT_TEST( getBaseTypesTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( SessionTest );
+
+libcmis_SessionPtr SessionTest::getTested( )
+{
+ libcmis_SessionPtr result = new libcmis_session();
+ libcmis::Session* handle = new dummies::Session( );
+ result->handle = handle;
+ return result;
+}
+
+void SessionTest::getRepositoriesTest( )
+{
+ libcmis_SessionPtr session = getTested( );
+ libcmis_vector_Repository_Ptr repos = libcmis_session_getRepositories( session );
+ size_t actualSize = libcmis_vector_repository_size( repos );
+ CPPUNIT_ASSERT_EQUAL( size_t( 2 ), actualSize );
+ libcmis_vector_repository_free( repos );
+ libcmis_session_free( session );
+}
+
+void SessionTest::getBaseTypesTest( )
+{
+ libcmis_SessionPtr session = getTested( );
+ libcmis_ErrorPtr error = libcmis_error_create( );
+
+ libcmis_vector_object_type_Ptr types = libcmis_session_getBaseTypes( session, error );
+
+ size_t size = libcmis_vector_object_type_size( types );
+ CPPUNIT_ASSERT_EQUAL( size_t( 1 ), size );
+
+ libcmis_error_free( error );
+ libcmis_vector_object_type_free( types );
+ libcmis_session_free( session );
+}
diff --git a/qa/libcmis/Makefile.am b/qa/libcmis/Makefile.am
new file mode 100644
index 0000000..b300854
--- /dev/null
+++ b/qa/libcmis/Makefile.am
@@ -0,0 +1,190 @@
+if !OS_WIN32
+mockup_tests = \
+ test-atom \
+ test-factory \
+ test-sharepoint \
+ test-ws
+endif
+
+# these tests need updating to work again
+# mockup_tests += \
+# test-gdrive \
+# test-onedrive
+
+check_PROGRAMS = \
+ test-json \
+ test-utils \
+ ${mockup_tests}
+
+check_LIBRARIES = \
+ libtest.a
+
+libtest_a_SOURCES = \
+ test-helpers.cxx \
+ test-helpers.hxx \
+ test-main.cxx
+
+if !OS_WIN32
+libtest_a_SOURCES += \
+ test-mockup-helpers.cxx \
+ test-mockup-helpers.hxx
+endif
+
+libtest_a_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(CURL_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+test_utils_SOURCES = \
+ test-commons.cxx \
+ test-decoder.cxx \
+ test-soap.cxx \
+ test-xmlutils.cxx
+
+test_utils_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ $(XML2_CFLAGS) \
+ $(CURL_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+test_utils_LDADD = \
+ libtest.a \
+ $(top_builddir)/src/libcmis/libcmis.la \
+ $(XML2_LIBS) \
+ $(CURL_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+test_atom_SOURCES = \
+ test-atom.cxx
+
+test_atom_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_atom_LDADD = \
+ libtest.a \
+ $(top_builddir)/qa/mockup/libcmis-mockup.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+test_gdrive_SOURCES = \
+ test-gdrive.cxx
+
+test_gdrive_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_gdrive_LDADD = \
+ libtest.a \
+ $(top_builddir)/qa/mockup/libcmis-mockup.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+test_onedrive_SOURCES = \
+ test-onedrive.cxx
+
+test_onedrive_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_onedrive_LDADD = \
+ libtest.a \
+ $(top_builddir)/qa/mockup/libcmis-mockup.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+test_sharepoint_SOURCES = \
+ test-sharepoint.cxx
+
+test_sharepoint_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_sharepoint_LDADD = \
+ libtest.a \
+ $(top_builddir)/qa/mockup/libcmis-mockup.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+
+test_ws_SOURCES = \
+ test-ws.cxx
+
+test_ws_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_ws_LDADD = \
+ libtest.a \
+ $(top_builddir)/qa/mockup/libcmis-mockup.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+test_json_SOURCES = \
+ test-jsonutils.cxx
+
+test_json_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_json_LDADD = \
+ libtest.a \
+ $(top_builddir)/src/libcmis/libcmis.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(CURL_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+
+test_factory_SOURCES = \
+ test-factory.cxx
+
+test_factory_CPPFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ -I$(top_srcdir)/qa/mockup \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS) \
+ -DDATA_DIR=\"$(top_srcdir)/qa/libcmis/data\"
+
+test_factory_LDADD = \
+ libtest.a \
+ $(top_builddir)/qa/mockup/libcmis-mockup.la \
+ $(XML2_LIBS) \
+ $(CPPUNIT_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
+
+TESTS = test-utils test-json ${mockup_tests}
diff --git a/qa/libcmis/data/atom/allowable-actions.xml b/qa/libcmis/data/atom/allowable-actions.xml
new file mode 100644
index 0000000..3e59c9d
--- /dev/null
+++ b/qa/libcmis/data/atom/allowable-actions.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<ns2:allowableActions xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/restatom/200908/">
+ <ns2:canDeleteObject>true</ns2:canDeleteObject>
+ <ns2:canUpdateProperties>true</ns2:canUpdateProperties>
+ <ns2:canGetFolderTree>true</ns2:canGetFolderTree>
+ <ns2:canGetProperties>true</ns2:canGetProperties>
+ <ns2:canGetObjectRelationships>false</ns2:canGetObjectRelationships>
+ <ns2:canGetObjectParents>true</ns2:canGetObjectParents>
+ <ns2:canGetFolderParent>true</ns2:canGetFolderParent>
+ <ns2:canGetDescendants>true</ns2:canGetDescendants>
+ <ns2:canMoveObject>true</ns2:canMoveObject>
+ <ns2:canDeleteContentStream>false</ns2:canDeleteContentStream>
+ <ns2:canCheckOut>false</ns2:canCheckOut>
+ <ns2:canCancelCheckOut>false</ns2:canCancelCheckOut>
+ <ns2:canCheckIn>false</ns2:canCheckIn>
+ <ns2:canSetContentStream>false</ns2:canSetContentStream>
+ <ns2:canGetAllVersions>false</ns2:canGetAllVersions>
+ <ns2:canAddObjectToFolder>false</ns2:canAddObjectToFolder>
+ <ns2:canRemoveObjectFromFolder>false</ns2:canRemoveObjectFromFolder>
+ <ns2:canGetContentStream>false</ns2:canGetContentStream>
+ <ns2:canApplyPolicy>false</ns2:canApplyPolicy>
+ <ns2:canGetAppliedPolicies>false</ns2:canGetAppliedPolicies>
+ <ns2:canRemovePolicy>false</ns2:canRemovePolicy>
+ <ns2:canGetChildren>true</ns2:canGetChildren>
+ <ns2:canCreateDocument>true</ns2:canCreateDocument>
+ <ns2:canCreateFolder>true</ns2:canCreateFolder>
+ <ns2:canCreateRelationship>false</ns2:canCreateRelationship>
+ <ns2:canDeleteTree>true</ns2:canDeleteTree>
+ <ns2:canGetRenditions>false</ns2:canGetRenditions>
+ <ns2:canGetACL>false</ns2:canGetACL>
+ <ns2:canApplyACL>false</ns2:canApplyACL>
+</ns2:allowableActions>
diff --git a/qa/libcmis/data/atom/create-document.xml b/qa/libcmis/data/atom/create-document.xml
new file mode 100644
index 0000000..73372bc
--- /dev/null
+++ b/qa/libcmis/data/atom/create-document.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-28T14:10:06Z</atom:published>
+ <atom:title>create document</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=create-document" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>create document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>create-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=create-document" type="application/atom+xml;type=entry" cmisra:id="create-document"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=create-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=create-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=create-document" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=create-document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=create-document" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=create-document" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/create-folder-bad-type.xml b/qa/libcmis/data/atom/create-folder-bad-type.xml
new file mode 100644
index 0000000..b43401c
--- /dev/null
+++ b/qa/libcmis/data/atom/create-folder-bad-type.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2012-11-29T16:14:47Z</atom:published>
+ <atom:title>create folder</atom:title>
+ <app:edited>2012-11-29T16:14:47Z</app:edited>
+ <atom:updated>2012-11-29T16:14:47Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/create folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>create folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>create-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=create-folder" type="application/atom+xml;type=entry" cmisra:id="create-folder"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=create-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=create-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=create-folder" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=create-folder" type="application/atom+xml;type=feed"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=create-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=create-folder" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/create-folder.xml b/qa/libcmis/data/atom/create-folder.xml
new file mode 100644
index 0000000..e7d3f9f
--- /dev/null
+++ b/qa/libcmis/data/atom/create-folder.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2012-11-29T16:14:47Z</atom:published>
+ <atom:title>create folder</atom:title>
+ <app:edited>2012-11-29T16:14:47Z</app:edited>
+ <atom:updated>2012-11-29T16:14:47Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/create folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>create folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>create-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=create-folder" type="application/atom+xml;type=entry" cmisra:id="create-folder"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=create-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=create-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Afolder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=create-folder" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=create-folder" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=create-folder" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=create-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=create-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=create-folder" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/get-versions.xml b/qa/libcmis/data/atom/get-versions.xml
new file mode 100644
index 0000000..1960975
--- /dev/null
+++ b/qa/libcmis/data/atom/get-versions.xml
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="via" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-28T14:10:06Z</atom:published>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=test-document-1" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>version-series</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>1.0</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document-1</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document-1</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=test-document-1" type="application/atom+xml;type=entry" cmisra:id="test-document-1"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=test-document-1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=test-document-1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=test-document-1" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=test-document-1" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=test-document-1" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=test-document-1" type="application/cmisacl+xml"/>
+ </atom:entry>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-28T14:10:06Z</atom:published>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=test-document-0" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>version-series</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>0.1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-27T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206754</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document-0</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-27T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document-0</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=test-document-0" type="application/atom+xml;type=entry" cmisra:id="test-document-0"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=test-document-0" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=test-document-0" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=test-document-0" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=test-document-0" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=test-document-0" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=test-document-0" type="application/cmisacl+xml"/>
+ </atom:entry>
+</atom:feed>
diff --git a/qa/libcmis/data/atom/root-children.xml b/qa/libcmis/data/atom/root-children.xml
new file mode 100644
index 0000000..cb31611
--- /dev/null
+++ b/qa/libcmis/data/atom/root-children.xml
@@ -0,0 +1,389 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:title>Root Folder</atom:title>
+ <app:edited>2013-01-30T09:26:10Z</app:edited>
+ <atom:updated>2013-01-30T09:26:10Z</atom:updated>
+ <cmisra:numItems>5</cmisra:numItems>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/children?id=root-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=root-folder" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=root-folder" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=root-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=root-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=root-folder" type="application/cmisacl+xml"/>
+ <app:collection href="http://mockup/mock/children?id=root-folder">
+ <atom:title type="text">Folder collection</atom:title>
+ <app:accept>application/cmisatom+xml</app:accept>
+ </app:collection>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-30T09:26:13Z</atom:published>
+ <atom:title>Child 1</atom:title>
+ <app:edited>2013-01-30T09:26:13Z</app:edited>
+ <atom:updated>2013-01-30T09:26:13Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=child1" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>33446</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:13.932Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537973932</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child1</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:13.932Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=child1" type="application/atom+xml;type=entry" cmisra:id="child1"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=child1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=child1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=child1" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=child1" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=child1" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=child1" type="application/cmisacl+xml"/>
+ </atom:entry>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-30T09:26:13Z</atom:published>
+ <atom:title>Child 2</atom:title>
+ <app:edited>2013-01-30T09:26:13Z</app:edited>
+ <atom:updated>2013-01-30T09:26:13Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=child2" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>33537</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:13.978Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537973978</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:13.978Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=child2" type="application/atom+xml;type=entry" cmisra:id="child2"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=child2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=child2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=child2" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=child2" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=child2" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=child2" type="application/cmisacl+xml"/>
+ </atom:entry>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-30T09:26:14Z</atom:published>
+ <atom:title>Child 3</atom:title>
+ <app:edited>2013-01-30T09:26:14Z</app:edited>
+ <atom:updated>2013-01-30T09:26:14Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=child3" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>33353</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 3</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:14.031Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537974031</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child3</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:14.031Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=child3" type="application/atom+xml;type=entry" cmisra:id="child3"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=child3" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=child3" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=child3" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=child3" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=child3" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=child3" type="application/cmisacl+xml"/>
+ </atom:entry>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-30T09:26:12Z</atom:published>
+ <atom:title>Child 4</atom:title>
+ <app:edited>2013-01-30T09:26:12Z</app:edited>
+ <atom:updated>2013-01-30T09:26:12Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Child 4</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 4</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child4</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:12.384Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537972384</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:12.384Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=child4" type="application/atom+xml;type=entry" cmisra:id="child4"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=child4" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=child4" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=child4" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=child4" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=child4" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=child4" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=child4" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=child4" type="application/cmisacl+xml"/>
+ </atom:entry>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-30T09:26:13Z</atom:published>
+ <atom:title>Child 5</atom:title>
+ <app:edited>2013-01-30T09:26:13Z</app:edited>
+ <atom:updated>2013-01-30T09:26:13Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Child 5</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 5</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child5</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:13.338Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537973338</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:13.338Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=child5" type="application/atom+xml;type=entry" cmisra:id="child5"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=child5" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=child5" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=child5" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=child5" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=child5" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=child5" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=child5" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=child5" type="application/cmisacl+xml"/>
+ </atom:entry>
+</atom:feed>
diff --git a/qa/libcmis/data/atom/root-folder.xml b/qa/libcmis/data/atom/root-folder.xml
new file mode 100644
index 0000000..5baa288
--- /dev/null
+++ b/qa/libcmis/data/atom/root-folder.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2012-11-29T16:14:47Z</atom:published>
+ <atom:title>Root Folder</atom:title>
+ <app:edited>2012-11-29T16:14:47Z</app:edited>
+ <atom:updated>2012-11-29T16:14:47Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Root Folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId"/>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>true</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>true</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>true</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>false</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>false</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>false</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>false</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>false</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>false</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>false</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>true</cmis:canGetChildren>
+ <cmis:canCreateDocument>true</cmis:canCreateDocument>
+ <cmis:canCreateFolder>true</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>true</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=root-folder" type="application/atom+xml;type=entry" cmisra:id="root-folder"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=root-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=root-folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Afolder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=root-folder" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=root-folder" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=root-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=root-folder" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=root-folder" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/test-document-parents.xml b/qa/libcmis/data/atom/test-document-parents.xml
new file mode 100644
index 0000000..3e24f0e
--- /dev/null
+++ b/qa/libcmis/data/atom/test-document-parents.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some Obscure Id</atom:id>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-01-31T08:04:37Z</app:edited>
+ <atom:updated>2013-01-31T08:04:37Z</atom:updated>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/parents?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:entry>
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some Obscure Id</atom:id>
+ <atom:published>2013-01-31T08:04:35Z</atom:published>
+ <atom:title>Parent 1</atom:title>
+ <app:edited>2013-01-31T08:04:35Z</app:edited>
+ <atom:updated>2013-01-31T08:04:35Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Parent 1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Parent 1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>parent1</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-31T08:04:35.866Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359619475867</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-31T08:04:35.867Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <cmisra:relativePathSegment>Test Document</cmisra:relativePathSegment>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=parent1" type="application/atom+xml;type=entry" cmisra:id="parent1"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=parent1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=parent1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=parent1" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=parent1" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=parent1" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=parent1" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=parent1" type="application/cmisacl+xml"/>
+ </atom:entry>
+ <atom:entry>
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some Obscure Id</atom:id>
+ <atom:published>2013-01-31T08:04:35Z</atom:published>
+ <atom:title>Parent 2</atom:title>
+ <app:edited>2013-01-31T08:04:35Z</app:edited>
+ <atom:updated>2013-01-31T08:04:35Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Parent 2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Parent 2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>parent2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-31T08:04:35.866Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359619475867</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-31T08:04:35.867Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmisra:object>
+ <cmisra:relativePathSegment>Test Document</cmisra:relativePathSegment>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/entry?id=parent2" type="application/atom+xml;type=entry" cmisra:id="parent2"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/entry?id=parent2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/entry?id=parent2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=parent2" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=parent2" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=parent2" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=parent2" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=parent2" type="application/cmisacl+xml"/>
+ </atom:entry>
+</atom:feed>
diff --git a/qa/libcmis/data/atom/test-document-relationships.xml b/qa/libcmis/data/atom/test-document-relationships.xml
new file mode 100644
index 0000000..bacfda8
--- /dev/null
+++ b/qa/libcmis/data/atom/test-document-relationships.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-28T14:10:06Z</atom:published>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=test-document" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>true</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>true</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ <cmis:relationship>
+ <cmis:properties>
+ <cmis:propertyId displayName="Target Id" localName="targetId" propertyDefinitionId="cmis:targetId" queryName="cmis:targetId">
+ <cmis:value>workspace://SpacesStore/5d8908d9-1b4a-4265-b1de-5d7244fcea70;2.2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId displayName="Object Type Id" localName="objectTypeId" propertyDefinitionId="cmis:objectTypeId" queryName="cmis:objectTypeId">
+ <cmis:value>R:cm:original</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString displayName="Last Modified By" localName="lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy" queryName="cmis:lastModifiedBy">
+ <cmis:value>admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId displayName="Source Id" localName="sourceId" propertyDefinitionId="cmis:sourceId" queryName="cmis:sourceId">
+ <cmis:value>workspace://SpacesStore/5d8908d9-1b4a-4265-b1de-5d7244fcea70;pwc</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString displayName="Name" localName="name" propertyDefinitionId="cmis:name" queryName="cmis:name">
+ <cmis:value>75|workspace://SpacesStore/3885d9a2-0540-41ab-810a-38ccb1b160d6|workspace://SpacesStore/5d8908d9-1b4a-4265-b1de-5d7244fcea70|{http://www.alfresco.org/model/content/1.0}original</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString displayName="Created by" localName="createdBy" propertyDefinitionId="cmis:createdBy" queryName="cmis:createdBy">
+ <cmis:value>admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId displayName="Object Id" localName="objectId" propertyDefinitionId="cmis:objectId" queryName="cmis:objectId">
+ <cmis:value>assoc:75</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime displayName="Creation Date" localName="creationDate" propertyDefinitionId="cmis:creationDate" queryName="cmis:creationDate">
+ <cmis:value>2010-05-01T00:00:00+02:00</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString displayName="Change token" localName="changeToken" propertyDefinitionId="cmis:changeToken" queryName="cmis:changeToken"/>
+ <cmis:propertyId displayName="Base Type Id" localName="baseTypeId" propertyDefinitionId="cmis:baseTypeId" queryName="cmis:baseTypeId">
+ <cmis:value>cmis:relationship</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId displayName="Alfresco Node Ref" localName="nodeRef" propertyDefinitionId="alfcmis:nodeRef" queryName="alfcmis:nodeRef">
+ <cmis:value>75|workspace://SpacesStore/3885d9a2-0540-41ab-810a-38ccb1b160d6|workspace://SpacesStore/5d8908d9-1b4a-4265-b1de-5d7244fcea70|{http://www.alfresco.org/model/content/1.0}original</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString displayName="Description" localName="description" propertyDefinitionId="cmis:description" queryName="cmis:description"/>
+ <cmis:propertyDateTime displayName="Last Modified Date" localName="lastModificationDate" propertyDefinitionId="cmis:lastModificationDate" queryName="cmis:lastModificationDate">
+ <cmis:value>2010-05-01T00:00:00+02:00</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmis:relationship>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry" cmisra:id="test-document"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=test-document" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=test-document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=test-document" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=test-document" type="application/cmisacl+xml"/>
+ <atom:link rel="version-history" href="http://mockup/mock/versions?id=test-document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="alternate" href="http://mockup/mock/renditions?id=test-document-rendition1" type="image/png" cmisra:renditionKind="cmis:thumbnail" title="picture" length="40385"/>
+ <atom:link rel="alternate" href="http://mockup/mock/renditions?id=test-document-rendition2" type="application/pdf" cmisra:renditionKind="pdf" title="Doc as PDF"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/test-document-updated.xml b/qa/libcmis/data/atom/test-document-updated.xml
new file mode 100644
index 0000000..31482f6
--- /dev/null
+++ b/qa/libcmis/data/atom/test-document-updated.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-28T14:10:06Z</atom:published>
+ <atom:title>New name</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=test-document" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>New name</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>false</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>false</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>New name</name>
+ </exampleExtension:exampleExtension>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry" cmisra:id="test-document"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=ComplexType" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=test-document" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=test-document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=test-document" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=test-document" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/test-document.xml b/qa/libcmis/data/atom/test-document.xml
new file mode 100644
index 0000000..242ded2
--- /dev/null
+++ b/qa/libcmis/data/atom/test-document.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-01-28T14:10:06Z</atom:published>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-01-28T14:10:06Z</app:edited>
+ <atom:updated>2013-01-28T14:10:06Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=test-document" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>true</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>true</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ <cmis:rendition>
+ <cmis:streamId>http://mockup/mock/renditions?id=test-document-rendition1</cmis:streamId>
+ <cmis:mimetype>image/png</cmis:mimetype>
+ <cmis:length>40385</cmis:length>
+ <cmis:kind>cmis:thumbnail</cmis:kind>
+ <cmis:title>picture</cmis:title>
+ <cmis:height>100</cmis:height>
+ <cmis:width>100</cmis:width>
+ </cmis:rendition>
+ <cmis:rendition>
+ <cmis:streamId>http://mockup/mock/renditions?id=test-document-rendition2</cmis:streamId>
+ <cmis:mimetype>application/pdf</cmis:mimetype>
+ <cmis:kind>pdf</cmis:kind>
+ <cmis:title>Doc as PDF</cmis:title>
+ </cmis:rendition>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry" cmisra:id="test-document"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=test-document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=test-document" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=test-document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=test-document" type="text/plain"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=test-document" type="application/cmisacl+xml"/>
+ <atom:link rel="version-history" href="http://mockup/mock/versions?id=test-document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="alternate" href="http://mockup/mock/renditions?id=test-document-rendition1" type="image/png" cmisra:renditionKind="cmis:thumbnail" title="picture" length="40385"/>
+ <atom:link rel="alternate" href="http://mockup/mock/renditions?id=test-document-rendition2" type="application/pdf" cmisra:renditionKind="pdf" title="Doc as PDF"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/type-docLevel1.xml b/qa/libcmis/data/atom/type-docLevel1.xml
new file mode 100644
index 0000000..20d70c4
--- /dev/null
+++ b/qa/libcmis/data/atom/type-docLevel1.xml
@@ -0,0 +1,404 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>Document Level 1</atom:title>
+ <app:edited>2013-01-25T09:47:39Z</app:edited>
+ <atom:updated>2013-01-25T09:47:39Z</atom:updated>
+ <cmisra:type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xsi:type="cmis:cmisTypeDocumentDefinitionType">
+ <cmis:id>DocumentLevel1</cmis:id>
+ <cmis:localName>DocumentLevel1</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 1</cmis:displayName>
+ <cmis:queryName>DocumentLevel1</cmis:queryName>
+ <cmis:description>Description of Document Level 1 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>cmis:document</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmisra:type>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry" cmisra:id="DocumentLevel1"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="up" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/types?typeId=DocumentLevel1" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=DocumentLevel1" type="application/cmistree+xml"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/type-docLevel2.xml b/qa/libcmis/data/atom/type-docLevel2.xml
new file mode 100644
index 0000000..eb7deeb
--- /dev/null
+++ b/qa/libcmis/data/atom/type-docLevel2.xml
@@ -0,0 +1,675 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>Document Level 2</atom:title>
+ <app:edited>2013-01-25T09:46:50Z</app:edited>
+ <atom:updated>2013-01-25T09:46:50Z</atom:updated>
+ <cmisra:type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xsi:type="cmis:cmisTypeDocumentDefinitionType">
+ <cmis:id>DocumentLevel2</cmis:id>
+ <cmis:localName>DocumentLevel2</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 2</cmis:displayName>
+ <cmis:queryName>DocumentLevel2</cmis:queryName>
+ <cmis:description>Description of Document Level 2 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>DocumentLevel1</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyHtmlDefinition>
+ <cmis:id>HtmlProp</cmis:id>
+ <cmis:localName>HtmlProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Html Property</cmis:displayName>
+ <cmis:queryName>HtmlProp</cmis:queryName>
+ <cmis:description>This is a Sample Html Property property.</cmis:description>
+ <cmis:propertyType>html</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyHtmlDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>IdProp</cmis:id>
+ <cmis:localName>IdProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Id Property</cmis:displayName>
+ <cmis:queryName>IdProp</cmis:queryName>
+ <cmis:description>This is a Sample Id Property property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>DateTimePropMV</cmis:id>
+ <cmis:localName>DateTimePropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample DateTime multi-value Property</cmis:displayName>
+ <cmis:queryName>DateTimePropMV</cmis:queryName>
+ <cmis:description>This is a Sample DateTime multi-value Property property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyUriDefinition>
+ <cmis:id>UriProp</cmis:id>
+ <cmis:localName>UriProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Uri Property</cmis:displayName>
+ <cmis:queryName>UriProp</cmis:queryName>
+ <cmis:description>This is a Sample Uri Property property.</cmis:description>
+ <cmis:propertyType>uri</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyUriDefinition>
+ <cmis:propertyDecimalDefinition>
+ <cmis:id>DecimalProp</cmis:id>
+ <cmis:localName>DecimalProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Decimal Property</cmis:displayName>
+ <cmis:queryName>DecimalProp</cmis:queryName>
+ <cmis:description>This is a Sample Decimal Property property.</cmis:description>
+ <cmis:propertyType>decimal</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDecimalDefinition>
+ <cmis:propertyUriDefinition>
+ <cmis:id>UriPropMV</cmis:id>
+ <cmis:localName>UriPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Uri multi-value Property</cmis:displayName>
+ <cmis:queryName>UriPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Uri multi-value Property property.</cmis:description>
+ <cmis:propertyType>uri</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyUriDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>IdPropMV</cmis:id>
+ <cmis:localName>IdPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Id Html multi-value Property</cmis:displayName>
+ <cmis:queryName>IdPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Id Html multi-value Property property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>PickListProp</cmis:id>
+ <cmis:localName>PickListProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Pick List Property</cmis:displayName>
+ <cmis:queryName>PickListProp</cmis:queryName>
+ <cmis:description>This is a Sample Pick List Property property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ <cmis:defaultValue propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:defaultValue>
+ <cmis:choice displayName="">
+ <cmis:value>red</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>green</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>blue</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>black</cmis:value>
+ </cmis:choice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>IntProp</cmis:id>
+ <cmis:localName>IntProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Int Property</cmis:displayName>
+ <cmis:queryName>IntProp</cmis:queryName>
+ <cmis:description>This is a Sample Int Property property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyHtmlDefinition>
+ <cmis:id>HtmlPropMV</cmis:id>
+ <cmis:localName>HtmlPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Html multi-value Property</cmis:displayName>
+ <cmis:queryName>HtmlPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Html multi-value Property property.</cmis:description>
+ <cmis:propertyType>html</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyHtmlDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>StringProp</cmis:id>
+ <cmis:localName>StringProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample String Property</cmis:displayName>
+ <cmis:queryName>StringProp</cmis:queryName>
+ <cmis:description>This is a Sample String Property property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDecimalDefinition>
+ <cmis:id>DecimalPropMV</cmis:id>
+ <cmis:localName>DecimalPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Decimal multi-value Property</cmis:displayName>
+ <cmis:queryName>DecimalPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Decimal multi-value Property property.</cmis:description>
+ <cmis:propertyType>decimal</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDecimalDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>DateTimeProp</cmis:id>
+ <cmis:localName>DateTimeProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample DateTime Property</cmis:displayName>
+ <cmis:queryName>DateTimeProp</cmis:queryName>
+ <cmis:description>This is a Sample DateTime Property property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>BooleanProp</cmis:id>
+ <cmis:localName>BooleanProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Boolean Property</cmis:displayName>
+ <cmis:queryName>BooleanProp</cmis:queryName>
+ <cmis:description>This is a Sample Boolean Property property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>BooleanPropMV</cmis:id>
+ <cmis:localName>BooleanPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Boolean multi-value Property</cmis:displayName>
+ <cmis:queryName>BooleanPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Boolean multi-value Property property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>IntPropMV</cmis:id>
+ <cmis:localName>IntPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Int multi-value Property</cmis:displayName>
+ <cmis:queryName>IntPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Int multi-value Property property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmisra:type>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry" cmisra:id="DocumentLevel2"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="up" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/types?typeId=DocumentLevel2" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=DocumentLevel2" type="application/cmistree+xml"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:document" type="application/atom+xml;type=entry"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/type-document.xml b/qa/libcmis/data/atom/type-document.xml
new file mode 100644
index 0000000..9bd661d
--- /dev/null
+++ b/qa/libcmis/data/atom/type-document.xml
@@ -0,0 +1,402 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>CMIS Document</atom:title>
+ <app:edited>2013-01-25T09:47:55Z</app:edited>
+ <atom:updated>2013-01-25T09:47:55Z</atom:updated>
+ <cmisra:type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xsi:type="cmis:cmisTypeDocumentDefinitionType">
+ <cmis:id>cmis:document</cmis:id>
+ <cmis:localName>cmis:document</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>CMIS Document</cmis:displayName>
+ <cmis:queryName>cmis:document</cmis:queryName>
+ <cmis:description>Description of CMIS Document Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmisra:type>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/type?id=cmis:document" type="application/atom+xml;type=entry" cmisra:id="cmis:document"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/type?id=cmis:document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/types?typeId=cmis:document" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=cmis:document" type="application/cmistree+xml"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:document" type="application/atom+xml;type=entry"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/type-folder.xml b/qa/libcmis/data/atom/type-folder.xml
new file mode 100644
index 0000000..5aed5ae
--- /dev/null
+++ b/qa/libcmis/data/atom/type-folder.xml
@@ -0,0 +1,224 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>CMIS Folder</atom:title>
+ <app:edited>2012-11-29T16:39:44Z</app:edited>
+ <atom:updated>2012-11-29T16:39:44Z</atom:updated>
+ <cmisra:type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xsi:type="cmis:cmisTypeFolderDefinitionType">
+ <cmis:id>cmis:folder</cmis:id>
+ <cmis:localName>cmis:folder</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>CMIS Folder</cmis:displayName>
+ <cmis:queryName>cmis:folder</cmis:queryName>
+ <cmis:description>Description of CMIS Folder Type</cmis:description>
+ <cmis:baseId>cmis:folder</cmis:baseId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:allowedChildObjectTypeIds</cmis:id>
+ <cmis:localName>cmis:allowedChildObjectTypeIds</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Allowed Child Types</cmis:displayName>
+ <cmis:queryName>cmis:allowedChildObjectTypeIds</cmis:queryName>
+ <cmis:description>This is a Allowed Child Types property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:path</cmis:id>
+ <cmis:localName>cmis:path</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Path</cmis:displayName>
+ <cmis:queryName>cmis:path</cmis:queryName>
+ <cmis:description>This is a Path property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:parentId</cmis:id>
+ <cmis:localName>cmis:parentId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Parent Id</cmis:displayName>
+ <cmis:queryName>cmis:parentId</cmis:queryName>
+ <cmis:description>This is a Parent Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ </cmisra:type>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry" cmisra:id="cmis:folder"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/types?typeId=cmis:folder" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=cmis:folder" type="application/cmistree+xml"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis:folder" type="application/atom+xml;type=entry"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/typechildren-docLevel1.xml b/qa/libcmis/data/atom/typechildren-docLevel1.xml
new file mode 100644
index 0000000..0d15971
--- /dev/null
+++ b/qa/libcmis/data/atom/typechildren-docLevel1.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>Document Level 1</atom:title>
+ <app:edited>2013-01-25T10:11:03Z</app:edited>
+ <atom:updated>2013-01-25T10:11:03Z</atom:updated>
+ <cmisra:numItems>1</cmisra:numItems>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/types?typeId=DocumentLevel1&amp;includePropertyDefinitions=false" type="application/atom+xml;type=entry" cmisra:id="DocumentLevel1"/>
+ <atom:link rel="via" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=DocumentLevel1" type="application/cmistree+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+ <atom:link rel="next" href="http://mockup/mock/types?typeId=DocumentLevel1&amp;includePropertyDefinitions=false&amp;skipCount=100&amp;maxItems=100" type="application/atom+xml;type=feed"/>
+ <app:collection href="http://mockup/mock/types?typeId=DocumentLevel1">
+ <atom:title type="text">Types Collection</atom:title>
+ <app:accept/>
+ </app:collection>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>Document Level 2</atom:title>
+ <app:edited>2013-01-25T10:11:03Z</app:edited>
+ <atom:updated>2013-01-25T10:11:03Z</atom:updated>
+ <cmisra:type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xsi:type="cmis:cmisTypeDocumentDefinitionType">
+ <cmis:id>DocumentLevel2</cmis:id>
+ <cmis:localName>DocumentLevel2</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 2</cmis:displayName>
+ <cmis:queryName>DocumentLevel2</cmis:queryName>
+ <cmis:description>Description of Document Level 2 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>DocumentLevel1</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmisra:type>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry" cmisra:id="DocumentLevel2"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="up" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/types?typeId=DocumentLevel2" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=DocumentLevel2" type="application/cmistree+xml"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+ </atom:entry>
+</atom:feed>
diff --git a/qa/libcmis/data/atom/typechildren-document.xml b/qa/libcmis/data/atom/typechildren-document.xml
new file mode 100644
index 0000000..b60c1b4
--- /dev/null
+++ b/qa/libcmis/data/atom/typechildren-document.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:feed xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>CMIS Document</atom:title>
+ <app:edited>2013-01-25T10:05:56Z</app:edited>
+ <atom:updated>2013-01-25T10:05:56Z</atom:updated>
+ <cmisra:numItems>1</cmisra:numItems>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/types?typeId=cmis:document&amp;includePropertyDefinitions=false" type="application/atom+xml;type=entry" cmisra:id="cmis:document"/>
+ <atom:link rel="via" href="http://mockup/mock/type?id=cmis:document" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=cmis:document" type="application/cmistree+xml"/>
+ <atom:link rel="next" href="http://mockup/mock/types?typeId=cmis:document&amp;includePropertyDefinitions=false&amp;skipCount=100&amp;maxItems=100" type="application/atom+xml;type=feed"/>
+ <app:collection href="http://mockup/mock/types?typeId=cmis:document">
+ <atom:title type="text">Types Collection</atom:title>
+ <app:accept/>
+ </app:collection>
+ <atom:entry>
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>http://mockup/mock/obscure id</atom:id>
+ <atom:title>Document Level 1</atom:title>
+ <app:edited>2013-01-25T10:05:56Z</app:edited>
+ <atom:updated>2013-01-25T10:05:56Z</atom:updated>
+ <cmisra:type xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xsi:type="cmis:cmisTypeDocumentDefinitionType">
+ <cmis:id>DocumentLevel1</cmis:id>
+ <cmis:localName>DocumentLevel1</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 1</cmis:displayName>
+ <cmis:queryName>DocumentLevel1</cmis:queryName>
+ <cmis:description>Description of Document Level 1 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>cmis:document</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmisra:type>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry" cmisra:id="DocumentLevel1"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/type?id=DocumentLevel1" type="application/atom+xml;type=entry"/>
+ <atom:link rel="up" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+ <atom:link rel="down" href="http://mockup/mock/types?typeId=DocumentLevel1" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/typedesc?typeId=DocumentLevel1" type="application/cmistree+xml"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Adocument" type="application/atom+xml;type=entry"/>
+ </atom:entry>
+</atom:feed>
diff --git a/qa/libcmis/data/atom/valid-object-noactions.xml b/qa/libcmis/data/atom/valid-object-noactions.xml
new file mode 100644
index 0000000..697c2a7
--- /dev/null
+++ b/qa/libcmis/data/atom/valid-object-noactions.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2012-11-29T16:14:47Z</atom:published>
+ <atom:title>Valid Object</atom:title>
+ <app:edited>2012-11-29T16:14:47Z</app:edited>
+ <atom:updated>2012-11-29T16:14:47Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Valid Object</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Valid Object</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>valid-object</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://my/cmis/extension" xmlns:exampleExtension="http://my/cmis/extension">
+ <objectId xmlns:ns0="http://my/cmis/extension" ns0:type="cmis:folder">valid-object</objectId>
+ <name>Valid Object</name>
+ </exampleExtension:exampleExtension>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=valid-object" type="application/atom+xml;type=entry" cmisra:id="valid-object"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=valid-object" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=valid-object" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Afolder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=valid-object" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=valid-object" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=valid-object" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=valid-object" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=valid-object" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=valid-object" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/valid-object.xml b/qa/libcmis/data/atom/valid-object.xml
new file mode 100644
index 0000000..65815b3
--- /dev/null
+++ b/qa/libcmis/data/atom/valid-object.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>Admin</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2012-11-29T16:14:47Z</atom:published>
+ <atom:title>Valid Object</atom:title>
+ <app:edited>2012-11-29T16:14:47Z</app:edited>
+ <atom:updated>2012-11-29T16:14:47Z</atom:updated>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Valid Object</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Valid Object</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>valid-object</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>true</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>true</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>true</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>false</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>false</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>false</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>false</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>false</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>false</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>false</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>true</cmis:canGetChildren>
+ <cmis:canCreateDocument>true</cmis:canCreateDocument>
+ <cmis:canCreateFolder>true</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>true</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://my/cmis/extension" xmlns:exampleExtension="http://my/cmis/extension">
+ <objectId xmlns:ns0="http://my/cmis/extension" ns0:type="cmis:folder">valid-object</objectId>
+ <name>Valid Object</name>
+ </exampleExtension:exampleExtension>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=valid-object" type="application/atom+xml;type=entry" cmisra:id="valid-object"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=valid-object" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=valid-object" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=cmis%3Afolder" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=valid-object" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=valid-object" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/children?id=valid-object" type="application/atom+xml;type=feed"/>
+ <atom:link rel="down" href="http://mockup/mock/descendants?id=valid-object" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=valid-object" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=valid-object" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/working-copy.xml b/qa/libcmis/data/atom/working-copy.xml
new file mode 100644
index 0000000..42a9bc7
--- /dev/null
+++ b/qa/libcmis/data/atom/working-copy.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/" xmlns:app="http://www.w3.org/2007/app">
+ <atom:author>
+ <atom:name>unknown</atom:name>
+ </atom:author>
+ <atom:id>Some obscure Id</atom:id>
+ <atom:published>2013-05-21T13:50:45Z</atom:published>
+ <atom:title>Test Document</atom:title>
+ <app:edited>2013-05-21T13:50:45Z</app:edited>
+ <atom:updated>2013-05-21T13:50:45Z</atom:updated>
+ <atom:content src="http://mockup/mock/content/data.txt?id=working-copy" type="text/plain"/>
+ <cmisra:object xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:properties>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId">
+ <cmis:value>working-copy</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="VersionedStringProp" displayName="Sample String Property" localName="VersionedStringProp" propertyDefinitionId="VersionedStringProp"/>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>version-series</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-05-21T13:50:45.300Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1369144245300</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>V 0.2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>working-copy</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-05-21T13:50:45.300Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">working-copy</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmisra:object>
+ <atom:link rel="service" href="http://mockup/mock" type="application/atomsvc+xml"/>
+ <atom:link rel="self" href="http://mockup/mock/id?id=working-copy" type="application/atom+xml;type=entry" cmisra:id="working-copy"/>
+ <atom:link rel="enclosure" href="http://mockup/mock/id?id=working-copy" type="application/atom+xml;type=entry"/>
+ <atom:link rel="edit" href="http://mockup/mock/id?id=working-copy" type="application/atom+xml;type=entry"/>
+ <atom:link rel="describedby" href="http://mockup/mock/type?id=DocumentLevel2" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions" href="http://mockup/mock/allowableactions?id=working-copy" type="application/cmisallowableactions+xml"/>
+ <atom:link rel="up" href="http://mockup/mock/parents?id=working-copy" type="application/atom+xml;type=feed"/>
+ <atom:link rel="version-history" href="http://mockup/mock/versions?id=working-copy&amp;versionSeries=version-series" type="application/atom+xml;type=feed"/>
+ <atom:link rel="edit-media" href="http://mockup/mock/content?id=working-copy" type="text/plain"/>
+ <atom:link rel="working-copy" href="http://mockup/mock/id?id=working-copy" type="application/atom+xml;type=entry"/>
+ <atom:link rel="via" href="http://mockup/mock/id?id=working-copy" type="application/atom+xml;type=entry"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/acl" href="http://mockup/mock/acl?id=working-copy" type="application/cmisacl+xml"/>
+</atom:entry>
diff --git a/qa/libcmis/data/atom/workspaces.xml b/qa/libcmis/data/atom/workspaces.xml
new file mode 100644
index 0000000..1448776
--- /dev/null
+++ b/qa/libcmis/data/atom/workspaces.xml
@@ -0,0 +1,238 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<app:service xmlns:app="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmisra="http://docs.oasis-open.org/ns/cmis/restatom/200908/">
+ <app:workspace>
+ <atom:title>Mockup</atom:title>
+ <app:collection href="http://mockup/mock/children?id=root">
+ <cmisra:collectionType>root</cmisra:collectionType>
+ <atom:title type="text">Root Collection</atom:title>
+ <app:accept>application/atom+xml;type=entry</app:accept>
+ <app:accept>application/cmisatom+xml</app:accept>
+ </app:collection>
+ <app:collection href="http://mockup/mock/types">
+ <cmisra:collectionType>types</cmisra:collectionType>
+ <atom:title type="text">Types Collection</atom:title>
+ <app:accept/>
+ </app:collection>
+ <app:collection href="http://mockup/mock/query">
+ <cmisra:collectionType>query</cmisra:collectionType>
+ <atom:title type="text">Query Collection</atom:title>
+ <app:accept>application/cmisquery+xml</app:accept>
+ </app:collection>
+ <app:collection href="http://mockup/mock/checkedout">
+ <cmisra:collectionType>checkedout</cmisra:collectionType>
+ <atom:title type="text">Checked Out Collection</atom:title>
+ <app:accept>application/cmisatom+xml</app:accept>
+ </app:collection>
+ <app:collection href="http://mockup/mock/unfiled">
+ <cmisra:collectionType>unfiled</cmisra:collectionType>
+ <atom:title type="text">Unfiled Collection</atom:title>
+ <app:accept>application/cmisatom+xml</app:accept>
+ </app:collection>
+ <cmisra:repositoryInfo xmlns:ns3="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmis:repositoryId>mock</cmis:repositoryId>
+ <cmis:repositoryName>Mockup</cmis:repositoryName>
+ <cmis:repositoryDescription>Repository sent by mockup server</cmis:repositoryDescription>
+ <cmis:vendorName>libcmis</cmis:vendorName>
+ <cmis:productName>Libcmis mockup</cmis:productName>
+ <cmis:productVersion>some-version</cmis:productVersion>
+ <cmis:rootFolderId>root-folder</cmis:rootFolderId>
+ <cmis:latestChangeLogToken>0</cmis:latestChangeLogToken>
+ <cmis:capabilities>
+ <cmis:capabilityACL>manage</cmis:capabilityACL>
+ <cmis:capabilityAllVersionsSearchable>false</cmis:capabilityAllVersionsSearchable>
+ <cmis:capabilityChanges>none</cmis:capabilityChanges>
+ <cmis:capabilityContentStreamUpdatability>anytime</cmis:capabilityContentStreamUpdatability>
+ <cmis:capabilityGetDescendants>true</cmis:capabilityGetDescendants>
+ <cmis:capabilityGetFolderTree>true</cmis:capabilityGetFolderTree>
+ <cmis:capabilityMultifiling>true</cmis:capabilityMultifiling>
+ <cmis:capabilityPWCSearchable>false</cmis:capabilityPWCSearchable>
+ <cmis:capabilityPWCUpdatable>true</cmis:capabilityPWCUpdatable>
+ <cmis:capabilityQuery>bothcombined</cmis:capabilityQuery>
+ <cmis:capabilityRenditions>none</cmis:capabilityRenditions>
+ <cmis:capabilityUnfiling>true</cmis:capabilityUnfiling>
+ <cmis:capabilityVersionSpecificFiling>false</cmis:capabilityVersionSpecificFiling>
+ <cmis:capabilityJoin>none</cmis:capabilityJoin>
+ </cmis:capabilities>
+ <cmis:aclCapability>
+ <cmis:supportedPermissions>basic</cmis:supportedPermissions>
+ <cmis:propagation>objectonly</cmis:propagation>
+ <cmis:permissions>
+ <cmis:permission>cmis:read</cmis:permission>
+ <cmis:description>Read</cmis:description>
+ </cmis:permissions>
+ <cmis:permissions>
+ <cmis:permission>cmis:write</cmis:permission>
+ <cmis:description>Write</cmis:description>
+ </cmis:permissions>
+ <cmis:permissions>
+ <cmis:permission>cmis:all</cmis:permission>
+ <cmis:description>All</cmis:description>
+ </cmis:permissions>
+ <cmis:mapping>
+ <cmis:key>canGetDescendents.Folder</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetChildren.Folder</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetParents.Folder</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetFolderParent.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateDocument.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateFolder.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateRelationship.Source</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateRelationship.Target</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetProperties.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canViewContent.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canUpdateProperties.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canMove.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canMove.Target</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canMove.Source</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canDelete.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canDeleteTree.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canSetContent.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canDeleteContent.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddToFolder.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddToFolder.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemoveFromFolder.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemoveFromFolder.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCheckout.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCancelCheckout.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCheckin.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetAllVersions.VersionSeries</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetObjectRelationships.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddPolicy.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddPolicy.Policy</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemovePolicy.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemovePolicy.Policy</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetAppliedPolicies.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetACL.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canApplyACL.Object</cmis:key>
+ <cmis:permission>cmis:all</cmis:permission>
+ </cmis:mapping>
+ </cmis:aclCapability>
+ <cmis:cmisVersionSupported>1.1</cmis:cmisVersionSupported>
+ <cmis:thinClientURI/>
+ <cmis:changesIncomplete>true</cmis:changesIncomplete>
+ <cmis:principalAnonymous>anonymous</cmis:principalAnonymous>
+ <cmis:principalAnyone>anyone</cmis:principalAnyone>
+ </cmisra:repositoryInfo>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/typedescendants" href="http://mockup/mock/typedesc" type="application/atom+xml;type=feed"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/foldertree" href="http://mockup/mock/foldertree?id=root" type="application/cmistree+xml"/>
+ <atom:link rel="http://docs.oasis-open.org/ns/cmis/link/200908/rootdescendants" href="http://mockup/mock/descendants?id=root" type="application/cmistree+xml" cmisra:id="root"/>
+ <cmisra:uritemplate>
+ <cmisra:template>http://mockup/mock/id?id={id}&amp;filter={filter}&amp;includeAllowableActions={includeAllowableActions}&amp;includeACL={includeACL}&amp;includePolicyIds={includePolicyIds}&amp;includeRelationships={includeRelationships}&amp;renditionFilter={renditionFilter}</cmisra:template>
+ <cmisra:type>objectbyid</cmisra:type>
+ <cmisra:mediatype>application/atom+xml;type=entry</cmisra:mediatype>
+ </cmisra:uritemplate>
+ <cmisra:uritemplate>
+ <cmisra:template>http://mockup/mock/path?path={path}&amp;filter={filter}&amp;includeAllowableActions={includeAllowableActions}&amp;includeACL={includeACL}&amp;includePolicyIds={includePolicyIds}&amp;includeRelationships={includeRelationships}&amp;renditionFilter={renditionFilter}</cmisra:template>
+ <cmisra:type>objectbypath</cmisra:type>
+ <cmisra:mediatype>application/atom+xml;type=entry</cmisra:mediatype>
+ </cmisra:uritemplate>
+ <cmisra:uritemplate>
+ <cmisra:template>http://mockup/mock/type?id={id}</cmisra:template>
+ <cmisra:type>typebyid</cmisra:type>
+ <cmisra:mediatype>application/atom+xml;type=entry</cmisra:mediatype>
+ </cmisra:uritemplate>
+ <cmisra:uritemplate>
+ <cmisra:template>http://mockup/mock/query?q={q}&amp;searchAllVersions={searchAllVersions}&amp;includeAllowableActions={includeAllowableActions}&amp;includeRelationships={includeRelationships}&amp;maxItems={maxItems}&amp;skipCount={skipCount}</cmisra:template>
+ <cmisra:type>query</cmisra:type>
+ <cmisra:mediatype>application/atom+xml;type=feed</cmisra:mediatype>
+ </cmisra:uritemplate>
+ </app:workspace>
+</app:service>
diff --git a/qa/libcmis/data/gdrive/allVersions.json b/qa/libcmis/data/gdrive/allVersions.json
new file mode 100644
index 0000000..cdbba67
--- /dev/null
+++ b/qa/libcmis/data/gdrive/allVersions.json
@@ -0,0 +1,49 @@
+{
+ "kind": "drive#revisionList",
+ "etag": "revisionEtag",
+ "selfLink": "revisionsLink",
+ "items": [
+ {
+ "kind": "drive#revision",
+ "etag": "\"anEtag\"",
+ "id": "versionId0",
+ "selfLink": "aSelfLink",
+ "mimeType": "application/vnd.google-apps.form",
+ "modifiedDate": "2010-07-04T12:30:07.355Z",
+ "published": false,
+ "exportLinks": {
+ "application/pdf": "pdfLink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "ODFLinks",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "msLink"
+ }
+ },
+ {
+ "kind": "drive#revision",
+ "etag": "\"anEtag\"",
+ "id": "versionId1",
+ "selfLink": "aSelfLink",
+ "mimeType": "application/vnd.google-apps.form",
+ "modifiedDate": "2010-07-04T12:30:07.355Z",
+ "published": false,
+ "exportLinks": {
+ "application/pdf": "pdfLink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "ODFLinks",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "msLink"
+ }
+ },
+ {
+ "kind": "drive#revision",
+ "etag": "\"anEtag\"",
+ "id": "versionId2",
+ "selfLink": "aSelfLink",
+ "mimeType": "application/vnd.google-apps.form",
+ "modifiedDate": "2010-07-04T12:30:07.355Z",
+ "published": false,
+ "exportLinks": {
+ "application/pdf": "pdfLink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "ODFLinks",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "msLink"
+ }
+ }
+ ]
+}
diff --git a/qa/libcmis/data/gdrive/approve.html b/qa/libcmis/data/gdrive/approve.html
new file mode 100644
index 0000000..cf4959b
--- /dev/null
+++ b/qa/libcmis/data/gdrive/approve.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<form action="https://approval/url" method="POST" id="submit_access_form">
+<input id="state_wrapper" name="state_wrapper" value="stateWrapper" type="hidden">
+<input id="submit_access" name="submit_access" value="" type="hidden">
+
+</form>
+</body>
+</html>
diff --git a/qa/libcmis/data/gdrive/authcode.html b/qa/libcmis/data/gdrive/authcode.html
new file mode 100644
index 0000000..7d28ba1
--- /dev/null
+++ b/qa/libcmis/data/gdrive/authcode.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<html>
+<body>
+<input id="code" readonly="readonly" value="AuthCode">
+</body>
+</html>
diff --git a/qa/libcmis/data/gdrive/challenge.html b/qa/libcmis/data/gdrive/challenge.html
new file mode 100644
index 0000000..a92124d
--- /dev/null
+++ b/qa/libcmis/data/gdrive/challenge.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html lang="en">
+<body>
+<form novalidate="" id="skip" action="/signin/challenge/skip" method="post">
+ <input id="skipChallenge" type="submit">
+</form>
+<form novalidate="" id="resend" action="/signin/challenge" method="post">
+ <input name="subAction" type="hidden" value="startChallenge">
+ <input name="challengeId" type="hidden" value="1">
+</form>
+<form novalidate="" id="challenge" action="/challenge/url" method="post">
+ <input name="continue" id="continue" value="redirectLink&amp;scope=Scope" type="hidden">
+ <input name="service" id="service" value="lso" type="hidden">
+ <input name="GALX" value="cookie" type="hidden">
+ <input name="Pin" id="Pin">
+</form>
+<form novalidate="" id="select_challenge" action="/signin/selectchallenge" method="post">
+ <input id="selectChallenge" type="submit">
+</form>
+</body>
+</html>
diff --git a/qa/libcmis/data/gdrive/document-updated.json b/qa/libcmis/data/gdrive/document-updated.json
new file mode 100644
index 0000000..e60ee79
--- /dev/null
+++ b/qa/libcmis/data/gdrive/document-updated.json
@@ -0,0 +1,67 @@
+{
+ "kind": "drive#file",
+ "id": "aFileId",
+ "etag": "\"an example tag\"",
+ "selfLink": "fileSelfLink",
+ "title": "New Title",
+ "mimeType": "application/vnd.google-apps.form",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2010-04-28T14:53:23.141Z",
+ "modifiedDate": "2010-09-30T21:01:37.504Z",
+ "lastViewedByMeDate": "2013-02-26T15:40:30.404Z",
+ "fileSize": "123",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "aFolderId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ },
+ {
+ "kind": "drive#parentReference",
+ "id": "aNewFolderId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ }
+ ],
+ "exportLinks": {
+ "application/pdf": "pdflink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "https://downloadLink",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlslink"
+ },
+ "thumbnailLink": "https://aThumbnailLink",
+ "userPermission": {
+ "kind": "drive#permission",
+ "id": "me",
+ "role": "owner",
+ "type": "user"
+ },
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "Owner Real Name"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "Mock file owner",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "Mock user",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": false
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": true
+}
diff --git a/qa/libcmis/data/gdrive/document.json b/qa/libcmis/data/gdrive/document.json
new file mode 100644
index 0000000..016a5bd
--- /dev/null
+++ b/qa/libcmis/data/gdrive/document.json
@@ -0,0 +1,67 @@
+{
+ "kind": "drive#file",
+ "id": "aFileId",
+ "etag": "\"an example tag\"",
+ "selfLink": "fileSelfLink",
+ "title": "GDrive File",
+ "mimeType": "application/vnd.google-apps.form",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2010-04-28T14:53:23.141Z",
+ "modifiedDate": "2010-09-30T21:01:37.504Z",
+ "lastViewedByMeDate": "2013-02-26T15:40:30.404Z",
+ "fileSize": "123",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "aFolderId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ },
+ {
+ "kind": "drive#parentReference",
+ "id": "aNewFolderId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ }
+ ],
+ "exportLinks": {
+ "application/pdf": "pdflink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "https://downloadLink",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlslink"
+ },
+ "thumbnailLink": "https://aThumbnailLink",
+ "userPermission": {
+ "kind": "drive#permission",
+ "id": "me",
+ "role": "owner",
+ "type": "user"
+ },
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "Owner Real Name"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "Mock file owner",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "Mock user",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": false
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": true
+}
diff --git a/qa/libcmis/data/gdrive/document2.json b/qa/libcmis/data/gdrive/document2.json
new file mode 100644
index 0000000..c55475e
--- /dev/null
+++ b/qa/libcmis/data/gdrive/document2.json
@@ -0,0 +1,62 @@
+{
+ "kind": "drive#file",
+ "id": "aFileId",
+ "etag": "\"an example tag\"",
+ "selfLink": "fileSelfLink",
+ "title": "GDrive File",
+ "mimeType": "application/vnd.google-apps.form",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2010-04-28T14:53:23.141Z",
+ "modifiedDate": "2010-09-30T21:01:37.504Z",
+ "lastViewedByMeDate": "2013-02-26T15:40:30.404Z",
+ "fileSize": "123",
+ "downloadUrl": "https://download/url",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "aFolderId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ },
+ {
+ "kind": "drive#parentReference",
+ "id": "anotherFolderId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ }
+ ],
+ "userPermission": {
+ "kind": "drive#permission",
+ "id": "me",
+ "role": "owner",
+ "type": "user"
+ },
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "Owner Real Name"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "Mock file owner",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "Mock user",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": false
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": true
+}
diff --git a/qa/libcmis/data/gdrive/document_parents.json b/qa/libcmis/data/gdrive/document_parents.json
new file mode 100644
index 0000000..21c033f
--- /dev/null
+++ b/qa/libcmis/data/gdrive/document_parents.json
@@ -0,0 +1,14 @@
+{
+ "kind": "drive#parentList",
+ "etag": "A parent etag",
+ "selfLink": "SelfLink",
+ "items": [
+ {
+ "kind": "drive#parentReference",
+ "id": "aFolderId",
+ "selfLink": "aSelfLink",
+ "parentLink": "AParentLink",
+ "isRoot": true
+ }
+ ]
+}
diff --git a/qa/libcmis/data/gdrive/folder.json b/qa/libcmis/data/gdrive/folder.json
new file mode 100644
index 0000000..2b07a48
--- /dev/null
+++ b/qa/libcmis/data/gdrive/folder.json
@@ -0,0 +1,47 @@
+{
+ "kind": "drive#file",
+ "id": "aFolderId",
+ "etag": "a folder etag",
+ "selfLink": "SelfLINK",
+ "title": "testFolder",
+ "mimeType": "application/vnd.google-apps.folder",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2013-03-22T17:53:10.290Z",
+ "modifiedDate": "2013-03-22T17:53:44.212Z",
+ "modifiedByMeDate": "2013-03-22T17:53:44.212Z",
+ "lastViewedByMeDate": "2013-04-05T15:27:47.261Z",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "parentID",
+ "isRoot": true
+ }
+ ],
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "User"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "User name of the last person modify",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "Last mofifying username",
+ "isAuthenticatedUser": true
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": false,
+ "appDataContents": false
+}
diff --git a/qa/libcmis/data/gdrive/folder2.json b/qa/libcmis/data/gdrive/folder2.json
new file mode 100644
index 0000000..1f54206
--- /dev/null
+++ b/qa/libcmis/data/gdrive/folder2.json
@@ -0,0 +1,47 @@
+{
+ "kind": "drive#file",
+ "id": "aNewFolderId",
+ "etag": "a folder etag",
+ "selfLink": "SelfLINK",
+ "title": "testFolder",
+ "mimeType": "application/vnd.google-apps.folder",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2013-03-22T17:53:10.290Z",
+ "modifiedDate": "2013-03-22T17:53:44.212Z",
+ "modifiedByMeDate": "2013-03-22T17:53:44.212Z",
+ "lastViewedByMeDate": "2013-04-05T15:27:47.261Z",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "parentID",
+ "isRoot": true
+ }
+ ],
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "User"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "User name of the last person modify",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "Last mofifying username",
+ "isAuthenticatedUser": true
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": false,
+ "appDataContents": false
+}
diff --git a/qa/libcmis/data/gdrive/folder_children.json b/qa/libcmis/data/gdrive/folder_children.json
new file mode 100644
index 0000000..55604e3
--- /dev/null
+++ b/qa/libcmis/data/gdrive/folder_children.json
@@ -0,0 +1,20 @@
+{
+ "kind": "drive#childrenList",
+ "etag": "A children etag",
+ "selfLink": "SelfLink",
+ "items": [
+ {
+ "kind": "drive#childrenReference",
+ "id": "aChildFolder",
+ "mimeType": "application/vnd.google-apps.folder",
+ "selfLink": "aSelfLink",
+ "childLink": "AchildrenLink"
+ },
+ {
+ "kind": "drive#childrenReference",
+ "id": "aChildDocument",
+ "selfLink": "aSelfLink2",
+ "childLink": "AchildrenLink2"
+ }
+ ]
+}
diff --git a/qa/libcmis/data/gdrive/gdoc-file.json b/qa/libcmis/data/gdrive/gdoc-file.json
new file mode 100644
index 0000000..b55690e
--- /dev/null
+++ b/qa/libcmis/data/gdrive/gdoc-file.json
@@ -0,0 +1,58 @@
+{
+ "kind": "drive#file",
+ "id": "aFileId",
+ "etag": "\"an example tag\"",
+ "selfLink": "fileSelfLink",
+ "title": "a file title",
+ "mimeType": "application/vnd.google-apps.form",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2010-04-28T14:53:23.141Z",
+ "modifiedDate": "2010-09-30T21:01:37.504Z",
+ "lastViewedByMeDate": "2013-02-26T15:40:30.404Z",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "parentId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ }
+ ],
+ "exportLinks": {
+ "application/pdf": "pdflink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "opendocumentlinks",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlslink"
+ },
+ "userPermission": {
+ "kind": "drive#permission",
+ "id": "me",
+ "role": "owner",
+ "type": "user"
+ },
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "Owner Real Name"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "Mock file owner",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "Mock user",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": false
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": true
+}
diff --git a/qa/libcmis/data/gdrive/jsontest-good.json b/qa/libcmis/data/gdrive/jsontest-good.json
new file mode 100644
index 0000000..939e599
--- /dev/null
+++ b/qa/libcmis/data/gdrive/jsontest-good.json
@@ -0,0 +1,60 @@
+{
+ "kind": "drive#file",
+ "id": "aFileId",
+ "etag": "\"an example tag\"",
+ "selfLink": "fileSelfLink",
+ "title": "a file title",
+ "mimeType": "application/vnd.google-apps.form",
+ "labels": {
+ "starred": false,
+ "hidden": false,
+ "trashed": false,
+ "restricted": false,
+ "viewed": true
+ },
+ "createdDate": "2010-04-28T14:53:23.141Z",
+ "modifiedDate": "2010-09-30T21:01:37.504Z",
+ "lastViewedByMeDate": "2013-02-26T15:40:30.404Z",
+ "intTest": "-123",
+ "doubleTest": "-123.456",
+ "parents": [
+ {
+ "kind": "drive#parentReference",
+ "id": "parentId",
+ "selfLink": "parentSelfLink",
+ "parentLink": "parentLink",
+ "isRoot": true
+ }
+ ],
+ "exportLinks": {
+ "application/pdf": "pdflink",
+ "application/x-vnd.oasis.opendocument.spreadsheet": "opendocumentlinks",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlslink"
+ },
+ "userPermission": {
+ "kind": "drive#permission",
+ "id": "me",
+ "role": "owner",
+ "type": "user"
+ },
+ "quotaBytesUsed": "0",
+ "ownerNames": [
+ "Owner Real Name"
+ ],
+ "owners": [
+ {
+ "kind": "drive#user",
+ "displayName": "Mock file owner",
+ "isAuthenticatedUser": true
+ }
+ ],
+ "lastModifyingUserName": "Mock user",
+ "lastModifyingUser": {
+ "kind": "drive#user",
+ "displayName": "User name",
+ "isAuthenticatedUser": false
+ },
+ "editable": true,
+ "writersCanShare": true,
+ "shared": true
+}
diff --git a/qa/libcmis/data/gdrive/login1.html b/qa/libcmis/data/gdrive/login1.html
new file mode 100644
index 0000000..b6da338
--- /dev/null
+++ b/qa/libcmis/data/gdrive/login1.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+<body>
+<form novalidate="" id="gaia_loginform" action="https://login2/url" method="post">
+ <input name="Page" type="hidden" value="PasswordSeparationSignIn">
+ <input name="continue" id="continue" value="redirectLink&amp;scope=Scope" type="hidden">
+ <input name="service" id="service" value="lso" type="hidden">
+ <input name="GALX" value="cookie" type="hidden">
+ <input spellcheck="false" name="Email" id="Email" value="" type="email">
+</form>
+</body>
+</html>
diff --git a/qa/libcmis/data/gdrive/login2.html b/qa/libcmis/data/gdrive/login2.html
new file mode 100644
index 0000000..6425091
--- /dev/null
+++ b/qa/libcmis/data/gdrive/login2.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<body>
+<form novalidate="" id="gaia_loginform" action="https://login/url" method="post">
+ <input name="continue" id="continue" value="redirectLink&amp;scope=Scope" type="hidden">
+ <input name="service" id="service" value="lso" type="hidden">
+ <input name="GALX" value="cookie" type="hidden">
+ <input name="Passwd" id="Passwd" type="password">
+</form>
+</body>
+</html>
diff --git a/qa/libcmis/data/gdrive/refresh_response.json b/qa/libcmis/data/gdrive/refresh_response.json
new file mode 100644
index 0000000..d4afc4b
--- /dev/null
+++ b/qa/libcmis/data/gdrive/refresh_response.json
@@ -0,0 +1,5 @@
+{
+ "access_token":"new-access-token",
+ "expires_in":3920,
+ "token_type":"Bearer"
+}
diff --git a/qa/libcmis/data/gdrive/root_child_missing.json b/qa/libcmis/data/gdrive/root_child_missing.json
new file mode 100644
index 0000000..3659806
--- /dev/null
+++ b/qa/libcmis/data/gdrive/root_child_missing.json
@@ -0,0 +1,4 @@
+{
+ "items": [
+ ]
+}
diff --git a/qa/libcmis/data/gdrive/root_child_search.json b/qa/libcmis/data/gdrive/root_child_search.json
new file mode 100644
index 0000000..79f5031
--- /dev/null
+++ b/qa/libcmis/data/gdrive/root_child_search.json
@@ -0,0 +1,13 @@
+{
+ "kind": "drive#childrenList",
+ "etag": "A children etag",
+ "selfLink": "SelfLink",
+ "items": [
+ {
+ "kind": "drive#childrenReference",
+ "id": "aRootChildId2",
+ "selfLink": "aSelfLink2",
+ "childLink": "AchildrenLink2"
+ }
+ ]
+}
diff --git a/qa/libcmis/data/gdrive/token-response.json b/qa/libcmis/data/gdrive/token-response.json
new file mode 100644
index 0000000..36b233c
--- /dev/null
+++ b/qa/libcmis/data/gdrive/token-response.json
@@ -0,0 +1,6 @@
+{
+ "access_token":"mock-access-token",
+ "expires_in":3920,
+ "token_type":"Bearer",
+ "refresh_token":"mock-refresh-token"
+} \ No newline at end of file
diff --git a/qa/libcmis/data/onedrive/file.json b/qa/libcmis/data/onedrive/file.json
new file mode 100644
index 0000000..29e42e9
--- /dev/null
+++ b/qa/libcmis/data/onedrive/file.json
@@ -0,0 +1,24 @@
+{
+ "id": "aFileId",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDriveFile",
+ "description": "short description",
+ "parent_id": "aParentId",
+ "size": 42,
+ "upload_location": "https://base/url/aFileId/content",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "source": "sourceUrl",
+ "link": "linkUrl",
+ "type": "file",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/folder-listed.json b/qa/libcmis/data/onedrive/folder-listed.json
new file mode 100644
index 0000000..ce66c4e
--- /dev/null
+++ b/qa/libcmis/data/onedrive/folder-listed.json
@@ -0,0 +1,51 @@
+{
+ "data": [
+ {
+ "id": "aFolderId",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDrive Folder",
+ "description": "short description",
+ "parent_id": "aParentId",
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "link": "linkUrl",
+ "type": "folder",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+ },
+ {
+ "id": "aFileId",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDrive File",
+ "description": "short description",
+ "parent_id": "aParentId",
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "source": "sourceUrl",
+ "link": "linkUrl",
+ "type": "file",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+ }
+ ]
+}
diff --git a/qa/libcmis/data/onedrive/folder.json b/qa/libcmis/data/onedrive/folder.json
new file mode 100644
index 0000000..576ad10
--- /dev/null
+++ b/qa/libcmis/data/onedrive/folder.json
@@ -0,0 +1,23 @@
+{
+ "id": "aFolderId",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDrive Folder",
+ "description": "short description",
+ "parent_id": "aParentId",
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "link": "linkUrl",
+ "type": "folder",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/folderA.json b/qa/libcmis/data/onedrive/folderA.json
new file mode 100644
index 0000000..d44cdf3
--- /dev/null
+++ b/qa/libcmis/data/onedrive/folderA.json
@@ -0,0 +1,23 @@
+{
+ "id": "folderA",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "SkyDrive",
+ "description": "short description",
+ "parent_id": null,
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "link": "linkUrl",
+ "type": "folder",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/folderB.json b/qa/libcmis/data/onedrive/folderB.json
new file mode 100644
index 0000000..1a69b00
--- /dev/null
+++ b/qa/libcmis/data/onedrive/folderB.json
@@ -0,0 +1,23 @@
+{
+ "id": "folderB",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "Folder B",
+ "description": "short description",
+ "parent_id": "folderA",
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "link": "linkUrl",
+ "type": "folder",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/folderC.json b/qa/libcmis/data/onedrive/folderC.json
new file mode 100644
index 0000000..f7b9854
--- /dev/null
+++ b/qa/libcmis/data/onedrive/folderC.json
@@ -0,0 +1,23 @@
+{
+ "id": "folderC",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "Folder C",
+ "description": "short description",
+ "parent_id": "folderB",
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "link": "linkUrl",
+ "type": "folder",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/new-file.json b/qa/libcmis/data/onedrive/new-file.json
new file mode 100644
index 0000000..0564a51
--- /dev/null
+++ b/qa/libcmis/data/onedrive/new-file.json
@@ -0,0 +1,5 @@
+{
+ "id": "aFileId",
+ "name": "OneDrive File",
+ "source": "sourceUrl"
+}
diff --git a/qa/libcmis/data/onedrive/parent-folder.json b/qa/libcmis/data/onedrive/parent-folder.json
new file mode 100644
index 0000000..972c926
--- /dev/null
+++ b/qa/libcmis/data/onedrive/parent-folder.json
@@ -0,0 +1,23 @@
+{
+ "id": "aParentId",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDrive Folder",
+ "description": "short description",
+ "parent_id": null,
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "link": "linkUrl",
+ "type": "folder",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/refresh-response.json b/qa/libcmis/data/onedrive/refresh-response.json
new file mode 100644
index 0000000..abc8f01
--- /dev/null
+++ b/qa/libcmis/data/onedrive/refresh-response.json
@@ -0,0 +1,8 @@
+{
+ "token_type":"bearer",
+ "expires_in":3600,
+ "scope":"wl.signin wl.skydrive",
+ "access_token":"new-access-token",
+ "refresh_token":"mock-refresh-token",
+ "user_id":"mock-user-id"
+}
diff --git a/qa/libcmis/data/onedrive/search-result.json b/qa/libcmis/data/onedrive/search-result.json
new file mode 100644
index 0000000..2482429
--- /dev/null
+++ b/qa/libcmis/data/onedrive/search-result.json
@@ -0,0 +1,52 @@
+{
+ "data":[
+ {
+ "id":"wrongFileId",
+ "from":{
+ "name":"aOneDriveUser",
+ "id":"1b4a1bc1bdb25a14"
+ },
+ "name":"OneDriveFile",
+ "description":"",
+ "parent_id":"folderA",
+ "size":18047,
+ "upload_location":"https://apis.live.net/v5.0/wrongFileId/content/",
+ "comments_count":0,
+ "comments_enabled":false,
+ "is_embeddable":true,
+ "source":"sourceUrl",
+ "link":"link",
+ "type":"file",
+ "shared_with":{
+ "access":"Just me"
+ },
+ "created_time":"2014-07-17T15:16:43+0000",
+ "updated_time":"2014-07-17T15:41:45+0000",
+ "client_updated_time":"2014-07-17T15:41:45+0000"
+ },
+ {
+ "id":"rightFile",
+ "from":{
+ "name":"aOneDriveUser",
+ "id":"1b4a1bc1bdb25a14"
+ },
+ "name":"OneDriveFile",
+ "description":"",
+ "parent_id":"folderC",
+ "size":4,
+ "upload_location":"https://apis.live.net/v5.0/rightFileId/content/",
+ "comments_count":0,
+ "comments_enabled":false,
+ "is_embeddable":true,
+ "source":"sourceUrl",
+ "link":"link",
+ "type":"file",
+ "shared_with":{
+ "access":"Just me"
+ },
+ "created_time":"2014-06-17T11:30:14+0000",
+ "updated_time":"2014-06-17T11:30:14+0000",
+ "client_updated_time":"2014-06-17T11:30:14+0000"
+ }
+ ]
+}
diff --git a/qa/libcmis/data/onedrive/searched-file.json b/qa/libcmis/data/onedrive/searched-file.json
new file mode 100644
index 0000000..9a3785c
--- /dev/null
+++ b/qa/libcmis/data/onedrive/searched-file.json
@@ -0,0 +1,24 @@
+{
+ "id": "rightFile",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDriveFile",
+ "description": "short description",
+ "parent_id": "folderC",
+ "size": 42,
+ "upload_location": "https://base/url/aFileId/content",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "source": "sourceUrl",
+ "link": "linkUrl",
+ "type": "file",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/searched-wrong-file.json b/qa/libcmis/data/onedrive/searched-wrong-file.json
new file mode 100644
index 0000000..4ce9d14
--- /dev/null
+++ b/qa/libcmis/data/onedrive/searched-wrong-file.json
@@ -0,0 +1,24 @@
+{
+ "id": "wrongFile",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "OneDriveFile",
+ "description": "short description",
+ "parent_id": "folderA",
+ "size": 42,
+ "upload_location": "https://base/url/aFileId/content",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "source": "sourceUrl",
+ "link": "linkUrl",
+ "type": "file",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "2014-06-09T08:24:04+0000",
+ "updated_time": "2014-06-09T08:24:04+0000",
+ "client_updated_time": "2014-06-09T08:24:04+0000"
+}
diff --git a/qa/libcmis/data/onedrive/token-response.json b/qa/libcmis/data/onedrive/token-response.json
new file mode 100644
index 0000000..93d8ea6
--- /dev/null
+++ b/qa/libcmis/data/onedrive/token-response.json
@@ -0,0 +1,8 @@
+{
+ "token_type":"bearer",
+ "expires_in":3600,
+ "scope":"wl.signin wl.skydrive",
+ "access_token":"mock-access-token",
+ "refresh_token":"mock-refresh-token",
+ "user_id":"mock-user-id"
+}
diff --git a/qa/libcmis/data/onedrive/updated-file.json b/qa/libcmis/data/onedrive/updated-file.json
new file mode 100644
index 0000000..d135ae9
--- /dev/null
+++ b/qa/libcmis/data/onedrive/updated-file.json
@@ -0,0 +1,24 @@
+{
+ "id": "aNewFileId",
+ "from": {
+ "name": "onedriveUser",
+ "id": "aUserId"
+ },
+ "name": "New File Name",
+ "description": "new description",
+ "parent_id": "aParentId",
+ "size": 42,
+ "upload_location": "uploadLocation",
+ "comments_count": 0,
+ "comments_enabled": true,
+ "is_embeddable": true,
+ "source": "sourceUrl",
+ "link": "linkUrl",
+ "type": "file",
+ "shared_with": {
+ "access": "Shared"
+ },
+ "created_time": "createdTime",
+ "updated_time": "updatedTime",
+ "client_updated_time": "clientUpdatedTime"
+}
diff --git a/qa/libcmis/data/sharepoint/auth-resp.json b/qa/libcmis/data/sharepoint/auth-resp.json
new file mode 100644
index 0000000..c238467
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/auth-resp.json
@@ -0,0 +1,191 @@
+{
+ "d":{
+ "AllProperties":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/AllProperties"
+ }
+ },
+ "AllowRssFeeds":true,
+ "AppInstanceId":"00000000-0000-0000-0000-000000000000",
+ "AssociatedMemberGroup":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/AssociatedMemberGroup"
+ }
+ },
+ "AssociatedOwnerGroup":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/AssociatedOwnerGroup"
+ }
+ },
+ "AssociatedVisitorGroup":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/AssociatedVisitorGroup"
+ }
+ },
+ "AvailableContentTypes":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/AvailableContentTypes"
+ }
+ },
+ "AvailableFields":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/AvailableFields"
+ }
+ },
+ "Configuration":0,
+ "ContentTypes":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/ContentTypes"
+ }
+ },
+ "Created":"2014-07-02T13:55:23",
+ "CurrentUser":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/CurrentUser"
+ }
+ },
+ "CustomMasterUrl":"/_catalogs/masterpage/seattle.master",
+ "Description":"",
+ "DocumentLibraryCalloutOfficeWebAppPreviewersDisabled":false,
+ "EnableMinimalDownload":false,
+ "EventReceivers":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/EventReceivers"
+ }
+ },
+ "Features":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/Features"
+ }
+ },
+ "Fields":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/Fields"
+ }
+ },
+ "FirstUniqueAncestorSecurableObject":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/FirstUniqueAncestorSecurableObject"
+ }
+ },
+ "Folders":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/Folders"
+ }
+ },
+ "Id":"98a58f26-7ed4-436c-917b-05fa37e06ab2",
+ "Language":1033,
+ "LastItemModifiedDate":"2014-07-03T10:51:32Z",
+ "ListTemplates":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/ListTemplates"
+ }
+ },
+ "Lists":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/Lists"
+ }
+ },
+ "MasterUrl":"/_catalogs/masterpage/seattle.master",
+ "Navigation":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/Navigation"
+ }
+ },
+ "ParentWeb":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/ParentWeb"
+ }
+ },
+ "PushNotificationSubscribers":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/PushNotificationSubscribers"
+ }
+ },
+ "QuickLaunchEnabled":true,
+ "RecycleBin":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/RecycleBin"
+ }
+ },
+ "RecycleBinEnabled":true,
+ "RegionalSettings":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/RegionalSettings"
+ }
+ },
+ "RoleAssignments":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/RoleAssignments"
+ }
+ },
+ "RoleDefinitions":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/RoleDefinitions"
+ }
+ },
+ "RootFolder":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/RootFolder"
+ }
+ },
+ "ServerRelativeUrl":"/",
+ "SiteGroups":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/SiteGroups"
+ }
+ },
+ "SiteUserInfoList":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/SiteUserInfoList"
+ }
+ },
+ "SiteUsers":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/SiteUsers"
+ }
+ },
+ "SyndicationEnabled":true,
+ "ThemeInfo":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/ThemeInfo"
+ }
+ },
+ "Title":"Home",
+ "TreeViewEnabled":false,
+ "UIVersion":15,
+ "UIVersionConfigurationEnabled":false,
+ "Url":"http://sp-cmis.cloudapp.net",
+ "UserCustomActions":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/UserCustomActions"
+ }
+ },
+ "WebInfos":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/WebInfos"
+ }
+ },
+ "WebTemplate":"STS",
+ "Webs":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/Webs"
+ }
+ },
+ "WorkflowAssociations":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/WorkflowAssociations"
+ }
+ },
+ "WorkflowTemplates":{
+ "__deferred":{
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web/WorkflowTemplates"
+ }
+ },
+ "__metadata":{
+ "id":"http://sp-cmis.cloudapp.net/_api/Web",
+ "type":"SP.Web",
+ "uri":"http://sp-cmis.cloudapp.net/_api/Web"
+ }
+ }
+} \ No newline at end of file
diff --git a/qa/libcmis/data/sharepoint/auth-xml-resp.xml b/qa/libcmis/data/sharepoint/auth-xml-resp.xml
new file mode 100644
index 0000000..1bf3396
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/auth-xml-resp.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xml:base="http://mock/_api/">
+ <id>http://mock/_api/Web</id>
+ <category term="SP.Web" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
+ <link rel="edit" href="Web" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/FirstUniqueAncestorSecurableObject" type="application/atom+xml;type=entry" title="FirstUniqueAncestorSecurableObject" href="Web/FirstUniqueAncestorSecurableObject" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RoleAssignments" type="application/atom+xml;type=feed" title="RoleAssignments" href="Web/RoleAssignments" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AllProperties" type="application/atom+xml;type=entry" title="AllProperties" href="Web/AllProperties" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AssociatedMemberGroup" type="application/atom+xml;type=entry" title="AssociatedMemberGroup" href="Web/AssociatedMemberGroup" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AssociatedOwnerGroup" type="application/atom+xml;type=entry" title="AssociatedOwnerGroup" href="Web/AssociatedOwnerGroup" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AssociatedVisitorGroup" type="application/atom+xml;type=entry" title="AssociatedVisitorGroup" href="Web/AssociatedVisitorGroup" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AvailableContentTypes" type="application/atom+xml;type=feed" title="AvailableContentTypes" href="Web/AvailableContentTypes" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/AvailableFields" type="application/atom+xml;type=feed" title="AvailableFields" href="Web/AvailableFields" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ContentTypes" type="application/atom+xml;type=feed" title="ContentTypes" href="Web/ContentTypes" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CurrentUser" type="application/atom+xml;type=entry" title="CurrentUser" href="Web/CurrentUser" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/EventReceivers" type="application/atom+xml;type=feed" title="EventReceivers" href="Web/EventReceivers" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Features" type="application/atom+xml;type=feed" title="Features" href="Web/Features" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Fields" type="application/atom+xml;type=feed" title="Fields" href="Web/Fields" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Folders" type="application/atom+xml;type=feed" title="Folders" href="Web/Folders" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Lists" type="application/atom+xml;type=feed" title="Lists" href="Web/Lists" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ListTemplates" type="application/atom+xml;type=feed" title="ListTemplates" href="Web/ListTemplates" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Navigation" type="application/atom+xml;type=entry" title="Navigation" href="Web/Navigation" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ParentWeb" type="application/atom+xml;type=entry" title="ParentWeb" href="Web/ParentWeb" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/PushNotificationSubscribers" type="application/atom+xml;type=feed" title="PushNotificationSubscribers" href="Web/PushNotificationSubscribers" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RecycleBin" type="application/atom+xml;type=feed" title="RecycleBin" href="Web/RecycleBin" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RegionalSettings" type="application/atom+xml;type=entry" title="RegionalSettings" href="Web/RegionalSettings" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RoleDefinitions" type="application/atom+xml;type=feed" title="RoleDefinitions" href="Web/RoleDefinitions" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RootFolder" type="application/atom+xml;type=entry" title="RootFolder" href="Web/RootFolder" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/SiteGroups" type="application/atom+xml;type=feed" title="SiteGroups" href="Web/SiteGroups" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/SiteUserInfoList" type="application/atom+xml;type=entry" title="SiteUserInfoList" href="Web/SiteUserInfoList" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/SiteUsers" type="application/atom+xml;type=feed" title="SiteUsers" href="Web/SiteUsers" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ThemeInfo" type="application/atom+xml;type=entry" title="ThemeInfo" href="Web/ThemeInfo" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/UserCustomActions" type="application/atom+xml;type=feed" title="UserCustomActions" href="Web/UserCustomActions" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Webs" type="application/atom+xml;type=feed" title="Webs" href="Web/Webs" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/WebInfos" type="application/atom+xml;type=feed" title="WebInfos" href="Web/WebInfos" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/WorkflowAssociations" type="application/atom+xml;type=feed" title="WorkflowAssociations" href="Web/WorkflowAssociations" />
+ <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/WorkflowTemplates" type="application/atom+xml;type=feed" title="WorkflowTemplates" href="Web/WorkflowTemplates" />
+ <title />
+ <updated>2014-07-10T07:24:26Z</updated>
+ <author>
+ <name />
+ </author>
+ <content type="application/xml">
+ <m:properties>
+ <d:AllowRssFeeds m:type="Edm.Boolean">true</d:AllowRssFeeds>
+ <d:AppInstanceId m:type="Edm.Guid">00000000-0000-0000-0000-000000000000</d:AppInstanceId>
+ <d:Configuration m:type="Edm.Int16">0</d:Configuration>
+ <d:Created m:type="Edm.DateTime">2014-07-02T13:55:23</d:Created>
+ <d:CustomMasterUrl>/_catalogs/masterpage/seattle.master</d:CustomMasterUrl>
+ <d:Description />
+ <d:DocumentLibraryCalloutOfficeWebAppPreviewersDisabled m:type="Edm.Boolean">false</d:DocumentLibraryCalloutOfficeWebAppPreviewersDisabled>
+ <d:EnableMinimalDownload m:type="Edm.Boolean">false</d:EnableMinimalDownload>
+ <d:Id m:type="Edm.Guid">98a58f26-7ed4-436c-917b-05fa37e06ab2</d:Id>
+ <d:Language m:type="Edm.Int32">1033</d:Language>
+ <d:LastItemModifiedDate m:type="Edm.DateTime">2014-07-08T09:29:30Z</d:LastItemModifiedDate>
+ <d:MasterUrl>/_catalogs/masterpage/seattle.master</d:MasterUrl>
+ <d:QuickLaunchEnabled m:type="Edm.Boolean">true</d:QuickLaunchEnabled>
+ <d:RecycleBinEnabled m:type="Edm.Boolean">true</d:RecycleBinEnabled>
+ <d:ServerRelativeUrl>/</d:ServerRelativeUrl>
+ <d:SyndicationEnabled m:type="Edm.Boolean">true</d:SyndicationEnabled>
+ <d:Title>Home</d:Title>
+ <d:TreeViewEnabled m:type="Edm.Boolean">false</d:TreeViewEnabled>
+ <d:UIVersion m:type="Edm.Int32">15</d:UIVersion>
+ <d:UIVersionConfigurationEnabled m:type="Edm.Boolean">false</d:UIVersionConfigurationEnabled>
+ <d:Url>http://mock</d:Url>
+ <d:WebTemplate>STS</d:WebTemplate>
+ </m:properties>
+ </content>
+</entry>
diff --git a/qa/libcmis/data/sharepoint/author.json b/qa/libcmis/data/sharepoint/author.json
new file mode 100644
index 0000000..91eb0fb
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/author.json
@@ -0,0 +1,28 @@
+{
+ "d":{
+ "Email":"",
+ "Groups":{
+ "__deferred":{
+ "uri":"http://mock/_api/Web/GetUserById(1)/Groups"
+ }
+ },
+ "Id":1,
+ "IsHiddenInUI":false,
+ "IsSiteAdmin":true,
+ "LoginName":"i:0#.w|sp-cmis\\aUserId",
+ "PrincipalType":1,
+ "Title":"aUserId",
+ "UserId":{
+ "NameId":"s-1-5-21-1673017749-4204619129-3521412262-500",
+ "NameIdIssuer":"urn:office:idp:activedirectory",
+ "__metadata":{
+ "type":"SP.UserIdInfo"
+ }
+ },
+ "__metadata":{
+ "id":"http://mock/_api/Web/GetUserById(1)",
+ "type":"SP.User",
+ "uri":"http://mock/_api/Web/GetUserById(1)"
+ }
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/children-files.json b/qa/libcmis/data/sharepoint/children-files.json
new file mode 100644
index 0000000..b09d46e
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/children-files.json
@@ -0,0 +1,60 @@
+{
+ "d":{
+ "results":[
+ {
+ "Author":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/Author"
+ }
+ },
+ "CheckInComment":"aCheckinComment",
+ "CheckOutType":2,
+ "CheckedOutByUser":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/CheckedOutByUser"
+ }
+ },
+ "ContentTag":"{AD7FC895-3E19-4553-AD77-9ADFC2A3B69A},1,2",
+ "CustomizedPageStatus":0,
+ "ETag":"\"{AD7FC895-3E19-4553-AD77-9ADFC2A3B69A},1\"",
+ "Exists":true,
+ "Length":"18045",
+ "Level":1,
+ "ListItemAllFields":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/ListItemAllFields"
+ }
+ },
+ "LockedByUser":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/LockedByUser"
+ }
+ },
+ "MajorVersion":2,
+ "MinorVersion":0,
+ "ModifiedBy":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/ModifiedBy"
+ }
+ },
+ "Name":"SharePoint File",
+ "ServerRelative_api/Web":"/Shared Documents/file.txt",
+ "TimeCreated":"2014-07-08T09:29:29Z",
+ "TimeLastModified":"2014-07-08T09:29:29Z",
+ "Title":"",
+ "UIVersion":512,
+ "UIVersionLabel":"1.0",
+ "Versions":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/Versions"
+ }
+ },
+ "__metadata":{
+ "id":"http://base/_api/Web/aFileId",
+ "type":"SP.File",
+ "uri":"http://base/_api/Web/aFileId"
+ }
+ }
+ ]
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/children-folders.json b/qa/libcmis/data/sharepoint/children-folders.json
new file mode 100644
index 0000000..25e4cb2
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/children-folders.json
@@ -0,0 +1,42 @@
+{
+ "d": {
+ "results":[
+ {
+ "Files": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/Files"
+ }
+ },
+ "Folders": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/Folders"
+ }
+ },
+ "ItemCount": 3,
+ "ListItemAllFields": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/ListItemAllFields"
+ }
+ },
+ "Name": "SharePoint Folder",
+ "ParentFolder": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/ParentFolder"
+ }
+ },
+ "Properties": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/Properties"
+ }
+ },
+ "ServerRelativeUrl": "/Shared Documents",
+ "WelcomePage": "",
+ "__metadata": {
+ "id": "http://base/_api/Web/aFolderId",
+ "type": "SP.Folder",
+ "uri": "http://base/_api/Web/aFolderId"
+ }
+ }
+ ]
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/file-v1.json b/qa/libcmis/data/sharepoint/file-v1.json
new file mode 100644
index 0000000..a40382e
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/file-v1.json
@@ -0,0 +1,56 @@
+{
+ "d":{
+ "Author":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/Author"
+ }
+ },
+ "CheckInComment":"aCheckinComment",
+ "CheckOutType":2,
+ "CheckedOutByUser":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/CheckedOutByUser"
+ }
+ },
+ "ContentTag":"{AD7FC895-3E19-4553-AD77-9ADFC2A3B69A},1,2",
+ "CustomizedPageStatus":0,
+ "ETag":"\"{AD7FC895-3E19-4553-AD77-9ADFC2A3B69A},1\"",
+ "Exists":true,
+ "Length":"18045",
+ "Level":1,
+ "ListItemAllFields":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/ListItemAllFields"
+ }
+ },
+ "LockedByUser":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/LockedByUser"
+ }
+ },
+ "MajorVersion":2,
+ "MinorVersion":0,
+ "ModifiedBy":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/ModifiedBy"
+ }
+ },
+ "Name":"SharePointFile",
+ "ServerRelativeUrl":"/Shared Documents/file.txt",
+ "TimeCreated":"2014-07-08T09:29:29Z",
+ "TimeLastModified":"2014-07-08T09:29:29Z",
+ "Title":"",
+ "UIVersion":512,
+ "UIVersionLabel":"1.0",
+ "Versions":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/Versions"
+ }
+ },
+ "__metadata":{
+ "id":"http://base/_api/Web/aFileId-v1",
+ "type":"SP.File",
+ "uri":"http://base/_api/Web/aFileId-v1"
+ }
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/file.json b/qa/libcmis/data/sharepoint/file.json
new file mode 100644
index 0000000..16d92a7
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/file.json
@@ -0,0 +1,56 @@
+{
+ "d":{
+ "Author":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/Author"
+ }
+ },
+ "CheckInComment":"aCheckinComment",
+ "CheckOutType":2,
+ "CheckedOutByUser":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/CheckedOutByUser"
+ }
+ },
+ "ContentTag":"{AD7FC895-3E19-4553-AD77-9ADFC2A3B69A},1,2",
+ "CustomizedPageStatus":0,
+ "ETag":"\"{AD7FC895-3E19-4553-AD77-9ADFC2A3B69A},1\"",
+ "Exists":true,
+ "Length":"18045",
+ "Level":1,
+ "ListItemAllFields":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/ListItemAllFields"
+ }
+ },
+ "LockedByUser":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/LockedByUser"
+ }
+ },
+ "MajorVersion":2,
+ "MinorVersion":0,
+ "ModifiedBy":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/ModifiedBy"
+ }
+ },
+ "Name":"SharePointFile",
+ "ServerRelativeUrl":"/Shared Documents/file.txt",
+ "TimeCreated":"2014-07-08T09:29:29Z",
+ "TimeLastModified":"2014-07-08T09:29:29Z",
+ "Title":"",
+ "UIVersion":512,
+ "UIVersionLabel":"1.0",
+ "Versions":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/aFileId/Versions"
+ }
+ },
+ "__metadata":{
+ "id":"http://base/_api/Web/aFileId",
+ "type":"SP.File",
+ "uri":"http://base/_api/Web/aFileId"
+ }
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/folder-properties.json b/qa/libcmis/data/sharepoint/folder-properties.json
new file mode 100644
index 0000000..44147a9
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/folder-properties.json
@@ -0,0 +1,35 @@
+{
+ "d": {
+ "__metadata": {
+ "id": "http://base/_api/web/aFolderId/properties",
+ "type": "SP.PropertyValues",
+ "uri": "http://base/_api/web/aFolderId/properties"
+ },
+ "vti_x005f_candeleteversion": "true",
+ "vti_x005f_dirlateststamp": "2014-07-28T16:10:28",
+ "vti_x005f_docstoretype": 1,
+ "vti_x005f_etag": "\"{61A348A0-D6D6-4B67-91E9-FFC87CCDE1BF},0\"",
+ "vti_x005f_folderitemcount": 3,
+ "vti_x005f_foldersubfolderitemcount": 0,
+ "vti_x005f_hassubdirs": "true",
+ "vti_x005f_isbrowsable": "true",
+ "vti_x005f_isexecutable": "false",
+ "vti_x005f_isscriptable": "false",
+ "vti_x005f_level": 1,
+ "vti_x005f_listbasetype": 1,
+ "vti_x005f_listenableminorversions": "true",
+ "vti_x005f_listenablemoderation": "false",
+ "vti_x005f_listenableversioning": "true",
+ "vti_x005f_listname": "{D0014F89-052C-4F0A-A65D-A61DFC837093}",
+ "vti_x005f_listrequirecheckout": "false",
+ "vti_x005f_listservertemplate": 101,
+ "vti_x005f_listtitle": "Documents",
+ "vti_x005f_metainfoversion": 1,
+ "vti_x005f_nexttolasttimemodified": "2014-07-08T09:29:29",
+ "vti_x005f_parentid": "{F3A8C5D9-525D-4BEB-A9DF-4CA122A5D074}",
+ "vti_x005f_replid": "rid:{61A348A0-D6D6-4B67-91E9-FFC87CCDE1BF}",
+ "vti_x005f_rtag": "rt:61A348A0-D6D6-4B67-91E9-FFC87CCDE1BF@00000000000",
+ "vti_x005f_timecreated": "2014-07-02T14:19:02",
+ "vti_x005f_timelastmodified": "2014-07-14T09:15:56"
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/folder.json b/qa/libcmis/data/sharepoint/folder.json
new file mode 100644
index 0000000..da658eb
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/folder.json
@@ -0,0 +1,38 @@
+{
+ "d": {
+ "Files": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/Files"
+ }
+ },
+ "Folders": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/Folders"
+ }
+ },
+ "ItemCount": 3,
+ "ListItemAllFields": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/ListItemAllFields"
+ }
+ },
+ "Name": "SharePointFolder",
+ "ParentFolder": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/ParentFolder"
+ }
+ },
+ "Properties": {
+ "__deferred": {
+ "uri": "http://base/_api/Web/aFolderId/Properties"
+ }
+ },
+ "ServerRelativeUrl": "/SharePointFolder",
+ "WelcomePage": "",
+ "__metadata": {
+ "id": "http://base/_api/Web/aFolderId",
+ "type": "SP.Folder",
+ "uri": "http://base/_api/Web/aFolderId"
+ }
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/new-xdigest.json b/qa/libcmis/data/sharepoint/new-xdigest.json
new file mode 100644
index 0000000..7d92f57
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/new-xdigest.json
@@ -0,0 +1,20 @@
+{
+ "d":{
+ "GetContextWebInformation":{
+ "FormDigestTimeoutSeconds":1800,
+ "FormDigestValue":"new-xdigest-code",
+ "LibraryVersion":"15.0.4420.1017",
+ "SiteFullUrl":"http://base/_api",
+ "SupportedSchemaVersions":{
+ "results":[
+ "14.0.0.0",
+ "15.0.0.0"
+ ]
+ },
+ "WebFullUrl":"http://base/_api",
+ "__metadata":{
+ "type":"SP.ContextWebInformation"
+ }
+ }
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/root-folder.json b/qa/libcmis/data/sharepoint/root-folder.json
new file mode 100644
index 0000000..7e60969
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/root-folder.json
@@ -0,0 +1,38 @@
+{
+ "d":{
+ "Files":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/rootFolderId/Files"
+ }
+ },
+ "Folders":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/rootFolderId/Folders"
+ }
+ },
+ "ItemCount":0,
+ "ListItemAllFields":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/rootFolderId/ListItemAllFields"
+ }
+ },
+ "Name":"",
+ "ParentFolder":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/rootFolderId/ParentFolder"
+ }
+ },
+ "Properties":{
+ "__deferred":{
+ "uri":"http://base/_api/Web/rootFolderId/Properties"
+ }
+ },
+ "ServerRelativeUrl":"/",
+ "WelcomePage":"SitePages/Home.aspx",
+ "__metadata":{
+ "id":"http://base/_api/Web/rootFolderId",
+ "type":"SP.Folder",
+ "uri":"http://base/_api/Web/rootFolderId"
+ }
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/versions.json b/qa/libcmis/data/sharepoint/versions.json
new file mode 100644
index 0000000..83b7f5a
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/versions.json
@@ -0,0 +1,44 @@
+{
+ "d": {
+ "results": [
+ {
+ "CheckInComment": "checkin Comment",
+ "Created": "2014-07-25T12:07:57Z",
+ "CreatedBy": {
+ "__deferred": {
+ "uri": "http://sp-cmis.cloudapp.net/_api/SP.FileVersionc617ba22-0ea6-4d05-a9ac-6135d8cede1a/CreatedBy"
+ }
+ },
+ "ID": 1,
+ "IsCurrentVersion": true,
+ "Size": 14027,
+ "Url": "_vti_history/512/Shared Documents/File Name",
+ "VersionLabel": "1.0",
+ "__metadata": {
+ "id": "http://sp-cmis.cloudapp.net/_api/SP.FileVersionc617ba22-0ea6-4d05-a9ac-6135d8cede1a",
+ "type": "SP.FileVersion",
+ "uri": "http://sp-cmis.cloudapp.net/_api/SP.FileVersionc617ba22-0ea6-4d05-a9ac-6135d8cede1a"
+ }
+ },
+ {
+ "CheckInComment": "checkin Comment",
+ "Created": "2014-07-25T12:13:47Z",
+ "CreatedBy": {
+ "__deferred": {
+ "uri": "http://sp-cmis.cloudapp.net/_api/SP.FileVersion5e4560d1-2047-4d3d-9f14-5be91aaf1f6c/CreatedBy"
+ }
+ },
+ "ID": 2,
+ "IsCurrentVersion": false,
+ "Size": 14120,
+ "Url": "_vti_history/513/Shared Documents/File Name",
+ "VersionLabel": "1.1",
+ "__metadata": {
+ "id": "http://sp-cmis.cloudapp.net/_api/SP.FileVersion5e4560d1-2047-4d3d-9f14-5be91aaf1f6c",
+ "type": "SP.FileVersion",
+ "uri": "http://sp-cmis.cloudapp.net/_api/SP.FileVersion5e4560d1-2047-4d3d-9f14-5be91aaf1f6c"
+ }
+ }
+ ]
+ }
+}
diff --git a/qa/libcmis/data/sharepoint/xdigest.json b/qa/libcmis/data/sharepoint/xdigest.json
new file mode 100644
index 0000000..661502f
--- /dev/null
+++ b/qa/libcmis/data/sharepoint/xdigest.json
@@ -0,0 +1,20 @@
+{
+ "d":{
+ "GetContextWebInformation":{
+ "FormDigestTimeoutSeconds":1800,
+ "FormDigestValue":"0xEBC52E4F66DE48475242A8F8291E9C6CAE1C71525B2EFFC8100F87746F4A5780E5EFCA2ABF063C8B3B08B987EBF56BF7ADE4A94714934D2C3928E060FBA4009A,14 Jul 2014 08:31:38 -0000",
+ "LibraryVersion":"15.0.4420.1017",
+ "SiteFullUrl":"http://base/_api",
+ "SupportedSchemaVersions":{
+ "results":[
+ "14.0.0.0",
+ "15.0.0.0"
+ ]
+ },
+ "WebFullUrl":"http://base/_api",
+ "__metadata":{
+ "type":"SP.ContextWebInformation"
+ }
+ }
+ }
+}
diff --git a/qa/libcmis/data/ws/CMISWS-Service.wsdl b/qa/libcmis/data/ws/CMISWS-Service.wsdl
new file mode 100644
index 0000000..5c998a6
--- /dev/null
+++ b/qa/libcmis/data/ws/CMISWS-Service.wsdl
@@ -0,0 +1,1262 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Content Management Interoperability Services (CMIS) Version 1.1
+ Committee Specification 01
+ 12 November 2012
+ Copyright (c) OASIS Open 2012. All Rights Reserved.
+ Source: http://docs.oasis-open.org/cmis/CMIS/v1.1/cs01/schema/
+ -->
+<!--
+ CMIS 1.1 WSDL
+ -->
+<definitions xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmisw="http://docs.oasis-open.org/ns/cmis/ws/200908/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" targetNamespace="http://docs.oasis-open.org/ns/cmis/ws/200908/" name="CMISWebServices">
+ <types>
+ <xsd:schema elementFormDefault="qualified" targetNamespace="http://docs.oasis-open.org/ns/cmis/ws/200908/">
+ <xsd:import schemaLocation="CMIS-Core.xsd" namespace="http://docs.oasis-open.org/ns/cmis/core/200908/"/>
+ <xsd:import schemaLocation="CMIS-Messaging.xsd" namespace="http://docs.oasis-open.org/ns/cmis/messaging/200908/"/>
+ </xsd:schema>
+ </types>
+ <message name="cmisException">
+ <part name="fault" element="cmism:cmisFault"/>
+ </message>
+ <message name="getACLRequest">
+ <part name="parameters" element="cmism:getACL"/>
+ </message>
+ <message name="getACLResponse">
+ <part name="parameters" element="cmism:getACLResponse"/>
+ </message>
+ <message name="applyACLRequest">
+ <part name="parameters" element="cmism:applyACL"/>
+ </message>
+ <message name="applyACLResponse">
+ <part name="parameters" element="cmism:applyACLResponse"/>
+ </message>
+ <message name="queryRequest">
+ <part name="parameters" element="cmism:query"/>
+ </message>
+ <message name="queryResponse">
+ <part name="parameters" element="cmism:queryResponse"/>
+ </message>
+ <message name="getContentChangesRequest">
+ <part name="parameters" element="cmism:getContentChanges"/>
+ </message>
+ <message name="getContentChangesResponse">
+ <part name="parameters" element="cmism:getContentChangesResponse"/>
+ </message>
+ <message name="addObjectToFolderRequest">
+ <part name="parameters" element="cmism:addObjectToFolder"/>
+ </message>
+ <message name="addObjectToFolderResponse">
+ <part name="parameters" element="cmism:addObjectToFolderResponse"/>
+ </message>
+ <message name="removeObjectFromFolderRequest">
+ <part name="parameters" element="cmism:removeObjectFromFolder"/>
+ </message>
+ <message name="removeObjectFromFolderResponse">
+ <part name="parameters" element="cmism:removeObjectFromFolderResponse"/>
+ </message>
+ <message name="getDescendantsRequest">
+ <part name="parameters" element="cmism:getDescendants"/>
+ </message>
+ <message name="getDescendantsResponse">
+ <part name="parameters" element="cmism:getDescendantsResponse"/>
+ </message>
+ <message name="getChildrenRequest">
+ <part name="parameters" element="cmism:getChildren"/>
+ </message>
+ <message name="getChildrenResponse">
+ <part name="parameters" element="cmism:getChildrenResponse"/>
+ </message>
+ <message name="getFolderParentRequest">
+ <part name="parameters" element="cmism:getFolderParent"/>
+ </message>
+ <message name="getFolderParentResponse">
+ <part name="parameters" element="cmism:getFolderParentResponse"/>
+ </message>
+ <message name="getObjectParentsRequest">
+ <part name="parameters" element="cmism:getObjectParents"/>
+ </message>
+ <message name="getObjectParentsResponse">
+ <part name="parameters" element="cmism:getObjectParentsResponse"/>
+ </message>
+ <message name="getRenditionsRequest">
+ <part name="parameters" element="cmism:getRenditions"/>
+ </message>
+ <message name="getRenditionsResponse">
+ <part name="parameters" element="cmism:getRenditionsResponse"/>
+ </message>
+ <message name="getCheckedOutDocsRequest">
+ <part name="parameters" element="cmism:getCheckedOutDocs"/>
+ </message>
+ <message name="getCheckedOutDocsResponse">
+ <part name="parameters" element="cmism:getCheckedOutDocsResponse"/>
+ </message>
+ <message name="createDocumentRequest">
+ <part name="parameters" element="cmism:createDocument"/>
+ </message>
+ <message name="createDocumentResponse">
+ <part name="parameters" element="cmism:createDocumentResponse"/>
+ </message>
+ <message name="createDocumentFromSourceRequest">
+ <part name="parameters" element="cmism:createDocumentFromSource"/>
+ </message>
+ <message name="createDocumentFromSourceResponse">
+ <part name="parameters" element="cmism:createDocumentFromSourceResponse"/>
+ </message>
+ <message name="createFolderRequest">
+ <part name="parameters" element="cmism:createFolder"/>
+ </message>
+ <message name="createFolderResponse">
+ <part name="parameters" element="cmism:createFolderResponse"/>
+ </message>
+ <message name="createRelationshipRequest">
+ <part name="parameters" element="cmism:createRelationship"/>
+ </message>
+ <message name="createRelationshipResponse">
+ <part name="parameters" element="cmism:createRelationshipResponse"/>
+ </message>
+ <message name="createPolicyRequest">
+ <part name="parameters" element="cmism:createPolicy"/>
+ </message>
+ <message name="createPolicyResponse">
+ <part name="parameters" element="cmism:createPolicyResponse"/>
+ </message>
+ <message name="createItemRequest">
+ <part name="parameters" element="cmism:createItem"/>
+ </message>
+ <message name="createItemResponse">
+ <part name="parameters" element="cmism:createItemResponse"/>
+ </message>
+ <message name="getAllowableActionsRequest">
+ <part name="parameters" element="cmism:getAllowableActions"/>
+ </message>
+ <message name="getAllowableActionsResponse">
+ <part name="parameters" element="cmism:getAllowableActionsResponse"/>
+ </message>
+ <message name="getObjectRequest">
+ <part name="parameters" element="cmism:getObject"/>
+ </message>
+ <message name="getObjectResponse">
+ <part name="parameters" element="cmism:getObjectResponse"/>
+ </message>
+ <message name="getPropertiesRequest">
+ <part name="parameters" element="cmism:getProperties"/>
+ </message>
+ <message name="getPropertiesResponse">
+ <part name="parameters" element="cmism:getPropertiesResponse"/>
+ </message>
+ <message name="getObjectByPathRequest">
+ <part name="parameters" element="cmism:getObjectByPath"/>
+ </message>
+ <message name="getObjectByPathResponse">
+ <part name="parameters" element="cmism:getObjectByPathResponse"/>
+ </message>
+ <message name="getContentStreamRequest">
+ <part name="parameters" element="cmism:getContentStream"/>
+ </message>
+ <message name="getContentStreamResponse">
+ <part name="parameters" element="cmism:getContentStreamResponse"/>
+ </message>
+ <message name="updatePropertiesRequest">
+ <part name="parameters" element="cmism:updateProperties"/>
+ </message>
+ <message name="updatePropertiesResponse">
+ <part name="parameters" element="cmism:updatePropertiesResponse"/>
+ </message>
+ <message name="bulkUpdatePropertiesRequest">
+ <part name="parameters" element="cmism:bulkUpdateProperties"/>
+ </message>
+ <message name="bulkUpdatePropertiesResponse">
+ <part name="parameters" element="cmism:bulkUpdatePropertiesResponse"/>
+ </message>
+ <message name="moveObjectRequest">
+ <part name="parameters" element="cmism:moveObject"/>
+ </message>
+ <message name="moveObjectResponse">
+ <part name="parameters" element="cmism:moveObjectResponse"/>
+ </message>
+ <message name="deleteObjectRequest">
+ <part name="parameters" element="cmism:deleteObject"/>
+ </message>
+ <message name="deleteObjectResponse">
+ <part name="parameters" element="cmism:deleteObjectResponse"/>
+ </message>
+ <message name="deleteTreeRequest">
+ <part name="parameters" element="cmism:deleteTree"/>
+ </message>
+ <message name="deleteTreeResponse">
+ <part name="parameters" element="cmism:deleteTreeResponse"/>
+ </message>
+ <message name="setContentStreamRequest">
+ <part name="parameters" element="cmism:setContentStream"/>
+ </message>
+ <message name="setContentStreamResponse">
+ <part name="parameters" element="cmism:setContentStreamResponse"/>
+ </message>
+ <message name="appendContentStreamRequest">
+ <part name="parameters" element="cmism:appendContentStream"/>
+ </message>
+ <message name="appendContentStreamResponse">
+ <part name="parameters" element="cmism:appendContentStreamResponse"/>
+ </message>
+ <message name="deleteContentStreamRequest">
+ <part name="parameters" element="cmism:deleteContentStream"/>
+ </message>
+ <message name="deleteContentStreamResponse">
+ <part name="parameters" element="cmism:deleteContentStreamResponse"/>
+ </message>
+ <message name="applyPolicyRequest">
+ <part name="parameters" element="cmism:applyPolicy"/>
+ </message>
+ <message name="applyPolicyResponse">
+ <part name="parameters" element="cmism:applyPolicyResponse"/>
+ </message>
+ <message name="removePolicyRequest">
+ <part name="parameters" element="cmism:removePolicy"/>
+ </message>
+ <message name="removePolicyResponse">
+ <part name="parameters" element="cmism:removePolicyResponse"/>
+ </message>
+ <message name="getAppliedPoliciesRequest">
+ <part name="parameters" element="cmism:getAppliedPolicies"/>
+ </message>
+ <message name="getAppliedPoliciesResponse">
+ <part name="parameters" element="cmism:getAppliedPoliciesResponse"/>
+ </message>
+ <message name="getObjectRelationshipsRequest">
+ <part name="parameters" element="cmism:getObjectRelationships"/>
+ </message>
+ <message name="getObjectRelationshipsResponse">
+ <part name="parameters" element="cmism:getObjectRelationshipsResponse"/>
+ </message>
+ <message name="getRepositoriesRequest">
+ <part name="parameters" element="cmism:getRepositories"/>
+ </message>
+ <message name="getRepositoriesResponse">
+ <part name="parameters" element="cmism:getRepositoriesResponse"/>
+ </message>
+ <message name="getRepositoryInfoRequest">
+ <part name="parameters" element="cmism:getRepositoryInfo"/>
+ </message>
+ <message name="getRepositoryInfoResponse">
+ <part name="parameters" element="cmism:getRepositoryInfoResponse"/>
+ </message>
+ <message name="getTypeChildrenRequest">
+ <part name="parameters" element="cmism:getTypeChildren"/>
+ </message>
+ <message name="getTypeChildrenResponse">
+ <part name="parameters" element="cmism:getTypeChildrenResponse"/>
+ </message>
+ <message name="getTypeDescendantsRequest">
+ <part name="parameters" element="cmism:getTypeDescendants"/>
+ </message>
+ <message name="getTypeDescendantsResponse">
+ <part name="parameters" element="cmism:getTypeDescendantsResponse"/>
+ </message>
+ <message name="getTypeDefinitionRequest">
+ <part name="parameters" element="cmism:getTypeDefinition"/>
+ </message>
+ <message name="getTypeDefinitionResponse">
+ <part name="parameters" element="cmism:getTypeDefinitionResponse"/>
+ </message>
+ <message name="createTypeRequest">
+ <part name="parameters" element="cmism:createType"/>
+ </message>
+ <message name="createTypeResponse">
+ <part name="parameters" element="cmism:createTypeResponse"/>
+ </message>
+ <message name="updateTypeRequest">
+ <part name="parameters" element="cmism:updateType"/>
+ </message>
+ <message name="updateTypeResponse">
+ <part name="parameters" element="cmism:updateTypeResponse"/>
+ </message>
+ <message name="deleteTypeRequest">
+ <part name="parameters" element="cmism:deleteType"/>
+ </message>
+ <message name="deleteTypeResponse">
+ <part name="parameters" element="cmism:deleteTypeResponse"/>
+ </message>
+ <message name="checkOutRequest">
+ <part name="parameters" element="cmism:checkOut"/>
+ </message>
+ <message name="checkOutResponse">
+ <part name="parameters" element="cmism:checkOutResponse"/>
+ </message>
+ <message name="cancelCheckOutRequest">
+ <part name="parameters" element="cmism:cancelCheckOut"/>
+ </message>
+ <message name="cancelCheckOutResponse">
+ <part name="parameters" element="cmism:cancelCheckOutResponse"/>
+ </message>
+ <message name="checkInRequest">
+ <part name="parameters" element="cmism:checkIn"/>
+ </message>
+ <message name="checkInResponse">
+ <part name="parameters" element="cmism:checkInResponse"/>
+ </message>
+ <message name="getObjectOfLatestVersionRequest">
+ <part name="parameters" element="cmism:getObjectOfLatestVersion"/>
+ </message>
+ <message name="getObjectOfLatestVersionResponse">
+ <part name="parameters" element="cmism:getObjectOfLatestVersionResponse"/>
+ </message>
+ <message name="getPropertiesOfLatestVersionRequest">
+ <part name="parameters" element="cmism:getPropertiesOfLatestVersion"/>
+ </message>
+ <message name="getPropertiesOfLatestVersionResponse">
+ <part name="parameters" element="cmism:getPropertiesOfLatestVersionResponse"/>
+ </message>
+ <message name="getAllVersionsRequest">
+ <part name="parameters" element="cmism:getAllVersions"/>
+ </message>
+ <message name="getAllVersionsResponse">
+ <part name="parameters" element="cmism:getAllVersionsResponse"/>
+ </message>
+ <message name="getFolderTreeRequest">
+ <part name="parameters" element="cmism:getFolderTree"/>
+ </message>
+ <message name="getFolderTreeResponse">
+ <part name="parameters" element="cmism:getFolderTreeResponse"/>
+ </message>
+ <portType name="DiscoveryServicePort">
+ <operation name="query">
+ <input message="cmisw:queryRequest"/>
+ <output message="cmisw:queryResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getContentChanges">
+ <input message="cmisw:getContentChangesRequest"/>
+ <output message="cmisw:getContentChangesResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="MultiFilingServicePort">
+ <operation name="addObjectToFolder">
+ <input message="cmisw:addObjectToFolderRequest"/>
+ <output message="cmisw:addObjectToFolderResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="removeObjectFromFolder">
+ <input message="cmisw:removeObjectFromFolderRequest"/>
+ <output message="cmisw:removeObjectFromFolderResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="NavigationServicePort">
+ <operation name="getDescendants">
+ <input message="cmisw:getDescendantsRequest"/>
+ <output message="cmisw:getDescendantsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getChildren">
+ <input message="cmisw:getChildrenRequest"/>
+ <output message="cmisw:getChildrenResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getFolderParent">
+ <input message="cmisw:getFolderParentRequest"/>
+ <output message="cmisw:getFolderParentResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getFolderTree">
+ <input message="cmisw:getFolderTreeRequest"/>
+ <output message="cmisw:getFolderTreeResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getObjectParents">
+ <input message="cmisw:getObjectParentsRequest"/>
+ <output message="cmisw:getObjectParentsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getCheckedOutDocs">
+ <input message="cmisw:getCheckedOutDocsRequest"/>
+ <output message="cmisw:getCheckedOutDocsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="ObjectServicePort">
+ <operation name="createDocument">
+ <input message="cmisw:createDocumentRequest"/>
+ <output message="cmisw:createDocumentResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="createDocumentFromSource">
+ <input message="cmisw:createDocumentFromSourceRequest"/>
+ <output message="cmisw:createDocumentFromSourceResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="createFolder">
+ <input message="cmisw:createFolderRequest"/>
+ <output message="cmisw:createFolderResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="createRelationship">
+ <input message="cmisw:createRelationshipRequest"/>
+ <output message="cmisw:createRelationshipResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="createPolicy">
+ <input message="cmisw:createPolicyRequest"/>
+ <output message="cmisw:createPolicyResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="createItem">
+ <input message="cmisw:createItemRequest"/>
+ <output message="cmisw:createItemResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getAllowableActions">
+ <input message="cmisw:getAllowableActionsRequest"/>
+ <output message="cmisw:getAllowableActionsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getObject">
+ <input message="cmisw:getObjectRequest"/>
+ <output message="cmisw:getObjectResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getProperties">
+ <input message="cmisw:getPropertiesRequest"/>
+ <output message="cmisw:getPropertiesResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getRenditions">
+ <input message="cmisw:getRenditionsRequest"/>
+ <output message="cmisw:getRenditionsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getObjectByPath">
+ <input message="cmisw:getObjectByPathRequest"/>
+ <output message="cmisw:getObjectByPathResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getContentStream">
+ <input message="cmisw:getContentStreamRequest"/>
+ <output message="cmisw:getContentStreamResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="updateProperties">
+ <input message="cmisw:updatePropertiesRequest"/>
+ <output message="cmisw:updatePropertiesResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="bulkUpdateProperties">
+ <input message="cmisw:bulkUpdatePropertiesRequest"/>
+ <output message="cmisw:bulkUpdatePropertiesResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="moveObject">
+ <input message="cmisw:moveObjectRequest"/>
+ <output message="cmisw:moveObjectResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="deleteObject">
+ <input message="cmisw:deleteObjectRequest"/>
+ <output message="cmisw:deleteObjectResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="deleteTree">
+ <input message="cmisw:deleteTreeRequest"/>
+ <output message="cmisw:deleteTreeResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="setContentStream">
+ <input message="cmisw:setContentStreamRequest"/>
+ <output message="cmisw:setContentStreamResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="appendContentStream">
+ <input message="cmisw:appendContentStreamRequest"/>
+ <output message="cmisw:appendContentStreamResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="deleteContentStream">
+ <input message="cmisw:deleteContentStreamRequest"/>
+ <output message="cmisw:deleteContentStreamResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="PolicyServicePort">
+ <operation name="applyPolicy">
+ <input message="cmisw:applyPolicyRequest"/>
+ <output message="cmisw:applyPolicyResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="removePolicy">
+ <input message="cmisw:removePolicyRequest"/>
+ <output message="cmisw:removePolicyResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getAppliedPolicies">
+ <input message="cmisw:getAppliedPoliciesRequest"/>
+ <output message="cmisw:getAppliedPoliciesResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="RelationshipServicePort">
+ <operation name="getObjectRelationships">
+ <input message="cmisw:getObjectRelationshipsRequest"/>
+ <output message="cmisw:getObjectRelationshipsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="RepositoryServicePort">
+ <operation name="getRepositories">
+ <input message="cmisw:getRepositoriesRequest"/>
+ <output message="cmisw:getRepositoriesResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getRepositoryInfo">
+ <input message="cmisw:getRepositoryInfoRequest"/>
+ <output message="cmisw:getRepositoryInfoResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getTypeChildren">
+ <input message="cmisw:getTypeChildrenRequest"/>
+ <output message="cmisw:getTypeChildrenResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getTypeDescendants">
+ <input message="cmisw:getTypeDescendantsRequest"/>
+ <output message="cmisw:getTypeDescendantsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getTypeDefinition">
+ <input message="cmisw:getTypeDefinitionRequest"/>
+ <output message="cmisw:getTypeDefinitionResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="createType">
+ <input message="cmisw:createTypeRequest"/>
+ <output message="cmisw:createTypeResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="updateType">
+ <input message="cmisw:updateTypeRequest"/>
+ <output message="cmisw:updateTypeResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="deleteType">
+ <input message="cmisw:deleteTypeRequest"/>
+ <output message="cmisw:deleteTypeResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="VersioningServicePort">
+ <operation name="checkOut">
+ <input message="cmisw:checkOutRequest"/>
+ <output message="cmisw:checkOutResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="cancelCheckOut">
+ <input message="cmisw:cancelCheckOutRequest"/>
+ <output message="cmisw:cancelCheckOutResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="checkIn">
+ <input message="cmisw:checkInRequest"/>
+ <output message="cmisw:checkInResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getObjectOfLatestVersion">
+ <input message="cmisw:getObjectOfLatestVersionRequest"/>
+ <output message="cmisw:getObjectOfLatestVersionResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getPropertiesOfLatestVersion">
+ <input message="cmisw:getPropertiesOfLatestVersionRequest"/>
+ <output message="cmisw:getPropertiesOfLatestVersionResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="getAllVersions">
+ <input message="cmisw:getAllVersionsRequest"/>
+ <output message="cmisw:getAllVersionsResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <portType name="ACLServicePort">
+ <operation name="getACL">
+ <input message="cmisw:getACLRequest"/>
+ <output message="cmisw:getACLResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ <operation name="applyACL">
+ <input message="cmisw:applyACLRequest"/>
+ <output message="cmisw:applyACLResponse"/>
+ <fault message="cmisw:cmisException" name="cmisException"/>
+ </operation>
+ </portType>
+ <binding name="DiscoveryServicePortBinding" type="cmisw:DiscoveryServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="query">
+ <soap:operation soapAction="query"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getContentChanges">
+ <soap:operation soapAction="getContentChanges"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="MultiFilingServicePortBinding" type="cmisw:MultiFilingServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="addObjectToFolder">
+ <soap:operation soapAction="addObjectToFolder"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="removeObjectFromFolder">
+ <soap:operation soapAction="removeObjectFromFolder"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="NavigationServicePortBinding" type="cmisw:NavigationServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="getDescendants">
+ <soap:operation soapAction="getDescendants"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getChildren">
+ <soap:operation soapAction="getChildren"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getFolderParent">
+ <soap:operation soapAction="getFolderParent"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getFolderTree">
+ <soap:operation soapAction="getFolderTree"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getObjectParents">
+ <soap:operation soapAction="getObjectParents"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getCheckedOutDocs">
+ <soap:operation soapAction="getCheckedOutDocs"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="ObjectServicePortBinding" type="cmisw:ObjectServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="createDocument">
+ <soap:operation soapAction="createDocument"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="createDocumentFromSource">
+ <soap:operation soapAction="createDocumentFromSource"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="createFolder">
+ <soap:operation soapAction="createFolder"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="createRelationship">
+ <soap:operation soapAction="createRelationship"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="createPolicy">
+ <soap:operation soapAction="createPolicy"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="createItem">
+ <soap:operation soapAction=""/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getAllowableActions">
+ <soap:operation soapAction="getAllowableActions"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getObject">
+ <soap:operation soapAction="getObject"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getProperties">
+ <soap:operation soapAction="getProperties"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getRenditions">
+ <soap:operation soapAction="getRenditions"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getObjectByPath">
+ <soap:operation soapAction="getObjectByPath"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getContentStream">
+ <soap:operation soapAction="getContentStream"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="updateProperties">
+ <soap:operation soapAction="updateProperties"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="bulkUpdateProperties">
+ <soap:operation soapAction="bulkUpdateProperties"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="moveObject">
+ <soap:operation soapAction="moveObject"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="deleteObject">
+ <soap:operation soapAction="deleteObject"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="deleteTree">
+ <soap:operation soapAction="deleteTree"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="setContentStream">
+ <soap:operation soapAction="setContentStream"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="appendContentStream">
+ <soap:operation soapAction="appendContentStream"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="deleteContentStream">
+ <soap:operation soapAction="deleteContentStream"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="PolicyServicePortBinding" type="cmisw:PolicyServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="applyPolicy">
+ <soap:operation soapAction="applyPolicy"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="removePolicy">
+ <soap:operation soapAction="removePolicy"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getAppliedPolicies">
+ <soap:operation soapAction="getAppliedPolicies"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="RelationshipServicePortBinding" type="cmisw:RelationshipServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="getObjectRelationships">
+ <soap:operation soapAction="getObjectRelationships"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="RepositoryServicePortBinding" type="cmisw:RepositoryServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="getRepositories">
+ <soap:operation soapAction="getRepositories"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getRepositoryInfo">
+ <soap:operation soapAction="getRepositoryInfo"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getTypeChildren">
+ <soap:operation soapAction="getTypeChildren"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getTypeDescendants">
+ <soap:operation soapAction="getTypeDescendants"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getTypeDefinition">
+ <soap:operation soapAction="getTypeDefinition"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="createType">
+ <soap:operation soapAction="createType"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="updateType">
+ <soap:operation soapAction="updateType"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="deleteType">
+ <soap:operation soapAction="deleteType"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="VersioningServicePortBinding" type="cmisw:VersioningServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="checkOut">
+ <soap:operation soapAction="checkOut"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="cancelCheckOut">
+ <soap:operation soapAction="cancelCheckOut"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="checkIn">
+ <soap:operation soapAction="checkIn"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getObjectOfLatestVersion">
+ <soap:operation soapAction="getObjectOfLatestVersion"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getPropertiesOfLatestVersion">
+ <soap:operation soapAction="getPropertiesOfLatestVersion"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="getAllVersions">
+ <soap:operation soapAction="getAllVersions"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <binding name="ACLServicePortBinding" type="cmisw:ACLServicePort">
+ <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+ <operation name="getACL">
+ <soap:operation soapAction="getACL"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ <operation name="applyACL">
+ <soap:operation soapAction="applyACL"/>
+ <input>
+ <soap:body use="literal"/>
+ </input>
+ <output>
+ <soap:body use="literal"/>
+ </output>
+ <fault name="cmisException">
+ <soap:fault name="cmisException" use="literal"/>
+ </fault>
+ </operation>
+ </binding>
+ <service name="DiscoveryService">
+ <port name="DiscoveryServicePort" binding="cmisw:DiscoveryServicePortBinding">
+ <soap:address location="http://mockup/ws/services/DiscoveryService"/>
+ </port>
+ </service>
+ <service name="MultiFilingService">
+ <port name="MultiFilingServicePort" binding="cmisw:MultiFilingServicePortBinding">
+ <soap:address location="http://mockup/ws/services/MultiFilingService"/>
+ </port>
+ </service>
+ <service name="NavigationService">
+ <port name="NavigationServicePort" binding="cmisw:NavigationServicePortBinding">
+ <soap:address location="http://mockup/ws/services/NavigationService"/>
+ </port>
+ </service>
+ <service name="ObjectService">
+ <port name="ObjectServicePort" binding="cmisw:ObjectServicePortBinding">
+ <soap:address location="http://mockup/ws/services/ObjectService"/>
+ </port>
+ </service>
+ <service name="PolicyService">
+ <port name="PolicyServicePort" binding="cmisw:PolicyServicePortBinding">
+ <soap:address location="http://mockup/ws/services/PolicyService"/>
+ </port>
+ </service>
+ <service name="RelationshipService">
+ <port name="RelationshipServicePort" binding="cmisw:RelationshipServicePortBinding">
+ <soap:address location="http://mockup/ws/services/RelationshipService"/>
+ </port>
+ </service>
+ <service name="RepositoryService">
+ <port name="RepositoryServicePort" binding="cmisw:RepositoryServicePortBinding">
+ <soap:address location="http://mockup/ws/services/RepositoryService"/>
+ </port>
+ </service>
+ <service name="VersioningService">
+ <port name="VersioningServicePort" binding="cmisw:VersioningServicePortBinding">
+ <soap:address location="http://mockup/ws/services/VersioningService"/>
+ </port>
+ </service>
+ <service name="ACLService">
+ <port name="ACLServicePort" binding="cmisw:ACLServicePortBinding">
+ <soap:address location="http://mockup/ws/services/ACLService"/>
+ </port>
+ </service>
+</definitions>
diff --git a/qa/libcmis/data/ws/cancel-checkout.http b/qa/libcmis/data/ws/cancel-checkout.http
new file mode 100644
index 0000000..24a1c71
--- /dev/null
+++ b/qa/libcmis/data/ws/cancel-checkout.http
@@ -0,0 +1,25 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:cancelCheckOutResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/"/>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/checked-in.http b/qa/libcmis/data/ws/checked-in.http
new file mode 100644
index 0000000..0fcbb8e
--- /dev/null
+++ b/qa/libcmis/data/ws/checked-in.http
@@ -0,0 +1,144 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>2.0</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>some-other-token</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment">
+ <cmis:value>Some check-in comment</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>filename.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>true</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>true</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/checkin.http b/qa/libcmis/data/ws/checkin.http
new file mode 100644
index 0000000..80868c1
--- /dev/null
+++ b/qa/libcmis/data/ws/checkin.http
@@ -0,0 +1,27 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:checkInResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>test-document</cmism:objectId>
+ </cmism:checkInResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/checkout.http b/qa/libcmis/data/ws/checkout.http
new file mode 100644
index 0000000..dc4e6aa
--- /dev/null
+++ b/qa/libcmis/data/ws/checkout.http
@@ -0,0 +1,28 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:checkOutResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>working-copy</cmism:objectId>
+ <cmism:contentCopied>true</cmism:contentCopied>
+ </cmism:checkOutResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/create-document.http b/qa/libcmis/data/ws/create-document.http
new file mode 100644
index 0000000..fce2d65
--- /dev/null
+++ b/qa/libcmis/data/ws/create-document.http
@@ -0,0 +1,25 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:createDocumentResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>created-document</cmism:objectId>
+ </cmism:createDocumentResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/create-folder-bad-type.http b/qa/libcmis/data/ws/create-folder-bad-type.http
new file mode 100644
index 0000000..9e79cd9
--- /dev/null
+++ b/qa/libcmis/data/ws/create-folder-bad-type.http
@@ -0,0 +1,33 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <S:Fault>
+ <faultcode>S:Server</faultcode>
+ <faultstring>Can't create folder with type cmis:document</faultstring>
+ <detail>
+ <cmisFault:cmisFault xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmisFault="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/">
+ <type>constraint</type>
+ <code>562</code>
+ <message>Can't create folder with type cmis:document</message>
+ </cmisFault:cmisFault>
+ </detail>
+ </S:Fault>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/create-folder.http b/qa/libcmis/data/ws/create-folder.http
new file mode 100644
index 0000000..5abd72c
--- /dev/null
+++ b/qa/libcmis/data/ws/create-folder.http
@@ -0,0 +1,25 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:createFolderResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>created-folder</cmism:objectId>
+ </cmism:createFolderResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/created-document.http b/qa/libcmis/data/ws/created-document.http
new file mode 100644
index 0000000..72a1bc8
--- /dev/null
+++ b/qa/libcmis/data/ws/created-document.http
@@ -0,0 +1,85 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>create document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>create-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/created-folder.http b/qa/libcmis/data/ws/created-folder.http
new file mode 100644
index 0000000..0e76c03
--- /dev/null
+++ b/qa/libcmis/data/ws/created-folder.http
@@ -0,0 +1,64 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/create folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>create folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>create-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/delete-object.http b/qa/libcmis/data/ws/delete-object.http
new file mode 100644
index 0000000..eaac13d
--- /dev/null
+++ b/qa/libcmis/data/ws/delete-object.http
@@ -0,0 +1,23 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:deleteObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/"/>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/delete-tree.http b/qa/libcmis/data/ws/delete-tree.http
new file mode 100644
index 0000000..b46c680
--- /dev/null
+++ b/qa/libcmis/data/ws/delete-tree.http
@@ -0,0 +1,27 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:deleteTreeResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:failedToDelete>
+ <cmism:objectIds>bad-delete</cmism:objectIds>
+ </cmism:failedToDelete>
+ </cmism:deleteTreeResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/get-content-stream.http b/qa/libcmis/data/ws/get-content-stream.http
new file mode 100644
index 0000000..3ea7c59
--- /dev/null
+++ b/qa/libcmis/data/ws/get-content-stream.http
@@ -0,0 +1,37 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getContentStreamResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:contentStream>
+ <cmism:mimeType>text/plain</cmism:mimeType>
+ <cmism:filename>test.txt</cmism:filename>
+ <cmism:stream>
+ <xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include"
+ href="cid:stream*someid"/></cmism:stream>
+ </cmism:contentStream>
+ </cmism:getContentStreamResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <stream*someid>
+Content-Type: application/xop+xml;charset=utf-8;type="text/plain"
+Content-Transfer-Encoding: binary
+
+Some content stream
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/get-renditions.http b/qa/libcmis/data/ws/get-renditions.http
new file mode 100644
index 0000000..383c888
--- /dev/null
+++ b/qa/libcmis/data/ws/get-renditions.http
@@ -0,0 +1,41 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getRenditionsResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:renditions>
+ <cmis:streamId>test-document-rendition1</cmis:streamId>
+ <cmis:mimetype>image/png</cmis:mimetype>
+ <cmis:length>40385</cmis:length>
+ <cmis:kind>cmis:thumbnail</cmis:kind>
+ <cmis:title>picture</cmis:title>
+ <cmis:height>100</cmis:height>
+ <cmis:width>100</cmis:width>
+ </cmism:renditions>
+ <cmism:renditions>
+ <cmis:streamId>test-document-rendition2</cmis:streamId>
+ <cmis:mimetype>application/pdf</cmis:mimetype>
+ <cmis:kind>pdf</cmis:kind>
+ <cmis:title>Doc as PDF</cmis:title>
+ </cmism:renditions>
+ </cmism:getRenditionsResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/get-versions.http b/qa/libcmis/data/ws/get-versions.http
new file mode 100644
index 0000000..68e2956
--- /dev/null
+++ b/qa/libcmis/data/ws/get-versions.http
@@ -0,0 +1,204 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getAllVersionsResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objects>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>version-series</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>1.0</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206736</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document-1</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document-1</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:objects>
+ <cmism:objects>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>version-series</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>0.1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-27T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359382206754</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document-0</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-27T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document-0</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:objects>
+ </cmism:getAllVersionsResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/getbypath-bad.http b/qa/libcmis/data/ws/getbypath-bad.http
new file mode 100644
index 0000000..e641af8
--- /dev/null
+++ b/qa/libcmis/data/ws/getbypath-bad.http
@@ -0,0 +1,33 @@
+Content-Type: multipart/related;start="<rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8";start-info="text/xml"
+
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8
+Content-Id: <rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version="1.0" encoding="UTF-8"?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-30T19:54:27Z</Created>
+ <Expires>2013-10-01T19:54:27Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <S:Fault>
+ <faultcode>S:Server</faultcode>
+ <faultstring>Path '/some/invalid/path' not found</faultstring>
+ <detail>
+ <cmisFault:cmisFault xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmisFault="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/">
+ <type>objectNotFound</type>
+ <code>562</code>
+ <message>Path not found: '/some/invalid/path'</message>
+ </cmisFault:cmisFault>
+ </detail>
+ </S:Fault>
+ </S:Body>
+</S:Envelope>
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8--
+
diff --git a/qa/libcmis/data/ws/move-object.http b/qa/libcmis/data/ws/move-object.http
new file mode 100644
index 0000000..1399a33
--- /dev/null
+++ b/qa/libcmis/data/ws/move-object.http
@@ -0,0 +1,27 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:moveObjectResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>test-document</cmism:objectId>
+ </cmism:moveObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/repositories.http b/qa/libcmis/data/ws/repositories.http
new file mode 100644
index 0000000..74ae6ca
--- /dev/null
+++ b/qa/libcmis/data/ws/repositories.http
@@ -0,0 +1,25 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <ns2:getRepositoriesResponse xmlns="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <ns2:repositories><ns2:repositoryId>mock</ns2:repositoryId><ns2:repositoryName>Mockup</ns2:repositoryName></ns2:repositories>
+ </ns2:getRepositoriesResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/repository-infos-bad.http b/qa/libcmis/data/ws/repository-infos-bad.http
new file mode 100644
index 0000000..fc6e676
--- /dev/null
+++ b/qa/libcmis/data/ws/repository-infos-bad.http
@@ -0,0 +1,33 @@
+Content-Type: multipart/related;start="<rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8";start-info="text/xml"
+
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8
+Content-Id: <rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version="1.0" encoding="UTF-8"?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-30T19:54:27Z</Created>
+ <Expires>2013-10-01T19:54:27Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <S:Fault>
+ <faultcode>S:Server</faultcode>
+ <faultstring>Repository 'bad' not found</faultstring>
+ <detail>
+ <cmisFault:cmisFault xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmisFault="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/">
+ <type>invalidArgument</type>
+ <code>562</code>
+ <message>Unknown repository id: 'bad'</message>
+ </cmisFault:cmisFault>
+ </detail>
+ </S:Fault>
+ </S:Body>
+</S:Envelope>
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8--
+
diff --git a/qa/libcmis/data/ws/repository-infos.http b/qa/libcmis/data/ws/repository-infos.http
new file mode 100644
index 0000000..75f3ec8
--- /dev/null
+++ b/qa/libcmis/data/ws/repository-infos.http
@@ -0,0 +1,207 @@
+Content-Type: multipart/related;start="<rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8";start-info="text/xml"
+
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8
+Content-Id: <rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version="1.0" encoding="UTF-8"?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-30T19:54:27Z</Created>
+ <Expires>2013-10-01T19:54:27Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <getRepositoryInfoResponse xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/">
+ <repositoryInfo>
+ <cmis:repositoryId>mock</cmis:repositoryId>
+ <cmis:repositoryName>Mockup</cmis:repositoryName>
+ <cmis:repositoryDescription>Repository sent by mockup server</cmis:repositoryDescription>
+ <cmis:vendorName>libcmis</cmis:vendorName>
+ <cmis:productName>Libcmis mockup</cmis:productName>
+ <cmis:productVersion>some-version</cmis:productVersion>
+ <cmis:rootFolderId>root-folder</cmis:rootFolderId>
+ <cmis:latestChangeLogToken>0</cmis:latestChangeLogToken>
+ <cmis:capabilities>
+ <cmis:capabilityACL>manage</cmis:capabilityACL>
+ <cmis:capabilityAllVersionsSearchable>false</cmis:capabilityAllVersionsSearchable>
+ <cmis:capabilityChanges>none</cmis:capabilityChanges>
+ <cmis:capabilityContentStreamUpdatability>anytime</cmis:capabilityContentStreamUpdatability>
+ <cmis:capabilityGetDescendants>true</cmis:capabilityGetDescendants>
+ <cmis:capabilityGetFolderTree>true</cmis:capabilityGetFolderTree>
+ <cmis:capabilityMultifiling>true</cmis:capabilityMultifiling>
+ <cmis:capabilityPWCSearchable>false</cmis:capabilityPWCSearchable>
+ <cmis:capabilityPWCUpdatable>true</cmis:capabilityPWCUpdatable>
+ <cmis:capabilityQuery>bothcombined</cmis:capabilityQuery>
+ <cmis:capabilityRenditions>read</cmis:capabilityRenditions>
+ <cmis:capabilityUnfiling>true</cmis:capabilityUnfiling>
+ <cmis:capabilityVersionSpecificFiling>false</cmis:capabilityVersionSpecificFiling>
+ <cmis:capabilityJoin>none</cmis:capabilityJoin>
+ </cmis:capabilities>
+ <cmis:aclCapability>
+ <cmis:supportedPermissions>basic</cmis:supportedPermissions>
+ <cmis:propagation>objectonly</cmis:propagation>
+ <cmis:permissions>
+ <cmis:permission>cmis:read</cmis:permission>
+ <cmis:description>Read</cmis:description>
+ </cmis:permissions>
+ <cmis:permissions>
+ <cmis:permission>cmis:write</cmis:permission>
+ <cmis:description>Write</cmis:description>
+ </cmis:permissions>
+ <cmis:permissions>
+ <cmis:permission>cmis:all</cmis:permission>
+ <cmis:description>All</cmis:description>
+ </cmis:permissions>
+ <cmis:mapping>
+ <cmis:key>canGetDescendents.Folder</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetChildren.Folder</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetParents.Folder</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetFolderParent.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateDocument.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateFolder.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateRelationship.Source</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCreateRelationship.Target</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetProperties.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canViewContent.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canUpdateProperties.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canMove.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canMove.Target</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canMove.Source</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canDelete.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canDeleteTree.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canSetContent.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canDeleteContent.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddToFolder.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddToFolder.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemoveFromFolder.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemoveFromFolder.Folder</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCheckout.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCancelCheckout.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canCheckin.Document</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetAllVersions.VersionSeries</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetObjectRelationships.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddPolicy.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canAddPolicy.Policy</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemovePolicy.Object</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canRemovePolicy.Policy</cmis:key>
+ <cmis:permission>cmis:write</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetAppliedPolicies.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canGetACL.Object</cmis:key>
+ <cmis:permission>cmis:read</cmis:permission>
+ </cmis:mapping>
+ <cmis:mapping>
+ <cmis:key>canApplyACL.Object</cmis:key>
+ <cmis:permission>cmis:all</cmis:permission>
+ </cmis:mapping>
+ </cmis:aclCapability>
+ <cmis:cmisVersionSupported>1.0</cmis:cmisVersionSupported>
+ <cmis:thinClientURI/>
+ <cmis:changesIncomplete>true</cmis:changesIncomplete>
+ <cmis:principalAnonymous>anonymous</cmis:principalAnonymous>
+ <cmis:principalAnyone>anyone</cmis:principalAnyone>
+ </repositoryInfo>
+ </getRepositoryInfoResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8--
+
diff --git a/qa/libcmis/data/ws/root-children.http b/qa/libcmis/data/ws/root-children.http
new file mode 100644
index 0000000..0d43497
--- /dev/null
+++ b/qa/libcmis/data/ws/root-children.http
@@ -0,0 +1,292 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getChildrenResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objects>
+ <cmism:objects>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>33446</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:13.932Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537973932</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child1</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:13.932Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>33537</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:13.978Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537973978</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:13.978Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>33353</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 3</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:14.031Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537974031</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child3</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:14.031Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Child 4</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 4</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child4</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:12.384Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537972384</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:12.384Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Child 5</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Child 5</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>child5</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-30T09:26:13.338Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359537973338</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-30T09:26:13.338Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ </cmism:objects>
+ </cmism:objects>
+ </cmism:getChildrenResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/root-folder.http b/qa/libcmis/data/ws/root-folder.http
new file mode 100644
index 0000000..5639383
--- /dev/null
+++ b/qa/libcmis/data/ws/root-folder.http
@@ -0,0 +1,93 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Root Folder</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId"/>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>true</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>true</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>true</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>false</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>false</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>false</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>false</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>false</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>false</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>false</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>true</cmis:canGetChildren>
+ <cmis:canCreateDocument>true</cmis:canCreateDocument>
+ <cmis:canCreateFolder>true</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>true</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/secondary-type.http b/qa/libcmis/data/ws/secondary-type.http
new file mode 100644
index 0000000..0d88b5b
--- /dev/null
+++ b/qa/libcmis/data/ws/secondary-type.http
@@ -0,0 +1,57 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeDefinitionResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:type>
+ <cmis:id>secondary-type</cmis:id>
+ <cmis:localName>secondary-type</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Secondary Type</cmis:displayName>
+ <cmis:queryName>secondary-type</cmis:queryName>
+ <cmis:description>Description of Secondary Type</cmis:description>
+ <cmis:baseId>cmis:secondary</cmis:baseId>
+ <cmis:parentId>cmis:secondary</cmis:parentId>
+ <cmis:creatable>false</cmis:creatable>
+ <cmis:fileable>false</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>false</cmis:controllableACL>
+ <cmis:propertyStringDefinition>
+ <cmis:id>secondary-prop</cmis:id>
+ <cmis:localName>secondary-prop</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>secondary-prop</cmis:displayName>
+ <cmis:queryName>secondary-prop</cmis:queryName>
+ <cmis:description>This is a Secondary type property</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ </cmism:type>
+ </cmism:getTypeDefinitionResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/set-content-stream.http b/qa/libcmis/data/ws/set-content-stream.http
new file mode 100644
index 0000000..9112cc1
--- /dev/null
+++ b/qa/libcmis/data/ws/set-content-stream.http
@@ -0,0 +1,28 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:setContentStreamResponse
+ xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/"
+ xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>test-document</cmism:objectId>
+ <cmism:changeToken>set-content-token</cmism:changeToken>
+ </cmism:setContentStreamResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/test-document-add-secondary.http b/qa/libcmis/data/ws/test-document-add-secondary.http
new file mode 100644
index 0000000..88433a9
--- /dev/null
+++ b/qa/libcmis/data/ws/test-document-add-secondary.http
@@ -0,0 +1,148 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>series-id</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>some-change-token</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:secondaryObjectTypeIds" displayName="cmis:secondaryObjectTypeIds" localName="cmis:secondaryObjectTypeIds" propertyDefinitionId="cmis:secondaryObjectTypeIds">
+ <cmis:value>secondary-type</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="secondary-prop" displayName="secondary-prop" localName="secondary-prop" propertyDefinitionId="secondary-prop">
+ <cmis:value>some-value</cmis:value>
+ </cmis:propertyString>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>true</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>true</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/test-document-parents.http b/qa/libcmis/data/ws/test-document-parents.http
new file mode 100644
index 0000000..1c5e398
--- /dev/null
+++ b/qa/libcmis/data/ws/test-document-parents.http
@@ -0,0 +1,106 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectParentsResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:parents>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Parent 1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Parent 1</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>parent1</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-31T08:04:35.866Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359619475867</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-31T08:04:35.867Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Parent 2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Parent 2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>parent2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-31T08:04:35.866Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1359619475867</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-31T08:04:35.867Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ </cmism:object>
+ </cmism:parents>
+ </cmism:getObjectParentsResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/test-document-updated.http b/qa/libcmis/data/ws/test-document-updated.http
new file mode 100644
index 0000000..a5c34e9
--- /dev/null
+++ b/qa/libcmis/data/ws/test-document-updated.http
@@ -0,0 +1,140 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId"/>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>New name</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>some-new-change-token</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>true</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>true</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/test-document.http b/qa/libcmis/data/ws/test-document.http
new file mode 100644
index 0000000..890274c
--- /dev/null
+++ b/qa/libcmis/data/ws/test-document.http
@@ -0,0 +1,142 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy"/>
+ <cmis:propertyHtml queryName="HtmlProp" displayName="Sample Html Property" localName="HtmlProp" propertyDefinitionId="HtmlProp"/>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId"/>
+ <cmis:propertyId queryName="IdProp" displayName="Sample Id Property" localName="IdProp" propertyDefinitionId="IdProp"/>
+ <cmis:propertyUri queryName="UriProp" displayName="Sample Uri Property" localName="UriProp" propertyDefinitionId="UriProp"/>
+ <cmis:propertyDateTime queryName="DateTimePropMV" displayName="Sample DateTime multi-value Property" localName="DateTimePropMV" propertyDefinitionId="DateTimePropMV"/>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>series-id</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDecimal queryName="DecimalProp" displayName="Sample Decimal Property" localName="DecimalProp" propertyDefinitionId="DecimalProp"/>
+ <cmis:propertyUri queryName="UriPropMV" displayName="Sample Uri multi-value Property" localName="UriPropMV" propertyDefinitionId="UriPropMV"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel"/>
+ <cmis:propertyBoolean queryName="BooleanProp" displayName="Sample Boolean Property" localName="BooleanProp" propertyDefinitionId="BooleanProp"/>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="IdPropMV" displayName="Sample Id Html multi-value Property" localName="IdPropMV" propertyDefinitionId="IdPropMV"/>
+ <cmis:propertyString queryName="PickListProp" displayName="Sample Pick List Property" localName="PickListProp" propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyHtml queryName="HtmlPropMV" displayName="Sample Html multi-value Property" localName="HtmlPropMV" propertyDefinitionId="HtmlPropMV"/>
+ <cmis:propertyInteger queryName="IntProp" displayName="Sample Int Property" localName="IntProp" propertyDefinitionId="IntProp"/>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="StringProp" displayName="Sample String Property" localName="StringProp" propertyDefinitionId="StringProp">
+ <cmis:value>My Doc StringProperty 6</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>some-change-token</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDecimal queryName="DecimalPropMV" displayName="Sample Decimal multi-value Property" localName="DecimalPropMV" propertyDefinitionId="DecimalPropMV"/>
+ <cmis:propertyDateTime queryName="DateTimeProp" displayName="Sample DateTime Property" localName="DateTimeProp" propertyDefinitionId="DateTimeProp"/>
+ <cmis:propertyBoolean queryName="BooleanPropMV" displayName="Sample Boolean multi-value Property" localName="BooleanPropMV" propertyDefinitionId="BooleanPropMV"/>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>test-document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyInteger queryName="IntPropMV" displayName="Sample Int multi-value Property" localName="IntPropMV" propertyDefinitionId="IntPropMV"/>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-01-28T14:10:06.736Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>false</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>false</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>false</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>true</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>true</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>true</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>true</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>true</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>true</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>true</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>false</cmis:canGetChildren>
+ <cmis:canCreateDocument>false</cmis:canCreateDocument>
+ <cmis:canCreateFolder>false</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>false</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">test-document</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/type-bad.http b/qa/libcmis/data/ws/type-bad.http
new file mode 100644
index 0000000..69825e7
--- /dev/null
+++ b/qa/libcmis/data/ws/type-bad.http
@@ -0,0 +1,33 @@
+Content-Type: multipart/related;start="<rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8";start-info="text/xml"
+
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8
+Content-Id: <rootpart*abd9e41c-b3aa-40a7-a73a-997c472010e8@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version="1.0" encoding="UTF-8"?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-30T19:54:27Z</Created>
+ <Expires>2013-10-01T19:54:27Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <S:Fault>
+ <faultcode>S:Server</faultcode>
+ <faultstring>Type 'bad' not found</faultstring>
+ <detail>
+ <cmisFault:cmisFault xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmisFault="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/">
+ <type>objectNotFound</type>
+ <code>562</code>
+ <message>Unknown type id: 'bad'</message>
+ </cmisFault:cmisFault>
+ </detail>
+ </S:Fault>
+ </S:Body>
+</S:Envelope>
+--uuid:abd9e41c-b3aa-40a7-a73a-997c472010e8--
+
diff --git a/qa/libcmis/data/ws/type-docLevel1.http b/qa/libcmis/data/ws/type-docLevel1.http
new file mode 100644
index 0000000..5320af2
--- /dev/null
+++ b/qa/libcmis/data/ws/type-docLevel1.http
@@ -0,0 +1,411 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeDefinitionResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:type>
+ <cmis:id>DocumentLevel1</cmis:id>
+ <cmis:localName>DocumentLevel1</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 1</cmis:displayName>
+ <cmis:queryName>DocumentLevel1</cmis:queryName>
+ <cmis:description>Description of Document Level 1 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>cmis:document</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmism:type>
+ </cmism:getTypeDefinitionResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/type-docLevel2-secondary.http b/qa/libcmis/data/ws/type-docLevel2-secondary.http
new file mode 100644
index 0000000..7ea2313
--- /dev/null
+++ b/qa/libcmis/data/ws/type-docLevel2-secondary.http
@@ -0,0 +1,698 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeDefinitionResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:type>
+ <cmis:id>DocumentLevel2</cmis:id>
+ <cmis:localName>DocumentLevel2</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 2</cmis:displayName>
+ <cmis:queryName>DocumentLevel2</cmis:queryName>
+ <cmis:description>Description of Document Level 2 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>DocumentLevel1</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyHtmlDefinition>
+ <cmis:id>HtmlProp</cmis:id>
+ <cmis:localName>HtmlProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Html Property</cmis:displayName>
+ <cmis:queryName>HtmlProp</cmis:queryName>
+ <cmis:description>This is a Sample Html Property property.</cmis:description>
+ <cmis:propertyType>html</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyHtmlDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>IdProp</cmis:id>
+ <cmis:localName>IdProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Id Property</cmis:displayName>
+ <cmis:queryName>IdProp</cmis:queryName>
+ <cmis:description>This is a Sample Id Property property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>DateTimePropMV</cmis:id>
+ <cmis:localName>DateTimePropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample DateTime multi-value Property</cmis:displayName>
+ <cmis:queryName>DateTimePropMV</cmis:queryName>
+ <cmis:description>This is a Sample DateTime multi-value Property property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyUriDefinition>
+ <cmis:id>UriProp</cmis:id>
+ <cmis:localName>UriProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Uri Property</cmis:displayName>
+ <cmis:queryName>UriProp</cmis:queryName>
+ <cmis:description>This is a Sample Uri Property property.</cmis:description>
+ <cmis:propertyType>uri</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyUriDefinition>
+ <cmis:propertyDecimalDefinition>
+ <cmis:id>DecimalProp</cmis:id>
+ <cmis:localName>DecimalProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Decimal Property</cmis:displayName>
+ <cmis:queryName>DecimalProp</cmis:queryName>
+ <cmis:description>This is a Sample Decimal Property property.</cmis:description>
+ <cmis:propertyType>decimal</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDecimalDefinition>
+ <cmis:propertyUriDefinition>
+ <cmis:id>UriPropMV</cmis:id>
+ <cmis:localName>UriPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Uri multi-value Property</cmis:displayName>
+ <cmis:queryName>UriPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Uri multi-value Property property.</cmis:description>
+ <cmis:propertyType>uri</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyUriDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>IdPropMV</cmis:id>
+ <cmis:localName>IdPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Id Html multi-value Property</cmis:displayName>
+ <cmis:queryName>IdPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Id Html multi-value Property property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>PickListProp</cmis:id>
+ <cmis:localName>PickListProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Pick List Property</cmis:displayName>
+ <cmis:queryName>PickListProp</cmis:queryName>
+ <cmis:description>This is a Sample Pick List Property property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ <cmis:defaultValue propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:defaultValue>
+ <cmis:choice displayName="">
+ <cmis:value>red</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>green</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>blue</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>black</cmis:value>
+ </cmis:choice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>IntProp</cmis:id>
+ <cmis:localName>IntProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Int Property</cmis:displayName>
+ <cmis:queryName>IntProp</cmis:queryName>
+ <cmis:description>This is a Sample Int Property property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyHtmlDefinition>
+ <cmis:id>HtmlPropMV</cmis:id>
+ <cmis:localName>HtmlPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Html multi-value Property</cmis:displayName>
+ <cmis:queryName>HtmlPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Html multi-value Property property.</cmis:description>
+ <cmis:propertyType>html</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyHtmlDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>StringProp</cmis:id>
+ <cmis:localName>StringProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample String Property</cmis:displayName>
+ <cmis:queryName>StringProp</cmis:queryName>
+ <cmis:description>This is a Sample String Property property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDecimalDefinition>
+ <cmis:id>DecimalPropMV</cmis:id>
+ <cmis:localName>DecimalPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Decimal multi-value Property</cmis:displayName>
+ <cmis:queryName>DecimalPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Decimal multi-value Property property.</cmis:description>
+ <cmis:propertyType>decimal</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDecimalDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>DateTimeProp</cmis:id>
+ <cmis:localName>DateTimeProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample DateTime Property</cmis:displayName>
+ <cmis:queryName>DateTimeProp</cmis:queryName>
+ <cmis:description>This is a Sample DateTime Property property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>BooleanProp</cmis:id>
+ <cmis:localName>BooleanProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Boolean Property</cmis:displayName>
+ <cmis:queryName>BooleanProp</cmis:queryName>
+ <cmis:description>This is a Sample Boolean Property property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>BooleanPropMV</cmis:id>
+ <cmis:localName>BooleanPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Boolean multi-value Property</cmis:displayName>
+ <cmis:queryName>BooleanPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Boolean multi-value Property property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>IntPropMV</cmis:id>
+ <cmis:localName>IntPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Int multi-value Property</cmis:displayName>
+ <cmis:queryName>IntPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Int multi-value Property property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:secondaryObjectTypeIds</cmis:id>
+ <cmis:localName>cmis:secondaryObjectTypeIds</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>cmis:secondaryObjectTypeIds</cmis:displayName>
+ <cmis:queryName>cmis:secondaryObjectTypeIds</cmis:queryName>
+ <cmis:description>This the property holding the Ids of the secondary types.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmism:type>
+ </cmism:getTypeDefinitionResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/type-docLevel2.http b/qa/libcmis/data/ws/type-docLevel2.http
new file mode 100644
index 0000000..2524387
--- /dev/null
+++ b/qa/libcmis/data/ws/type-docLevel2.http
@@ -0,0 +1,682 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeDefinitionResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:type>
+ <cmis:id>DocumentLevel2</cmis:id>
+ <cmis:localName>DocumentLevel2</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 2</cmis:displayName>
+ <cmis:queryName>DocumentLevel2</cmis:queryName>
+ <cmis:description>Description of Document Level 2 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>DocumentLevel1</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyHtmlDefinition>
+ <cmis:id>HtmlProp</cmis:id>
+ <cmis:localName>HtmlProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Html Property</cmis:displayName>
+ <cmis:queryName>HtmlProp</cmis:queryName>
+ <cmis:description>This is a Sample Html Property property.</cmis:description>
+ <cmis:propertyType>html</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyHtmlDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>IdProp</cmis:id>
+ <cmis:localName>IdProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Id Property</cmis:displayName>
+ <cmis:queryName>IdProp</cmis:queryName>
+ <cmis:description>This is a Sample Id Property property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>DateTimePropMV</cmis:id>
+ <cmis:localName>DateTimePropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample DateTime multi-value Property</cmis:displayName>
+ <cmis:queryName>DateTimePropMV</cmis:queryName>
+ <cmis:description>This is a Sample DateTime multi-value Property property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyUriDefinition>
+ <cmis:id>UriProp</cmis:id>
+ <cmis:localName>UriProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Uri Property</cmis:displayName>
+ <cmis:queryName>UriProp</cmis:queryName>
+ <cmis:description>This is a Sample Uri Property property.</cmis:description>
+ <cmis:propertyType>uri</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyUriDefinition>
+ <cmis:propertyDecimalDefinition>
+ <cmis:id>DecimalProp</cmis:id>
+ <cmis:localName>DecimalProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Decimal Property</cmis:displayName>
+ <cmis:queryName>DecimalProp</cmis:queryName>
+ <cmis:description>This is a Sample Decimal Property property.</cmis:description>
+ <cmis:propertyType>decimal</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDecimalDefinition>
+ <cmis:propertyUriDefinition>
+ <cmis:id>UriPropMV</cmis:id>
+ <cmis:localName>UriPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Uri multi-value Property</cmis:displayName>
+ <cmis:queryName>UriPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Uri multi-value Property property.</cmis:description>
+ <cmis:propertyType>uri</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyUriDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>IdPropMV</cmis:id>
+ <cmis:localName>IdPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Id Html multi-value Property</cmis:displayName>
+ <cmis:queryName>IdPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Id Html multi-value Property property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>PickListProp</cmis:id>
+ <cmis:localName>PickListProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Pick List Property</cmis:displayName>
+ <cmis:queryName>PickListProp</cmis:queryName>
+ <cmis:description>This is a Sample Pick List Property property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ <cmis:defaultValue propertyDefinitionId="PickListProp">
+ <cmis:value>blue</cmis:value>
+ </cmis:defaultValue>
+ <cmis:choice displayName="">
+ <cmis:value>red</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>green</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>blue</cmis:value>
+ </cmis:choice>
+ <cmis:choice displayName="">
+ <cmis:value>black</cmis:value>
+ </cmis:choice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>IntProp</cmis:id>
+ <cmis:localName>IntProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Int Property</cmis:displayName>
+ <cmis:queryName>IntProp</cmis:queryName>
+ <cmis:description>This is a Sample Int Property property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyHtmlDefinition>
+ <cmis:id>HtmlPropMV</cmis:id>
+ <cmis:localName>HtmlPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Html multi-value Property</cmis:displayName>
+ <cmis:queryName>HtmlPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Html multi-value Property property.</cmis:description>
+ <cmis:propertyType>html</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyHtmlDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>StringProp</cmis:id>
+ <cmis:localName>StringProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample String Property</cmis:displayName>
+ <cmis:queryName>StringProp</cmis:queryName>
+ <cmis:description>This is a Sample String Property property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDecimalDefinition>
+ <cmis:id>DecimalPropMV</cmis:id>
+ <cmis:localName>DecimalPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Decimal multi-value Property</cmis:displayName>
+ <cmis:queryName>DecimalPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Decimal multi-value Property property.</cmis:description>
+ <cmis:propertyType>decimal</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDecimalDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>DateTimeProp</cmis:id>
+ <cmis:localName>DateTimeProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample DateTime Property</cmis:displayName>
+ <cmis:queryName>DateTimeProp</cmis:queryName>
+ <cmis:description>This is a Sample DateTime Property property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>BooleanProp</cmis:id>
+ <cmis:localName>BooleanProp</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Boolean Property</cmis:displayName>
+ <cmis:queryName>BooleanProp</cmis:queryName>
+ <cmis:description>This is a Sample Boolean Property property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>BooleanPropMV</cmis:id>
+ <cmis:localName>BooleanPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Boolean multi-value Property</cmis:displayName>
+ <cmis:queryName>BooleanPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Boolean multi-value Property property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>IntPropMV</cmis:id>
+ <cmis:localName>IntPropMV</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Sample Int multi-value Property</cmis:displayName>
+ <cmis:queryName>IntPropMV</cmis:queryName>
+ <cmis:description>This is a Sample Int multi-value Property property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmism:type>
+ </cmism:getTypeDefinitionResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/type-document.http b/qa/libcmis/data/ws/type-document.http
new file mode 100644
index 0000000..7cda82b
--- /dev/null
+++ b/qa/libcmis/data/ws/type-document.http
@@ -0,0 +1,410 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeDefinitionResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:type>
+ <cmis:id>cmis:document</cmis:id>
+ <cmis:localName>cmis:document</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>CMIS Document</cmis:displayName>
+ <cmis:queryName>cmis:document</cmis:queryName>
+ <cmis:description>Description of CMIS Document Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmism:type>
+ </cmism:getTypeDefinitionResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/type-folder.http b/qa/libcmis/data/ws/type-folder.http
new file mode 100644
index 0000000..bb47d01
--- /dev/null
+++ b/qa/libcmis/data/ws/type-folder.http
@@ -0,0 +1,232 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeDefinitionResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:type>
+ <cmis:id>cmis:folder</cmis:id>
+ <cmis:localName>cmis:folder</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>CMIS Folder</cmis:displayName>
+ <cmis:queryName>cmis:folder</cmis:queryName>
+ <cmis:description>Description of CMIS Folder Type</cmis:description>
+ <cmis:baseId>cmis:folder</cmis:baseId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:allowedChildObjectTypeIds</cmis:id>
+ <cmis:localName>cmis:allowedChildObjectTypeIds</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Allowed Child Types</cmis:displayName>
+ <cmis:queryName>cmis:allowedChildObjectTypeIds</cmis:queryName>
+ <cmis:description>This is a Allowed Child Types property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>multi</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:path</cmis:id>
+ <cmis:localName>cmis:path</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Path</cmis:displayName>
+ <cmis:queryName>cmis:path</cmis:queryName>
+ <cmis:description>This is a Path property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:parentId</cmis:id>
+ <cmis:localName>cmis:parentId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Parent Id</cmis:displayName>
+ <cmis:queryName>cmis:parentId</cmis:queryName>
+ <cmis:description>This is a Parent Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>false</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ </cmism:type>
+ </cmism:getTypeDefinitionResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/typechildren-document.http b/qa/libcmis/data/ws/typechildren-document.http
new file mode 100644
index 0000000..d7df653
--- /dev/null
+++ b/qa/libcmis/data/ws/typechildren-document.http
@@ -0,0 +1,413 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getTypeChildrenResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:types>
+ <cmism:types>
+ <cmis:id>DocumentLevel1</cmis:id>
+ <cmis:localName>DocumentLevel1</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Document Level 1</cmis:displayName>
+ <cmis:queryName>DocumentLevel1</cmis:queryName>
+ <cmis:description>Description of Document Level 1 Type</cmis:description>
+ <cmis:baseId>cmis:document</cmis:baseId>
+ <cmis:parentId>cmis:document</cmis:parentId>
+ <cmis:creatable>true</cmis:creatable>
+ <cmis:fileable>true</cmis:fileable>
+ <cmis:queryable>false</cmis:queryable>
+ <cmis:fulltextIndexed>false</cmis:fulltextIndexed>
+ <cmis:includedInSupertypeQuery>true</cmis:includedInSupertypeQuery>
+ <cmis:controllablePolicy>false</cmis:controllablePolicy>
+ <cmis:controllableACL>true</cmis:controllableACL>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestMajorVersion</cmis:id>
+ <cmis:localName>cmis:isLatestMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:contentStreamId</cmis:id>
+ <cmis:localName>cmis:contentStreamId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Stream Id</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamId</cmis:queryName>
+ <cmis:description>This is a Stream Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIntegerDefinition>
+ <cmis:id>cmis:contentStreamLength</cmis:id>
+ <cmis:localName>cmis:contentStreamLength</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Content Length</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamLength</cmis:queryName>
+ <cmis:description>This is a Content Length property.</cmis:description>
+ <cmis:propertyType>integer</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIntegerDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutBy</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out By</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutBy</cmis:queryName>
+ <cmis:description>This is a Checked Out By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectTypeId</cmis:id>
+ <cmis:localName>cmis:objectTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:objectTypeId</cmis:queryName>
+ <cmis:description>This is a Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>oncreate</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesCheckedOutId</cmis:id>
+ <cmis:localName>cmis:versionSeriesCheckedOutId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesCheckedOutId</cmis:queryName>
+ <cmis:description>This is a Checked Out Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:name</cmis:id>
+ <cmis:localName>cmis:name</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Name</cmis:displayName>
+ <cmis:queryName>cmis:name</cmis:queryName>
+ <cmis:description>This is a Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readwrite</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>true</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamMimeType</cmis:id>
+ <cmis:localName>cmis:contentStreamMimeType</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Mime Type</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamMimeType</cmis:queryName>
+ <cmis:description>This is a Mime Type property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:versionSeriesId</cmis:id>
+ <cmis:localName>cmis:versionSeriesId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Series Id</cmis:displayName>
+ <cmis:queryName>cmis:versionSeriesId</cmis:queryName>
+ <cmis:description>This is a Version Series Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:creationDate</cmis:id>
+ <cmis:localName>cmis:creationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Creation Date</cmis:displayName>
+ <cmis:queryName>cmis:creationDate</cmis:queryName>
+ <cmis:description>This is a Creation Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:changeToken</cmis:id>
+ <cmis:localName>cmis:changeToken</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Change Token</cmis:displayName>
+ <cmis:queryName>cmis:changeToken</cmis:queryName>
+ <cmis:description>This is a Change Token property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isLatestVersion</cmis:id>
+ <cmis:localName>cmis:isLatestVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Latest Version</cmis:displayName>
+ <cmis:queryName>cmis:isLatestVersion</cmis:queryName>
+ <cmis:description>This is a Is Latest Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:versionLabel</cmis:id>
+ <cmis:localName>cmis:versionLabel</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Version Label</cmis:displayName>
+ <cmis:queryName>cmis:versionLabel</cmis:queryName>
+ <cmis:description>This is a Version Label property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isVersionSeriesCheckedOut</cmis:id>
+ <cmis:localName>cmis:isVersionSeriesCheckedOut</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checked Out</cmis:displayName>
+ <cmis:queryName>cmis:isVersionSeriesCheckedOut</cmis:queryName>
+ <cmis:description>This is a Checked Out property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:lastModifiedBy</cmis:id>
+ <cmis:localName>cmis:lastModifiedBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modified By</cmis:displayName>
+ <cmis:queryName>cmis:lastModifiedBy</cmis:queryName>
+ <cmis:description>This is a Modified By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:createdBy</cmis:id>
+ <cmis:localName>cmis:createdBy</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Created By</cmis:displayName>
+ <cmis:queryName>cmis:createdBy</cmis:queryName>
+ <cmis:description>This is a Created By property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:checkinComment</cmis:id>
+ <cmis:localName>cmis:checkinComment</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Checkin Comment</cmis:displayName>
+ <cmis:queryName>cmis:checkinComment</cmis:queryName>
+ <cmis:description>This is a Checkin Comment property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:objectId</cmis:id>
+ <cmis:localName>cmis:objectId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Object Id</cmis:displayName>
+ <cmis:queryName>cmis:objectId</cmis:queryName>
+ <cmis:description>This is a Object Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isMajorVersion</cmis:id>
+ <cmis:localName>cmis:isMajorVersion</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Is Major Version</cmis:displayName>
+ <cmis:queryName>cmis:isMajorVersion</cmis:queryName>
+ <cmis:description>This is a Is Major Version property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyBooleanDefinition>
+ <cmis:id>cmis:isImmutable</cmis:id>
+ <cmis:localName>cmis:isImmutable</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Immutable</cmis:displayName>
+ <cmis:queryName>cmis:isImmutable</cmis:queryName>
+ <cmis:description>This is a Immutable property.</cmis:description>
+ <cmis:propertyType>boolean</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyBooleanDefinition>
+ <cmis:propertyIdDefinition>
+ <cmis:id>cmis:baseTypeId</cmis:id>
+ <cmis:localName>cmis:baseTypeId</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Base-Type-Id</cmis:displayName>
+ <cmis:queryName>cmis:baseTypeId</cmis:queryName>
+ <cmis:description>This is a Base-Type-Id property.</cmis:description>
+ <cmis:propertyType>id</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyIdDefinition>
+ <cmis:propertyDateTimeDefinition>
+ <cmis:id>cmis:lastModificationDate</cmis:id>
+ <cmis:localName>cmis:lastModificationDate</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>Modification Date</cmis:displayName>
+ <cmis:queryName>cmis:lastModificationDate</cmis:queryName>
+ <cmis:description>This is a Modification Date property.</cmis:description>
+ <cmis:propertyType>datetime</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyDateTimeDefinition>
+ <cmis:propertyStringDefinition>
+ <cmis:id>cmis:contentStreamFileName</cmis:id>
+ <cmis:localName>cmis:contentStreamFileName</cmis:localName>
+ <cmis:localNamespace>local</cmis:localNamespace>
+ <cmis:displayName>File Name</cmis:displayName>
+ <cmis:queryName>cmis:contentStreamFileName</cmis:queryName>
+ <cmis:description>This is a File Name property.</cmis:description>
+ <cmis:propertyType>string</cmis:propertyType>
+ <cmis:cardinality>single</cmis:cardinality>
+ <cmis:updatability>readonly</cmis:updatability>
+ <cmis:inherited>true</cmis:inherited>
+ <cmis:required>false</cmis:required>
+ <cmis:queryable>true</cmis:queryable>
+ <cmis:orderable>true</cmis:orderable>
+ <cmis:openChoice>false</cmis:openChoice>
+ </cmis:propertyStringDefinition>
+ <cmis:versionable>false</cmis:versionable>
+ <cmis:contentStreamAllowed>allowed</cmis:contentStreamAllowed>
+ </cmism:types>
+ </cmism:types>
+ </cmism:getTypeChildrenResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/update-properties.http b/qa/libcmis/data/ws/update-properties.http
new file mode 100644
index 0000000..0113a99
--- /dev/null
+++ b/qa/libcmis/data/ws/update-properties.http
@@ -0,0 +1,26 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:updatePropertiesResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:objectId>test-document</cmism:objectId>
+ <cmism:changeToken>some-new-changeToken</cmism:changeToken>
+ </cmism:updatePropertiesResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/valid-object.http b/qa/libcmis/data/ws/valid-object.http
new file mode 100644
index 0000000..5815443
--- /dev/null
+++ b/qa/libcmis/data/ws/valid-object.http
@@ -0,0 +1,99 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyId queryName="cmis:allowedChildObjectTypeIds" displayName="Allowed Child Types" localName="cmis:allowedChildObjectTypeIds" propertyDefinitionId="cmis:allowedChildObjectTypeIds">
+ <cmis:value>*</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:path" displayName="Path" localName="cmis:path" propertyDefinitionId="cmis:path">
+ <cmis:value>/Valid Object</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>Admin</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Valid Object</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>valid-object</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2012-11-29T16:14:47.019Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1354205687020</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyId queryName="cmis:parentId" displayName="Parent Id" localName="cmis:parentId" propertyDefinitionId="cmis:parentId">
+ <cmis:value>root-folder</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2012-11-29T16:14:47.020Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <cmis:allowableActions>
+ <cmis:canDeleteObject>true</cmis:canDeleteObject>
+ <cmis:canUpdateProperties>true</cmis:canUpdateProperties>
+ <cmis:canGetFolderTree>true</cmis:canGetFolderTree>
+ <cmis:canGetProperties>true</cmis:canGetProperties>
+ <cmis:canGetObjectRelationships>false</cmis:canGetObjectRelationships>
+ <cmis:canGetObjectParents>true</cmis:canGetObjectParents>
+ <cmis:canGetFolderParent>true</cmis:canGetFolderParent>
+ <cmis:canGetDescendants>true</cmis:canGetDescendants>
+ <cmis:canMoveObject>true</cmis:canMoveObject>
+ <cmis:canDeleteContentStream>false</cmis:canDeleteContentStream>
+ <cmis:canCheckOut>false</cmis:canCheckOut>
+ <cmis:canCancelCheckOut>false</cmis:canCancelCheckOut>
+ <cmis:canCheckIn>false</cmis:canCheckIn>
+ <cmis:canSetContentStream>false</cmis:canSetContentStream>
+ <cmis:canGetAllVersions>false</cmis:canGetAllVersions>
+ <cmis:canAddObjectToFolder>false</cmis:canAddObjectToFolder>
+ <cmis:canRemoveObjectFromFolder>false</cmis:canRemoveObjectFromFolder>
+ <cmis:canGetContentStream>false</cmis:canGetContentStream>
+ <cmis:canApplyPolicy>false</cmis:canApplyPolicy>
+ <cmis:canGetAppliedPolicies>false</cmis:canGetAppliedPolicies>
+ <cmis:canRemovePolicy>false</cmis:canRemovePolicy>
+ <cmis:canGetChildren>true</cmis:canGetChildren>
+ <cmis:canCreateDocument>true</cmis:canCreateDocument>
+ <cmis:canCreateFolder>true</cmis:canCreateFolder>
+ <cmis:canCreateRelationship>false</cmis:canCreateRelationship>
+ <cmis:canDeleteTree>true</cmis:canDeleteTree>
+ <cmis:canGetRenditions>false</cmis:canGetRenditions>
+ <cmis:canGetACL>false</cmis:canGetACL>
+ <cmis:canApplyACL>false</cmis:canApplyACL>
+ </cmis:allowableActions>
+ <exampleExtension:exampleExtension xmlns="http://my/cmis/extension" xmlns:exampleExtension="http://my/cmis/extension">
+ <objectId xmlns:ns0="http://my/cmis/extension" ns0:type="cmis:folder">valid-object</objectId>
+ <name>Valid Object</name>
+ </exampleExtension:exampleExtension>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/data/ws/working-copy.http b/qa/libcmis/data/ws/working-copy.http
new file mode 100644
index 0000000..21d2e85
--- /dev/null
+++ b/qa/libcmis/data/ws/working-copy.http
@@ -0,0 +1,98 @@
+Content-Type: multipart/related;start="<rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:846b7f14-435a-4809-845f-b98822f936ab";start-info="text/xml"
+
+--uuid:846b7f14-435a-4809-845f-b98822f936ab
+Content-Id: <rootpart*846b7f14-435a-4809-845f-b98822f936ab@example.jaxws.sun.com>
+Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
+Content-Transfer-Encoding: binary
+
+<?xml version='1.0' encoding='UTF-8'?>
+<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2013-09-16T13:34:16Z</Created>
+ <Expires>2013-09-17T13:34:16Z</Expires>
+ </Timestamp>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <cmism:getObjectResponse xmlns:cmis="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/">
+ <cmism:object>
+ <cmis:properties>
+ <cmis:propertyBoolean queryName="cmis:isLatestMajorVersion" displayName="Is Latest Major Version" localName="cmis:isLatestMajorVersion" propertyDefinitionId="cmis:isLatestMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyInteger queryName="cmis:contentStreamLength" displayName="Content Length" localName="cmis:contentStreamLength" propertyDefinitionId="cmis:contentStreamLength">
+ <cmis:value>12345</cmis:value>
+ </cmis:propertyInteger>
+ <cmis:propertyString queryName="cmis:contentStreamId" displayName="Stream Id" localName="cmis:contentStreamId" propertyDefinitionId="cmis:contentStreamId"/>
+ <cmis:propertyId queryName="cmis:objectTypeId" displayName="Type-Id" localName="cmis:objectTypeId" propertyDefinitionId="cmis:objectTypeId">
+ <cmis:value>DocumentLevel2</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:versionSeriesCheckedOutBy" displayName="Checked Out By" localName="cmis:versionSeriesCheckedOutBy" propertyDefinitionId="cmis:versionSeriesCheckedOutBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:versionSeriesCheckedOutId" displayName="Checked Out Id" localName="cmis:versionSeriesCheckedOutId" propertyDefinitionId="cmis:versionSeriesCheckedOutId">
+ <cmis:value>working-copy</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:name" displayName="Name" localName="cmis:name" propertyDefinitionId="cmis:name">
+ <cmis:value>Test Document</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="VersionedStringProp" displayName="Sample String Property" localName="VersionedStringProp" propertyDefinitionId="VersionedStringProp"/>
+ <cmis:propertyString queryName="cmis:contentStreamMimeType" displayName="Mime Type" localName="cmis:contentStreamMimeType" propertyDefinitionId="cmis:contentStreamMimeType">
+ <cmis:value>text/plain</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyId queryName="cmis:versionSeriesId" displayName="Version Series Id" localName="cmis:versionSeriesId" propertyDefinitionId="cmis:versionSeriesId">
+ <cmis:value>version-series</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyDateTime queryName="cmis:creationDate" displayName="Creation Date" localName="cmis:creationDate" propertyDefinitionId="cmis:creationDate">
+ <cmis:value>2013-05-21T13:50:45.300Z</cmis:value>
+ </cmis:propertyDateTime>
+ <cmis:propertyString queryName="cmis:changeToken" displayName="Change Token" localName="cmis:changeToken" propertyDefinitionId="cmis:changeToken">
+ <cmis:value>1369144245300</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:versionLabel" displayName="Version Label" localName="cmis:versionLabel" propertyDefinitionId="cmis:versionLabel">
+ <cmis:value>V 0.2</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyBoolean queryName="cmis:isLatestVersion" displayName="Is Latest Version" localName="cmis:isLatestVersion" propertyDefinitionId="cmis:isLatestVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isVersionSeriesCheckedOut" displayName="Checked Out" localName="cmis:isVersionSeriesCheckedOut" propertyDefinitionId="cmis:isVersionSeriesCheckedOut">
+ <cmis:value>true</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyString queryName="cmis:lastModifiedBy" displayName="Modified By" localName="cmis:lastModifiedBy" propertyDefinitionId="cmis:lastModifiedBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:createdBy" displayName="Created By" localName="cmis:createdBy" propertyDefinitionId="cmis:createdBy">
+ <cmis:value>unknown</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyString queryName="cmis:checkinComment" displayName="Checkin Comment" localName="cmis:checkinComment" propertyDefinitionId="cmis:checkinComment"/>
+ <cmis:propertyId queryName="cmis:objectId" displayName="Object Id" localName="cmis:objectId" propertyDefinitionId="cmis:objectId">
+ <cmis:value>working-copy</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyBoolean queryName="cmis:isMajorVersion" displayName="Is Major Version" localName="cmis:isMajorVersion" propertyDefinitionId="cmis:isMajorVersion">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyBoolean queryName="cmis:isImmutable" displayName="Immutable" localName="cmis:isImmutable" propertyDefinitionId="cmis:isImmutable">
+ <cmis:value>false</cmis:value>
+ </cmis:propertyBoolean>
+ <cmis:propertyId queryName="cmis:baseTypeId" displayName="Base-Type-Id" localName="cmis:baseTypeId" propertyDefinitionId="cmis:baseTypeId">
+ <cmis:value>cmis:document</cmis:value>
+ </cmis:propertyId>
+ <cmis:propertyString queryName="cmis:contentStreamFileName" displayName="File Name" localName="cmis:contentStreamFileName" propertyDefinitionId="cmis:contentStreamFileName">
+ <cmis:value>data.txt</cmis:value>
+ </cmis:propertyString>
+ <cmis:propertyDateTime queryName="cmis:lastModificationDate" displayName="Modification Date" localName="cmis:lastModificationDate" propertyDefinitionId="cmis:lastModificationDate">
+ <cmis:value>2013-05-21T13:50:45.300Z</cmis:value>
+ </cmis:propertyDateTime>
+ </cmis:properties>
+ <exampleExtension:exampleExtension xmlns="http://mockup/cmis/extension" xmlns:exampleExtension="http://mockup/cmis/extension">
+ <objectId xmlns:ns0="http://mockup/cmis/extension" ns0:type="DocumentLevel2">working-copy</objectId>
+ <name>Test Document</name>
+ </exampleExtension:exampleExtension>
+ </cmism:object>
+ </cmism:getObjectResponse>
+ </S:Body>
+</S:Envelope>
+--uuid:846b7f14-435a-4809-845f-b98822f936ab--
+
diff --git a/qa/libcmis/test-atom.cxx b/qa/libcmis/test-atom.cxx
new file mode 100644
index 0000000..f0ce29f
--- /dev/null
+++ b/qa/libcmis/test-atom.cxx
@@ -0,0 +1,1250 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <memory>
+#include <sstream>
+
+#define SERVER_URL string( "http://mockup/binding" )
+#define SERVER_REPOSITORY string( "mock" )
+#define SERVER_USERNAME "tester"
+#define SERVER_PASSWORD "somepass"
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <libcmis/document.hxx>
+#include <libcmis/session-factory.hxx>
+
+#include <mockup-config.h>
+#include "test-helpers.hxx"
+#include "atom-session.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+typedef std::unique_ptr<AtomPubSession> AtomPubSessionPtr;
+
+class AtomTest : public CppUnit::TestFixture
+{
+ public:
+ void sessionCreationTest( );
+ void sessionCreationBadAuthTest( );
+ void sessionCreationProxyTest( );
+ void authCallbackTest( );
+ void invalidSSLTest( );
+ void getRepositoriesTest( );
+ void getTypeTest( );
+ void getUnexistantTypeTest( );
+ void getTypeParentsTest( );
+ void getTypeChildrenTest( );
+ void getObjectTest( );
+ void getDocumentTest( );
+ void getDocumentRelationshipsTest( );
+ void getUnexistantObjectTest( );
+ void getFolderTest( );
+ void getFolderBadTypeTest( );
+ void getByPathValidTest( );
+ void getByPathInvalidTest( );
+ void getRenditionsTest( );
+ void getAllowableActionsTest( );
+ void getAllowableActionsNotIncludedTest( );
+ void getChildrenTest( );
+ void getDocumentParentsTest( );
+ void getContentStreamTest( );
+ void setContentStreamTest( );
+ void updatePropertiesTest( );
+ void updatePropertiesEmptyTest( );
+ void createFolderTest( );
+ void createFolderBadTypeTest( );
+ void createDocumentTest( );
+ void deleteDocumentTest( );
+ void deleteFolderTreeTest( );
+ void checkOutTest( );
+ void cancelCheckOutTest( );
+ void checkInTest( );
+ void getAllVersionsTest( );
+ void moveTest( );
+
+ CPPUNIT_TEST_SUITE( AtomTest );
+ CPPUNIT_TEST( sessionCreationTest );
+ CPPUNIT_TEST( sessionCreationBadAuthTest );
+ CPPUNIT_TEST( sessionCreationProxyTest );
+ CPPUNIT_TEST( authCallbackTest );
+ CPPUNIT_TEST( invalidSSLTest );
+ CPPUNIT_TEST( getRepositoriesTest );
+ CPPUNIT_TEST( getTypeTest );
+ CPPUNIT_TEST( getUnexistantTypeTest );
+ CPPUNIT_TEST( getTypeParentsTest );
+ CPPUNIT_TEST( getTypeChildrenTest );
+ CPPUNIT_TEST( getObjectTest );
+ CPPUNIT_TEST( getDocumentTest );
+ CPPUNIT_TEST( getDocumentRelationshipsTest );
+ CPPUNIT_TEST( getUnexistantObjectTest );
+ CPPUNIT_TEST( getFolderTest );
+ CPPUNIT_TEST( getFolderBadTypeTest );
+ CPPUNIT_TEST( getByPathValidTest );
+ CPPUNIT_TEST( getByPathInvalidTest );
+ CPPUNIT_TEST( getRenditionsTest );
+ CPPUNIT_TEST( getAllowableActionsTest );
+ CPPUNIT_TEST( getAllowableActionsNotIncludedTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( getDocumentParentsTest );
+ CPPUNIT_TEST( getContentStreamTest );
+ CPPUNIT_TEST( setContentStreamTest );
+ CPPUNIT_TEST( updatePropertiesTest );
+ CPPUNIT_TEST( updatePropertiesEmptyTest );
+ CPPUNIT_TEST( createFolderTest );
+ CPPUNIT_TEST( createFolderBadTypeTest );
+ CPPUNIT_TEST( createDocumentTest );
+ CPPUNIT_TEST( deleteDocumentTest );
+ CPPUNIT_TEST( deleteFolderTreeTest );
+ CPPUNIT_TEST( checkOutTest );
+ CPPUNIT_TEST( cancelCheckOutTest );
+ CPPUNIT_TEST( checkInTest );
+ CPPUNIT_TEST( getAllVersionsTest );
+ CPPUNIT_TEST( moveTest );
+ CPPUNIT_TEST_SUITE_END( );
+
+ AtomPubSessionPtr getTestSession( string username = string( ), string password = string( ) );
+};
+
+class TestAuthProvider : public libcmis::AuthProvider
+{
+ bool m_fail;
+
+ public:
+ TestAuthProvider( bool fail ) : m_fail( fail ) { }
+
+ bool authenticationQuery( std::string&, std::string& password )
+ {
+ password = SERVER_PASSWORD;
+ return !m_fail;
+ }
+};
+
+class TestCertValidationHandler : public libcmis::CertValidationHandler
+{
+ public:
+
+ bool m_fail;
+ vector< string > m_chain;
+
+ TestCertValidationHandler( bool fail ) : m_fail( fail ), m_chain() { }
+
+ bool validateCertificate( vector< string > chain )
+ {
+ m_chain = chain;
+ return !m_fail;
+ }
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( AtomTest );
+
+void AtomTest::sessionCreationTest( )
+{
+ // Response showing one mock repository
+ curl_mockup_reset( );
+ curl_mockup_setResponse( DATA_DIR "/atom/workspaces.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, SERVER_PASSWORD );
+
+ // Check for the mandatory collection URLs
+ CPPUNIT_ASSERT_MESSAGE( "root collection URL missing",
+ !session.getAtomRepository()->getCollectionUrl( Collection::Root ).empty() );
+ CPPUNIT_ASSERT_MESSAGE( "types collection URL missing",
+ !session.getAtomRepository()->getCollectionUrl( Collection::Types ).empty() );
+ CPPUNIT_ASSERT_MESSAGE( "query collection URL missing",
+ !session.getAtomRepository()->getCollectionUrl( Collection::Query ).empty() );
+
+ // The optional collection URLs are present on InMemory, so check them
+ CPPUNIT_ASSERT_MESSAGE( "checkedout collection URL missing",
+ !session.getAtomRepository()->getCollectionUrl( Collection::CheckedOut ).empty() );
+ CPPUNIT_ASSERT_MESSAGE( "unfiled collection URL missing",
+ !session.getAtomRepository()->getCollectionUrl( Collection::Unfiled ).empty() );
+
+ // Check for the mandatory URI template URLs
+ CPPUNIT_ASSERT_MESSAGE( "objectbyid URI template URL missing",
+ !session.getAtomRepository()->getUriTemplate( UriTemplate::ObjectById ).empty() );
+ CPPUNIT_ASSERT_MESSAGE( "objectbypath URI template URL missing",
+ !session.getAtomRepository()->getUriTemplate( UriTemplate::ObjectByPath ).empty() );
+ CPPUNIT_ASSERT_MESSAGE( "typebyid URI template URL missing",
+ !session.getAtomRepository()->getUriTemplate( UriTemplate::TypeById ).empty() );
+
+ // The optional URI template URL is present on InMemory, so check it
+ CPPUNIT_ASSERT_MESSAGE( "query URI template URL missing",
+ !session.getAtomRepository()->getUriTemplate( UriTemplate::Query ).empty() );
+
+ // Check that the root id is defined
+ CPPUNIT_ASSERT_MESSAGE( "Root node ID is missing",
+ !session.getRootId().empty() );
+}
+
+void AtomTest::sessionCreationBadAuthTest( )
+{
+ // Response showing one mock repository
+ curl_mockup_reset( );
+ curl_mockup_setResponse( DATA_DIR "/atom/workspaces.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ try
+ {
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, "bad", "bad" );
+ CPPUNIT_FAIL( "Exception should have been thrown" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "permissionDenied" ), e.getType( ) );
+ }
+}
+
+void AtomTest::sessionCreationProxyTest( )
+{
+ // Response showing one mock repository
+ curl_mockup_reset( );
+ curl_mockup_setResponse( DATA_DIR "/atom/workspaces.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string proxy( "proxy" );
+ string noProxy( "noProxy" );
+ string proxyUser( "proxyUser" );
+ string proxyPass( "proxyPass" );
+
+ libcmis::SessionFactory::setProxySettings( proxy, noProxy, proxyUser, proxyPass );
+
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, SERVER_PASSWORD );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Proxy not set", proxy, string( curl_mockup_getProxy( session.m_curlHandle ) ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "NoProxy not set", noProxy, string( curl_mockup_getNoProxy( session.m_curlHandle ) ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Proxy User not set", proxyUser, string( curl_mockup_getProxyUser( session.m_curlHandle ) ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Proxy Pass not set", proxyPass, string( curl_mockup_getProxyPass( session.m_curlHandle ) ) );
+
+ // Reset proxy settings to default for next tests
+ libcmis::SessionFactory::setProxySettings( string(), string(), string(), string() );
+}
+
+void AtomTest::authCallbackTest( )
+{
+ // Response showing one mock repository
+ curl_mockup_reset( );
+ curl_mockup_setResponse( DATA_DIR "/atom/workspaces.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+
+ // Test cancelled authentication
+ {
+ libcmis::AuthProviderPtr authProvider( new TestAuthProvider( true ) );
+ libcmis::SessionFactory::setAuthenticationProvider( authProvider );
+ try
+ {
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, string( ) );
+ CPPUNIT_FAIL( "Should raise an exception saying the user cancelled the authentication" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception message",
+ string( "User cancelled authentication request" ), string( e.what() ) );
+ }
+ }
+
+ // Test provided authentication
+ {
+ libcmis::AuthProviderPtr authProvider( new TestAuthProvider( false ) );
+ libcmis::SessionFactory::setAuthenticationProvider( authProvider );
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, string( ) );
+ }
+}
+
+void AtomTest::invalidSSLTest( )
+{
+ // Response showing one mock repository
+ curl_mockup_reset( );
+ curl_mockup_setResponse( DATA_DIR "/atom/workspaces.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string badCert( "A really invalid SSL Certificate" );
+ curl_mockup_setSSLBadCertificate( badCert.c_str() );
+
+ // Test validated certificate case
+ {
+ libcmis::CertValidationHandlerPtr handler( new TestCertValidationHandler( false ) );
+ libcmis::SessionFactory::setCertificateValidationHandler( handler );
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, SERVER_PASSWORD );
+
+ TestCertValidationHandler* handler_impl = static_cast< TestCertValidationHandler* >( handler.get( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of certificates provided", size_t( 1 ), handler_impl->m_chain.size( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad certificate provided", badCert, handler_impl->m_chain.front() );
+ }
+
+ // Test cancelled validation case
+ {
+ libcmis::CertValidationHandlerPtr handler( new TestCertValidationHandler( true ) );
+ libcmis::SessionFactory::setCertificateValidationHandler( handler );
+ try
+ {
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, SERVER_PASSWORD );
+ CPPUNIT_FAIL( "Should raise an exception saying the user didn't validate the SSL certificate" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception message",
+ string( "Invalid SSL certificate" ), string( e.what() ) );
+ }
+ }
+}
+
+void AtomTest::getRepositoriesTest( )
+{
+ // Response showing one mock repository
+ curl_mockup_reset( );
+ curl_mockup_setResponse( DATA_DIR "/atom/workspaces.xml" );
+
+ AtomPubSession session( SERVER_URL, SERVER_REPOSITORY, SERVER_USERNAME, SERVER_PASSWORD );
+ vector< libcmis::RepositoryPtr > actual = session.getRepositories( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of repositories", size_t( 1 ), actual.size( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong repository found", SERVER_REPOSITORY, actual.front()->getId( ) );
+}
+
+void AtomTest::getTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "cmis:folder" );
+ libcmis::ObjectTypePtr actual = session->getType( expectedId );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Id for fetched type", expectedId, actual->getId( ) );
+}
+
+void AtomTest::getUnexistantTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "bad_type" );
+ try
+ {
+ session->getType( expectedId );
+ CPPUNIT_FAIL( "Exception should be raised: invalid ID" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "objectNotFound" ), e.getType() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception message", string( "No such type: bad_type" ), string( e.what() ) );
+ }
+}
+
+void AtomTest::getTypeParentsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel1", "GET", DATA_DIR "/atom/type-docLevel1.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:document", "GET", DATA_DIR "/atom/type-document.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectTypePtr actual = session->getType( "DocumentLevel2" );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Parent type", string( "DocumentLevel1" ), actual->getParentType( )->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Base type", string( "cmis:document" ), actual->getBaseType( )->getId( ) );
+}
+
+void AtomTest::getTypeChildrenTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel1", "GET", DATA_DIR "/atom/type-docLevel1.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:document", "GET", DATA_DIR "/atom/type-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/types", "typeId=cmis:document", "GET", DATA_DIR "/atom/typechildren-document.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectTypePtr actual = session->getType( "cmis:document" );
+ vector< libcmis::ObjectTypePtr > children = actual->getChildren( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of children", size_t( 1 ), children.size( ) );
+}
+
+void AtomTest::getObjectTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=valid-object", "GET", DATA_DIR "/atom/valid-object.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "valid-object" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Id for fetched object", expectedId, actual->getId( ) );
+}
+
+void AtomTest::getDocumentTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "test-document" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ // Do we have a document?
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( actual );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+
+ // Test the document properties
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document ID", expectedId, document->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document name", string( "Test Document" ), document->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document type", string( "text/plain" ), document->getContentType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:document" ), document->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !document->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !document->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !document->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !document->getLastModificationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "ChangeToken is missing", !document->getChangeToken( ).empty( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "Content length is missing", 12345 == document->getContentLength( ) );
+}
+
+void AtomTest::getDocumentRelationshipsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document-relationships.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "test-document" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ // Do we have a document?
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( actual );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+
+ // Test the document properties
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document ID", expectedId, document->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document name", string( "Test Document" ), document->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document type", string( "text/plain" ), document->getContentType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:document" ), document->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !document->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !document->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !document->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !document->getLastModificationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "ChangeToken is missing", !document->getChangeToken( ).empty( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "Content length is missing", 12345 == document->getContentLength( ) );
+}
+
+void AtomTest::getFolderTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=valid-object", "GET", DATA_DIR "/atom/valid-object.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=root-folder", "GET", DATA_DIR "/atom/root-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "valid-object" );
+ libcmis::FolderPtr actual = session->getFolder( expectedId );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder ID", expectedId, actual->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder name", string( "Valid Object" ), actual->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder path", string( "/Valid Object" ), actual->getPath( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder paths",
+ string( "/Valid Object" ), actual->getPaths( )[0] );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Folder should have only one path",
+ size_t(1), actual->getPaths( ).size() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:folder" ), actual->getBaseType( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Missing folder parent", actual->getFolderParent( ).get( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a root folder", !actual->isRootFolder() );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !actual->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !actual->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !actual->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !actual->getLastModificationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "ChangeToken is missing", !actual->getChangeToken( ).empty( ) );
+}
+
+void AtomTest::getFolderBadTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::FolderPtr actual = session->getFolder( "test-document" );
+
+ CPPUNIT_ASSERT_MESSAGE( "returned folder should be an empty pointer", NULL == actual );
+}
+
+void AtomTest::getUnexistantObjectTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string id( "bad_object" );
+ try
+ {
+ session->getObject( id );
+ CPPUNIT_FAIL( "Exception should be raised: invalid ID" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong CMIS exception type", string( "objectNotFound" ), e.getType() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception message", string( "No such node: " ) + id, string( e.what() ) );
+ }
+}
+
+void AtomTest::getByPathValidTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/path", "path=/Valid Object", "GET", DATA_DIR "/atom/valid-object.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr actual = session->getObjectByPath( string( "/Valid Object" ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Id for fetched object", string( "valid-object" ), actual->getId( ) );
+}
+
+void AtomTest::getByPathInvalidTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ try
+ {
+ session->getObjectByPath( string( "/some/invalid/path" ) );
+ CPPUNIT_FAIL( "Exception should be thrown: invalid Path" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "objectNotFound" ), e.getType() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception message",
+ string( "No node corresponding to path: /some/invalid/path" ), string( e.what() ) );
+ }
+
+}
+
+void AtomTest::getRenditionsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "test-document" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ std::vector< libcmis::RenditionPtr > renditions = actual->getRenditions( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad renditions count", size_t( 2 ), renditions.size( ) );
+
+ libcmis::RenditionPtr rendition = renditions[0];
+ CPPUNIT_ASSERT( rendition->isThumbnail() );
+
+ rendition = renditions[1];
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition mime type", string( "application/pdf" ), rendition->getMimeType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition href", string( "http://mockup/mock/renditions?id=test-document-rendition2" ), rendition->getUrl() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition length - default case", long( -1 ), rendition->getLength( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition Title", string( "Doc as PDF" ), rendition->getTitle( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition kind", string( "pdf" ), rendition->getKind( ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition length - filled case", long( 40385 ), renditions[0]->getLength( ) );
+}
+
+void AtomTest::getAllowableActionsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=valid-object", "GET", DATA_DIR "/atom/valid-object.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "valid-object" );
+ libcmis::FolderPtr actual = session->getFolder( expectedId );
+
+ boost::shared_ptr< libcmis::AllowableActions > toCheck = actual->getAllowableActions( );
+ CPPUNIT_ASSERT_MESSAGE( "ApplyACL allowable action not defined... are all the actions read?",
+ toCheck->isDefined( libcmis::ObjectAction::ApplyACL ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetChildren allowable action should be true",
+ toCheck->isDefined( libcmis::ObjectAction::GetChildren ) &&
+ toCheck->isAllowed( libcmis::ObjectAction::GetChildren ) );
+}
+
+void AtomTest::getAllowableActionsNotIncludedTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=valid-object", "GET", DATA_DIR "/atom/valid-object-noactions.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/allowableactions", "id=valid-object", "GET", DATA_DIR "/atom/allowable-actions.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ string expectedId( "valid-object" );
+ libcmis::FolderPtr actual = session->getFolder( expectedId );
+
+ // In some cases (mostly when getting folder children), we may not have the allowable actions
+ // included in the object answer. Test that we are querying them when needed in those cases.
+ boost::shared_ptr< libcmis::AllowableActions > toCheck = actual->getAllowableActions( );
+ CPPUNIT_ASSERT_MESSAGE( "ApplyACL allowable action not defined... are all the actions read?",
+ toCheck->isDefined( libcmis::ObjectAction::ApplyACL ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetChildren allowable action should be true",
+ toCheck->isDefined( libcmis::ObjectAction::GetChildren ) &&
+ toCheck->isAllowed( libcmis::ObjectAction::GetChildren ) );
+}
+
+void AtomTest::getChildrenTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/children", "id=root-folder", "GET", DATA_DIR "/atom/root-children.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=root-folder", "GET", DATA_DIR "/atom/root-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ vector< libcmis::ObjectPtr > children = session->getRootFolder()->getChildren( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of children", size_t( 5 ), children.size() );
+
+ int folderCount = 0;
+ int documentCount = 0;
+ for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
+ it != children.end( ); ++it )
+ {
+ if ( NULL != boost::dynamic_pointer_cast< libcmis::Folder >( *it ) )
+ ++folderCount;
+ else if ( NULL != boost::dynamic_pointer_cast< libcmis::Document >( *it ) )
+ ++documentCount;
+ }
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of folder children", 2, folderCount );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of document children", 3, documentCount );
+}
+
+void AtomTest::getDocumentParentsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/parents", "id=test-document", "GET", DATA_DIR "/atom/test-document-parents.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ CPPUNIT_ASSERT_MESSAGE( "Document expected", document != NULL );
+ vector< libcmis::FolderPtr > actual = document->getParents( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of parents", size_t( 2 ), actual.size() );
+
+ vector< string > paths = document->getPaths();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of paths", size_t( 2 ), paths.size() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad document paths",
+ string( "/Parent 1/Test Document" ), paths[0] );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad document paths",
+ string( "/Parent 2/Test Document" ), paths[1] );
+}
+
+void AtomTest::getContentStreamTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+
+ string expectedContent( "Some content stream" );
+ curl_mockup_addResponse( "http://mockup/mock/content/data.txt", "id=test-document", "GET", expectedContent.c_str( ), 0, false );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream( );
+ ostringstream out;
+ out << is->rdbuf();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", expectedContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void AtomTest::setContentStreamTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/content/data.txt", "id=test-document", "PUT", "Updated", 0, false );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ try
+ {
+ string expectedContent( "Some content stream to set" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "name.txt" );
+ document->setContentStream( os, "text/plain", filename );
+
+ CPPUNIT_ASSERT_MESSAGE( "Object not refreshed during setContentStream", object->getRefreshTimestamp( ) > 0 );
+
+ // Check the content has been properly uploaded
+ const char* content = curl_mockup_getRequestBody( "http://mockup/mock/content/", "id=test-document", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void AtomTest::updatePropertiesTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "PUT", DATA_DIR "/atom/test-document-updated.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ // Values for the test
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ string propertyName( "cmis:name" );
+ string expectedValue( "New name" );
+
+ // Fill the map of properties to change
+ PropertyPtrMap newProperties;
+
+ libcmis::ObjectTypePtr objectType = object->getTypeDescription( );
+ map< string, libcmis::PropertyTypePtr >::iterator it = objectType->getPropertiesTypes( ).find( propertyName );
+ vector< string > values;
+ values.push_back( expectedValue );
+ libcmis::PropertyPtr property( new libcmis::Property( it->second, values ) );
+ newProperties[ propertyName ] = property;
+
+ // Update the properties (method to test)
+ libcmis::ObjectPtr updated = object->updateProperties( newProperties );
+
+ // Check that the proper request has been send
+ // In order to avoid to check changing strings (containing a timestamp),
+ // get the cmisra:object tree and compare it.
+ string request( curl_mockup_getRequestBody( "http://mockup/mock/id", "id=test-document", "PUT" ) );
+ string actualObject = test::getXmlNodeAsString( request, "/atom:entry/cmisra:object" );
+
+ string expectedObject = "<cmisra:object>"
+ "<cmis:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>New name</cmis:value>"
+ "</cmis:propertyString>"
+ "</cmis:properties>"
+ "</cmisra:object>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request content sent", expectedObject, actualObject );
+
+ // Check that the properties are updated after the call
+ PropertyPtrMap::iterator propIt = updated->getProperties( ).find( propertyName );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong value after refresh", expectedValue, propIt->second->getStrings().front( ) );
+}
+
+void AtomTest::updatePropertiesEmptyTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ // Values for the test
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+
+ // Just leave the map empty and update
+ PropertyPtrMap emptyProperties;
+ libcmis::ObjectPtr updated = object->updateProperties( emptyProperties );
+
+ // Check that no HTTP request was sent
+ int count = curl_mockup_getRequestsCount( "http://mockup/mock/id",
+ "id=test-document", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "No HTTP request should have been sent", 0, count );
+
+ // Check that the object we got is the same than previous one
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong change token", object->getChangeToken(), updated->getChangeToken() );
+}
+
+void AtomTest::createFolderTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/children", "id=root-folder", "POST", DATA_DIR "/atom/create-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=root-folder", "GET", DATA_DIR "/atom/root-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "cmis:folder" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ string expectedName( "create folder" );
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( expectedName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "cmis:folder" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Actually send the folder creation request
+ libcmis::FolderPtr created = parent->createFolder( props );
+
+ // Check that something came back
+ CPPUNIT_ASSERT_MESSAGE( "Change token shouldn't be empty: object should have been refreshed",
+ !created->getChangeToken( ).empty() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong name", expectedName, created->getName( ) );
+
+ // Check that the proper request has been sent
+ string request( curl_mockup_getRequestBody( "http://mockup/mock/children", "id=root-folder", "POST" ) );
+ string actualObject = test::getXmlNodeAsString( request, "/atom:entry/cmisra:object" );
+
+ string expectedObject = "<cmisra:object>"
+ "<cmis:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>create folder</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyId propertyDefinitionId=\"cmis:objectTypeId\" localName=\"cmis:objectTypeId\""
+ " displayName=\"Type-Id\" queryName=\"cmis:objectTypeId\">"
+ "<cmis:value>cmis:folder</cmis:value>"
+ "</cmis:propertyId>"
+ "</cmis:properties>"
+ "</cmisra:object>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request content sent", expectedObject, actualObject );
+}
+
+void AtomTest::createFolderBadTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/children", "id=root-folder", "POST",
+ "Not a cmis:folder derived type", 409, false );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=root-folder", "GET", DATA_DIR "/atom/root-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:document", "GET", DATA_DIR "/atom/type-document.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "cmis:folder" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ string expectedName( "create folder" );
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( expectedName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "cmis:document" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Actually send the folder creation request
+ try
+ {
+ parent->createFolder( props );
+ CPPUNIT_FAIL( "Should not succeed to return a folder" );
+ }
+ catch ( libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "constraint" ), e.getType() );
+ }
+
+ // Check that the proper request has been sent
+ string request( curl_mockup_getRequestBody( "http://mockup/mock/children", "id=root-folder", "POST" ) );
+ string actualObject = test::getXmlNodeAsString( request, "/atom:entry/cmisra:object" );
+
+ string expectedObject = "<cmisra:object>"
+ "<cmis:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>create folder</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyId propertyDefinitionId=\"cmis:objectTypeId\" localName=\"cmis:objectTypeId\""
+ " displayName=\"Type-Id\" queryName=\"cmis:objectTypeId\">"
+ "<cmis:value>cmis:document</cmis:value>"
+ "</cmis:propertyId>"
+ "</cmis:properties>"
+ "</cmisra:object>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request content sent", expectedObject, actualObject );
+}
+
+void AtomTest::createDocumentTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/children", "id=root-folder", "POST", "Response body up to server", 201, false,
+ "Location: http://mockup/mock/id?id=create-document\r\n" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=create-document", "GET", DATA_DIR "/atom/create-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=root-folder", "GET", DATA_DIR "/atom/root-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:document", "GET", DATA_DIR "/atom/type-document.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "cmis:document" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ string expectedName( "create document" );
+
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( expectedName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "cmis:document" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Actually send the document creation request
+ string content = "Some content";
+ boost::shared_ptr< ostream > os ( new stringstream( content ) );
+ string contentType = "text/plain";
+ string filename( "name.txt" );
+ libcmis::DocumentPtr created = parent->createDocument( props, os, contentType, filename );
+
+ // Check that something came back
+ CPPUNIT_ASSERT_MESSAGE( "Change token shouldn't be empty: object should have been refreshed",
+ !created->getChangeToken( ).empty() );
+
+ // Check that the name is ok
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong name set", expectedName, created->getName( ) );
+
+ // Check that the request is the expected one
+ string request( curl_mockup_getRequestBody( "http://mockup/mock/children", "id=root-folder", "POST" ) );
+ string actualContent = test::getXmlNodeAsString( request, "/atom:entry/cmisra:content" );
+ string expectedContent = "<cmisra:content>"
+ "<cmisra:mediatype>text/plain</cmisra:mediatype>"
+ "<cmisra:base64>U29tZSBjb250ZW50</cmisra:base64>"
+ "</cmisra:content>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request content sent", expectedContent, actualContent );
+
+ string actualObject = test::getXmlNodeAsString( request, "/atom:entry/cmisra:object" );
+ string expectedObject = "<cmisra:object>"
+ "<cmis:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>create document</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyId propertyDefinitionId=\"cmis:objectTypeId\" localName=\"cmis:objectTypeId\""
+ " displayName=\"Type-Id\" queryName=\"cmis:objectTypeId\">"
+ "<cmis:value>cmis:document</cmis:value>"
+ "</cmis:propertyId>"
+ "</cmis:properties>"
+ "</cmisra:object>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request object sent", expectedObject, actualObject );
+}
+
+void AtomTest::deleteDocumentTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "DELETE", "", 204, false );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get() );
+
+ document->remove( );
+
+ // Test the sent request
+ const char* request = curl_mockup_getRequestBody( "http://mockup/mock/id", "id=test-document", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "DELETE request not sent", request );
+}
+
+void AtomTest::deleteFolderTreeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=valid-object", "GET", DATA_DIR "/atom/valid-object.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/descendants", "id=valid-object", "DELETE", "", 204, false );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "valid-object" );
+ libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( object.get() );
+
+ folder->removeTree( );
+
+ // Test the sent request
+ const struct HttpRequest* request = curl_mockup_getRequest( "http://mockup/mock/descendants", "id=valid-object", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "DELETE request not sent", request );
+ curl_mockup_HttpRequest_free( request );
+}
+
+void AtomTest::checkOutTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/checkedout", "", "POST", DATA_DIR "/atom/working-copy.xml", 201 );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get() );
+
+ libcmis::DocumentPtr pwc = document->checkOut( );
+
+ CPPUNIT_ASSERT_MESSAGE( "Missing returned Private Working Copy", pwc.get( ) != NULL );
+
+ PropertyPtrMap::iterator it = pwc->getProperties( ).find( string( "cmis:isVersionSeriesCheckedOut" ) );
+ vector< bool > values = it->second->getBools( );
+ CPPUNIT_ASSERT_MESSAGE( "cmis:isVersionSeriesCheckedOut isn't true", values.front( ) );
+}
+
+void AtomTest::cancelCheckOutTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=working-copy", "GET", DATA_DIR "/atom/working-copy.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=working-copy", "DELETE", "", 204, false );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ // First get a checked out document
+ libcmis::ObjectPtr object = session->getObject( "working-copy" );
+ libcmis::DocumentPtr pwc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ pwc->cancelCheckout( );
+
+ // Check that the DELETE request was sent out
+ const struct HttpRequest* request = curl_mockup_getRequest( "http://mockup/mock/id", "id=working-copy", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "DELETE request not sent", request );
+ curl_mockup_HttpRequest_free( request );
+}
+
+void AtomTest::checkInTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=working-copy", "GET", DATA_DIR "/atom/working-copy.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=working-copy", "PUT", DATA_DIR "/atom/test-document.xml", 200, true,
+ "Location: http://mockup/mock/id?id=valid-object" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ // First get a checked out document
+ libcmis::ObjectPtr object = session->getObject( "working-copy" );
+ libcmis::DocumentPtr pwc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ // Do the checkin
+ bool isMajor = true;
+ string comment( "Some check-in comment" );
+ PropertyPtrMap properties;
+ string newContent = "Some New content to check in";
+ boost::shared_ptr< ostream > stream ( new stringstream( newContent ) );
+ pwc->checkIn( isMajor, comment, properties, stream, "text/plain", "filename.txt" );
+
+ // Make sure that the expected request has been sent
+ const struct HttpRequest* request = curl_mockup_getRequest( "http://mockup/mock/id", "id=working-copy", "PUT" );
+ CPPUNIT_ASSERT_MESSAGE( "PUT request not sent", request );
+
+ string actualContent = test::getXmlNodeAsString( request->body, "/atom:entry/cmisra:content" );
+ string expectedContent = "<cmisra:content><cmisra:mediatype>text/plain</cmisra:mediatype><cmisra:base64>U29tZSBOZXcgY29udGVudCB0byBjaGVjayBpbg==</cmisra:base64></cmisra:content>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong content sent", expectedContent, actualContent );
+
+ // Still needs to test that checkin request parameters were OK
+ string url( request->url );
+ CPPUNIT_ASSERT_MESSAGE( "Sent checkin request has wrong major parameter", url.find("major=true") != string::npos );
+ CPPUNIT_ASSERT_MESSAGE( "Sent checkin request has wrong checkinComment parameter", url.find( "checkinComment=" + comment ) != string::npos );
+ CPPUNIT_ASSERT_MESSAGE( "Sent checkin request has no checkin parameter", url.find("checkin=true") != string::npos );
+
+ curl_mockup_HttpRequest_free( request );
+}
+
+void AtomTest::getAllVersionsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/versions", "id=test-document", "GET", DATA_DIR "/atom/get-versions.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ // First get a document
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::DocumentPtr doc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ // Get all the versions (method to check)
+ vector< libcmis::DocumentPtr > versions = doc->getAllVersions( );
+
+ // Checks
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of versions", size_t( 2 ), versions.size( ) );
+}
+
+void AtomTest::moveTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=DocumentLevel2", "GET", DATA_DIR "/atom/type-docLevel2.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=test-document", "GET", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/parents", "id=test-document", "GET", DATA_DIR "/atom/test-document-parents.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/id", "id=valid-object", "GET", DATA_DIR "/atom/valid-object.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/type", "id=cmis:folder", "GET", DATA_DIR "/atom/type-folder.xml" );
+ curl_mockup_addResponse( "http://mockup/mock/children", "id=valid-object", "POST", DATA_DIR "/atom/test-document.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ AtomPubSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD );
+
+ libcmis::ObjectPtr object = session->getObject( "test-document" );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get() );
+
+ string destFolderId = "valid-object";
+ libcmis::FolderPtr src = document->getParents( ).front( );
+ libcmis::FolderPtr dest = session->getFolder( destFolderId );
+
+ document->move( src, dest );
+
+ // Check that the sent request has the expected params
+ const struct HttpRequest* request = curl_mockup_getRequest( "http://mockup/mock/children", "id=valid-object", "POST" );
+ string url( request->url );
+ CPPUNIT_ASSERT_MESSAGE( "Sent move request has wrong or missing sourceFolderId", url.find("sourceFolderId=parent1") != string::npos );
+
+ // Check that we had the atom entry in the request body
+ string actualObject = test::getXmlNodeAsString( request->body, "/atom:entry/cmisra:object/cmis:properties/cmis:propertyId[@propertyDefinitionId='cmis:objectId']" );
+ string expectedObject = "<cmis:propertyId propertyDefinitionId=\"cmis:objectId\" localName=\"cmis:objectId\""
+ " displayName=\"Object Id\" queryName=\"cmis:objectId\">"
+ "<cmis:value>test-document</cmis:value>"
+ "</cmis:propertyId>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request object sent", expectedObject, actualObject );
+
+ curl_mockup_HttpRequest_free( request );
+}
+
+AtomPubSessionPtr AtomTest::getTestSession( string username, string password )
+{
+ AtomPubSessionPtr session( new AtomPubSession( ) );
+ string buf;
+ test::loadFromFile( DATA_DIR "/atom/workspaces.xml", buf );
+ session->parseServiceDocument( buf );
+
+ session->m_username = username;
+ session->m_password = password;
+
+ return session;
+}
diff --git a/qa/libcmis/test-commons.cxx b/qa/libcmis/test-commons.cxx
new file mode 100644
index 0000000..df271e9
--- /dev/null
+++ b/qa/libcmis/test-commons.cxx
@@ -0,0 +1,223 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 SUSE <cedric@bosdonnat.fr>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <time.h>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <libxml/tree.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <libcmis/oauth2-data.hxx>
+#include <libcmis/object-type.hxx>
+
+#include "oauth2-handler.hxx"
+
+using namespace libcmis;
+using namespace std;
+
+class CommonsTest : public CppUnit::TestFixture
+{
+ public:
+
+ // constructors tests
+ void oauth2DataCopyTest();
+ void oauth2HandlerCopyTest();
+ void objectTypeCopyTest();
+
+ // Methods that should never be called
+ void objectTypeNocallTest();
+
+ CPPUNIT_TEST_SUITE( CommonsTest );
+ CPPUNIT_TEST( oauth2DataCopyTest );
+ CPPUNIT_TEST( oauth2HandlerCopyTest );
+ CPPUNIT_TEST( objectTypeCopyTest );
+ CPPUNIT_TEST( objectTypeNocallTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+static void assertOAuth2DataEquals( const OAuth2Data& expected, const OAuth2Data& actual )
+{
+ CPPUNIT_ASSERT_EQUAL( expected.m_authUrl, actual.m_authUrl );
+ CPPUNIT_ASSERT_EQUAL( expected.m_tokenUrl, actual.m_tokenUrl );
+ CPPUNIT_ASSERT_EQUAL( expected.m_scope, actual.m_scope );
+ CPPUNIT_ASSERT_EQUAL( expected.m_redirectUri, actual.m_redirectUri );
+ CPPUNIT_ASSERT_EQUAL( expected.m_clientId, actual.m_clientId );
+ CPPUNIT_ASSERT_EQUAL( expected.m_clientSecret, actual.m_clientSecret );
+}
+
+void CommonsTest::oauth2DataCopyTest( )
+{
+ OAuth2Data data( "url", "token", "scope", "redirect",
+ "clientid", "clientsecret" );
+ {
+ OAuth2Data copy;
+ copy = data;
+ assertOAuth2DataEquals( data, copy );
+ }
+
+ {
+ OAuth2Data copy( data );
+ assertOAuth2DataEquals( data, copy );
+ }
+}
+
+string DummyOAuth2Parser( HttpSession*, const string&, const string&, const string& )
+{
+ return "Fake";
+}
+
+void CommonsTest::oauth2HandlerCopyTest( )
+{
+ OAuth2DataPtr data( new OAuth2Data ( "url", "token", "scope", "redirect",
+ "clientid", "clientsecret" ) );
+ HttpSession session( "user", "pass" );
+ OAuth2Handler handler( &session, data );
+ handler.m_access = "access";
+ handler.m_refresh = "refresh";
+ handler.m_oauth2Parser = &DummyOAuth2Parser;
+
+ {
+ OAuth2Handler copy;
+ copy = handler;
+
+ CPPUNIT_ASSERT_EQUAL( &session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL( data, copy.m_data );
+ CPPUNIT_ASSERT_EQUAL( handler.m_access, copy.m_access );
+ CPPUNIT_ASSERT_EQUAL( handler.m_refresh, copy.m_refresh );
+ CPPUNIT_ASSERT_EQUAL( &DummyOAuth2Parser, copy.m_oauth2Parser );
+ }
+
+ {
+ OAuth2Handler copy( handler );
+
+ CPPUNIT_ASSERT_EQUAL( &session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL( data, copy.m_data );
+ CPPUNIT_ASSERT_EQUAL( handler.m_access, copy.m_access );
+ CPPUNIT_ASSERT_EQUAL( handler.m_refresh, copy.m_refresh );
+ CPPUNIT_ASSERT_EQUAL( &DummyOAuth2Parser, copy.m_oauth2Parser );
+ }
+}
+
+static void assertObjectTypeEquals( const ObjectType& expected, const ObjectType& actual )
+{
+ CPPUNIT_ASSERT_EQUAL( expected.getRefreshTimestamp(), actual.getRefreshTimestamp() );
+ CPPUNIT_ASSERT_EQUAL( expected.getId(), actual.getId() );
+ CPPUNIT_ASSERT_EQUAL( expected.getLocalName(), actual.getLocalName() );
+ CPPUNIT_ASSERT_EQUAL( expected.getLocalNamespace(), actual.getLocalNamespace() );
+ CPPUNIT_ASSERT_EQUAL( expected.getDisplayName(), actual.getDisplayName() );
+ CPPUNIT_ASSERT_EQUAL( expected.getQueryName(), actual.getQueryName() );
+ CPPUNIT_ASSERT_EQUAL( expected.getDescription(), actual.getDescription() );
+ CPPUNIT_ASSERT_EQUAL( expected.getParentTypeId(), actual.getParentTypeId() );
+ CPPUNIT_ASSERT_EQUAL( expected.getBaseTypeId(), actual.getBaseTypeId() );
+ CPPUNIT_ASSERT_EQUAL( expected.isCreatable(), actual.isCreatable() );
+ CPPUNIT_ASSERT_EQUAL( expected.isFileable(), actual.isFileable() );
+ CPPUNIT_ASSERT_EQUAL( expected.isQueryable(), actual.isQueryable() );
+ CPPUNIT_ASSERT_EQUAL( expected.isFulltextIndexed(), actual.isFulltextIndexed() );
+ CPPUNIT_ASSERT_EQUAL( expected.isIncludedInSupertypeQuery(), actual.isIncludedInSupertypeQuery() );
+ CPPUNIT_ASSERT_EQUAL( expected.isControllablePolicy(), actual.isControllablePolicy() );
+ CPPUNIT_ASSERT_EQUAL( expected.isControllableACL(), actual.isControllableACL() );
+ CPPUNIT_ASSERT_EQUAL( expected.isVersionable(), actual.isVersionable() );
+ CPPUNIT_ASSERT_EQUAL( expected.getContentStreamAllowed(), actual.getContentStreamAllowed() );
+ CPPUNIT_ASSERT_EQUAL( const_cast< ObjectType& >( expected ).getPropertiesTypes().size(),
+ const_cast< ObjectType& >( actual ).getPropertiesTypes().size() );
+}
+
+void CommonsTest::objectTypeCopyTest( )
+{
+ ObjectType type;
+ time_t refresh = time( NULL );
+ type.m_refreshTimestamp = refresh;
+ type.m_id = "id";
+ type.m_baseTypeId = "base";
+
+ {
+ ObjectType copy;
+ copy = type;
+ assertObjectTypeEquals( type, copy );
+ }
+
+ {
+ ObjectType copy ( type );
+ assertObjectTypeEquals( type, copy );
+ }
+}
+
+void CommonsTest::objectTypeNocallTest( )
+{
+ ObjectType type;
+
+ try
+ {
+ type.refresh();
+ CPPUNIT_FAIL( "refresh() shouldn't succeed" );
+ }
+ catch ( const Exception& e )
+ {
+ }
+
+ try
+ {
+ type.getParentType();
+ CPPUNIT_FAIL( "getParentType() shouldn't succeed" );
+ }
+ catch ( const Exception& e )
+ {
+ }
+
+ try
+ {
+ type.getBaseType();
+ CPPUNIT_FAIL( "getBaseType() shouldn't succeed" );
+ }
+ catch ( const Exception& e )
+ {
+ }
+
+ try
+ {
+ type.getChildren();
+ CPPUNIT_FAIL( "getChildren() shouldn't succeed" );
+ }
+ catch ( const Exception& e )
+ {
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( CommonsTest );
diff --git a/qa/libcmis/test-decoder.cxx b/qa/libcmis/test-decoder.cxx
new file mode 100644
index 0000000..c7b4748
--- /dev/null
+++ b/qa/libcmis/test-decoder.cxx
@@ -0,0 +1,221 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+#include <libcmis/xml-utils.hxx>
+
+#define BASE64_ENCODING string( "base64" )
+
+using namespace std;
+
+class DecoderTest : public CppUnit::TestFixture
+{
+ private:
+ libcmis::EncodedData* data;
+ FILE* stream;
+
+ string getActual( );
+
+ public:
+
+ DecoderTest( );
+ DecoderTest( const DecoderTest& rCopy );
+
+ DecoderTest& operator=( const DecoderTest& rCopy );
+
+ void setUp( );
+ void tearDown( );
+
+ void noEncodingTest();
+
+ void base64DecodeSimpleBlockTest( );
+ void base64DecodePaddedBlockTest( );
+ void base64DecodeNoEqualsPaddedBlockTest( );
+ void base64DecodeSplitRunsTest( );
+
+ void base64EncodeSimpleBlockTest( );
+ void base64EncodePaddedBlockTest( );
+ void base64EncodeSplitRunsTest( );
+
+ void base64encodeTest( );
+
+ CPPUNIT_TEST_SUITE( DecoderTest );
+ CPPUNIT_TEST( noEncodingTest );
+ CPPUNIT_TEST( base64DecodeSimpleBlockTest );
+ CPPUNIT_TEST( base64DecodePaddedBlockTest );
+ CPPUNIT_TEST( base64DecodeNoEqualsPaddedBlockTest );
+ CPPUNIT_TEST( base64DecodeSplitRunsTest );
+ CPPUNIT_TEST( base64EncodeSimpleBlockTest );
+ CPPUNIT_TEST( base64EncodePaddedBlockTest );
+ CPPUNIT_TEST( base64EncodeSplitRunsTest );
+ CPPUNIT_TEST( base64encodeTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+DecoderTest::DecoderTest( ) :
+ CppUnit::TestFixture( ),
+ data( NULL ),
+ stream( NULL )
+{
+}
+
+DecoderTest::DecoderTest( const DecoderTest& rCopy ) :
+ CppUnit::TestFixture( ),
+ data( rCopy.data ),
+ stream( rCopy.stream )
+{
+}
+
+DecoderTest& DecoderTest::operator=( const DecoderTest& rCopy )
+{
+ if ( this != &rCopy )
+ {
+ data = rCopy.data;
+ stream = rCopy.stream;
+ }
+ return *this;
+}
+
+void DecoderTest::setUp( )
+{
+ stream = tmpfile();
+ data = new libcmis::EncodedData( stream );
+}
+
+void DecoderTest::tearDown( )
+{
+ fclose( stream );
+ delete data;
+}
+
+string DecoderTest::getActual( )
+{
+ string actual;
+
+ rewind( stream );
+ size_t bufSize = 100;
+ char buf[100];
+ size_t readBytes = 0;
+ do {
+ readBytes = fread( buf, 1, bufSize, stream );
+ actual += string( buf, readBytes );
+ } while ( readBytes == bufSize );
+
+ return actual;
+}
+
+void DecoderTest::noEncodingTest()
+{
+ data->decode( ( void* )"pleasure.", 1, 9 );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "pleasure." ), getActual( ) );
+}
+
+/*
+ * All the test values for the Base64 have been taken from
+ * the wikipedia article: http://en.wikipedia.org/wiki/Base64
+ */
+
+void DecoderTest::base64DecodeSimpleBlockTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input( "cGxlYXN1cmUu" );
+ data->decode( ( void* )input.c_str( ), 1, input.size() );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "pleasure." ), getActual( ) );
+}
+
+void DecoderTest::base64DecodePaddedBlockTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input( "c3VyZS4=" );
+ data->decode( ( void* )input.c_str( ), 1, input.size( ) );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "sure." ), getActual( ) );
+}
+
+void DecoderTest::base64DecodeNoEqualsPaddedBlockTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input( "c3VyZS4" );
+ data->decode( ( void* )input.c_str( ), 1, input.size( ) );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "sure." ), getActual( ) );
+}
+
+void DecoderTest::base64DecodeSplitRunsTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input1( "cGxlYXN1c" );
+ data->decode( ( void* )input1.c_str( ), 1, input1.size( ) );
+ string input2( "mUu" );
+ data->decode( ( void* )input2.c_str( ), 1, input2.size( ) );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "pleasure." ), getActual( ) );
+}
+
+void DecoderTest::base64EncodeSimpleBlockTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input( "pleasure." );
+ data->encode( ( void* )input.c_str(), 1, input.size() );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "cGxlYXN1cmUu" ), getActual( ) );
+}
+
+void DecoderTest::base64EncodePaddedBlockTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input( "sure." );
+ data->encode( ( void* )input.c_str(), 1, input.size() );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "c3VyZS4=" ), getActual( ) );
+}
+
+void DecoderTest::base64EncodeSplitRunsTest( )
+{
+ data->setEncoding( BASE64_ENCODING );
+ string input1( "plea" );
+ data->encode( ( void* )input1.c_str(), 1, input1.size() );
+ string input2( "sure." );
+ data->encode( ( void* )input2.c_str(), 1, input2.size() );
+ data->finish( );
+ CPPUNIT_ASSERT_EQUAL( string( "cGxlYXN1cmUu" ), getActual( ) );
+}
+
+void DecoderTest::base64encodeTest( )
+{
+ string actual = libcmis::base64encode( "sure." );
+ CPPUNIT_ASSERT_EQUAL( string( "c3VyZS4=" ), actual );
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( DecoderTest );
diff --git a/qa/libcmis/test-factory.cxx b/qa/libcmis/test-factory.cxx
new file mode 100644
index 0000000..74a6b02
--- /dev/null
+++ b/qa/libcmis/test-factory.cxx
@@ -0,0 +1,336 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <memory>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <libcmis/session-factory.hxx>
+
+#include <atom-session.hxx>
+#include <ws-session.hxx>
+#include <gdrive-session.hxx>
+#include <onedrive-session.hxx>
+#include <sharepoint-session.hxx>
+
+#include <mockup-config.h>
+#include <test-helpers.hxx>
+#include <test-mockup-helpers.hxx>
+
+#define BINDING_ATOM string( "http://mockup/atom" )
+#define BINDING_WS string( "http://mockup/ws" )
+#define BINDING_SHAREPOINT string ( "http://mockup/sharepoint/_api/web" )
+#define CONTEXTINFO_URL string ( "http://mockup/sharepoint/_api/contextinfo" )
+#define BINDING_BAD "http://mockup/bad"
+#define BINDING_GDRIVE string ( "https://www.googleapis.com/drive/v3" )
+#define BINDING_ONEDRIVE string ( "https://graph.microsoft.com/v1.0" )
+#define SERVER_REPOSITORY string( "mock" )
+#define SERVER_USERNAME "tester"
+#define SERVER_PASSWORD "somepass"
+
+#define OAUTH_CLIENT_ID string ( "mock-id" )
+#define OAUTH_CLIENT_SECRET string ( "mock-secret" )
+#define OAUTH_SCOPE string ( "https://scope/url" )
+#define OAUTH_REDIRECT_URI string ("redirect:uri" )
+
+#define GDRIVE_AUTH_URL string ( "https://auth/url" )
+#define GDRIVE_LOGIN_URL string ("https://login/url" )
+#define GDRIVE_LOGIN_URL2 string ("https://login2/url" )
+#define GDRIVE_APPROVAL_URL string ("https://approval/url" )
+#define GDRIVE_TOKEN_URL string ( "https://token/url" )
+
+#define ONEDRIVE_AUTH_URL string ( "https://auth/url" )
+#define ONEDRIVE_TOKEN_URL string ( "https://token/url" )
+
+using namespace std;
+
+namespace
+{
+ void lcl_init_mockup_ws( )
+ {
+ curl_mockup_reset( );
+ curl_mockup_addResponse( BINDING_WS.c_str( ), "", "GET",
+ DATA_DIR "/ws/CMISWS-Service.wsdl" );
+ test::addWsResponse( string( BINDING_WS + "/services/RepositoryService" ).c_str(),
+ DATA_DIR "/ws/repositories.http" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ }
+
+ void lcl_init_mockup_atom( )
+ {
+ curl_mockup_reset( );
+ curl_mockup_addResponse( BINDING_ATOM.c_str( ), "", "GET",
+ DATA_DIR "/atom/workspaces.xml" );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ }
+
+ void lcl_init_mockup_gdrive( )
+ {
+ curl_mockup_reset( );
+
+ //login response
+ string loginIdentifier = string("scope=") + OAUTH_SCOPE +
+ string("&redirect_uri=") + OAUTH_REDIRECT_URI +
+ string("&response_type=code") +
+ string("&client_id=") + OAUTH_CLIENT_ID;
+
+ curl_mockup_addResponse ( GDRIVE_AUTH_URL.c_str(), loginIdentifier.c_str( ),
+ "GET", DATA_DIR "/gdrive/login1.html", 200, true);
+
+ //authentication email
+ curl_mockup_addResponse( GDRIVE_LOGIN_URL2.c_str( ), "", "POST",
+ DATA_DIR "/gdrive/login2.html", 200, true);
+
+ //authentication password,
+ curl_mockup_addResponse( GDRIVE_LOGIN_URL.c_str( ), "", "POST",
+ DATA_DIR "/gdrive/approve.html", 200, true);
+
+ //approval response
+ curl_mockup_addResponse( GDRIVE_APPROVAL_URL.c_str( ), "",
+ "POST", DATA_DIR "/gdrive/authcode.html", 200, true);
+
+ curl_mockup_addResponse ( GDRIVE_TOKEN_URL.c_str( ), "", "POST",
+ DATA_DIR "/gdrive/token-response.json", 200, true );
+ }
+
+ char* authCodeFallback( const char* /*url*/, const char* /*username*/, const char* /*password*/ )
+ {
+ char *authCode = strdup( "authCode" );
+ return authCode;
+ }
+
+ void lcl_init_mockup_sharepoint( )
+ {
+ curl_mockup_reset( );
+
+ curl_mockup_addResponse( BINDING_SHAREPOINT.c_str( ), "", "GET", "", 401, false );
+ curl_mockup_addResponse( ( BINDING_SHAREPOINT + "/currentuser" ).c_str( ), "", "GET",
+ DATA_DIR "/sharepoint/auth-resp.json", 200, true );
+ curl_mockup_addResponse( CONTEXTINFO_URL.c_str( ), "", "POST",
+ DATA_DIR "/sharepoint/xdigest.json", 200, true );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ }
+}
+
+class FactoryTest : public CppUnit::TestFixture
+{
+ public:
+
+ void createSessionAtomTest( );
+ void createSessionAtomBadAuthTest( );
+ void createSessionWSTest( );
+ void createSessionWSBadAuthTest( );
+ void createSessionNoCmisTest( );
+ void createSessionGDriveTest( );
+ void createSessionOneDriveTest( );
+ void createSessionSharePointTest( );
+ void createSessionSharePointDefaultAuthTest( );
+ void createSessionSharePointBadAuthTest( );
+
+ CPPUNIT_TEST_SUITE( FactoryTest );
+ CPPUNIT_TEST( createSessionAtomTest );
+ CPPUNIT_TEST( createSessionAtomBadAuthTest );
+ CPPUNIT_TEST( createSessionWSTest );
+ CPPUNIT_TEST( createSessionWSBadAuthTest );
+ CPPUNIT_TEST( createSessionNoCmisTest );
+ CPPUNIT_TEST( createSessionGDriveTest );
+ CPPUNIT_TEST( createSessionOneDriveTest );
+ CPPUNIT_TEST( createSessionSharePointTest );
+ CPPUNIT_TEST( createSessionSharePointDefaultAuthTest );
+ CPPUNIT_TEST( createSessionSharePointBadAuthTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( FactoryTest );
+
+void FactoryTest::createSessionAtomTest( )
+{
+ lcl_init_mockup_atom( );
+
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_ATOM, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not an AtomPubSession",
+ dynamic_cast< AtomPubSession* >( session.get() ) != NULL );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "More than one request for the binding",
+ int( 1 ), curl_mockup_getRequestsCount( BINDING_ATOM.c_str( ), "", "GET" ) );
+}
+
+void FactoryTest::createSessionAtomBadAuthTest( )
+{
+ lcl_init_mockup_atom( );
+
+ try
+ {
+ libcmis::SessionFactory::createSession(
+ BINDING_ATOM, "Bad user", "Bad Password",
+ SERVER_REPOSITORY );
+ CPPUNIT_FAIL( "Should throw exception" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception type",
+ string( "permissionDenied" ), e.getType( ) );
+ }
+}
+
+void FactoryTest::createSessionWSTest( )
+{
+ lcl_init_mockup_ws( );
+
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_WS, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a WSSession",
+ dynamic_cast< WSSession* >( session.get() ) != NULL );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "More than one request for the binding",
+ int( 1 ), curl_mockup_getRequestsCount( BINDING_WS.c_str( ), "", "GET" ) );
+}
+
+void FactoryTest::createSessionWSBadAuthTest( )
+{
+ lcl_init_mockup_ws( );
+
+ try
+ {
+ libcmis::SessionFactory::createSession(
+ BINDING_WS, "Bad User", "Bad Pass",
+ SERVER_REPOSITORY );
+ CPPUNIT_FAIL( "Should throw exception" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception type",
+ string( "permissionDenied" ), e.getType( ) );
+ }
+}
+
+void FactoryTest::createSessionGDriveTest( )
+{
+ lcl_init_mockup_gdrive( );
+
+ libcmis::OAuth2DataPtr oauth2Data(
+ new libcmis::OAuth2Data( GDRIVE_AUTH_URL, GDRIVE_TOKEN_URL,
+ OAUTH_SCOPE, OAUTH_REDIRECT_URI,
+ OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET ));
+
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_GDRIVE, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY, false,
+ oauth2Data ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a GDriveSession",
+ dynamic_cast< GDriveSession* >( session.get() ) != NULL );
+}
+
+void FactoryTest::createSessionOneDriveTest( )
+{
+ lcl_init_mockup_gdrive( );
+
+ libcmis::OAuth2DataPtr oauth2Data(
+ new libcmis::OAuth2Data( ONEDRIVE_AUTH_URL, ONEDRIVE_TOKEN_URL,
+ OAUTH_SCOPE, OAUTH_REDIRECT_URI,
+ OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET ));
+
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( authCodeFallback );
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_ONEDRIVE, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY, false,
+ oauth2Data ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a OneDriveSession",
+ dynamic_cast< OneDriveSession* >( session.get() ) != NULL );
+}
+
+void FactoryTest::createSessionSharePointTest( )
+{
+ lcl_init_mockup_sharepoint( );
+
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_SHAREPOINT, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a SharePoint Session",
+ dynamic_cast< SharePointSession* >( session.get() ) != NULL );
+}
+
+void FactoryTest::createSessionSharePointDefaultAuthTest( )
+{
+ curl_mockup_addResponse( BINDING_SHAREPOINT.c_str( ), "", "GET",
+ DATA_DIR "/sharepoint/auth-xml-resp.xml", 200, true );
+ curl_mockup_addResponse( CONTEXTINFO_URL.c_str( ), "", "POST",
+ DATA_DIR "/sharepoint/xdigest.json", 200, true );
+
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_SHAREPOINT, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a SharePoint Session",
+ dynamic_cast< SharePointSession* >( session.get() ) != NULL );
+}
+
+void FactoryTest::createSessionSharePointBadAuthTest( )
+{
+ lcl_init_mockup_sharepoint( );
+
+ try
+ {
+ libcmis::SessionFactory::createSession(
+ BINDING_ATOM, "Bad user", "Bad Password",
+ SERVER_REPOSITORY );
+ CPPUNIT_FAIL( "Should throw exception" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception type",
+ string( "permissionDenied" ), e.getType( ) );
+ }
+}
+
+void FactoryTest::createSessionNoCmisTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( BINDING_BAD, "", "GET",
+ "<p>Some non CMIS content</p>", 200, false );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ unique_ptr< libcmis::Session > session( libcmis::SessionFactory::createSession(
+ BINDING_BAD, SERVER_USERNAME, SERVER_PASSWORD,
+ SERVER_REPOSITORY ) );
+ CPPUNIT_ASSERT_MESSAGE( "Session should be NULL", !session );
+}
diff --git a/qa/libcmis/test-gdrive.cxx b/qa/libcmis/test-gdrive.cxx
new file mode 100644
index 0000000..c89017a
--- /dev/null
+++ b/qa/libcmis/test-gdrive.cxx
@@ -0,0 +1,1318 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <memory>
+#include <string>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <libcmis/document.hxx>
+#include <libcmis/session-factory.hxx>
+
+#include <mockup-config.h>
+
+#include "gdrive-session.hxx"
+#include "gdrive-property.hxx"
+#include "oauth2-handler.hxx"
+#include "gdrive-object.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+static const string CLIENT_ID ( "mock-id" );
+static const string CLIENT_SECRET ( "mock-secret" );
+static const string USERNAME( "mock-user" );
+static const string PASSWORD( "mock-password" );
+static const string USERNAME2( "mock-user2" );
+static const string PASSWORD2( "mock-password2" );
+static const string LOGIN_URL ("https://login/url" );
+static const string LOGIN_URL2 ("https://login2/url" );
+static const string APPROVAL_URL ("https://approval/url" );
+static const string CHALLENGE_URL ("https://accounts.google.com/challenge/url" );
+static const string AUTH_URL ( "https://auth/url" );
+static const string TOKEN_URL ( "https://token/url" );
+static const string SCOPE ( "https://scope/url" );
+static const string REDIRECT_URI ("redirect:uri" );
+static const string BASE_URL ( "https://base/url" );
+
+#define PIN "123321"
+
+namespace
+{
+ char* lcl_authCodeFallback( const char* /*url*/, const char* /*username*/, const char* /*password*/ )
+ {
+ char *authCode = strdup( PIN );
+ return authCode;
+ }
+}
+
+typedef std::unique_ptr<GDriveSession> GDriveSessionPtr;
+
+class GDriveTest : public CppUnit::TestFixture
+{
+ public:
+ void sessionAuthenticationTest( );
+ void sessionAuthenticationTestWith2FA( );
+ void sessionExpiryTokenGetTest( );
+ void sessionExpiryTokenPostTest( );
+ void sessionExpiryTokenPutTest( );
+ void sessionExpiryTokenDeleteTest( );
+ void setRepositoryTest( );
+ void getRepositoriesTest( );
+ void getTypeTest( );
+ void getObjectTest( );
+ void getObjectByPathRootTest( );
+ void getObjectByPathTest( );
+ void getObjectByPathMissingTest( );
+ void getDocumentTest( );
+ void getFolderTest( );
+ void getDocumentParentsTest( );
+ void getContentStreamTest( );
+ void setContentStreamTest( );
+ void setContentStreamGdocTest( );
+ void getChildrenTest( );
+ void getDocumentAllowableActionsTest( );
+ void getFolderAllowableActionsTest( );
+ void checkOutTest( );
+ void checkInTest( );
+ void deleteTest( );
+ void moveTest( );
+ void createDocumentTest( );
+ void createFolderTest( );
+ void updatePropertiesTest( );
+ void propertyCopyTest( );
+ void removeTreeTest( );
+ void getContentStreamWithRenditionsTest( );
+ void getRefreshTokenTest( );
+ void getThumbnailUrlTest( );
+ void getAllVersionsTest( );
+
+ CPPUNIT_TEST_SUITE( GDriveTest );
+ CPPUNIT_TEST( sessionAuthenticationTest );
+ CPPUNIT_TEST( sessionAuthenticationTestWith2FA );
+ CPPUNIT_TEST( sessionExpiryTokenGetTest );
+ CPPUNIT_TEST( sessionExpiryTokenPutTest );
+ CPPUNIT_TEST( sessionExpiryTokenPostTest );
+ CPPUNIT_TEST( sessionExpiryTokenDeleteTest );
+ CPPUNIT_TEST( setRepositoryTest );
+ CPPUNIT_TEST( getRepositoriesTest );
+ CPPUNIT_TEST( getTypeTest );
+ CPPUNIT_TEST( getObjectTest );
+ CPPUNIT_TEST( getObjectByPathRootTest );
+ CPPUNIT_TEST( getObjectByPathTest );
+ CPPUNIT_TEST( getObjectByPathMissingTest );
+ CPPUNIT_TEST( getDocumentTest );
+ CPPUNIT_TEST( getFolderTest );
+ CPPUNIT_TEST( getDocumentParentsTest );
+ CPPUNIT_TEST( getContentStreamTest );
+ CPPUNIT_TEST( setContentStreamTest );
+ CPPUNIT_TEST( setContentStreamGdocTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( getDocumentAllowableActionsTest );
+ CPPUNIT_TEST( getFolderAllowableActionsTest );
+ CPPUNIT_TEST( checkOutTest );
+ CPPUNIT_TEST( checkInTest );
+ CPPUNIT_TEST( deleteTest );
+ CPPUNIT_TEST( moveTest );
+ CPPUNIT_TEST( createDocumentTest );
+ CPPUNIT_TEST( createFolderTest );
+ CPPUNIT_TEST( updatePropertiesTest );
+ CPPUNIT_TEST( propertyCopyTest );
+ CPPUNIT_TEST( removeTreeTest );
+ CPPUNIT_TEST( getContentStreamWithRenditionsTest );
+ CPPUNIT_TEST( getRefreshTokenTest );
+ CPPUNIT_TEST( getThumbnailUrlTest );
+ CPPUNIT_TEST( getAllVersionsTest );
+ CPPUNIT_TEST_SUITE_END( );
+
+ private:
+ GDriveSessionPtr getTestSession( string username, string password, bool with2FA = false );
+};
+
+GDriveSessionPtr GDriveTest::getTestSession( string username, string password, bool with2FA )
+{
+ libcmis::OAuth2DataPtr oauth2(
+ new libcmis::OAuth2Data( AUTH_URL, TOKEN_URL, SCOPE,
+ REDIRECT_URI, CLIENT_ID, CLIENT_SECRET ));
+ curl_mockup_reset( );
+ string empty;
+ //login response
+ string loginIdentifier = string("scope=") + SCOPE +
+ string("&redirect_uri=") + REDIRECT_URI +
+ string("&response_type=code") +
+ string("&client_id=") + CLIENT_ID;
+
+ curl_mockup_addResponse ( AUTH_URL.c_str(), loginIdentifier.c_str( ),
+ "GET", DATA_DIR "/gdrive/login1.html", 200, true);
+
+ //authentication email
+ curl_mockup_addResponse( LOGIN_URL2.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/gdrive/login2.html", 200, true);
+
+ //challenge - pin code
+ if( with2FA == true )
+ {
+ curl_mockup_addResponse( LOGIN_URL.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/gdrive/challenge.html", 200, true);
+
+ //approval response
+ curl_mockup_addResponse( CHALLENGE_URL.c_str( ), empty.c_str( ),
+ "POST", DATA_DIR "/gdrive/approve.html", 200, true);
+ }
+ else
+ {
+ //authentication password,
+ curl_mockup_addResponse( LOGIN_URL.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/gdrive/approve.html", 200, true);
+ }
+
+ //approval response
+ curl_mockup_addResponse( APPROVAL_URL.c_str( ), empty.c_str( ),
+ "POST", DATA_DIR "/gdrive/authcode.html", 200, true);
+
+ curl_mockup_addResponse ( TOKEN_URL.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/gdrive/token-response.json", 200, true );
+
+ return GDriveSessionPtr( new GDriveSession( BASE_URL, username, password, oauth2, false ) );
+}
+
+void GDriveTest::sessionAuthenticationTest( )
+{
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string empty;
+
+ // Check authentication request for email
+ string authRequestEmail( curl_mockup_getRequestBody( LOGIN_URL2.c_str(), empty.c_str( ),
+ "POST" ) );
+ string expectedAuthRequestEmail =
+ string ( "Page=PasswordSeparationSignIn&continue=redirectLink&scope=Scope&service=lso&GALX=cookie"
+ "&Email=") + USERNAME;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong authentication request for Email",
+ expectedAuthRequestEmail, authRequestEmail );
+
+ // Check authentication request for password
+ string authRequestPassword( curl_mockup_getRequestBody( LOGIN_URL.c_str(), empty.c_str( ),
+ "POST" ) );
+ string expectedAuthRequestPassword =
+ string ( "continue=redirectLink&scope=Scope&service=lso&GALX=cookie"
+ "&Passwd=") + PASSWORD;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong authentication request for Password",
+ expectedAuthRequestPassword, authRequestPassword );
+
+ // Check code request
+ string codeRequest( curl_mockup_getRequestBody( APPROVAL_URL.c_str(),
+ empty.c_str( ), "POST" ) );
+ string expectedCodeRequest = string( "state_wrapper=stateWrapper&submit_access=true" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong approval request",
+ expectedCodeRequest, codeRequest);
+
+ // Check token request
+ string expectedTokenRequest =
+ string( "code=AuthCode") +
+ string( "&client_id=") + CLIENT_ID +
+ string( "&redirect_uri=") + REDIRECT_URI +
+ string( "&scope=") + SCOPE +
+ string( "&grant_type=authorization_code" );
+
+ string tokenRequest( curl_mockup_getRequestBody( TOKEN_URL.c_str(), empty.c_str( ),
+ "POST" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong token request",
+ expectedTokenRequest, tokenRequest );
+
+ // Check token
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "Wrong access token",
+ string ( "mock-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "Wrong refresh token",
+ string ("mock-refresh-token"),
+ session->m_oauth2Handler->getRefreshToken( ));
+}
+
+void GDriveTest::sessionAuthenticationTestWith2FA( )
+{
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( lcl_authCodeFallback );
+
+ GDriveSessionPtr session = getTestSession( USERNAME2, PASSWORD2, true );
+ string empty;
+
+ // Check authentication request for email
+ string authRequestEmail( curl_mockup_getRequestBody( LOGIN_URL2.c_str(), empty.c_str( ),
+ "POST" ) );
+ string expectedAuthRequestEmail =
+ string ( "Page=PasswordSeparationSignIn&continue=redirectLink&scope=Scope&service=lso&GALX=cookie"
+ "&Email=") + USERNAME2;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong authentication request for Email",
+ expectedAuthRequestEmail, authRequestEmail );
+
+ // Check authentication request for password
+ string authRequestPassword( curl_mockup_getRequestBody( LOGIN_URL.c_str(), empty.c_str( ),
+ "POST" ) );
+ string expectedAuthRequestPassword =
+ string ( "continue=redirectLink&scope=Scope&service=lso&GALX=cookie"
+ "&Passwd=") + PASSWORD2;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong authentication request for Password",
+ expectedAuthRequestPassword, authRequestPassword );
+
+ // Check request for pin code
+ string authRequestPin( curl_mockup_getRequestBody( CHALLENGE_URL.c_str(), empty.c_str( ),
+ "POST" ) );
+ string expectedAuthRequestPin =
+ string ( "continue=redirectLink&scope=Scope&service=lso&GALX=cookie"
+ "&Pin=") + PIN;
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong authentication request for Pin",
+ expectedAuthRequestPin, authRequestPin );
+
+ // Check code request
+ string codeRequest( curl_mockup_getRequestBody( APPROVAL_URL.c_str(),
+ empty.c_str( ), "POST" ) );
+ string expectedCodeRequest = string( "state_wrapper=stateWrapper&submit_access=true" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong approval request",
+ expectedCodeRequest, codeRequest);
+
+ // Check token request
+ string expectedTokenRequest =
+ string( "code=AuthCode") +
+ string( "&client_id=") + CLIENT_ID +
+ string( "&redirect_uri=") + REDIRECT_URI +
+ string( "&scope=") + SCOPE +
+ string( "&grant_type=authorization_code" );
+
+ string tokenRequest( curl_mockup_getRequestBody( TOKEN_URL.c_str(), empty.c_str( ),
+ "POST" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong token request",
+ expectedTokenRequest, tokenRequest );
+
+ // Check token
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "Wrong access token",
+ string ( "mock-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "Wrong refresh token",
+ string ("mock-refresh-token"),
+ session->m_oauth2Handler->getRefreshToken( ));
+}
+
+void GDriveTest::sessionExpiryTokenGetTest( )
+{
+ // Access_token will expire after expires_in seconds,
+ // We need to use the refresh key to get a new one.
+
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ curl_mockup_reset( );
+ static const string objectId("aFileId");
+ string url = BASE_URL + "/files/" + objectId;
+
+ // 401 response, token is expired
+ curl_mockup_addResponse( url.c_str( ),"", "GET", "", 401, false );
+
+ curl_mockup_addResponse( TOKEN_URL.c_str(), "",
+ "POST", DATA_DIR "/gdrive/refresh_response.json", 200, true);
+ try
+ {
+ // GET expires, need to refresh then GET again
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+ }
+ catch ( ... )
+ {
+ if ( session->getHttpStatus( ) == 401 )
+ {
+ // Check if access token is refreshed
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "wrong access token",
+ string ( "new-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ) );
+ }
+ }
+}
+
+void GDriveTest::sessionExpiryTokenPostTest( )
+{
+ // Access_token will expire after expires_in seconds,
+ // We need to use the refresh key to get a new one.
+
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ curl_mockup_reset( );
+ static const string folderId("aFileId");
+ const string folderUrl = BASE_URL + "/files/" + folderId;
+ const string metaUrl = BASE_URL + "/files";
+
+ curl_mockup_addResponse( TOKEN_URL.c_str(), "",
+ "POST", DATA_DIR "/gdrive/refresh_response.json", 200, true);
+
+ curl_mockup_addResponse( folderUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true );
+
+ // 401 response, token is expired
+ // refresh and then POST again
+ curl_mockup_addResponse( metaUrl.c_str( ), "",
+ "POST", "", 401, false );
+ libcmis::FolderPtr parent = session->getFolder( folderId );
+
+ try
+ {
+ PropertyPtrMap properties;
+ // POST expires, need to refresh then POST again
+ parent->createFolder( properties );
+ }
+ catch ( ... )
+ {
+ if ( session->getHttpStatus( ) == 401 )
+ {
+ // Check if access token is refreshed
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "wrong access token",
+ string ( "new-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ) );
+ }
+ }
+}
+
+void GDriveTest::sessionExpiryTokenDeleteTest( )
+{
+ // Access_token will expire after expires_in seconds,
+ // We need to use the refresh key to get a new one.
+
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ curl_mockup_reset( );
+ static const string objectId("aFileId");
+ string url = BASE_URL + "/files/" + objectId;
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document2.json", 200, true);
+
+ curl_mockup_addResponse( TOKEN_URL.c_str(), "",
+ "POST", DATA_DIR "/gdrive/refresh_response.json", 200, true);
+ // 401 response, token is expired
+ curl_mockup_addResponse( url.c_str( ),"", "DELETE", "", 401, false);
+
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ try
+ {
+ // DELETE expires, need to refresh then DELETE again
+ object->remove( );
+ }
+ catch ( ... )
+ {
+ if ( session->getHttpStatus( ) == 401 )
+ {
+ // Check if access token is refreshed
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "wrong access token",
+ string ( "new-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ) );
+ const struct HttpRequest* deleteRequest = curl_mockup_getRequest( url.c_str( ), "", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "Delete request not sent", deleteRequest );
+ curl_mockup_HttpRequest_free( deleteRequest );
+ }
+ }
+
+}
+
+void GDriveTest::sessionExpiryTokenPutTest( )
+{
+ // Access_token will expire after expires_in seconds,
+ // We need to use the refresh key to get a new one.
+
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ curl_mockup_reset( );
+ static const string objectId("aFileId");
+ string url = BASE_URL + "/files/" + objectId;
+
+ curl_mockup_addResponse( TOKEN_URL.c_str(), "",
+ "POST", DATA_DIR "/gdrive/refresh_response.json", 200, true);
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true );
+
+ // 401 response, token is expired
+ curl_mockup_addResponse( url.c_str( ),"", "PUT", "", 401, false );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ try
+ {
+ // PUT expires, need to refresh then PUT again
+ object->updateProperties( object->getProperties( ) );
+ }
+ catch ( ... )
+ {
+ if ( session->getHttpStatus( ) == 401 )
+ {
+ // Check if access token is refreshed
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "wrong access token",
+ string ( "new-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ) );
+ }
+ }
+}
+
+void GDriveTest::setRepositoryTest( )
+{
+ GDriveSession session;
+ CPPUNIT_ASSERT_MESSAGE( "Should never fail", session.setRepository( "foobar" ) );
+}
+
+void GDriveTest::getDocumentTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFileId");
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/files/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+
+ // Check if we got the document object.
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( obj );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+
+ // Test the document properties
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document ID", objectId, document->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document name",
+ string( "GDrive File" ),
+ document->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document type",
+ string( "application/vnd.google-apps.form" ),
+ document->getContentType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:document" ), document->getBaseType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type", string( "cmis:document" ), document->getType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !document->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !document->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !document->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !document->getLastModificationDate( ).is_not_a_date_time() );
+
+ CPPUNIT_ASSERT_MESSAGE( "Content length is incorrect", 123 == document->getContentLength( ) );
+}
+
+void GDriveTest::getFolderTest( )
+{
+ curl_mockup_reset( );
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ static const string folderId( "aFolderId" );
+ static const string parentId( "parentID" );
+ string url = BASE_URL + "/files/" + folderId;
+ string parentUrl = BASE_URL + "/files/" + parentId;
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+ curl_mockup_addResponse( parentUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+ // Check if we got the Folder object.
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::FolderPtr",
+ NULL != folder );
+
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder ID", folderId, folder->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder name", string( "testFolder" ), folder->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:folder" ), folder->getBaseType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type", string( "cmis:folder" ), folder->getType( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Missing folder parent", folder->getFolderParent( ).get( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a root folder", !folder->isRootFolder() );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !folder->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !folder->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !folder->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !folder->getLastModificationDate( ).is_not_a_date_time() );
+}
+
+void GDriveTest::getDocumentParentsTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ static const string documentId( "aFileId" );
+ static const string parentId( "aFolderId" );
+ static const string parentId2( "aNewFolderId" );
+ string url = BASE_URL + "/files/" + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+
+ string parent1Url = BASE_URL + "/files/" + parentId;
+ string parent2Url = BASE_URL + "/files/" + parentId2;
+ curl_mockup_addResponse( parent1Url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+ curl_mockup_addResponse( parent2Url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder2.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( "aFileId" );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ CPPUNIT_ASSERT_MESSAGE( "Document expected", document != NULL );
+
+ vector< libcmis::FolderPtr > parents= document->getParents( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of parents", size_t( 2 ), parents.size() );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong parent Id", parentId, parents[0]->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong parent Id", parentId2, parents[1]->getId( ) );
+}
+
+void GDriveTest::getContentStreamTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ static const string documentId( "aFileId" );
+ string url = BASE_URL + "/files/" + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+ string expectedContent( "Test content stream" );
+ string downloadUrl = "https://downloadLink";
+ curl_mockup_addResponse( downloadUrl.c_str( ), "", "GET", expectedContent.c_str( ), 0, false );
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream( );
+ ostringstream out;
+ out << is->rdbuf();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", expectedContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void GDriveTest::setContentStreamTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ const string documentId( "aFileId" );
+ const string uploadBaseUrl = "https://www.googleapis.com/upload/drive/v2/files/";
+
+ string url = BASE_URL + "/files/" + documentId;
+ string putUrl = uploadBaseUrl + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document2.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "PUT", DATA_DIR "/gdrive/document2.json", 200, true);
+ curl_mockup_addResponse( putUrl.c_str( ), "", "PUT", "Updated", 0, false );
+ try
+ {
+ string expectedContent( "Test set content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "aFileName" );
+ document->setContentStream( os, "text/plain", filename );
+
+ CPPUNIT_ASSERT_MESSAGE( "Object not refreshed during setContentStream", object->getRefreshTimestamp( ) > 0 );
+
+ // Check if metadata has been properly uploaded
+ const char* meta = curl_mockup_getRequestBody( url.c_str( ), "", "PUT" );
+ string expectedMeta = "{\n \"title\": \"aFileName\"\n}\n";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad meta uploaded", expectedMeta, string( meta ) );
+ // Check the content has been properly uploaded
+ const char* content = curl_mockup_getRequestBody( putUrl.c_str( ), "", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void GDriveTest::setContentStreamGdocTest( )
+{
+
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ const string documentId( "aFileId" );
+ const string uploadBaseUrl = "https://www.googleapis.com/upload/drive/v2/files/";
+
+ string url = BASE_URL + "/files/" + documentId;
+ string putUrl = uploadBaseUrl + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ curl_mockup_addResponse( url.c_str( ), "convert=true",
+ "PUT", DATA_DIR "/gdrive/document.json", 200, true);
+ curl_mockup_addResponse( putUrl.c_str( ), "convert=true", "PUT", "Updated", 0, false );
+ try
+ {
+ string expectedContent( "Test set content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "aFileName" );
+ document->setContentStream( os, "text/plain", filename );
+
+ CPPUNIT_ASSERT_MESSAGE( "Object not refreshed during setContentStream", object->getRefreshTimestamp( ) > 0 );
+
+ // Check the content has been properly uploaded
+ const char* content = curl_mockup_getRequestBody( putUrl.c_str( ), "", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void GDriveTest::getChildrenTest( )
+{
+ curl_mockup_reset( );
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ static const string folderId ("aFolderId");
+ string url = BASE_URL + "/files/" + folderId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+
+ string urlChildFolder = BASE_URL + "/files/" + string ("aChildFolder");
+ curl_mockup_addResponse( urlChildFolder.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+
+ string urlChildDocument = BASE_URL + "/files/" + string ("aChildDocument");
+ curl_mockup_addResponse( urlChildDocument.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( folderId );
+
+ // Check if we got the Folder object.
+ libcmis::FolderPtr folder = boost::dynamic_pointer_cast< libcmis::Folder >( obj );
+
+ CPPUNIT_ASSERT_MESSAGE( "Folder expected", folder != NULL );
+
+
+ string query = "q=\"" + folderId + "\"+in+parents+and+trashed+=+false";
+ string childrenUrl = BASE_URL + "/files";
+ curl_mockup_addResponse( childrenUrl.c_str( ), query.c_str( ),
+ "GET", DATA_DIR "/gdrive/folder_children.json", 200, true);
+
+ vector< libcmis::ObjectPtr > children= folder->getChildren( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of children", size_t( 2 ), children.size() );
+
+ int folderCount = 0;
+ int documentCount = 0;
+ for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
+ it != children.end( ); ++it )
+ {
+ if ( NULL != boost::dynamic_pointer_cast< libcmis::Folder >( *it ) )
+ ++folderCount;
+ else if ( NULL != boost::dynamic_pointer_cast< libcmis::Document >( *it ) )
+ ++documentCount;
+ }
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of folder children", 1, folderCount );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of document children", 1, documentCount );
+}
+
+void GDriveTest::getTypeTest( )
+{
+ curl_mockup_reset( );
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ string expectedId( "cmis:document" );
+ libcmis::ObjectTypePtr actual = session->getType( expectedId );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Id for fetched type", expectedId, actual->getId( ) );
+}
+
+void GDriveTest::getRepositoriesTest( )
+{
+ curl_mockup_reset( );
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ vector< libcmis::RepositoryPtr > actual = session->getRepositories( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of repositories", size_t( 1 ),
+ actual.size( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong repository found",
+ string ( "GoogleDrive" ),
+ actual.front()->getId( ) );
+}
+
+void GDriveTest::getObjectTest()
+{
+ static const string objectId ("aFileId");
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/files/" + objectId;
+ curl_mockup_addResponse ( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/gdoc-file.json", 200, true);
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ boost::shared_ptr<GDriveObject> obj = boost::dynamic_pointer_cast
+ <GDriveObject>(object);
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Object Id", objectId,
+ obj->getId( ) );
+}
+
+void GDriveTest::getObjectByPathRootTest()
+{
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string rootUrl = BASE_URL + "/files/root";
+ curl_mockup_addResponse ( rootUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObjectByPath( "/" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Object Id",
+ string("testFolder"), object->getName( ) );
+}
+
+void GDriveTest::getObjectByPathTest()
+{
+ // Mockup setup
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string rootChildUrl = BASE_URL + "/files/root/children/";
+ curl_mockup_addResponse ( rootChildUrl.c_str( ), "q=title+=+'GDrive File'",
+ "GET", DATA_DIR "/gdrive/root_child_search.json", 200, true );
+
+ string urlRootChildDoc = BASE_URL + "/files/aRootChildId2";
+ curl_mockup_addResponse( urlRootChildDoc.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true );
+
+ // Tested method
+ libcmis::ObjectPtr object = session->getObjectByPath( "/GDrive File" );
+
+ // Check the result
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Object",
+ string("GDrive File"), object->getName( ) );
+}
+
+void GDriveTest::getObjectByPathMissingTest()
+{
+ // Mockup setup
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string rootChildUrl = BASE_URL + "/files/root/children/";
+ curl_mockup_addResponse ( rootChildUrl.c_str( ), "q=title+=+'GDrive File'",
+ "GET", DATA_DIR "/gdrive/root_child_missing.json", 200, true );
+
+ // Tested method
+ try
+ {
+ libcmis::ObjectPtr object = session->getObjectByPath( "/GDrive File" );
+ CPPUNIT_FAIL( "objectNotFound exception expected" );
+ }
+ catch ( libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE("Bad exception type",
+ string( "objectNotFound" ), e.getType( ) );
+ }
+}
+
+void GDriveTest::getDocumentAllowableActionsTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFileId");
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/files/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( obj );
+
+ boost::shared_ptr< libcmis::AllowableActions > actions = document->getAllowableActions( );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetContentStream allowable action should be true",
+ actions->isDefined( libcmis::ObjectAction::GetContentStream ) &&
+ actions->isAllowed( libcmis::ObjectAction::GetContentStream ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreateDocument allowable action should be false",
+ actions->isDefined( libcmis::ObjectAction::CreateDocument ) &&
+ !actions->isAllowed( libcmis::ObjectAction::CreateDocument ) );
+}
+
+void GDriveTest::getFolderAllowableActionsTest( )
+{
+ curl_mockup_reset( );
+ static const string folderId ("aFolderId");
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/files/" + folderId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true);
+
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+
+ boost::shared_ptr< libcmis::AllowableActions > actions = folder->getAllowableActions( );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreateDocument allowable action should be true",
+ actions->isDefined( libcmis::ObjectAction::CreateDocument ) &&
+ actions->isAllowed( libcmis::ObjectAction::CreateDocument ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetContentStream allowable action should be false",
+ actions->isDefined( libcmis::ObjectAction::GetContentStream ) &&
+ !actions->isAllowed( libcmis::ObjectAction::GetContentStream ) );
+}
+
+void GDriveTest::checkOutTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ static const string documentId( "aFileId" );
+ string url = BASE_URL + "/files/" + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ libcmis::DocumentPtr checkout = document->checkOut( );
+ CPPUNIT_ASSERT_MESSAGE( "CheckOut failed", NULL != checkout );
+}
+
+void GDriveTest::checkInTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ const string documentId( "aFileId" );
+ const string uploadBaseUrl = "https://www.googleapis.com/upload/drive/v2/files/";
+
+ string url = BASE_URL + "/files/" + documentId;
+ string putUrl = uploadBaseUrl + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document2.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "PUT", DATA_DIR "/gdrive/document2.json", 200, true);
+ curl_mockup_addResponse( putUrl.c_str( ), "", "PUT", "Updated", 0, false );
+
+ string expectedContent( "content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "aFileName" );
+
+ const PropertyPtrMap& properties = document->getProperties( );
+ libcmis::DocumentPtr checkIn = document->checkIn( true, "", properties, os, "text/plain", filename);
+ CPPUNIT_ASSERT_MESSAGE( "CheckIn failed", NULL != checkIn );
+}
+
+void GDriveTest::deleteTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ const string objectId( "aFileId" );
+
+ string url = BASE_URL + "/files/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document2.json", 200, true);
+ curl_mockup_addResponse( url.c_str( ),"", "DELETE", "", 204, false);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ object->remove( );
+ const struct HttpRequest* deleteRequest = curl_mockup_getRequest( url.c_str( ), "", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "Delete request not sent", deleteRequest );
+ curl_mockup_HttpRequest_free( deleteRequest );
+}
+
+void GDriveTest::moveTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string objectId( "aFileId" );
+ const string sourceId( "aFolderId" );
+ const string desId( "aNewFolderId" );
+
+ string url = BASE_URL + "/files/" + objectId;
+ string sourceUrl = BASE_URL + "/files/" + sourceId;
+ string desUrl = BASE_URL + "/files/" + desId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document2.json", 200, true );
+ curl_mockup_addResponse( url.c_str( ), "",
+ "PUT", DATA_DIR "/gdrive/document2.json", 200, true );
+ curl_mockup_addResponse( sourceUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true );
+ curl_mockup_addResponse( desUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder2.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ libcmis::FolderPtr source = session->getFolder( sourceId );
+ libcmis::FolderPtr destination = session->getFolder( desId );
+
+ object->move( source, destination );
+ const char* moveRequest = curl_mockup_getRequestBody( url.c_str( ), "", "PUT" );
+ Json parentJson = Json::parse( string( moveRequest ) );
+ string newParentId = parentJson["parents"].getList().front()["id"].toString( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad new parent folder",
+ desId, newParentId);
+}
+
+void GDriveTest::createDocumentTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string documentId( "aFileId" );
+ const string folderId( "aFolderId" );
+
+ const string folderUrl = BASE_URL + "/files/" + folderId;
+ const string metaUrl = BASE_URL + "/files/";
+ const string uploadBaseUrl = "https://www.googleapis.com/upload/drive/v2/files/";
+ string uploadUrl = uploadBaseUrl + documentId;
+ string documentUrl = metaUrl + documentId;
+
+ curl_mockup_addResponse( folderUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true );
+ curl_mockup_addResponse( metaUrl.c_str( ), "",
+ "POST", DATA_DIR "/gdrive/document.json", 200, true );
+ curl_mockup_addResponse( uploadUrl.c_str( ), "",
+ "PUT", "updated", 0, false );
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document2.json", 200, true);
+
+ libcmis::FolderPtr parent = session->getFolder( folderId );
+
+ try
+ {
+ string expectedContent( "Test set content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "aFileName" );
+ PropertyPtrMap properties;
+
+ // function to test
+ parent->createDocument( properties, os, "text/plain", filename );
+
+ const char* createRequest = curl_mockup_getRequestBody( metaUrl.c_str( ), "", "POST" );
+ Json request = Json::parse( string( createRequest ) );
+ string sentParentId = request["parents"].getList( ).front( )["id"].toString( );
+ string sentFilename = request["title"].toString( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad parents sent", folderId, sentParentId );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad filename sent", filename, sentFilename );
+
+ const char* content = curl_mockup_getRequestBody( uploadUrl.c_str( ), "", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void GDriveTest::createFolderTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string folderId( "aFolderId" );
+
+ const string folderUrl = BASE_URL + "/files/" + folderId;
+ const string metaUrl = BASE_URL + "/files/";
+
+ curl_mockup_addResponse( folderUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true );
+ curl_mockup_addResponse( metaUrl.c_str( ), "",
+ "POST", DATA_DIR "/gdrive/folder2.json", 200, true );
+ libcmis::FolderPtr parent = session->getFolder( folderId );
+ try
+ {
+ PropertyPtrMap properties;
+
+ // function to test
+ parent->createFolder( properties );
+
+ const char* createRequest = curl_mockup_getRequestBody( metaUrl.c_str( ), "", "POST" );
+ Json request = Json::parse( string( createRequest ) );
+
+ string sentParentId = request["parents"].getList( ).front( )["id"].toString( );
+ string sentMimeType = request["mimeType"].toString( );
+ string expectedMimeType( "application/vnd.google-apps.folder" );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad parents sent", folderId, sentParentId );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad mimeType", expectedMimeType, sentMimeType );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void GDriveTest::removeTreeTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string folderId( "aFolderId" );
+
+ const string folderUrl = BASE_URL + "/files/" + folderId;
+ const string trashUrl = folderUrl + "/trash";
+
+ curl_mockup_addResponse( folderUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/folder.json", 200, true );
+ curl_mockup_addResponse( trashUrl.c_str( ), "",
+ "POST", "", 200, false );
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+
+ // just make sure it doesn't crash
+ folder->removeTree( );
+}
+
+void GDriveTest::getContentStreamWithRenditionsTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ static const string documentId( "aFileId" );
+ string url = BASE_URL + "/files/" + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ // pdf stream
+ string pdfContent( "pdf Content stream" );
+ string pdfUrl = "pdflink";
+ curl_mockup_addResponse( pdfUrl.c_str( ), "", "GET", pdfContent.c_str( ), 0, false );
+
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream( "application/pdf" );
+ ostringstream out;
+ out << is->rdbuf();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", pdfContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+
+ // ODF stream
+ string odfContent( "open document Content stream" );
+ string odfUrl = "https://downloadLink";
+ curl_mockup_addResponse( odfUrl.c_str( ), "", "GET", odfContent.c_str( ), 0, false );
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream( "application/x-vnd.oasis.opendocument.spreadsheet" );
+ ostringstream out;
+ out << is->rdbuf();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", odfContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+
+ // MS stream
+ string msContent( "office document Content stream" );
+ string msUrl = "xlslink";
+ curl_mockup_addResponse( msUrl.c_str( ), "", "GET", msContent.c_str( ), 0, false );
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream(
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" );
+ ostringstream out;
+ out << is->rdbuf();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", msContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void GDriveTest::updatePropertiesTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string documentId( "aFileId" );
+ const string documentUrl = BASE_URL + "/files/" + documentId;
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true );
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "PUT", DATA_DIR "/gdrive/document-updated.json", 200, true );
+
+
+ // Values for the test
+ string propertyName( "cmis:name" );
+ string expectedValue( "New Title" );
+ libcmis::ObjectPtr object = session->getObject( documentId );
+
+ // Fill the map of properties to change
+ PropertyPtrMap newProperties;
+
+ libcmis::ObjectTypePtr objectType = object->getTypeDescription( );
+ map< string, libcmis::PropertyTypePtr >::iterator it = objectType->getPropertiesTypes( ).find( propertyName );
+ vector< string > values;
+ values.push_back( expectedValue );
+ libcmis::PropertyPtr property( new libcmis::Property( it->second, values ) );
+ newProperties[ propertyName ] = property;
+
+ // Update the properties (method to test)
+ object->updateProperties( newProperties );
+
+ // Check that the sent request is OK
+ const char* updateRequest = curl_mockup_getRequestBody( documentUrl.c_str( ), "", "PUT" );
+
+ // Check the sent properties
+ Json json = Json::parse( string( updateRequest ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Only the updated properties should be sent",
+ size_t( 1 ), json.getObjects().size( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "title key not present",
+ expectedValue, json["title"].toString( ) );
+
+ // Check that the object is updated
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Object not updated",
+ expectedValue, object->getName() );
+}
+
+void GDriveTest::propertyCopyTest( )
+{
+ string name = "cmis:name";
+ string value = "some value";
+
+ GDriveProperty property( name, Json( value.c_str() ) );
+ {
+ GDriveProperty copy = property;
+
+ CPPUNIT_ASSERT_EQUAL( name, copy.getPropertyType()->getId() );
+ CPPUNIT_ASSERT_EQUAL( value, copy.getStrings()[0] );
+ }
+
+ {
+ GDriveProperty copy;
+ copy = property;
+
+ CPPUNIT_ASSERT_EQUAL( name, copy.getPropertyType()->getId() );
+ CPPUNIT_ASSERT_EQUAL( value, copy.getStrings()[0] );
+ }
+}
+
+void GDriveTest::getRefreshTokenTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Refresh token does not match",
+ string ("mock-refresh-token"),
+ session->getRefreshToken( ) );
+}
+
+void GDriveTest::getThumbnailUrlTest( )
+{
+ curl_mockup_reset( );
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string documentId( "aFileId" );
+
+ const string documentUrl = BASE_URL + "/files/" + documentId;
+
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true );
+
+ libcmis::ObjectPtr document = session->getObject( documentId );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Thumbnail URL does not match",
+ string ("https://aThumbnailLink"),
+ document->getThumbnailUrl( ) );
+
+}
+
+void GDriveTest::getAllVersionsTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFileId");
+
+ GDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/files/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/document.json", 200, true);
+ string revisionUrl = url + "/revisions";
+ curl_mockup_addResponse( revisionUrl.c_str( ), "",
+ "GET", DATA_DIR "/gdrive/allVersions.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( obj );
+
+ // Method to test
+ vector< libcmis::DocumentPtr > versions = document->getAllVersions( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of versions", size_t( 3 ), versions.size( ) );
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( GDriveTest );
+
diff --git a/qa/libcmis/test-helpers.cxx b/qa/libcmis/test-helpers.cxx
new file mode 100644
index 0000000..0ef2452
--- /dev/null
+++ b/qa/libcmis/test-helpers.cxx
@@ -0,0 +1,187 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "test-helpers.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+namespace test
+{
+
+ XmlNodeRef::XmlNodeRef( xmlNodePtr node, boost::shared_ptr< xmlDoc > doc )
+ : m_node( node )
+ , m_doc( doc )
+ {
+ }
+
+ XmlNodeRef::XmlNodeRef( const XmlNodeRef& other )
+ : m_node( other.m_node )
+ , m_doc( other.m_doc )
+ {
+ }
+
+ XmlNodeRef& XmlNodeRef::operator=( const XmlNodeRef& other )
+ {
+ m_node = other.m_node;
+ m_doc = other.m_doc;
+ return *this;
+ }
+
+ XmlNodeRef::operator xmlNodePtr( ) const
+ {
+ return m_node;
+ }
+
+ XmlNodeRef getXmlNode( string str )
+ {
+ xmlNodePtr node = NULL;
+ const boost::shared_ptr< xmlDoc > doc( xmlReadMemory( str.c_str( ), str.size( ), "tester", NULL, 0 ), xmlFreeDoc );
+ if ( bool( doc ) )
+ node = xmlDocGetRootElement( doc.get() );
+
+ return XmlNodeRef( node, doc );
+ }
+
+ const char* getXmlns( )
+ {
+ return "xmlns:cmis=\"http://docs.oasis-open.org/ns/cmis/core/200908/\" xmlns:cmisra=\"http://docs.oasis-open.org/ns/cmis/restatom/200908/\" ";
+ }
+
+ string writeXml( boost::shared_ptr< libcmis::XmlSerializable > serializable )
+ {
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+ serializable->toXml( writer );
+ xmlTextWriterEndDocument( writer );
+
+ string str( ( const char * )xmlBufferContent( buf ) );
+
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ return str;
+ }
+
+ string getXmlNodeAsString( const string& xmlDoc, const string& xpath )
+ {
+ string result;
+ xmlDocPtr doc = xmlReadMemory( xmlDoc.c_str(), xmlDoc.size(), "", NULL, 0 );
+
+ if ( NULL != doc )
+ {
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+ libcmis::registerCmisWSNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( xpath.c_str() ), xpathCtx );
+
+ if ( xpathObj != NULL )
+ {
+ int nbResults = 0;
+ if ( xpathObj->nodesetval )
+ nbResults = xpathObj->nodesetval->nodeNr;
+
+ for ( int i = 0; i < nbResults; ++i )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlNodeDump( buf, doc, node, 0, 0 );
+ result += string( ( char * )xmlBufferContent( buf ) );
+ xmlBufferFree( buf );
+ }
+ }
+ xmlXPathFreeObject( xpathObj);
+ }
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ throw libcmis::Exception( "Failed to parse service document" );
+
+ xmlFreeDoc( doc );
+
+ return result;
+ }
+
+ libcmis::DocumentPtr createVersionableDocument( libcmis::Session* session, string docName )
+ {
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "VersionableType" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( docName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "VersionableType" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Actually send the document creation request
+ string contentStr = "Some content";
+ boost::shared_ptr< ostream > os ( new stringstream( contentStr ) );
+ string contentType = "text/plain";
+ string filename( "name.txt" );
+
+ return parent->createDocument( props, os, contentType, filename );
+ }
+
+ void loadFromFile( const char* path, string& buf )
+ {
+ ifstream in( path );
+
+ in.seekg( 0, ios::end );
+ int length = in.tellg( );
+ in.seekg( 0, ios::beg );
+
+ char* buffer = new char[length];
+ in.read( buffer, length );
+ in.close( );
+
+ buf = string( buffer, length );
+ delete[] buffer;
+ }
+}
diff --git a/qa/libcmis/test-helpers.hxx b/qa/libcmis/test-helpers.hxx
new file mode 100644
index 0000000..9e02357
--- /dev/null
+++ b/qa/libcmis/test-helpers.hxx
@@ -0,0 +1,63 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include <libcmis/document.hxx>
+#include <libcmis/session.hxx>
+#include <libcmis/xmlserializable.hxx>
+
+namespace test
+{
+ class XmlNodeRef
+ {
+ public:
+ XmlNodeRef( xmlNodePtr node, boost::shared_ptr< xmlDoc > doc );
+ XmlNodeRef( const XmlNodeRef& other );
+ XmlNodeRef& operator=( const XmlNodeRef& other );
+
+ operator xmlNodePtr( ) const;
+
+ private:
+ xmlNodePtr m_node;
+ boost::shared_ptr< xmlDoc > m_doc;
+ };
+
+ // Test helper functions for parser and writer tests
+ XmlNodeRef getXmlNode( std::string str );
+ const char* getXmlns( );
+ std::string writeXml( boost::shared_ptr< libcmis::XmlSerializable > serializable );
+
+ std::string getXmlNodeAsString( const std::string& xmlDoc, const std::string& xpath );
+
+ libcmis::DocumentPtr createVersionableDocument( libcmis::Session* session, std::string docName );
+ void loadFromFile( const char* path, std::string& buf );
+}
diff --git a/qa/libcmis/test-jsonutils.cxx b/qa/libcmis/test-jsonutils.cxx
new file mode 100644
index 0000000..4a9fd49
--- /dev/null
+++ b/qa/libcmis/test-jsonutils.cxx
@@ -0,0 +1,182 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <string>
+#include <fstream>
+#include <cerrno>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <libcmis/property.hxx>
+#include <libcmis/property-type.hxx>
+
+#include "json-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+class JsonTest : public CppUnit::TestFixture
+{
+ public:
+ void parseTest( );
+ void parseTypeTest( );
+ void createFromPropertyTest( );
+ void createFromPropertiesTest( );
+ void badKeyTest( );
+ void addTest( );
+
+ CPPUNIT_TEST_SUITE( JsonTest );
+ CPPUNIT_TEST( parseTest );
+ CPPUNIT_TEST( parseTypeTest );
+ CPPUNIT_TEST( createFromPropertyTest );
+ CPPUNIT_TEST( createFromPropertiesTest );
+ CPPUNIT_TEST( badKeyTest );
+ CPPUNIT_TEST( addTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+string getFileContents( const char *filename)
+{
+ std::ifstream in( filename, std::ios::in | std::ios::binary );
+ if (in)
+ {
+ std::string contents;
+ in.seekg( 0, std::ios::end );
+ contents.resize(in.tellg( ) );
+ in.seekg( 0, std::ios::beg );
+ in.read( &contents[0], contents.size( ) );
+ in.close( );
+ return contents;
+ }
+ throw ( errno );
+}
+
+Json parseFile( string fileName )
+{
+ Json json = Json::parse( getFileContents( fileName.c_str( ) ) );
+ return json;
+}
+
+void JsonTest::parseTest( )
+{
+ Json json = parseFile( DATA_DIR "/gdrive/jsontest-good.json" );
+ string kind = json["kind"].toString( );
+ string id = json["id"].toString( );
+ string mimeType = json["mimeType"].toString( );
+ string createdDate = json["createdDate"].toString( );
+ string intTest = json["intTest"].toString( );
+ string doubleTest = json["doubleTest"].toString( );
+ string editable = json["editable"].toString( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong kind", string( "drive#file" ), kind );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id", string( "aFileId"), id );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong mimeType", string( "application/vnd.google-apps.form"), mimeType );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong createdDate", string( "2010-04-28T14:53:23.141Z"), createdDate );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong intTest", string("-123"), intTest );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong doubleTest", string("-123.456"), doubleTest );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong editable", string( "true"), editable );
+}
+
+void JsonTest::parseTypeTest( )
+{
+ Json json = parseFile( DATA_DIR "/gdrive/jsontest-good.json" );
+ Json::Type stringType = json["kind"].getDataType( );
+ Json::Type boolType = json["editable"].getDataType( );
+ Json::Type intType = json["intTest"].getDataType( );
+ Json::Type doubleType = json["doubleTest"].getDataType( );
+ Json::Type dateTimeType = json["createdDate"].getDataType( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong string type", Json::json_string, stringType );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong bool type", Json::json_bool, boolType );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong int type", Json::json_int, intType );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong double type", Json::json_double, doubleType );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong datetime type", Json::json_datetime, dateTimeType );
+}
+
+void JsonTest::createFromPropertyTest( )
+{
+ vector< string > values;
+ string expected("Value 1" );
+ values.push_back( expected );
+
+ PropertyTypePtr propertyType( new PropertyType( ) );
+
+ PropertyPtr property( new Property( propertyType, values ) );
+
+ Json json( property );
+
+ CPPUNIT_ASSERT_EQUAL( expected, json.toString( ) );
+}
+
+void JsonTest::createFromPropertiesTest( )
+{
+ vector< string > values;
+ string expected( "value" );
+ values.push_back( "value" );
+
+ PropertyTypePtr propertyType( new PropertyType( ) );
+
+ PropertyPtr property( new libcmis::Property( propertyType, values ) );
+
+ PropertyPtrMap properties;
+ properties[ "key" ] = property;
+
+ Json json( properties );
+
+ CPPUNIT_ASSERT_EQUAL( expected, json["key"].toString( ) );
+}
+
+void JsonTest::badKeyTest( )
+{
+ Json json = parseFile( DATA_DIR "/gdrive/jsontest-good.json" );
+ // just make sure it doesn't crash here
+ string notExist = json["nonExistedKey"].toString( );
+ CPPUNIT_ASSERT_EQUAL( string( ), notExist);
+}
+
+void JsonTest::addTest( )
+{
+ Json json = parseFile( DATA_DIR "/gdrive/jsontest-good.json" );
+ Json addJson("added");
+ json.add( "new", addJson);
+ CPPUNIT_ASSERT_EQUAL( addJson.toString( ), json["new"].toString( ) );
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( JsonTest );
diff --git a/qa/libcmis/test-main.cxx b/qa/libcmis/test-main.cxx
new file mode 100644
index 0000000..23555e9
--- /dev/null
+++ b/qa/libcmis/test-main.cxx
@@ -0,0 +1,39 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+int main( int, char** )
+{
+ CppUnit::TextUi::TestRunner runner;
+ CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ runner.addTest( registry.makeTest() );
+ bool wasSuccess = runner.run( "", false );
+ return !wasSuccess;
+}
diff --git a/qa/libcmis/test-mockup-helpers.cxx b/qa/libcmis/test-mockup-helpers.cxx
new file mode 100644
index 0000000..40c3605
--- /dev/null
+++ b/qa/libcmis/test-mockup-helpers.cxx
@@ -0,0 +1,50 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <test-helpers.hxx>
+#include <mockup-config.h>
+
+using namespace std;
+
+namespace test
+{
+ void addWsResponse( const char* url, const char* filename,
+ const char* bodyMatch = 0 )
+ {
+ string outBuf;
+ loadFromFile( filename, outBuf );
+
+ string emptyLine = ( "\n\n" );
+ size_t pos = outBuf.find( emptyLine );
+ string headers = outBuf.substr( 0, pos );
+ string body = outBuf.substr( pos + emptyLine.size() );
+
+ curl_mockup_addResponse( url, "", "POST", body.c_str(), 0, false,
+ headers.c_str(), bodyMatch );
+ }
+}
diff --git a/qa/libcmis/test-mockup-helpers.hxx b/qa/libcmis/test-mockup-helpers.hxx
new file mode 100644
index 0000000..75e854a
--- /dev/null
+++ b/qa/libcmis/test-mockup-helpers.hxx
@@ -0,0 +1,33 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+namespace test
+{
+ void addWsResponse( const char* url, const char* filename,
+ const char* bodyMatch = 0 );
+}
diff --git a/qa/libcmis/test-onedrive.cxx b/qa/libcmis/test-onedrive.cxx
new file mode 100644
index 0000000..b15edd1
--- /dev/null
+++ b/qa/libcmis/test-onedrive.cxx
@@ -0,0 +1,781 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <string>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <mockup-config.h>
+
+#include <fstream>
+
+#include <libcmis/document.hxx>
+
+#include "onedrive-object.hxx"
+#include "onedrive-property.hxx"
+#include "onedrive-session.hxx"
+#include "oauth2-handler.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+static const string CLIENT_ID ( "mock-id" );
+static const string CLIENT_SECRET ( "mock-secret" );
+static const string USERNAME( "mock-user" );
+static const string PASSWORD( "mock-password" );
+static const string LOGIN_URL ("https://login/url" );
+static const string LOGIN_URL2 ("https://login2/url" );
+static const string APPROVAL_URL ("https://approval/url" );
+static const string AUTH_URL ( "https://auth/url" );
+static const string TOKEN_URL ( "https://token/url" );
+static const string SCOPE ( "https://scope/url" );
+static const string REDIRECT_URI ("redirect:uri" );
+static const string BASE_URL ( "https://base/url" );
+
+typedef std::unique_ptr<OneDriveSession> OneDriveSessionPtr;
+
+class OneDriveTest : public CppUnit::TestFixture
+{
+ public:
+ void sessionAuthenticationTest( );
+ void sessionExpiryTokenGetTest( );
+ void getRepositoriesTest( );
+ void getObjectTypeDocumentTest( );
+ void getObjectTypeFolderTest( );
+ void getObjectTest( );
+ void filePropertyTest( );
+ void deleteTest( );
+ void updatePropertiesTest( );
+ void getFileAllowableActionsTest( );
+ void getFolderAllowableActionsTest( );
+ void getFolderTest( );
+ void getChildrenTest( );
+ void moveTest( );
+ void getDocumentTest( );
+ void getDocumentParentTest( );
+ void getContentStreamTest( );
+ void setContentStreamTest( );
+ void createDocumentTest( );
+ void getObjectByPathTest( );
+
+ CPPUNIT_TEST_SUITE( OneDriveTest );
+ CPPUNIT_TEST( sessionAuthenticationTest );
+ CPPUNIT_TEST( sessionExpiryTokenGetTest );
+ CPPUNIT_TEST( getRepositoriesTest );
+ CPPUNIT_TEST( getObjectTypeDocumentTest );
+ CPPUNIT_TEST( getObjectTypeFolderTest );
+ CPPUNIT_TEST( getObjectTest );
+ CPPUNIT_TEST( filePropertyTest );
+ CPPUNIT_TEST( deleteTest );
+ CPPUNIT_TEST( updatePropertiesTest );
+ CPPUNIT_TEST( getFileAllowableActionsTest );
+ CPPUNIT_TEST( getFolderAllowableActionsTest );
+ CPPUNIT_TEST( getFolderTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( moveTest );
+ CPPUNIT_TEST( getDocumentTest );
+ CPPUNIT_TEST( getDocumentParentTest );
+ CPPUNIT_TEST( getContentStreamTest );
+ CPPUNIT_TEST( setContentStreamTest );
+ CPPUNIT_TEST( createDocumentTest );
+ CPPUNIT_TEST( getObjectByPathTest );
+ CPPUNIT_TEST_SUITE_END( );
+
+ private:
+ OneDriveSessionPtr getTestSession( string username, string password );
+};
+
+OneDriveSessionPtr OneDriveTest::getTestSession( string username, string password )
+{
+ libcmis::OAuth2DataPtr oauth2(
+ new libcmis::OAuth2Data( AUTH_URL, TOKEN_URL, SCOPE,
+ REDIRECT_URI, CLIENT_ID, CLIENT_SECRET ));
+ curl_mockup_reset( );
+ string empty;
+ // login, authentication & approval are done manually at the moment, so I'll
+ // temporarily borrow them from gdrive
+ //login response
+ string loginIdentifier = string("scope=") + SCOPE +
+ string("&redirect_uri=") + REDIRECT_URI +
+ string("&response_type=code") +
+ string("&client_id=") + CLIENT_ID;
+
+ curl_mockup_addResponse ( AUTH_URL.c_str(), loginIdentifier.c_str( ),
+ "GET", DATA_DIR "/gdrive/login1.html", 200, true);
+
+ //authentication email
+ curl_mockup_addResponse( LOGIN_URL2.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/gdrive/login2.html", 200, true);
+
+ //authentication password
+ curl_mockup_addResponse( LOGIN_URL.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/gdrive/approve.html", 200, true);
+
+ //approval response
+ curl_mockup_addResponse( APPROVAL_URL.c_str( ), empty.c_str( ),
+ "POST", DATA_DIR "/gdrive/authcode.html", 200, true);
+
+
+ // token response
+ curl_mockup_addResponse ( TOKEN_URL.c_str( ), empty.c_str( ), "POST",
+ DATA_DIR "/onedrive/token-response.json", 200, true );
+
+ return OneDriveSessionPtr( new OneDriveSession( BASE_URL, username, password, oauth2, false ) );
+}
+
+void OneDriveTest::sessionAuthenticationTest( )
+{
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string empty;
+
+ // Check token request
+ string expectedTokenRequest =
+ string( "code=AuthCode") +
+ string( "&client_id=") + CLIENT_ID +
+ string( "&client_secret=") + CLIENT_SECRET +
+ string( "&redirect_uri=") + REDIRECT_URI +
+ string( "&grant_type=authorization_code" );
+
+ string tokenRequest( curl_mockup_getRequestBody( TOKEN_URL.c_str(), empty.c_str( ),
+ "POST" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong token request",
+ expectedTokenRequest, tokenRequest );
+
+ // Check token
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "Wrong access token",
+ string ( "mock-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ));
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "Wrong refresh token",
+ string ("mock-refresh-token"),
+ session->m_oauth2Handler->getRefreshToken( ));
+}
+
+void OneDriveTest::sessionExpiryTokenGetTest( )
+{
+ // Access_token will expire after expires_in seconds,
+ // We need to use the refresh key to get a new one.
+
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ curl_mockup_reset( );
+ static const string objectId("aFileId");
+ string url = BASE_URL + "/me/skydrive/files/" + objectId;
+
+ // 401 response, token is expired
+ curl_mockup_addResponse( url.c_str( ),"", "GET", "", 401, false );
+
+ curl_mockup_addResponse( TOKEN_URL.c_str(), "",
+ "POST", DATA_DIR "/onedrive/refresh-response.json", 200, true);
+ try
+ {
+ // GET expires, need to refresh then GET again
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+ }
+ catch ( ... )
+ {
+ if ( session->getHttpStatus( ) == 401 )
+ {
+ // Check if access token is refreshed
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "wrong access token",
+ string ( "new-access-token" ),
+ session->m_oauth2Handler->getAccessToken( ) );
+ }
+ }
+}
+
+void OneDriveTest::getRepositoriesTest( )
+{
+ curl_mockup_reset( );
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ vector< libcmis::RepositoryPtr > actual = session->getRepositories( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of repositories", size_t( 1 ),
+ actual.size( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong repository found",
+ string ( "OneDrive" ),
+ actual.front()->getId( ) );
+}
+
+void OneDriveTest::getObjectTypeDocumentTest()
+{
+ curl_mockup_reset( );
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ libcmis::ObjectTypePtr actual = session->getType("cmis:document");
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type ID", string("cmis:document"),
+ actual->getId() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type queryName",
+ string("cmis:document"),
+ actual->getQueryName() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong parent", string(""),
+ actual->getParentTypeId() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string("cmis:document"),
+ actual->getBaseTypeId() );
+
+ CPPUNIT_ASSERT( actual->getParentType().get() == NULL );
+ CPPUNIT_ASSERT_EQUAL( string( "cmis:document" ),
+ actual->getBaseType()->getId() );
+
+ CPPUNIT_ASSERT( actual->isCreatable() );
+ CPPUNIT_ASSERT( !actual->isVersionable() );
+ CPPUNIT_ASSERT( actual->isFileable() );
+ CPPUNIT_ASSERT( actual->isQueryable() );
+ CPPUNIT_ASSERT( actual->isFulltextIndexed() );
+ CPPUNIT_ASSERT_EQUAL( libcmis::ObjectType::Allowed,
+ actual->getContentStreamAllowed() );
+
+ map< string, libcmis::PropertyTypePtr > props = actual->getPropertiesTypes();
+
+ CPPUNIT_ASSERT_MESSAGE( "Missing property cmis:name",
+ props.find("cmis:name") != props.end() );
+
+ CPPUNIT_ASSERT_MESSAGE( "Missing property cmis:name",
+ props.find("cmis:name") != props.end() );
+ CPPUNIT_ASSERT_MESSAGE( "Missing property cmis:contentStreamFileName",
+ props.find("cmis:contentStreamFileName") != props.end() );
+ CPPUNIT_ASSERT_MESSAGE( "Missing property cmis:contentStreamLength",
+ props.find("cmis:contentStreamLength") != props.end() );
+}
+
+void OneDriveTest::getObjectTypeFolderTest()
+{
+ curl_mockup_reset( );
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ libcmis::ObjectTypePtr actual = session->getType("cmis:folder");
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type ID", string("cmis:folder"),
+ actual->getId() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type queryName",
+ string("cmis:folder"),
+ actual->getQueryName() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong parent", string(""),
+ actual->getParentTypeId() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string("cmis:folder"),
+ actual->getBaseTypeId() );
+
+ CPPUNIT_ASSERT( actual->getParentType().get() == NULL );
+ CPPUNIT_ASSERT_EQUAL( string( "cmis:folder" ),
+ actual->getBaseType()->getId() );
+
+ CPPUNIT_ASSERT( actual->isCreatable() );
+ CPPUNIT_ASSERT( !actual->isVersionable() );
+ CPPUNIT_ASSERT( actual->isFileable() );
+ CPPUNIT_ASSERT( actual->isQueryable() );
+ CPPUNIT_ASSERT( !actual->isFulltextIndexed() );
+ CPPUNIT_ASSERT_EQUAL( libcmis::ObjectType::NotAllowed,
+ actual->getContentStreamAllowed() );
+
+ map< string, libcmis::PropertyTypePtr > props = actual->getPropertiesTypes();
+
+ CPPUNIT_ASSERT_MESSAGE( "Missing property cmis:name",
+ props.find("cmis:name") != props.end() );
+ CPPUNIT_ASSERT_MESSAGE( "Property cmis:contentStreamFileName shouldn't be set",
+ props.find("cmis:contentStreamFileName") == props.end() );
+ CPPUNIT_ASSERT_MESSAGE( "Property cmis:contentStreamLength shouldn't be set",
+ props.find("cmis:contentStreamLength") == props.end() );
+}
+
+void OneDriveTest::getObjectTest()
+{
+ static const string objectId ("aFileId");
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/" + objectId;
+ curl_mockup_addResponse ( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ boost::shared_ptr<OneDriveObject> obj = boost::dynamic_pointer_cast
+ <OneDriveObject>( object );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Object Id", objectId,
+ obj->getId( ) );
+}
+
+void OneDriveTest::filePropertyTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFileId");
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong creation date",
+ string ( "2014-06-09T08:24:04+0000" ),
+ obj->getStringProperty( "cmis:creationDate" ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong object id",
+ string ( "aFileId" ),
+ obj->getStringProperty( "cmis:objectId" ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong author",
+ string ( "onedriveUser" ),
+ obj->getStringProperty( "cmis:createdBy" ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong file name",
+ string ( "OneDriveFile" ),
+ obj->getStringProperty( "cmis:contentStreamFileName" ) );
+}
+
+void OneDriveTest::deleteTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ const string objectId( "aFileId" );
+
+ string url = BASE_URL + "/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+ curl_mockup_addResponse( url.c_str( ),"", "DELETE", "", 204, false);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ object->remove( );
+ const struct HttpRequest* deleteRequest = curl_mockup_getRequest( url.c_str( ), "", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "Delete request not sent", deleteRequest );
+ curl_mockup_HttpRequest_free( deleteRequest );
+}
+
+void OneDriveTest::updatePropertiesTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string objectId( "aFileId" );
+ const string newObjectId( "aNewFileId" );
+
+ const string objectUrl = BASE_URL + "/" + objectId;
+ const string newObjectUrl = BASE_URL + "/" + newObjectId;
+
+ curl_mockup_addResponse( objectUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true );
+ curl_mockup_addResponse( newObjectUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/updated-file.json", 200, true );
+ curl_mockup_addResponse( objectUrl.c_str( ), "",
+ "PUT", DATA_DIR "/onedrive/updated-file.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::ObjectPtr newObject = session->getObject( newObjectId );
+
+ object->updateProperties( newObject->getProperties( ) );
+
+ const char* updateRequest = curl_mockup_getRequestBody( objectUrl.c_str( ), "", "PUT" );
+
+ Json json = Json::parse( string( updateRequest ) );
+ string name = json["name"].toString( );
+ string description = json["description"].toString( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Name key not converted",
+ string( "New File Name"),
+ name );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Description key not converted",
+ string( "new description"),
+ description );
+}
+
+void OneDriveTest::getFileAllowableActionsTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFileId");
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ boost::shared_ptr< libcmis::AllowableActions > actions = object->getAllowableActions( );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetContentStream allowable action should be true",
+ actions->isDefined( libcmis::ObjectAction::GetContentStream ) &&
+ actions->isAllowed( libcmis::ObjectAction::GetContentStream ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreateDocument allowable action should be false",
+ actions->isDefined( libcmis::ObjectAction::CreateDocument ) &&
+ !actions->isAllowed( libcmis::ObjectAction::CreateDocument ) );
+}
+
+void OneDriveTest::getFolderAllowableActionsTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFolderId");
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folder.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ boost::shared_ptr< libcmis::AllowableActions > actions = object->getAllowableActions( );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreateDocument allowable action should be true",
+ actions->isDefined( libcmis::ObjectAction::CreateDocument ) &&
+ actions->isAllowed( libcmis::ObjectAction::CreateDocument ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetContentStream allowable action should be false",
+ actions->isDefined( libcmis::ObjectAction::GetContentStream ) &&
+ !actions->isAllowed( libcmis::ObjectAction::GetContentStream ) );
+}
+
+void OneDriveTest::getFolderTest( )
+{
+ curl_mockup_reset( );
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ static const string folderId( "aFolderId" );
+ static const string parentId( "aParentId" );
+ string url = BASE_URL + "/" + folderId;
+ string parentUrl = BASE_URL + "/" + parentId;
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folder.json", 200, true);
+
+ curl_mockup_addResponse( parentUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/parent-folder.json", 200, true);
+
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::FolderPtr",
+ NULL != folder );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder ID", folderId, folder->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder name", string( "OneDrive Folder" ), folder->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:folder" ), folder->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "Missing folder parent", folder->getFolderParent( ).get( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a root folder", !folder->isRootFolder() );
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !folder->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !folder->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !folder->getLastModificationDate( ).is_not_a_date_time() );
+}
+
+void OneDriveTest::getChildrenTest( )
+{
+ curl_mockup_reset( );
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ static const string folderId ("aFolderId");
+ string url = BASE_URL + "/" + folderId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folder.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( folderId );
+
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::FolderPtr",
+ NULL != folder );
+
+ string childrenUrl = BASE_URL + "/" + folderId + "/files";
+ curl_mockup_addResponse( childrenUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folder-listed.json", 200, true);
+
+ vector< libcmis::ObjectPtr > children= folder->getChildren( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of children", size_t( 2 ), children.size() );
+
+ int folderCount = 0;
+ int fileCount = 0;
+ for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
+ it != children.end( ); ++it )
+ {
+ if ( NULL != boost::dynamic_pointer_cast< libcmis::Folder >( *it ) )
+ ++folderCount;
+ else
+ ++fileCount;
+ }
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of folder children", 1, folderCount );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of file children", 1, fileCount );
+}
+
+void OneDriveTest::moveTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string objectId( "aFileId" );
+ const string sourceId( "aFolderId" );
+ const string desId( "aParentId" );
+
+ string url = BASE_URL + "/" + objectId;
+ string sourceUrl = BASE_URL + "/" + sourceId;
+ string desUrl = BASE_URL + "/" + desId;
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true );
+ curl_mockup_addResponse( url.c_str( ), "method=MOVE",
+ "POST", DATA_DIR "/onedrive/file.json", 200, true );
+ curl_mockup_addResponse( desUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/parent-folder.json", 200, true );
+ curl_mockup_addResponse( sourceUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folder.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::FolderPtr source = session->getFolder( sourceId );
+ libcmis::FolderPtr destination = session->getFolder( desId );
+
+ object->move( source, destination );
+ const char* moveRequest = curl_mockup_getRequestBody( url.c_str( ), "method=MOVE", "POST" );
+ Json parentJson = Json::parse( string( moveRequest ) );
+ string newParentId = parentJson["destination"].toString( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad new parent folder", desId, newParentId);
+}
+
+void OneDriveTest::getDocumentTest( )
+{
+ curl_mockup_reset( );
+ static const string objectId ("aFileId");
+
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string url = BASE_URL + "/" + objectId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+
+ libcmis::ObjectPtr obj = session->getObject( objectId );
+
+ // Check if we got the document object.
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( obj );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+
+ // Test the document properties
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document ID", objectId, document->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document name",
+ string( "OneDriveFile" ),
+ document->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:document" ), document->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !document->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !document->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !document->getLastModificationDate( ).is_not_a_date_time() );
+
+ CPPUNIT_ASSERT_MESSAGE( "Content length is incorrect", 42 == document->getContentLength( ) );
+}
+
+void OneDriveTest::getDocumentParentTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ static const string documentId( "aFileId" );
+ static const string parentId( "aParentId" );
+ string url = BASE_URL + "/" + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+
+ string parentUrl = BASE_URL + "/" + parentId;
+ curl_mockup_addResponse( parentUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/parent-folder.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( "aFileId" );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ CPPUNIT_ASSERT_MESSAGE( "Document expected", document != NULL );
+
+ vector< libcmis::FolderPtr > parents= document->getParents( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of parents", size_t( 1 ), parents.size() );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong parent Id", parentId, parents[0]->getId( ) );
+}
+
+void OneDriveTest::getContentStreamTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ static const string documentId( "aFileId" );
+ string url = BASE_URL + "/" + documentId;
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+ string expectedContent( "Test content stream" );
+ string downloadUrl = "sourceUrl";
+ curl_mockup_addResponse( downloadUrl.c_str( ), "", "GET", expectedContent.c_str( ), 0, false );
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream( );
+ ostringstream out;
+ out << is->rdbuf();
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", expectedContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void OneDriveTest::setContentStreamTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ const string documentId( "aFileId" );
+
+ string url = BASE_URL + "/" + documentId;
+ string putUrl = BASE_URL + "/aParentId/files/OneDriveFile";
+ curl_mockup_addResponse( url.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( documentId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ curl_mockup_addResponse( url.c_str( ), "",
+ "PUT", DATA_DIR "/onedrive/file.json", 200, true);
+ curl_mockup_addResponse( putUrl.c_str( ), "overwrite=true", "PUT", "Updated", 0, false );
+ try
+ {
+ string expectedContent( "Test set content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "aFileName" );
+ document->setContentStream( os, "text/plain", filename );
+
+ CPPUNIT_ASSERT_MESSAGE( "Object not refreshed during setContentStream", object->getRefreshTimestamp( ) > 0 );
+
+ // Check if metadata has been properly uploaded
+ const char* meta = curl_mockup_getRequestBody( url.c_str( ), "", "PUT" );
+ string expectedMeta = "{\n \"name\": \"aFileName\"\n}\n";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad meta uploaded", expectedMeta, string( meta ) );
+ // Check the content has been properly uploaded
+ const char* content = curl_mockup_getRequestBody( putUrl.c_str( ), "", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void OneDriveTest::createDocumentTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string documentId( "aFileId" );
+ const string folderId( "aParentId" );
+ const string filename( "aFileName" );
+
+ const string folderUrl = BASE_URL + "/" + folderId;
+ const string uploadUrl = folderUrl + "/files/" + filename;
+ const string documentUrl = BASE_URL + "/" + documentId;
+
+ curl_mockup_addResponse( folderUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/parent-folder.json", 200, true );
+ curl_mockup_addResponse( uploadUrl.c_str( ), "",
+ "PUT", DATA_DIR "/onedrive/new-file.json", 200, true );
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "PUT", DATA_DIR "/onedrive/file.json", 200, true );
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/file.json", 200, true );
+
+ libcmis::FolderPtr parent = session->getFolder( folderId );
+ try
+ {
+ string expectedContent( "Test set content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ PropertyPtrMap properties;
+
+ parent->createDocument( properties, os, "text/plain", filename );
+
+ curl_mockup_getRequestBody( documentUrl.c_str( ), "", "PUT" );
+ const char* content = curl_mockup_getRequestBody( uploadUrl.c_str( ), "", "PUT" );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what( );
+ CPPUNIT_FAIL( msg.c_str( ) );
+ }
+}
+
+void OneDriveTest::getObjectByPathTest( )
+{
+ curl_mockup_reset( );
+ OneDriveSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ const string documentId( "rightFile" );
+ const string wrongDocumentId( "wrongFile" );
+ const string folderAId( "folderA" ); // root
+ const string folderBId( "folderB" );
+ const string folderCId( "folderC" );
+ const string path( "/Folder B/Folder C/OneDriveFile" );
+
+ const string documentUrl = BASE_URL + "/" + documentId;
+ const string wrongDocumentUrl = BASE_URL + "/" + wrongDocumentId;
+ const string folderAUrl = BASE_URL + "/" + folderAId;
+ const string folderBUrl = BASE_URL + "/" + folderBId;
+ const string folderCUrl = BASE_URL + "/" + folderCId;
+ const string searchUrl = BASE_URL + "/me/skydrive/search";
+
+ curl_mockup_addResponse( documentUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/searched-file.json", 200, true );
+ curl_mockup_addResponse( wrongDocumentUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/searched-wrong-file.json", 200, true );
+ curl_mockup_addResponse( searchUrl.c_str( ), "q=OneDriveFile",
+ "GET", DATA_DIR "/onedrive/search-result.json", 200, true );
+ curl_mockup_addResponse( folderAUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folderA.json", 200, true );
+ curl_mockup_addResponse( folderBUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folderB.json", 200, true );
+ curl_mockup_addResponse( folderCUrl.c_str( ), "",
+ "GET", DATA_DIR "/onedrive/folderC.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObjectByPath( path );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong objectFetched", documentId, object->getId( ) );
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( OneDriveTest );
diff --git a/qa/libcmis/test-sharepoint.cxx b/qa/libcmis/test-sharepoint.cxx
new file mode 100644
index 0000000..91a2367
--- /dev/null
+++ b/qa/libcmis/test-sharepoint.cxx
@@ -0,0 +1,733 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#include <string>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <mockup-config.h>
+
+#include <fstream>
+#include "test-helpers.hxx"
+#include "sharepoint-document.hxx"
+#include "sharepoint-object.hxx"
+#include "sharepoint-property.hxx"
+#include "sharepoint-session.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+static const string USERNAME( "mock-user" );
+static const string PASSWORD( "mock-password" );
+static const string BASE_URL( "http://base/_api/Web" );
+static const string CONTEXTINFO_URL( "http://base/_api/contextinfo" );
+
+typedef std::unique_ptr<SharePointSession> SharePointSessionPtr;
+
+class SharePointTest : public CppUnit::TestFixture
+{
+ public:
+ void setRepositoryTest( );
+ void getRepositoriesTest( );
+ void getObjectTest( );
+ void propertiesTest( );
+ void deleteTest( );
+ void xdigestExpiredTest( );
+ void getFileAllowableActionsTest( );
+ void getFolderAllowableActionsTest( );
+ void getDocumentTest( );
+ void getContentStreamTest( );
+ void setContentStreamTest( );
+ void checkOutTest( );
+ void checkInTest( );
+ void getAllVersionsTest( );
+ void getFolderTest( );
+ void getChildrenTest( );
+ void createFolderTest( );
+ void createDocumentTest( );
+ void moveTest( );
+ void getObjectByPathTest( );
+
+ void propertyCopyTest( );
+ void objectCopyTest( );
+
+ CPPUNIT_TEST_SUITE( SharePointTest );
+ CPPUNIT_TEST( setRepositoryTest );
+ CPPUNIT_TEST( getRepositoriesTest );
+ CPPUNIT_TEST( getObjectTest );
+ CPPUNIT_TEST( propertiesTest );
+ CPPUNIT_TEST( deleteTest );
+ CPPUNIT_TEST( xdigestExpiredTest );
+ CPPUNIT_TEST( getFileAllowableActionsTest );
+ CPPUNIT_TEST( getFolderAllowableActionsTest );
+ CPPUNIT_TEST( getDocumentTest );
+ CPPUNIT_TEST( getContentStreamTest );
+ CPPUNIT_TEST( setContentStreamTest );
+ CPPUNIT_TEST( checkOutTest );
+ CPPUNIT_TEST( checkInTest );
+ CPPUNIT_TEST( getAllVersionsTest );
+ CPPUNIT_TEST( getFolderTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( createFolderTest );
+ CPPUNIT_TEST( createDocumentTest );
+ CPPUNIT_TEST( moveTest );
+ CPPUNIT_TEST( getObjectByPathTest );
+ CPPUNIT_TEST( propertyCopyTest );
+ CPPUNIT_TEST( objectCopyTest );
+ CPPUNIT_TEST_SUITE_END( );
+
+ private:
+ SharePointSessionPtr getTestSession( string username, string password );
+};
+
+SharePointSessionPtr SharePointTest::getTestSession( string username, string password )
+{
+ curl_mockup_reset( );
+ curl_mockup_addResponse( BASE_URL.c_str( ), "", "GET", "", 401, false );
+ curl_mockup_addResponse( ( BASE_URL + "/currentuser" ).c_str( ), "", "GET",
+ DATA_DIR "/sharepoint/auth-resp.json", 200, true );
+ curl_mockup_addResponse( CONTEXTINFO_URL.c_str( ), "", "POST",
+ DATA_DIR "/sharepoint/xdigest.json", 200, true );
+
+ return SharePointSessionPtr( new SharePointSession( BASE_URL, username, password, false ) );
+}
+
+void SharePointTest::setRepositoryTest( )
+{
+ curl_mockup_reset( );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ CPPUNIT_ASSERT_MESSAGE( "setRepository should never fail", session->setRepository( "Anything" ));
+}
+
+void SharePointTest::getRepositoriesTest( )
+{
+ curl_mockup_reset( );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ vector< libcmis::RepositoryPtr > actual = session->getRepositories( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of repositories", size_t( 1 ),
+ actual.size( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong repository found",
+ string ( "SharePoint" ),
+ actual.front()->getId( ) );
+}
+
+void SharePointTest::getObjectTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ boost::shared_ptr<SharePointObject> obj = boost::dynamic_pointer_cast
+ <SharePointObject>( object );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Object Id", objectId,
+ obj->getId( ) );
+}
+
+void SharePointTest::propertiesTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong creation date",
+ string ( "2014-07-08T09:29:29Z" ),
+ object->getStringProperty( "cmis:creationDate" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong object id",
+ string ( "http://base/_api/Web/aFileId" ),
+ object->getStringProperty( "cmis:objectId" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong author",
+ string ( "aUserId" ),
+ object->getStringProperty( "cmis:createdBy" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong file name",
+ string ( "SharePointFile" ),
+ object->getStringProperty( "cmis:contentStreamFileName" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong checkin comment",
+ string ( "aCheckinComment" ),
+ object->getStringProperty( "cmis:checkinComment" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong version",
+ string ( "1.0" ),
+ object->getStringProperty( "cmis:versionLabel" ) );
+}
+
+void SharePointTest::deleteTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse( objectId.c_str( ),"", "DELETE", "", 204, false);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+
+ object->remove( );
+ const struct HttpRequest* deleteRequest = curl_mockup_getRequest( objectId.c_str( ), "", "DELETE" );
+ CPPUNIT_ASSERT_MESSAGE( "Delete request not sent", deleteRequest );
+ curl_mockup_HttpRequest_free( deleteRequest );
+}
+
+void SharePointTest::xdigestExpiredTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse( objectId.c_str( ),"", "DELETE", "", 401, false);
+ curl_mockup_addResponse( CONTEXTINFO_URL.c_str( ), "", "POST",
+ DATA_DIR "/sharepoint/new-xdigest.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ try
+ {
+ object->remove( );
+ }
+ catch ( ... )
+ {
+ if ( session->getHttpStatus( ) == 401 )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(
+ "wrong xdigest code",
+ string ( "new-xdigest-code" ),
+ session->m_digestCode );
+ }
+ }
+}
+
+void SharePointTest::getFileAllowableActionsTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ boost::shared_ptr< libcmis::AllowableActions > actions = object->getAllowableActions( );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetContentStream allowable action should be true",
+ actions->isDefined( libcmis::ObjectAction::GetContentStream ) &&
+ actions->isAllowed( libcmis::ObjectAction::GetContentStream ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreateDocument allowable action should be false",
+ actions->isDefined( libcmis::ObjectAction::CreateDocument ) &&
+ !actions->isAllowed( libcmis::ObjectAction::CreateDocument ) );
+}
+
+void SharePointTest::getFolderAllowableActionsTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFolderId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string folderPropUrl = objectId + "/Properties";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder.json", 200, true);
+ curl_mockup_addResponse ( folderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ boost::shared_ptr< libcmis::AllowableActions > actions = object->getAllowableActions( );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreateDocument allowable action should be true",
+ actions->isDefined( libcmis::ObjectAction::CreateDocument ) &&
+ actions->isAllowed( libcmis::ObjectAction::CreateDocument ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "GetContentStream allowable action should be false",
+ actions->isDefined( libcmis::ObjectAction::GetContentStream ) &&
+ !actions->isAllowed( libcmis::ObjectAction::GetContentStream ) );
+}
+
+void SharePointTest::getDocumentTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ // Check if we got the document object.
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+
+ // Test the document properties
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document ID", objectId, document->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document name",
+ string( "SharePointFile" ),
+ document->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:document" ), document->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !document->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !document->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !document->getLastModificationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "Content length is incorrect", 18045 == document->getContentLength( ) );
+}
+
+void SharePointTest::getContentStreamTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ string expectedContent( "Test content stream" );
+ string downloadUrl = objectId + "/%24value";
+
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse( downloadUrl.c_str( ), "", "GET", expectedContent.c_str( ), 0, false );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ try
+ {
+ boost::shared_ptr< istream > is = document->getContentStream( );
+ ostringstream out;
+ out << is->rdbuf();
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match", expectedContent, out.str( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void SharePointTest::setContentStreamTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ string expectedContent( "Test content stream" );
+ string putUrl = objectId + "/%24value";
+
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse( putUrl.c_str( ), "", "PUT", "Updated", 0, false );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ try
+ {
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "aFileName" );
+ document->setContentStream( os, "text/plain", filename );
+
+ CPPUNIT_ASSERT_MESSAGE( "Object not refreshed during setContentStream", object->getRefreshTimestamp( ) > 0 );
+ // Check the content has been properly uploaded
+ const char* content = curl_mockup_getRequestBody( putUrl.c_str( ), "", "PUT" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void SharePointTest::checkOutTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+ static const string authorUrl = objectId + "/Author";
+ static const string checkOutUrl = objectId + "/checkout";
+ static const string cancelCheckOutUrl = objectId + "/undocheckout";
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ curl_mockup_addResponse( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true );
+ curl_mockup_addResponse( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true );
+ curl_mockup_addResponse( checkOutUrl.c_str( ), "",
+ "POST", DATA_DIR "/sharepoint/file.json", 200, true );
+ curl_mockup_addResponse( cancelCheckOutUrl.c_str( ), "",
+ "POST", DATA_DIR "/sharepoint/file.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ libcmis::DocumentPtr checkedOutDocument = document->checkOut( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong checkedOut document",
+ objectId,
+ checkedOutDocument->getId( ) );
+
+ checkedOutDocument->cancelCheckout( );
+}
+
+void SharePointTest::checkInTest( )
+{
+ static const string objectId( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ string expectedContent( "Test content stream" );
+ string putUrl = objectId + "/%24value";
+ string checkInUrl = objectId + "/checkin(comment='checkin_comment',checkintype=1)";
+
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse( putUrl.c_str( ), "", "PUT", "Updated", 0, false );
+ curl_mockup_addResponse( checkInUrl.c_str( ), "",
+ "POST", DATA_DIR "/sharepoint/file.json", 200, true );
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ PropertyPtrMap properties;
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string fileName( "aFileName" );
+ string checkInComment( "checkin_comment" );
+
+ libcmis::DocumentPtr checkedInDocument;
+ checkedInDocument = document->checkIn( true, checkInComment, properties, os, "", fileName );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong checkedIn document", objectId, checkedInDocument->getId( ) );
+}
+
+void SharePointTest::getAllVersionsTest( )
+{
+ static const string objectId( "http://base/_api/Web/aFileId" );
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ string versionsUrl = objectId + "/Versions";
+ string objectV1Url = versionsUrl +"(1)";
+ string objectV2Url = versionsUrl +"(2)";
+ string objectV1Id = objectId + "-v1";
+
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse ( versionsUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/versions.json", 200, true);
+ curl_mockup_addResponse ( objectV1Url.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( objectV2Url.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file-v1.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObject( objectId );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ vector< libcmis::DocumentPtr > allVersions = document->getAllVersions( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong version of the document - 1",
+ objectId, allVersions[1]->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong version of the document - 2",
+ objectV1Id, allVersions[2]->getId( ) );
+}
+
+void SharePointTest::getFolderTest( )
+{
+ static const string folderId( "http://base/_api/Web/aFolderId" );
+ static const string parentId( "http://base/_api/Web/rootFolderId" );
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ string parentUrl = folderId + "/ParentFolder";
+ string folderPropUrl = folderId + "/Properties";
+ string parentFolderPropUrl = parentId + "/Properties";
+ curl_mockup_addResponse( folderId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder.json", 200, true );
+ curl_mockup_addResponse( folderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( parentFolderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( parentUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/root-folder.json", 200, true );
+ curl_mockup_addResponse( parentId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/root-folder.json", 200, true );
+
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::FolderPtr",
+ NULL != folder );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder ID", folderId, folder->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder name", string( "SharePointFolder" ), folder->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:folder" ), folder->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "Missing folder parent", folder->getFolderParent( ).get( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Not a root folder", !folder->isRootFolder() );
+}
+
+void SharePointTest::getChildrenTest( )
+{
+ static const string folderId( "http://base/_api/Web/aFolderId" );
+ static const string authorUrl( "http://base/_api/Web/aFileId/Author" );
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ string filesUrl = folderId + "/Files";
+ string foldersUrl = folderId + "/Folders";
+ string folderPropUrl = folderId + "/Properties";
+ curl_mockup_addResponse( folderId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder.json", 200, true );
+ curl_mockup_addResponse( folderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( filesUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/children-files.json", 200, true );
+ curl_mockup_addResponse( foldersUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/children-folders.json", 200, true );
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::FolderPtr",
+ NULL != folder );
+
+ vector< libcmis::ObjectPtr > children= folder->getChildren( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of children", size_t( 2 ), children.size() );
+
+ int folderCount = 0;
+ int fileCount = 0;
+ for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
+ it != children.end( ); ++it )
+ {
+ if ( NULL != boost::dynamic_pointer_cast< libcmis::Folder >( *it ) )
+ ++folderCount;
+ else {
+ ++fileCount;
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( *it );
+ vector< libcmis::FolderPtr > parents= document->getParents( );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of parents", size_t( 1 ), parents.size() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong parent Id", folderId, parents[0]->getId( ) );
+ }
+
+ }
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of folder children", 1, folderCount );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of file children", 1, fileCount );
+}
+
+void SharePointTest::createFolderTest( )
+{
+ static const string folderId( "http://base/_api/Web/aFolderId" );
+ static const string parentId( "http://base/_api/Web/rootFolderId" );
+ static const string newFolderUrl ( "http://base/_api/Web/folders/add('/SharePointFolder')" );
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ string folderPropUrl = folderId + "/Properties";
+ string parentFolderPropUrl = parentId + "/Properties";
+ curl_mockup_addResponse( folderId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder.json", 200, true );
+ curl_mockup_addResponse( folderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( parentFolderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( parentId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/root-folder.json", 200, true );
+ curl_mockup_addResponse( newFolderUrl.c_str( ), "",
+ "POST", DATA_DIR "/sharepoint/folder.json", 200, true );
+
+ libcmis::FolderPtr folder = session->getFolder( parentId );
+ PropertyPtrMap properties = session->getFolder( folderId )->getProperties( );
+
+ libcmis::FolderPtr newFolder = folder->createFolder( properties );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "New folder not created", folderId, newFolder->getId( ) );
+}
+
+void SharePointTest::createDocumentTest( )
+{
+ static const string folderId( "http://base/_api/Web/aFolderId" );
+ static const string fileId( "http://base/_api/Web/aFileId" );
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+
+ string folderPropUrl = folderId + "/Properties";
+ string newDocUrl = folderId + "/files/add(overwrite=true,url='NewDoc')";
+ string authorUrl = fileId + "/Author";
+ curl_mockup_addResponse( folderId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder.json", 200, true );
+ curl_mockup_addResponse( folderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( newDocUrl.c_str( ), "",
+ "POST", DATA_DIR "/sharepoint/file.json", 200, true );
+ curl_mockup_addResponse( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true );
+
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+ try
+ {
+ string expectedContent( "Test set content stream" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ PropertyPtrMap properties;
+ string fileName = "NewDoc";
+
+ libcmis::DocumentPtr document = folder->createDocument( properties, os,
+ "text/plain", fileName );
+
+ const char* content = curl_mockup_getRequestBody( newDocUrl.c_str( ), "", "POST" );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad content uploaded", expectedContent, string( content ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad document id", fileId, document->getId( ) );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what( );
+ CPPUNIT_FAIL( msg.c_str( ) );
+ }
+}
+
+void SharePointTest::moveTest( )
+{
+ static const string fileId ( "http://base/_api/Web/aFileId" );
+ static const string folderId( "http://base/_api/Web/aFolderId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = fileId + "/Author";
+ string folderPropUrl = folderId + "/Properties";
+ string moveUrl = fileId + "/moveto(newurl='/SharePointFolder/SharePointFile',flags=1)";
+ curl_mockup_addResponse ( fileId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+ curl_mockup_addResponse ( folderId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder.json", 200, true);
+ curl_mockup_addResponse( folderPropUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/folder-properties.json", 200, true );
+ curl_mockup_addResponse( moveUrl.c_str( ), "",
+ "POST", DATA_DIR "/sharepoint/file.json", 200, true );
+
+ libcmis::ObjectPtr document = session->getObject( fileId );
+ libcmis::FolderPtr folder = session->getFolder( folderId );
+
+ document->move( folder, folder );
+ // nothing to assert, making the right reqeusts should be enough
+}
+
+void SharePointTest::getObjectByPathTest( )
+{
+ static const string folderUrl( "http://base/_api/Web/getFolderByServerRelativeUrl('/SharePointFile')" );
+ static const string fileUrl( "http://base/_api/Web/getFileByServerRelativeUrl('/SharePointFile')" );
+ static string authorUrl( "http://base/_api/Web/aFileId/Author" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ curl_mockup_addResponse( fileUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse( folderUrl.c_str( ), "",
+ "GET", "", 400, true);
+ curl_mockup_addResponse( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ libcmis::ObjectPtr object = session->getObjectByPath( "/SharePointFile" );
+ // Check if we got the document object.
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+}
+
+void SharePointTest::propertyCopyTest( )
+{
+ SharePointProperty property("Author",
+ "\"__deferred\":{"
+ " \"uri\":\"http://base/_api/Web/aFileId/Author\""
+ "}");
+
+ {
+ SharePointProperty copy;
+ copy = property;
+
+ CPPUNIT_ASSERT_EQUAL( property.m_propertyType->m_id, copy.m_propertyType->m_id );
+ CPPUNIT_ASSERT_EQUAL( property.m_strValues[0], copy.m_strValues[0]);
+ }
+
+ {
+ SharePointProperty copy( property );
+
+ CPPUNIT_ASSERT_EQUAL( property.m_propertyType->m_id, copy.m_propertyType->m_id );
+ CPPUNIT_ASSERT_EQUAL( property.m_strValues[0], copy.m_strValues[0]);
+ }
+}
+
+void SharePointTest::objectCopyTest( )
+{
+ static const string objectId ( "http://base/_api/Web/aFileId" );
+
+ SharePointSessionPtr session = getTestSession( USERNAME, PASSWORD );
+ string authorUrl = objectId + "/Author";
+ curl_mockup_addResponse ( objectId.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/file.json", 200, true);
+ curl_mockup_addResponse ( authorUrl.c_str( ), "",
+ "GET", DATA_DIR "/sharepoint/author.json", 200, true);
+
+ boost::shared_ptr< SharePointObject > object = boost::dynamic_pointer_cast< SharePointObject >(session->getObject( objectId ) );
+
+ {
+ SharePointObject copy( *object );
+ CPPUNIT_ASSERT_EQUAL( object->m_refreshTimestamp, copy.m_refreshTimestamp );
+ }
+
+ {
+ SharePointObject copy( session.get( ) );
+ copy = *object;
+ CPPUNIT_ASSERT_EQUAL( object->m_refreshTimestamp, copy.m_refreshTimestamp );
+ }
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( SharePointTest );
diff --git a/qa/libcmis/test-soap.cxx b/qa/libcmis/test-soap.cxx
new file mode 100644
index 0000000..e401971
--- /dev/null
+++ b/qa/libcmis/test-soap.cxx
@@ -0,0 +1,563 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/ui/text/TestRunner.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include "ws-relatedmultipart.hxx"
+#include "ws-requests.hxx"
+#include "ws-soap.hxx"
+#include "test-helpers.hxx"
+
+using namespace std;
+
+class SoapTest : public CppUnit::TestFixture
+{
+ private:
+ map< string, SoapResponseCreator > getTestMapping( );
+ map< string, string > getTestNamespaces( );
+ map< string, SoapFaultDetailCreator > getTestDetailMapping( );
+
+ public:
+
+ // Copy tests
+ void soapResponseFactoryCopyTest();
+
+ // Soap Responses tests
+
+ void createResponseTest( );
+ void parseFaultDetailEmptyTest( );
+ void parseFaultDetailUnknownTest( );
+ void parseFaultDetailValidTest( );
+ void createFaultDefaultTest( );
+ void parseResponseTest( );
+ void parseResponseXmlTest( );
+ void parseResponseFaultTest( );
+
+ // RelatedMultipart tests
+
+ void serializeMultipartSimpleTest( );
+ void serializeMultipartComplexTest( );
+ void parseMultipartTest( );
+ void getStreamFromNodeXopTest( );
+ void getStreamFromNodeBase64Test( );
+
+ // CMISM utilities tests
+ void writeCmismStreamTest( );
+
+ CPPUNIT_TEST_SUITE( SoapTest );
+ CPPUNIT_TEST( soapResponseFactoryCopyTest );
+
+ CPPUNIT_TEST( createResponseTest );
+ CPPUNIT_TEST( parseFaultDetailEmptyTest );
+ CPPUNIT_TEST( parseFaultDetailUnknownTest );
+ CPPUNIT_TEST( parseFaultDetailValidTest );
+ CPPUNIT_TEST( parseResponseTest );
+ CPPUNIT_TEST( parseResponseXmlTest );
+ CPPUNIT_TEST( parseResponseFaultTest );
+
+ CPPUNIT_TEST( serializeMultipartSimpleTest );
+ CPPUNIT_TEST( serializeMultipartComplexTest );
+ CPPUNIT_TEST( parseMultipartTest );
+ CPPUNIT_TEST( getStreamFromNodeXopTest );
+ CPPUNIT_TEST( getStreamFromNodeBase64Test );
+
+ CPPUNIT_TEST( writeCmismStreamTest );
+
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( SoapTest );
+
+/** Dummy response class to use for testing
+ */
+class TestResponse : public SoapResponse
+{
+ private:
+ TestResponse( ) { };
+
+ public:
+
+ static SoapResponsePtr create( xmlNodePtr, RelatedMultipart&, SoapSession* )
+ {
+ SoapResponsePtr resp ( new TestResponse( ) );
+ return resp;
+ }
+};
+
+class TestFaultDetail : public SoapFaultDetail
+{
+ private:
+ TestFaultDetail( ) : SoapFaultDetail( ) { };
+
+ public:
+ ~TestFaultDetail( ) noexcept { };
+
+ static SoapFaultDetailPtr create( xmlNodePtr )
+ {
+ return SoapFaultDetailPtr( new TestFaultDetail( ) );
+ }
+};
+
+map< string, SoapResponseCreator > SoapTest::getTestMapping( )
+{
+ map< string, SoapResponseCreator > mapping;
+ mapping[ "{test-ns-url}testResponse" ] = &TestResponse::create;
+ return mapping;
+}
+
+map< string, SoapFaultDetailCreator > SoapTest::getTestDetailMapping( )
+{
+ map< string, SoapFaultDetailCreator > mapping;
+ mapping[ "{test-ns-url}testFault" ] = &TestFaultDetail::create;
+ return mapping;
+}
+
+map< string, string > SoapTest::getTestNamespaces( )
+{
+ map< string, string > namespaces;
+ namespaces[ "test" ] = "test-ns-url";
+ return namespaces;
+}
+
+void SoapTest::soapResponseFactoryCopyTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ {
+ SoapResponseFactory copy;
+ copy = factory;
+
+ CPPUNIT_ASSERT_EQUAL( factory.m_mapping.size(), copy.m_mapping.size() );
+ CPPUNIT_ASSERT_EQUAL( factory.m_namespaces.size(), copy.m_namespaces.size() );
+ CPPUNIT_ASSERT_EQUAL( factory.m_detailMapping.size(), copy.m_detailMapping.size() );
+ CPPUNIT_ASSERT_EQUAL( factory.m_session, copy.m_session );
+ }
+
+ {
+ SoapResponseFactory copy( factory );
+
+ CPPUNIT_ASSERT_EQUAL( factory.m_mapping.size(), copy.m_mapping.size() );
+ CPPUNIT_ASSERT_EQUAL( factory.m_namespaces.size(), copy.m_namespaces.size() );
+ CPPUNIT_ASSERT_EQUAL( factory.m_detailMapping.size(), copy.m_detailMapping.size() );
+ CPPUNIT_ASSERT_EQUAL( factory.m_session, copy.m_session );
+ }
+}
+
+void SoapTest::createResponseTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<n1:testResponse xmlns:n1=\"test-ns-url\"/>";
+ RelatedMultipart multipart; // Multipart won't be used in that test
+
+ SoapResponsePtr actual = factory.createResponse( test::getXmlNode( xml ), multipart );
+ CPPUNIT_ASSERT_MESSAGE( "Wrong response created", dynamic_cast< TestResponse* >( actual.get( ) ) != NULL );
+}
+
+void SoapTest::parseFaultDetailEmptyTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<detail/>";
+
+ vector< SoapFaultDetailPtr > actual = factory.parseFaultDetail( test::getXmlNode( xml ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shouldn't have any detail", size_t( 0 ), actual.size() );
+}
+
+void SoapTest::parseFaultDetailUnknownTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<detail><unknown-detail/></detail>";
+
+ vector< SoapFaultDetailPtr > actual = factory.parseFaultDetail( test::getXmlNode( xml ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Shouldn't have ignored unknonw details", size_t( 0 ), actual.size() );
+}
+void SoapTest::parseFaultDetailValidTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<detail><n1:testFault xmlns:n1=\"test-ns-url\"/></detail>";
+
+ vector< SoapFaultDetailPtr > actual = factory.parseFaultDetail( test::getXmlNode( xml ) );
+ CPPUNIT_ASSERT_MESSAGE( "Wrong fault detail created",
+ dynamic_cast< TestFaultDetail* >( actual.front( ).get( ) ) != NULL );
+}
+
+void SoapTest::parseResponseTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body>"
+ "<test:testResponse xmlns:test=\"test-ns-url\"/>"
+ "<test:testResponse xmlns:test=\"test-ns-url\"/>"
+ "</S:Body></S:Envelope>";
+ string name( "name" );
+ string type( "application/xop+xml" );
+ RelatedPartPtr requestPart( new RelatedPart( name, type, xml ) );
+
+ RelatedMultipart multipart;
+ string cid = multipart.addPart( requestPart );
+ string startInfo( "text/xml" );
+ multipart.setStart( cid, startInfo );
+
+ vector< SoapResponsePtr > actual = factory.parseResponse( multipart );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of responses", size_t( 2 ), actual.size( ) );
+}
+
+void SoapTest::parseResponseXmlTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body>"
+ "<test:testResponse xmlns:test=\"test-ns-url\"/>"
+ "<test:testResponse xmlns:test=\"test-ns-url\"/>"
+ "</S:Body></S:Envelope>";
+
+ vector< SoapResponsePtr > actual = factory.parseResponse( xml );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of responses", size_t( 2 ), actual.size( ) );
+}
+
+void SoapTest::parseResponseFaultTest( )
+{
+ SoapResponseFactory factory;
+ factory.setMapping( getTestMapping() );
+ factory.setNamespaces( getTestNamespaces( ) );
+ factory.setDetailMapping( getTestDetailMapping( ) );
+
+ string xml = "<S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\""
+ " xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\""
+ " xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">"
+ " <S:Body><S:Fault>"
+ " <faultcode xsi:type=\"xsd:string\">S:Client</faultcode>"
+ " <faultstring xsi:type=\"xsd:string\">Some Error Message</faultstring>"
+ " <detail><n1:testFault xmlns:n1=\"test-ns-url\"/></detail>"
+ " </S:Fault></S:Body>"
+ "</S:Envelope>";
+
+ string name( "name" );
+ string type( "application/xop+xml" );
+ RelatedPartPtr requestPart( new RelatedPart( name, type, xml ) );
+
+ RelatedMultipart multipart;
+ string cid = multipart.addPart( requestPart );
+ string startInfo( "text/xml" );
+ multipart.setStart( cid, startInfo );
+
+ try
+ {
+ factory.parseResponse( multipart );
+ CPPUNIT_FAIL( "Should have thrown the SoapFault" );
+ }
+ catch ( const SoapFault& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong detail string", string( "Some Error Message" ), e.getFaultstring() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong detail string", string( "Client" ), e.getFaultcode() );
+ CPPUNIT_ASSERT_MESSAGE( "Wrong fault detail created",
+ dynamic_cast< TestFaultDetail* >( e.getDetail( ).front( ).get( ) ) != NULL );
+ }
+}
+
+void SoapTest::serializeMultipartSimpleTest( )
+{
+ string partName = "data";
+ string partType = "text/plain";
+ string partContent = "Some content";
+ string startInfo = "some info";
+
+
+ RelatedMultipart multipart;
+ RelatedPartPtr part( new RelatedPart( partName, partType, partContent ) );
+ string cid = multipart.addPart( part );
+ multipart.setStart( cid, startInfo );
+
+ boost::shared_ptr< istringstream > actual = multipart.toStream( );
+
+ string boundary = multipart.getBoundary( );
+ string expected = "\r\n--" + boundary + "\r\n" +
+ "Content-Id: <" + cid + ">\r\n" +
+ "Content-Type: " + partType + "\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ partContent +
+ "\r\n--" + boundary + "--\r\n";
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong body", expected, actual->str() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong content type",
+ "multipart/related;start=\"" + cid + "\";type=\"" + partType + "\";boundary=\"" + boundary + "\";start-info=\"" + startInfo + "\"",
+ multipart.getContentType() );
+}
+
+void SoapTest::serializeMultipartComplexTest( )
+{
+ string rootName = "root";
+ string rootType = "text/plain";
+ string rootContent = "Some content";
+
+ string part2Name = "part2";
+ string part2Type = "application/octet-stream";
+ string part2Content = "Some content 2";
+
+ string startInfo = "some info";
+
+
+ RelatedMultipart multipart;
+ RelatedPartPtr rootPart( new RelatedPart( rootName, rootType, rootContent ) );
+ string rootCid = multipart.addPart( rootPart );
+
+ RelatedPartPtr part2( new RelatedPart( part2Name, part2Type, part2Content ) );
+ string part2Cid = multipart.addPart( part2 );
+
+ multipart.setStart( rootCid, startInfo );
+
+ boost::shared_ptr< istringstream > actual = multipart.toStream( );
+
+ string boundary = multipart.getBoundary( );
+ string expected = "\r\n--" + boundary + "\r\n" +
+ "Content-Id: <" + rootCid + ">\r\n" +
+ "Content-Type: " + rootType + "\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ rootContent +
+ "\r\n--" + boundary + "\r\n" +
+ "Content-Id: <" + part2Cid + ">\r\n" +
+ "Content-Type: " + part2Type + "\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ part2Content +
+ "\r\n--" + boundary + "--\r\n";
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong body", expected, actual->str() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong content type",
+ "multipart/related;start=\"" + rootCid + "\";type=\"" + rootType + "\";boundary=\"" + boundary + "\";start-info=\"" + startInfo + "\"",
+ multipart.getContentType() );
+}
+
+void SoapTest::parseMultipartTest( )
+{
+ string rootCid = "root-cid";
+ string rootType = "text/plain";
+ string rootContent = "Some content";
+
+ string part2Cid = "part2-cid";
+ string part2Type = "application/octet-stream";
+ string part2Content = "Some content 2\r\nwith windows-style line endings\r\n";
+
+ string startInfo = "some info";
+
+ string boundary = "------------ABCDEF-Boundary";
+ string body = "\r\n--" + boundary + "\r\n" +
+ "Content-Id: <" + rootCid + ">\r\n" +
+ "Content-Type: " + rootType + "\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ rootContent +
+ "\r\n--" + boundary + "\r\n" +
+ // Voluntarily make a case-sensitivity error to test the SharePoint case
+ "Content-ID: <" + part2Cid + ">\r\n" +
+ "Content-Type: " + part2Type + "\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ part2Content +
+ "\r\n--" + boundary + "--\r\n";
+
+ // Added a space before one of the items as it may happen
+ string contentType = "multipart/related; start=\"" + rootCid + "\";type=\"" + rootType + "\";" +
+ "boundary=\"" + boundary + "\";start-info=\"" + startInfo + "\"";
+
+ RelatedMultipart multipart( body, contentType );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong start Content id", rootCid, multipart.getStartId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong start info", startInfo, multipart.getStartInfo( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong boundary", boundary, multipart.getBoundary( ) );
+
+ vector< string > cids = multipart.getIds( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of parts parsed", size_t( 2 ), cids.size( ) );
+
+ RelatedPartPtr actualRoot = multipart.getPart( rootCid );
+ CPPUNIT_ASSERT_MESSAGE( "No part corresponding to root cid", actualRoot.get( ) != NULL );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong root part content type", rootType, actualRoot->getContentType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong root part content", rootContent, actualRoot->getContent( ) );
+
+ RelatedPartPtr actualPart2 = multipart.getPart( part2Cid );
+ CPPUNIT_ASSERT_MESSAGE( "No part corresponding to part2 cid", actualPart2.get( ) != NULL );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong part2 part content type", part2Type, actualPart2->getContentType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong part2 part content", part2Content, actualPart2->getContent( ) );
+}
+
+void SoapTest::getStreamFromNodeXopTest( )
+{
+ // Create the test multipart
+ string dataCid = "http://data-cid";
+ string dataCidEncoded = "http%3A%2F%2Fdata-cid";
+ string dataContent = "Some transfered content";
+
+ string boundary = "------------ABCDEF-Boundary";
+ string body = "\r\n--" + boundary + "\r\n" +
+ "Content-Id: <root-cid>\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ "Who cares? we assume, this has been properly extracted in this test" +
+ "\r\n--" + boundary + "\r\n" +
+ "Content-Id: " + dataCid + "\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ dataContent +
+ "\r\n--" + boundary + "--\r\n";
+
+ string contentType = string( "multipart/related;start=\"root-cid\";type=\"text/plain\";" ) +
+ "boundary=\"" + boundary + "\";start-info=\"info\"";
+
+ RelatedMultipart multipart( body, contentType );
+
+ // Create test node
+ stringstream buf;
+ buf << "<stream>"
+ << " <xop:Include xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" href=\"cid:" << dataCidEncoded << "\"/>"
+ << "</stream>";
+ test::XmlNodeRef node = test::getXmlNode( buf.str( ) );
+
+ // Run the tested method
+ boost::shared_ptr< istream > stream = getStreamFromNode( node, multipart );
+
+ // Checks
+ stringstream out;
+ out << stream->rdbuf( );
+ CPPUNIT_ASSERT_EQUAL( dataContent, out.str( ) );
+}
+
+void SoapTest::getStreamFromNodeBase64Test( )
+{
+ // Create the test multipart
+ string boundary = "------------ABCDEF-Boundary";
+ string body = "\r\n--" + boundary + "\r\n" +
+ "Content-Id: <root-cid>\r\n" +
+ "Content-Type: text/plain\r\n" +
+ "Content-Transfer-Encoding: binary\r\n" +
+ "\r\n" +
+ "Who cares? we assume, this has been properly extracted in this test" +
+ "\r\n--" + boundary + "--\r\n";
+
+ string contentType = string( "multipart/related;start=\"root-cid\";type=\"text/plain\";" ) +
+ "boundary=\"" + boundary + "\";start-info=\"info\"";
+
+ RelatedMultipart multipart( body, contentType );
+
+ // Create test node
+ string dataContent = "U29tZSB0cmFuc2ZlcmVkIGNvbnRlbnQ=";
+ string expectedContent = "Some transfered content";
+
+ stringstream buf;
+ buf << "<stream>" << dataContent << "</stream>";
+ test::XmlNodeRef node = test::getXmlNode( buf.str( ) );
+
+ // Run the tested method
+ boost::shared_ptr< istream > stream = getStreamFromNode( node, multipart );
+
+ // Checks
+ stringstream out;
+ out << stream->rdbuf( );
+ CPPUNIT_ASSERT_EQUAL( expectedContent, out.str( ) );
+}
+
+void SoapTest::writeCmismStreamTest( )
+{
+ // Initialize the writer
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ // Test writeCmismStream
+ RelatedMultipart multipart;
+ string contentType( "text/plain" );
+ string content( "Expected content" );
+ string filename( "name.txt" );
+ boost::shared_ptr< ostream > os( new stringstream( content ) );
+ writeCmismStream( writer, multipart, os, contentType, filename );
+
+ // Close the writer and check the results
+ xmlTextWriterEndDocument( writer );
+ string str( ( const char * )xmlBufferContent( buf ) );
+
+ vector< string > ids = multipart.getIds( );
+ CPPUNIT_ASSERT_EQUAL( size_t( 1 ), ids.size( ) );
+ string partId = ids.front( );
+
+ RelatedPartPtr part = multipart.getPart( partId );
+ CPPUNIT_ASSERT_MESSAGE( "Missing stream related part", part.get( ) != NULL );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content not properly attached", content, part->getContent( ) );
+
+ stringstream expectedXml;
+ expectedXml << "<?xml version=\"1.0\"?>\n"
+ << "<cmism:length>" << content.size( ) << "</cmism:length>"
+ << "<cmism:mimeType>" << contentType << "</cmism:mimeType>"
+ << "<cmism:filename>" << filename << "</cmism:filename>"
+ << "<cmism:stream>"
+ << "<xop:Include xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" href=\"cid:" << partId << "\"/>"
+ << "</cmism:stream>\n";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Envelope part isn't correct", expectedXml.str( ), str );
+
+ // Free it all
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+}
diff --git a/qa/libcmis/test-ws.cxx b/qa/libcmis/test-ws.cxx
new file mode 100644
index 0000000..6857e63
--- /dev/null
+++ b/qa/libcmis/test-ws.cxx
@@ -0,0 +1,1505 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <memory>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#define protected public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <ws-session.hxx>
+#include <ws-object-type.hxx>
+
+#include <mockup-config.h>
+#include <test-helpers.hxx>
+#include <test-mockup-helpers.hxx>
+
+#define SERVER_URL string( "http://mockup/ws" )
+#define SERVER_REPOSITORY string( "mock" )
+#define SERVER_USERNAME "tester"
+#define SERVER_PASSWORD "somepass"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+namespace
+{
+ string lcl_getStreamAsString( boost::shared_ptr< istream > is )
+ {
+ is->seekg( 0, ios::end );
+ long size = is->tellg( );
+ is->seekg( 0, ios::beg );
+
+ char* buf = new char[ size ];
+ is->read( buf, size );
+ string content( buf, size );
+ delete[ ] buf;
+
+ return content;
+ }
+
+ string lcl_getCmisRequestXml( string url, const char* bodyMatch = NULL )
+ {
+ const struct HttpRequest* request = curl_mockup_getRequest( url.c_str(), "", "POST", bodyMatch );
+ char* contentType = curl_mockup_HttpRequest_getHeader( request, "Content-Type" );
+ RelatedMultipart multipart( request->body, string( contentType ) );
+ RelatedPartPtr part = multipart.getPart( multipart.getStartId() );
+ string xml = part->getContent( );
+ curl_mockup_HttpRequest_free( request );
+ free( contentType );
+
+ string requestStr = test::getXmlNodeAsString( xml, "/soap-env:Envelope/soap-env:Body/child::*" );
+
+ // Obfuscate the xop:Include ids
+ string xopSearch = "<xop:Include xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" href=\"cid:";
+ size_t pos = requestStr.find( xopSearch );
+ if ( pos != string::npos )
+ {
+ pos = pos + xopSearch.size();
+ size_t endPos = requestStr.find( "\"", pos );
+ requestStr = requestStr.replace( pos,
+ endPos - pos,
+ "obfuscated" );
+ }
+ return requestStr;
+ }
+
+ string lcl_getExpectedNs( )
+ {
+ string ns = " xmlns:cmis=\"http://docs.oasis-open.org/ns/cmis/core/200908/\""
+ " xmlns:cmism=\"http://docs.oasis-open.org/ns/cmis/messaging/200908/\"";
+ return ns;
+ }
+}
+
+typedef std::unique_ptr<WSSession> WSSessionPtr;
+
+class WSTest : public CppUnit::TestFixture
+{
+ public:
+
+ void getRepositoriesTest( );
+ void getRepositoryInfosTest( );
+ void getRepositoryInfosBadTest( );
+
+ void getTypeTest( );
+ void getTypeRefreshTest( );
+ void objectTypeCopyTest( );
+ void getUnexistantTypeTest( );
+ void getTypeParentsTest( );
+ void getTypeChildrenTest( );
+
+ void getObjectTest( );
+ void getDocumentTest( );
+ void getFolderTest( );
+ void getByPathValidTest( );
+ void getByPathInvalidTest( );
+ void getDocumentParentsTest( );
+ void getChildrenTest( );
+ void getContentStreamTest( );
+ void setContentStreamTest( );
+ void getRenditionsTest( );
+ void updatePropertiesTest( );
+ void updatePropertiesEmptyTest( );
+ void createFolderTest( );
+ void createFolderBadTypeTest( );
+ void createDocumentTest( );
+ void deleteDocumentTest( );
+ void deleteFolderTreeTest( );
+ void moveTest( );
+ void addSecondaryTypeTest( );
+
+ void checkOutTest( );
+ void cancelCheckOutTest( );
+ void checkInTest( );
+ void getAllVersionsTest( );
+
+ void navigationServiceCopyTest();
+ void repositoryServiceCopyTest();
+ void objectServiceCopyTest();
+ void versioningServiceCopyTest();
+
+ CPPUNIT_TEST_SUITE( WSTest );
+ CPPUNIT_TEST( getRepositoriesTest );
+ CPPUNIT_TEST( getRepositoryInfosTest );
+ CPPUNIT_TEST( getRepositoryInfosBadTest );
+ CPPUNIT_TEST( getTypeTest );
+ CPPUNIT_TEST( getTypeRefreshTest );
+ CPPUNIT_TEST( objectTypeCopyTest );
+ CPPUNIT_TEST( getUnexistantTypeTest );
+ CPPUNIT_TEST( getTypeParentsTest );
+ CPPUNIT_TEST( getTypeChildrenTest );
+ CPPUNIT_TEST( getObjectTest );
+ CPPUNIT_TEST( getDocumentTest );
+ CPPUNIT_TEST( getFolderTest );
+ CPPUNIT_TEST( getByPathValidTest );
+ CPPUNIT_TEST( getByPathInvalidTest );
+ CPPUNIT_TEST( getDocumentParentsTest );
+ CPPUNIT_TEST( getChildrenTest );
+ CPPUNIT_TEST( getContentStreamTest );
+ CPPUNIT_TEST( setContentStreamTest );
+ CPPUNIT_TEST( getRenditionsTest );
+ CPPUNIT_TEST( updatePropertiesTest );
+ CPPUNIT_TEST( updatePropertiesEmptyTest );
+ CPPUNIT_TEST( createFolderTest );
+ CPPUNIT_TEST( createFolderBadTypeTest );
+ CPPUNIT_TEST( createDocumentTest );
+ CPPUNIT_TEST( deleteDocumentTest );
+ CPPUNIT_TEST( deleteFolderTreeTest );
+ CPPUNIT_TEST( moveTest );
+ CPPUNIT_TEST( addSecondaryTypeTest );
+ CPPUNIT_TEST( checkOutTest );
+ CPPUNIT_TEST( cancelCheckOutTest );
+ CPPUNIT_TEST( checkInTest );
+ CPPUNIT_TEST( getAllVersionsTest );
+ CPPUNIT_TEST( navigationServiceCopyTest );
+ CPPUNIT_TEST( repositoryServiceCopyTest );
+ CPPUNIT_TEST( objectServiceCopyTest );
+ CPPUNIT_TEST( versioningServiceCopyTest );
+ CPPUNIT_TEST_SUITE_END( );
+
+ libcmis::RepositoryPtr getTestRepository( );
+ WSSessionPtr getTestSession( string username, string password, bool noRepos = false );
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION( WSTest );
+
+void WSTest::getRepositoriesTest()
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/repositories.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ map< string, string > actual = session->getRepositoryService().getRepositories( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of repositories", size_t( 1 ), actual.size( ) );
+
+ // Test the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService" );
+ string expectedRequest = "<cmism:getRepositories" + lcl_getExpectedNs() + "/>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getRepositoryInfosTest()
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/repository-infos.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ string validId = "mock";
+ libcmis::RepositoryPtr actual = session->getRepositoryService().getRepositoryInfo( validId );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Root folder is wrong", string( "root-folder" ), actual->getRootId( ) );
+
+ // Test the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService" );
+ string expectedRequest = "<cmism:getRepositoryInfo" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>" + validId + "</cmism:repositoryId>"
+ "</cmism:getRepositoryInfo>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getRepositoryInfosBadTest()
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/repository-infos-bad.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ string badId = "bad";
+ try
+ {
+ session->getRepositoryService().getRepositoryInfo( badId );
+ }
+ catch( const libcmis::Exception& e )
+ {
+ // Test the caught exception
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong exception type", string( "invalidArgument" ), e.getType( ) );
+
+ // Test the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService" );
+ string expectedRequest = "<cmism:getRepositoryInfo" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>" + badId + "</cmism:repositoryId>"
+ "</cmism:getRepositoryInfo>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+ }
+
+}
+
+void WSTest::getTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ string id( "cmis:folder" );
+ libcmis::ObjectTypePtr actual = session->getType( id );
+
+ // Check the returned type
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id", id, actual->getId( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService" );
+ string expectedRequest = "<cmism:getTypeDefinition" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:typeId>" + id + "</cmism:typeId>"
+ "</cmism:getTypeDefinition>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getTypeRefreshTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/type-docLevel2.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ string id( "DocumentLevel2" );
+ libcmis::ObjectTypePtr actual = session->getType( id );
+
+ // Check the returned type
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id", id, actual->getId( ) );
+
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/type-docLevel1.http" );
+
+
+ // Do the refresh
+ actual->refresh();
+
+ // Check the refreshed object
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id", string( "DocumentLevel1" ),
+ actual->getId( ) );
+}
+
+void WSTest::objectTypeCopyTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ string id( "cmis:folder" );
+ libcmis::ObjectTypePtr expected = session->getType( id );
+ WSObjectType* type = dynamic_cast< WSObjectType* >( expected.get( ) );
+
+ {
+ WSObjectType copy( *type );
+
+ CPPUNIT_ASSERT_EQUAL( type->getId( ), copy.getId( ) );
+ CPPUNIT_ASSERT_EQUAL( type->m_session, copy.m_session );
+ }
+
+ {
+ WSObjectType copy;
+ copy = *type;
+
+ CPPUNIT_ASSERT_EQUAL( type->getId( ), copy.getId( ) );
+ CPPUNIT_ASSERT_EQUAL( type->m_session, copy.m_session );
+ }
+}
+
+void WSTest::getUnexistantTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-bad.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ string id( "bad_type" );
+ try
+ {
+ session->getType( id );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ // Check the caught exception
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "objectNotFound" ), e.getType() );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService" );
+ string expectedRequest = "<cmism:getTypeDefinition" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:typeId>" + id + "</cmism:typeId>"
+ "</cmism:getTypeDefinition>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+ }
+}
+
+void WSTest::getTypeParentsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/type-docLevel2.http",
+ "<cmism:typeId>DocumentLevel2</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/type-docLevel1.http",
+ "<cmism:typeId>DocumentLevel1</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/type-document.http",
+ "<cmism:typeId>cmis:document</cmism:typeId>" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "DocumentLevel2";
+ libcmis::ObjectTypePtr actual = session->getType( id );
+
+ // Check the resulting type
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Parent type Id", string( "DocumentLevel1" ),
+ actual->getParentTypeId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Base type Id", string( "cmis:document" ),
+ actual->getBaseTypeId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Parent type", string( "DocumentLevel1" ),
+ actual->getParentType()->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Base type", string( "cmis:document" ),
+ actual->getBaseType()->getId( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService" );
+ string expectedRequest = "<cmism:getTypeDefinition" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:typeId>" + id + "</cmism:typeId>"
+ "</cmism:getTypeDefinition>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getTypeChildrenTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/typechildren-document.http",
+ "<cmism:getTypeChildren ");
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService",
+ DATA_DIR "/ws/type-document.http",
+ "<cmism:typeId>cmis:document</cmism:typeId>" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "cmis:document";
+ libcmis::ObjectTypePtr actual = session->getType( id );
+ vector< libcmis::ObjectTypePtr > children = actual->getChildren();
+
+ // Check the actual children returned
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of children", size_t( 1 ), children.size( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/RepositoryService",
+ "<cmism:getTypeChildren " );
+ string expectedRequest = "<cmism:getTypeChildren" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:typeId>" + id + "</cmism:typeId>"
+ "<cmism:includePropertyDefinitions>true</cmism:includePropertyDefinitions>"
+ "</cmism:getTypeChildren>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getObjectTest( )
+{
+ // Setup the mockup
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/valid-object.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // Run the tested method
+ string expectedId( "valid-object" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ // Check the returned object
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Id for fetched object",
+ expectedId, actual->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong type for fetched object",
+ string( "cmis:folder" ), actual->getType() );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService" );
+ string expectedRequest = "<cmism:getObject" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + expectedId + "</cmism:objectId>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "<cmism:renditionFilter>*</cmism:renditionFilter>"
+ "</cmism:getObject>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getDocumentTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string expectedId( "test-document" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ // Do we have a document?
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( actual );
+ CPPUNIT_ASSERT_MESSAGE( "Fetched object should be an instance of libcmis::DocumentPtr",
+ NULL != document );
+
+ // Check the document properties
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document ID", expectedId, document->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document name", string( "Test Document" ), document->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong document type", string( "text/plain" ), document->getContentType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:document" ), document->getBaseType( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !document->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !document->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !document->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !document->getLastModificationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "ChangeToken is missing", !document->getChangeToken( ).empty( ) );
+
+ CPPUNIT_ASSERT_MESSAGE( "Content length is missing", 12345 == document->getContentLength( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService" );
+ string expectedRequest = "<cmism:getObject" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + expectedId + "</cmism:objectId>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "<cmism:renditionFilter>*</cmism:renditionFilter>"
+ "</cmism:getObject>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getFolderTest( )
+{
+ // Setup the mockup
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/valid-object.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // Run the method under test
+ string expectedId( "valid-object" );
+ libcmis::FolderPtr actual = session->getFolder( expectedId );
+
+ // Check the returned folder
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder ID", expectedId, actual->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder name", string( "Valid Object" ), actual->getName( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong folder path", string( "/Valid Object" ), actual->getPath( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong base type", string( "cmis:folder" ), actual->getBaseType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Missing folder parent ID",
+ string( "root-folder" ), actual->getParentId() );
+ CPPUNIT_ASSERT_MESSAGE( "Not a root folder", !actual->isRootFolder() );
+
+ CPPUNIT_ASSERT_MESSAGE( "CreatedBy is missing", !actual->getCreatedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "CreationDate is missing", !actual->getCreationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "LastModifiedBy is missing", !actual->getLastModifiedBy( ).empty( ) );
+ CPPUNIT_ASSERT_MESSAGE( "LastModificationDate is missing", !actual->getLastModificationDate( ).is_not_a_date_time() );
+ CPPUNIT_ASSERT_MESSAGE( "ChangeToken is missing", !actual->getChangeToken( ).empty( ) );
+
+ // No need to check the request: we do the same one in another test
+}
+
+void WSTest::getByPathValidTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/valid-object.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string path = "/Valid Object";
+ libcmis::ObjectPtr actual = session->getObjectByPath( path );
+
+ // Check the returned object
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong Id for fetched object", string( "valid-object" ), actual->getId( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService" );
+ string expectedRequest = "<cmism:getObjectByPath" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:path>" + path + "</cmism:path>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "<cmism:renditionFilter>*</cmism:renditionFilter>"
+ "</cmism:getObjectByPath>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getByPathInvalidTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/getbypath-bad.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string path = "/some/invalid/path";
+ try
+ {
+ session->getObjectByPath( path );
+ CPPUNIT_FAIL( "Exception should be thrown: invalid Path" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ // Check the caught exception
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "objectNotFound" ), e.getType() );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService" );
+ string expectedRequest = "<cmism:getObjectByPath" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:path>" + path + "</cmism:path>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "<cmism:renditionFilter>*</cmism:renditionFilter>"
+ "</cmism:getObjectByPath>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+ }
+
+}
+
+void WSTest::getDocumentParentsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/NavigationService", DATA_DIR "/ws/test-document-parents.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "test-document";
+ vector< libcmis::FolderPtr > actual = session->getNavigationService().
+ getObjectParents( session->m_repositoryId,
+ id );
+
+ // Check the actual parents
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad number of parents", size_t( 2 ), actual.size() );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/NavigationService" );
+ string expectedRequest = "<cmism:getObjectParents" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "<cmism:renditionFilter>*</cmism:renditionFilter>"
+ "</cmism:getObjectParents>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getChildrenTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http", "<cmism:typeId>cmis:folder</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http", "<cmism:typeId>DocumentLevel2</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/NavigationService", DATA_DIR "/ws/root-children.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+
+ string id = "root-folder";
+ vector< libcmis::ObjectPtr > children = session->getNavigationService().
+ getChildren( session->m_repositoryId,
+ id );
+
+ // Check the returned children
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of children", size_t( 5 ), children.size() );
+
+ int folderCount = 0;
+ int documentCount = 0;
+ for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
+ it != children.end( ); ++it )
+ {
+ if ( NULL != boost::dynamic_pointer_cast< libcmis::Folder >( *it ) )
+ ++folderCount;
+ else if ( NULL != boost::dynamic_pointer_cast< libcmis::Document >( *it ) )
+ ++documentCount;
+ }
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of folder children", 2, folderCount );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of document children", 3, documentCount );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/NavigationService" );
+ string expectedRequest = "<cmism:getChildren" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:folderId>" + id + "</cmism:folderId>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "<cmism:renditionFilter>*</cmism:renditionFilter>"
+ "</cmism:getChildren>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getContentStreamTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/get-content-stream.http", "<cmism:getContentStream " );
+
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ boost::shared_ptr< istream > is = document->getContentStream( );
+
+ // Check the fetched content
+ string actualContent = lcl_getStreamAsString( is );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Content stream doesn't match",
+ string( "Some content stream" ), actualContent );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:getContentStream " );
+ string expectedRequest = "<cmism:getContentStream" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "</cmism:getContentStream>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::setContentStreamTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/set-content-stream.http", "<cmism:setContentStream " );
+ curl_mockup_addResponse( "http://mockup/mock/content/data.txt", "id=test-document", "PUT", "Updated", 0, false );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::DocumentPtr document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ try
+ {
+ string oldChangeToken = object->getChangeToken( );
+ string expectedContent( "Some content stream to set" );
+ boost::shared_ptr< ostream > os ( new stringstream ( expectedContent ) );
+ string filename( "name.txt" );
+ string contentType( "text/plain" );
+ document->setContentStream( os, contentType, filename, true );
+
+ CPPUNIT_ASSERT_MESSAGE( "Object not refreshed during setContentStream", object->getRefreshTimestamp( ) > 0 );
+ // We do not check the change token as we are lazy
+ // That would require to write another answer file for the refresh
+
+ // Check the sent request
+ ostringstream converter;
+ converter << expectedContent.size( );
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:setContentStream " );
+ string expectedRequest = "<cmism:setContentStream" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:overwriteFlag>true</cmism:overwriteFlag>"
+ "<cmism:changeToken>" + oldChangeToken + "</cmism:changeToken>"
+ "<cmism:contentStream>"
+ "<cmism:length>" + converter.str() + "</cmism:length>"
+ "<cmism:mimeType>" + contentType + "</cmism:mimeType>"
+ "<cmism:filename>" + filename + "</cmism:filename>"
+ "<cmism:stream>"
+ "<xop:Include xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" "
+ "href=\"cid:obfuscated\"/>"
+ "</cmism:stream>"
+ "</cmism:contentStream>"
+ "</cmism:setContentStream>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = "Unexpected exception: ";
+ msg += e.what();
+ CPPUNIT_FAIL( msg.c_str() );
+ }
+}
+
+void WSTest::getRenditionsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/get-renditions.http", "<cmism:getRenditions " );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string expectedId( "test-document" );
+ libcmis::ObjectPtr actual = session->getObject( expectedId );
+
+ std::vector< libcmis::RenditionPtr > renditions = actual->getRenditions( );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad renditions count", size_t( 2 ), renditions.size( ) );
+
+ libcmis::RenditionPtr rendition = renditions[1];
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition mime type", string( "application/pdf" ), rendition->getMimeType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition stream id", string( "test-document-rendition2" ), rendition->getStreamId() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition length - default case", long( -1 ), rendition->getLength( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition Title", string( "Doc as PDF" ), rendition->getTitle( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition kind", string( "pdf" ), rendition->getKind( ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad rendition length - filled case", long( 40385 ), renditions[0]->getLength( ) );
+}
+
+void WSTest::updatePropertiesTest( )
+{
+ curl_mockup_reset( );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/update-properties.http", "<cmism:updateProperties " );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // Values for the test
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ string propertyName( "cmis:name" );
+ string expectedValue( "New name" );
+
+ // Fill the map of properties to change
+ PropertyPtrMap newProperties;
+
+ libcmis::ObjectTypePtr objectType = object->getTypeDescription( );
+ map< string, libcmis::PropertyTypePtr >::iterator it = objectType->getPropertiesTypes( ).find( propertyName );
+ vector< string > values;
+ values.push_back( expectedValue );
+ libcmis::PropertyPtr property( new libcmis::Property( it->second, values ) );
+ newProperties[ propertyName ] = property;
+
+ // Change the object response to provide the updated values
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document-updated.http", "<cmism:getObject " );
+
+ // Update the properties (method to test)
+ libcmis::ObjectPtr updated = object->updateProperties( newProperties );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:updateProperties " );
+ string expectedRequest = "<cmism:updateProperties" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:changeToken>some-change-token</cmism:changeToken>"
+ "<cmism:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>New name</cmis:value>"
+ "</cmis:propertyString>"
+ "</cmism:properties>"
+ "</cmism:updateProperties>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+
+ // Check that the properties are updated after the call
+ PropertyPtrMap::iterator propIt = updated->getProperties( ).find( propertyName );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong value after refresh", expectedValue, propIt->second->getStrings().front( ) );
+}
+
+void WSTest::updatePropertiesEmptyTest( )
+{
+ curl_mockup_reset( );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // Values for the test
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+
+ // Just leave the map empty and update
+ PropertyPtrMap emptyProperties;
+ libcmis::ObjectPtr updated = object->updateProperties( emptyProperties );
+
+ // Check that no HTTP request was sent
+ int count = curl_mockup_getRequestsCount( "http://mockup/ws/services/ObjectService",
+ "", "POST", "<cmism:updateProperties" );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "No HTTP request should have been sent", 0, count );
+
+ // Check that the object we got is the same than previous one
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong change token", object->getChangeToken(), updated->getChangeToken() );
+}
+
+void WSTest::createFolderTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/root-folder.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/create-folder.http", "<cmism:createFolder " );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "cmis:folder" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ string expectedName( "create folder" );
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( expectedName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "cmis:folder" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Set the mockup to send the updated folder now that we had the parent
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/created-folder.http", "<cmism:getObject " );
+
+ // Actually send the folder creation request
+ libcmis::FolderPtr created = parent->createFolder( props );
+
+ // Check that something came back
+ CPPUNIT_ASSERT_MESSAGE( "Change token shouldn't be empty: object should have been refreshed",
+ !created->getChangeToken( ).empty() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong name", expectedName, created->getName( ) );
+
+ // Check that the proper request has been sent
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:createFolder " );
+ string expectedRequest = "<cmism:createFolder" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>create folder</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyId propertyDefinitionId=\"cmis:objectTypeId\" localName=\"cmis:objectTypeId\""
+ " displayName=\"Type-Id\" queryName=\"cmis:objectTypeId\">"
+ "<cmis:value>cmis:folder</cmis:value>"
+ "</cmis:propertyId>"
+ "</cmism:properties>"
+ "<cmism:folderId>root-folder</cmism:folderId>"
+ "</cmism:createFolder>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::createFolderBadTypeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/root-folder.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/create-folder-bad-type.http", "<cmism:createFolder " );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "cmis:folder" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ string expectedName( "create folder" );
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( expectedName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "cmis:document" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Actually send the folder creation request
+ try
+ {
+ libcmis::FolderPtr created = parent->createFolder( props );
+ CPPUNIT_FAIL( "Should not succeed to return a folder" );
+ }
+ catch ( libcmis::Exception& e )
+ {
+ // Check the caught exception
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong error type", string( "constraint" ), e.getType() );
+
+ // Check that the proper request has been sent
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:createFolder " );
+ string expectedRequest = "<cmism:createFolder" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>create folder</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyId propertyDefinitionId=\"cmis:objectTypeId\" localName=\"cmis:objectTypeId\""
+ " displayName=\"Type-Id\" queryName=\"cmis:objectTypeId\">"
+ "<cmis:value>cmis:document</cmis:value>"
+ "</cmis:propertyId>"
+ "</cmism:properties>"
+ "<cmism:folderId>root-folder</cmism:folderId>"
+ "</cmism:createFolder>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+ }
+}
+
+void WSTest::createDocumentTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/create-document.http", "<cmism:createDocument " );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/root-folder.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ libcmis::FolderPtr parent = session->getRootFolder( );
+
+ // Make the mockup know about cmis:document now
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-document.http" );
+
+ // Prepare the properties for the new object, object type is cmis:folder
+ PropertyPtrMap props;
+ libcmis::ObjectTypePtr type = session->getType( "cmis:document" );
+ map< string, libcmis::PropertyTypePtr > propTypes = type->getPropertiesTypes( );
+
+ // Set the object name
+ string expectedName( "create document" );
+
+ map< string, libcmis::PropertyTypePtr >::iterator it = propTypes.find( string( "cmis:name" ) );
+ vector< string > nameValues;
+ nameValues.push_back( expectedName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( it->second, nameValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // set the object type
+ it = propTypes.find( string( "cmis:objectTypeId" ) );
+ vector< string > typeValues;
+ typeValues.push_back( "cmis:document" );
+ libcmis::PropertyPtr typeProperty( new libcmis::Property( it->second, typeValues ) );
+ props.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeProperty ) );
+
+ // Make the mockup able to send the response to update the object
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/created-document.http", "<cmism:getObject " );
+
+ // Actually send the document creation request
+ string content = "Some content";
+ boost::shared_ptr< ostream > os ( new stringstream( content ) );
+ string contentType = "text/plain";
+ string filename( "name.txt" );
+ libcmis::DocumentPtr created = parent->createDocument( props, os, contentType, filename );
+
+ // Check that something came back
+ CPPUNIT_ASSERT_MESSAGE( "Change token shouldn't be empty: object should have been refreshed",
+ !created->getChangeToken( ).empty() );
+
+ // Check that the name is ok
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong name set", expectedName, created->getName( ) );
+
+ // Check that the sent request is the expected one
+ ostringstream converter;
+ converter << content.size( );
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:createDocument " );
+ string expectedRequest = "<cmism:createDocument" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:name\" localName=\"cmis:name\" "
+ "displayName=\"Name\" queryName=\"cmis:name\">"
+ "<cmis:value>create document</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyId propertyDefinitionId=\"cmis:objectTypeId\" localName=\"cmis:objectTypeId\""
+ " displayName=\"Type-Id\" queryName=\"cmis:objectTypeId\">"
+ "<cmis:value>cmis:document</cmis:value>"
+ "</cmis:propertyId>"
+ "</cmism:properties>"
+ "<cmism:folderId>root-folder</cmism:folderId>"
+ "<cmism:contentStream>"
+ "<cmism:length>" + converter.str( ) + "</cmism:length>"
+ "<cmism:mimeType>" + contentType + "</cmism:mimeType>"
+ "<cmism:filename>" + filename + "</cmism:filename>"
+ "<cmism:stream>"
+ "<xop:Include xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" "
+ "href=\"cid:obfuscated\"/>"
+ "</cmism:stream>"
+ "</cmism:contentStream>"
+ "</cmism:createDocument>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::deleteDocumentTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/delete-object.http", "<cmism:deleteObject " );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get() );
+
+ // Run the tested method. Here we delete the object with all its versions
+ document->remove( true );
+
+ // Check that the proper request has been sent
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:deleteObject " );
+ string expectedRequest = "<cmism:deleteObject" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:allVersions>true</cmism:allVersions>"
+ "</cmism:deleteObject>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::deleteFolderTreeTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/valid-object.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/delete-tree.http", "<cmism:deleteTree " );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "valid-object";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( object.get() );
+
+ vector<string> failed = folder->removeTree( true, libcmis::UnfileObjects::Delete, false );
+
+ // Check that we had the failed ids
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong ids for non-deleted objects",
+ string( "bad-delete" ), failed[0] );
+
+ // Test the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:deleteTree " );
+ string expectedRequest = "<cmism:deleteTree" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:folderId>valid-object</cmism:folderId>"
+ "<cmism:allVersions>true</cmism:allVersions>"
+ "<cmism:unfileObjects>delete</cmism:unfileObjects>"
+ "<cmism:continueOnFailure>false</cmism:continueOnFailure>"
+ "</cmism:deleteTree>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::moveTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-folder.http", "<cmism:typeId>cmis:folder</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http", "<cmism:typeId>DocumentLevel2</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/NavigationService", DATA_DIR "/ws/test-document-parents.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/move-object.http", "<cmism:moveObject " );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get() );
+
+ string destFolderId = "valid-object";
+ libcmis::FolderPtr src = document->getParents( ).front( );
+
+ // Tell the mockup about the destination folder
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/valid-object.http", "<cmism:getObject " );
+ libcmis::FolderPtr dest = session->getFolder( destFolderId );
+
+ document->move( src, dest );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:moveObject " );
+ string expectedRequest = "<cmism:moveObject" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:targetFolderId>" + destFolderId + "</cmism:targetFolderId>"
+ "<cmism:sourceFolderId>" + src->getId( ) + "</cmism:sourceFolderId>"
+ "</cmism:moveObject>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::addSecondaryTypeTest( )
+{
+ curl_mockup_reset( );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/secondary-type.http",
+ "<cmism:typeId>secondary-type</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2-secondary.http",
+ "<cmism:typeId>DocumentLevel2</cmism:typeId>" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:getObject " );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/update-properties.http", "<cmism:updateProperties " );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // Values for the test
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ string secondaryType = "secondary-type";
+ string propertyName = "secondary-prop";
+ string expectedValue = "some-value";
+
+ // Fill the map of properties to change
+ PropertyPtrMap newProperties;
+
+ libcmis::ObjectTypePtr objectType = session->getType( secondaryType );
+ map< string, libcmis::PropertyTypePtr >::iterator it = objectType->getPropertiesTypes( ).find( propertyName );
+ vector< string > values;
+ values.push_back( expectedValue );
+ libcmis::PropertyPtr property( new libcmis::Property( it->second, values ) );
+ newProperties[ propertyName ] = property;
+
+ // Change the object response to provide the updated values
+ test::addWsResponse( "http://mockup/ws/services/ObjectService",
+ DATA_DIR "/ws/test-document-add-secondary.http",
+ "<cmism:getObject " );
+
+ // add the secondary type (method to test)
+ libcmis::ObjectPtr updated = object->addSecondaryType( secondaryType, newProperties );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/ObjectService", "<cmism:updateProperties " );
+ string expectedRequest = "<cmism:updateProperties" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:changeToken>some-change-token</cmism:changeToken>"
+ "<cmism:properties>"
+ "<cmis:propertyString propertyDefinitionId=\"cmis:secondaryObjectTypeIds\""
+ " localName=\"cmis:secondaryObjectTypeIds\""
+ " displayName=\"cmis:secondaryObjectTypeIds\""
+ " queryName=\"cmis:secondaryObjectTypeIds\">"
+ "<cmis:value>" + secondaryType + "</cmis:value>"
+ "</cmis:propertyString>"
+ "<cmis:propertyString propertyDefinitionId=\"" + propertyName + "\""
+ " localName=\"" + propertyName + "\""
+ " displayName=\"" + propertyName + "\""
+ " queryName=\"" + propertyName + "\">"
+ "<cmis:value>" + expectedValue + "</cmis:value>"
+ "</cmis:propertyString>"
+ "</cmism:properties>"
+ "</cmism:updateProperties>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+
+ // Check that the properties are updated after the call
+ PropertyPtrMap::iterator propIt = updated->getProperties( ).find( propertyName );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong value after refresh", expectedValue, propIt->second->getStrings().front( ) );
+}
+
+void WSTest::checkOutTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http", "<cmism:objectId>test-document</cmism:objectId>" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/working-copy.http", "<cmism:objectId>working-copy</cmism:objectId>" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/VersioningService", DATA_DIR "/ws/checkout.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( object.get() );
+
+ libcmis::DocumentPtr pwc = document->checkOut( );
+
+ // Check that we have a PWC
+ CPPUNIT_ASSERT_MESSAGE( "Missing returned Private Working Copy", pwc.get( ) != NULL );
+
+ PropertyPtrMap::iterator it = pwc->getProperties( ).find( string( "cmis:isVersionSeriesCheckedOut" ) );
+ vector< bool > values = it->second->getBools( );
+ CPPUNIT_ASSERT_MESSAGE( "cmis:isVersionSeriesCheckedOut isn't true", values.front( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/VersioningService" );
+ string expectedRequest = "<cmism:checkOut" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "</cmism:checkOut>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::cancelCheckOutTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/working-copy.http" );
+ test::addWsResponse( "http://mockup/ws/services/VersioningService", DATA_DIR "/ws/cancel-checkout.http" );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // First get a checked out document
+ string id = "working-copy";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::DocumentPtr pwc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ pwc->cancelCheckout( );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/VersioningService" );
+ string expectedRequest = "<cmism:cancelCheckOut" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "</cmism:cancelCheckOut>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::checkInTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/working-copy.http", "<cmism:objectId>working-copy</cmism:objectId>" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/checked-in.http", "<cmism:objectId>test-document</cmism:objectId>" );
+ test::addWsResponse( "http://mockup/ws/services/VersioningService", DATA_DIR "/ws/checkin.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // First get a checked out document
+ string id = "working-copy";
+ libcmis::ObjectPtr object = session->getObject( id );
+ libcmis::DocumentPtr pwc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ // Do the checkin
+ bool isMajor = true;
+ string comment( "Some check-in comment" );
+ PropertyPtrMap properties;
+ string newContent = "Some New content to check in";
+ boost::shared_ptr< ostream > stream ( new stringstream( newContent ) );
+ string contentType = "text/plain";
+ string filename = "filename.txt";
+ libcmis::DocumentPtr updated = pwc->checkIn( isMajor, comment, properties,
+ stream, contentType, filename );
+
+ // Check that we had the new version
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong filename: probably not the new version",
+ filename, updated->getContentFilename() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong commit comment: not the new version",
+ comment, updated->getStringProperty( "cmis:checkinComment" ) );
+
+ // Check the sent request
+ ostringstream converter;
+ converter << newContent.size( );
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/VersioningService" );
+ string expectedRequest = "<cmism:checkIn" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + id + "</cmism:objectId>"
+ "<cmism:major>true</cmism:major>"
+ "<cmism:properties/>"
+ "<cmism:contentStream>"
+ "<cmism:length>" + converter.str() + "</cmism:length>"
+ "<cmism:mimeType>" + contentType + "</cmism:mimeType>"
+ "<cmism:filename>" + filename + "</cmism:filename>"
+ "<cmism:stream>"
+ "<xop:Include xmlns:xop=\"http://www.w3.org/2004/08/xop/include\" "
+ "href=\"cid:obfuscated\"/>"
+ "</cmism:stream>"
+ "</cmism:contentStream>"
+ "<cmism:checkinComment>" + comment + "</cmism:checkinComment>"
+ "</cmism:checkIn>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::getAllVersionsTest( )
+{
+ curl_mockup_reset( );
+ curl_mockup_setCredentials( SERVER_USERNAME, SERVER_PASSWORD );
+ test::addWsResponse( "http://mockup/ws/services/RepositoryService", DATA_DIR "/ws/type-docLevel2.http" );
+ test::addWsResponse( "http://mockup/ws/services/ObjectService", DATA_DIR "/ws/test-document.http" );
+ test::addWsResponse( "http://mockup/ws/services/VersioningService", DATA_DIR "/ws/get-versions.http" );
+
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+
+ // First get a document
+ string id = "test-document";
+ libcmis::ObjectPtr object = session->getObject( id );
+ string seriesId = object->getStringProperty( "cmis:versionSeriesId" );
+ libcmis::DocumentPtr doc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ // Get all the versions (method to check)
+ vector< libcmis::DocumentPtr > versions = doc->getAllVersions( );
+
+ // Checks
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of versions", size_t( 2 ), versions.size( ) );
+
+ // Check the sent request
+ string xmlRequest = lcl_getCmisRequestXml( "http://mockup/ws/services/VersioningService" );
+ string expectedRequest = "<cmism:getAllVersions" + lcl_getExpectedNs() + ">"
+ "<cmism:repositoryId>mock</cmism:repositoryId>"
+ "<cmism:objectId>" + seriesId + "</cmism:objectId>"
+ "<cmism:includeAllowableActions>true</cmism:includeAllowableActions>"
+ "</cmism:getAllVersions>";
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong request sent", expectedRequest, xmlRequest );
+}
+
+void WSTest::navigationServiceCopyTest()
+{
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ NavigationService service( session.get() );
+
+ {
+ NavigationService copy( service );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+
+ {
+ NavigationService copy;
+ copy = service;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+}
+
+void WSTest::repositoryServiceCopyTest()
+{
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ RepositoryService service( session.get() );
+
+ {
+ RepositoryService copy( service );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+
+ {
+ RepositoryService copy;
+ copy = service;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+}
+
+void WSTest::objectServiceCopyTest()
+{
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ ObjectService service( session.get() );
+
+ {
+ ObjectService copy( service );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+
+ {
+ ObjectService copy;
+ copy = service;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+}
+
+void WSTest::versioningServiceCopyTest()
+{
+ WSSessionPtr session = getTestSession( SERVER_USERNAME, SERVER_PASSWORD, true );
+ VersioningService service( session.get() );
+
+ {
+ VersioningService copy( service );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+
+ {
+ VersioningService copy;
+ copy = service;
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Session not copied", service.m_session, copy.m_session );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "URL not copied", service.m_url, copy.m_url );
+ }
+}
+
+WSSessionPtr WSTest::getTestSession( string username, string password, bool noRepos )
+{
+ WSSessionPtr session( new WSSession( ) );
+ session->m_username = username;
+ session->m_password = password;
+
+ string buf;
+ test::loadFromFile( DATA_DIR "/ws/CMISWS-Service.wsdl", buf );
+ session->parseWsdl( buf );
+ session->initializeResponseFactory( );
+
+ // Manually define the repositories to avoid the HTTP query
+ if ( noRepos )
+ {
+ libcmis::RepositoryPtr repo = getTestRepository( );
+ session->m_repositories.push_back( repo );
+ session->m_repositoryId = repo->getId( );
+ }
+
+ return session;
+}
+
+libcmis::RepositoryPtr WSTest::getTestRepository()
+{
+ libcmis::RepositoryPtr repo( new libcmis::Repository( ) );
+ repo->m_id = "mock";
+ repo->m_name = "Mockup";
+ repo->m_description = "Repository sent by mockup server";
+ repo->m_vendorName = "libcmis";
+ repo->m_productName = "Libcmis mockup";
+ repo->m_productVersion = "some-version";
+ repo->m_cmisVersionSupported = "1.1";
+ repo->m_rootId = "root-folder";
+
+ map< libcmis::Repository::Capability, string > capabilities;
+ capabilities[libcmis::Repository::ACL] = "manage";
+ capabilities[libcmis::Repository::AllVersionsSearchable] = "false";
+ capabilities[libcmis::Repository::Changes] = "none";
+ capabilities[libcmis::Repository::ContentStreamUpdatability] = "anytime";
+ capabilities[libcmis::Repository::GetDescendants] = "true";
+ capabilities[libcmis::Repository::GetFolderTree] = "true";
+ capabilities[libcmis::Repository::Multifiling] = "true";
+ capabilities[libcmis::Repository::PWCSearchable] = "false";
+ capabilities[libcmis::Repository::PWCUpdatable] = "true";
+ capabilities[libcmis::Repository::Query] = "bothcombined";
+ capabilities[libcmis::Repository::Renditions] = "read";
+ capabilities[libcmis::Repository::Unfiling] = "true";
+ capabilities[libcmis::Repository::VersionSpecificFiling] = "false";
+ capabilities[libcmis::Repository::Join] = "none";
+ repo->m_capabilities = capabilities;
+
+ return repo;
+}
diff --git a/qa/libcmis/test-xmlutils.cxx b/qa/libcmis/test-xmlutils.cxx
new file mode 100644
index 0000000..e4d5339
--- /dev/null
+++ b/qa/libcmis/test-xmlutils.cxx
@@ -0,0 +1,626 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <ctime>
+#include <sstream>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestFixture.h>
+#include <cppunit/TestAssert.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <libxml/tree.h>
+
+#if defined __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wkeyword-macro"
+#endif
+#define private public
+#if defined __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <libcmis/object-type.hxx>
+#include <libcmis/property.hxx>
+#include <libcmis/property-type.hxx>
+#include <libcmis/xml-utils.hxx>
+
+#include "test-helpers.hxx"
+
+using namespace boost;
+using namespace std;
+using namespace test;
+
+class XmlTest : public CppUnit::TestFixture
+{
+ public:
+
+ // Parser tests
+ void parseDateTimeTest( );
+ void parseBoolTest( );
+ void parseIntegerTest( );
+ void parseDoubleTest( );
+
+ void parsePropertyStringTest( );
+ void parsePropertyIntegerTest( );
+ void parsePropertyDateTimeTest( );
+ void parsePropertyBoolTest( );
+
+ void parseEmptyPropertyTest( );
+ void parsePropertyNoTypeTest( );
+
+ void parseRenditionTest( );
+ void parseRepositoryCapabilitiesTest( );
+
+ // Writer tests
+ void propertyStringAsXmlTest( );
+ void propertyIntegerAsXmlTest( );
+
+ // Other tests
+ void sha1Test( );
+ void propertyTypeUpdateTest( );
+ void escapeTest( );
+ void unescapeTest( );
+
+ CPPUNIT_TEST_SUITE( XmlTest );
+ CPPUNIT_TEST( parseDateTimeTest );
+ CPPUNIT_TEST( parseBoolTest );
+ CPPUNIT_TEST( parseIntegerTest );
+ CPPUNIT_TEST( parseDoubleTest );
+ CPPUNIT_TEST( parsePropertyStringTest );
+ CPPUNIT_TEST( parsePropertyIntegerTest );
+ CPPUNIT_TEST( parsePropertyDateTimeTest );
+ CPPUNIT_TEST( parsePropertyBoolTest );
+ CPPUNIT_TEST( parseEmptyPropertyTest );
+ CPPUNIT_TEST( parsePropertyNoTypeTest );
+ CPPUNIT_TEST( parseRenditionTest );
+ CPPUNIT_TEST( parseRepositoryCapabilitiesTest );
+ CPPUNIT_TEST( propertyStringAsXmlTest );
+ CPPUNIT_TEST( propertyIntegerAsXmlTest );
+ CPPUNIT_TEST( sha1Test );
+ CPPUNIT_TEST( propertyTypeUpdateTest );
+ CPPUNIT_TEST( escapeTest );
+ CPPUNIT_TEST( unescapeTest );
+ CPPUNIT_TEST_SUITE_END( );
+};
+
+/** Dummy ObjectType implementation used as a PropertyType factory.
+ */
+class ObjectTypeDummy : public libcmis::ObjectType
+{
+ public:
+ ObjectTypeDummy( );
+ virtual ~ObjectTypeDummy() { };
+};
+
+ObjectTypeDummy::ObjectTypeDummy( )
+{
+ // String Property
+ {
+ libcmis::PropertyTypePtr prop ( new libcmis::PropertyType( ) );
+ prop->setId( string( "STR-ID" ) );
+ prop->setLocalName( string( "LOCAL" ) );
+ prop->setDisplayName( string( "DISPLAY" ) );
+ prop->setQueryName( string( "QUERY" ) );
+ prop->setTypeFromXml( "string" );
+
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( prop->getId( ), prop ) );
+ }
+
+ // Integer Property
+ {
+ libcmis::PropertyTypePtr prop ( new libcmis::PropertyType( ) );
+ prop->setId( string( "INT-ID" ) );
+ prop->setLocalName( string( "LOCAL" ) );
+ prop->setDisplayName( string( "DISPLAY" ) );
+ prop->setQueryName( string( "QUERY" ) );
+ prop->setTypeFromXml( "integer" );
+
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( prop->getId( ), prop ) );
+ }
+
+ // DateTime Property
+ {
+ libcmis::PropertyTypePtr prop ( new libcmis::PropertyType( ) );
+ prop->setId( string( "DATE-ID" ) );
+ prop->setLocalName( string( "LOCAL" ) );
+ prop->setDisplayName( string( "DISPLAY" ) );
+ prop->setQueryName( string( "QUERY" ) );
+ prop->setTypeFromXml( "datetime" );
+
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( prop->getId( ), prop ) );
+ }
+
+ // Boolean Property
+ {
+ libcmis::PropertyTypePtr prop ( new libcmis::PropertyType( ) );
+ prop->setId( string( "BOOL-ID" ) );
+ prop->setLocalName( string( "LOCAL" ) );
+ prop->setDisplayName( string( "DISPLAY" ) );
+ prop->setQueryName( string( "QUERY" ) );
+ prop->setTypeFromXml( "boolean" );
+
+ m_propertiesTypes.insert( pair< string, libcmis::PropertyTypePtr >( prop->getId( ), prop ) );
+ }
+}
+
+void XmlTest::parseDateTimeTest( )
+{
+ tm basis;
+ basis.tm_year = 2011 - 1900;
+ basis.tm_mon = 8; // Months are in 0..11 range
+ basis.tm_mday = 28;
+ basis.tm_hour = 12;
+ basis.tm_min = 44;
+ basis.tm_sec = 28;
+
+ // Broken strings
+ {
+ posix_time::ptime expected( boost::date_time::not_a_date_time );
+
+ posix_time::ptime t = libcmis::parseDateTime( string() );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Broken time string case failed #1",
+ expected, t );
+
+ char toParse[50];
+ strftime( toParse, sizeof( toParse ), "%FT", &basis );
+ t = libcmis::parseDateTime( string( toParse ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Broken time string case failed #2",
+ expected, t );
+
+ strftime( toParse, sizeof( toParse ), "T%T", &basis );
+ t = libcmis::parseDateTime( string( toParse ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Broken time string case failed #3",
+ expected, t );
+
+ strftime( toParse, sizeof( toParse ), "%T", &basis );
+ t = libcmis::parseDateTime( string( toParse ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Broken time string case failed #4",
+ expected, t );
+ }
+
+ // No time zone test
+ {
+ char toParse[50];
+ strftime( toParse, sizeof( toParse ), "%FT%T", &basis );
+ posix_time::ptime t = libcmis::parseDateTime( string( toParse ) );
+
+ gregorian::date expDate( basis.tm_year + 1900, basis.tm_mon + 1, basis.tm_mday );
+ posix_time::time_duration expTime( basis.tm_hour, basis.tm_min, basis.tm_sec );
+ posix_time::ptime expected( expDate, expTime );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "No time zone case failed", expected, t );
+ }
+
+ // Z time zone test
+ {
+ char toParse[50];
+ strftime( toParse, sizeof( toParse ), "%FT%TZ", &basis );
+ posix_time::ptime t = libcmis::parseDateTime( string( toParse ) );
+
+ gregorian::date expDate( basis.tm_year + 1900, basis.tm_mon + 1, basis.tm_mday );
+ posix_time::time_duration expTime( basis.tm_hour, basis.tm_min, basis.tm_sec );
+ posix_time::ptime expected( expDate, expTime );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Z time zone case failed", expected, t );
+ }
+
+ // +XX:XX time zone test
+ {
+ char toParse[50];
+ strftime( toParse, sizeof( toParse ), "%FT%T+02:00", &basis );
+ posix_time::ptime t = libcmis::parseDateTime( string( toParse ) );
+
+ gregorian::date expDate( basis.tm_year + 1900, basis.tm_mon + 1, basis.tm_mday );
+ posix_time::time_duration expTime( basis.tm_hour + 2, basis.tm_min, basis.tm_sec );
+ posix_time::ptime expected( expDate, expTime );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "+XX:XX time zone case failed", expected, t );
+ }
+
+ // -XX:XX time zone test
+ {
+ char toParse[50];
+ strftime( toParse, sizeof( toParse ), "%FT%T-02:00", &basis );
+ posix_time::ptime t = libcmis::parseDateTime( string( toParse ) );
+
+ gregorian::date expDate( basis.tm_year + 1900, basis.tm_mon + 1, basis.tm_mday );
+ posix_time::time_duration expTime( basis.tm_hour - 2, basis.tm_min, basis.tm_sec );
+ posix_time::ptime expected( expDate, expTime );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "+XX:XX time zone case failed", expected, t );
+ }
+
+ // Error test
+ {
+ posix_time::ptime t = libcmis::parseDateTime( string( "Nothing interesting 9990" ) );
+ CPPUNIT_ASSERT_MESSAGE( "Error case failed", t.is_not_a_date_time( ) );
+ }
+}
+
+void XmlTest::parseBoolTest( )
+{
+ // 'true' test
+ {
+ bool result = libcmis::parseBool( string( "true" ) );
+ CPPUNIT_ASSERT_MESSAGE( "'true' can't be parsed properly", result );
+ }
+
+ // '1' test
+ {
+ bool result = libcmis::parseBool( string( "1" ) );
+ CPPUNIT_ASSERT_MESSAGE( "'1' can't be parsed properly", result );
+ }
+
+ // 'false' test
+ {
+ bool result = libcmis::parseBool( string( "false" ) );
+ CPPUNIT_ASSERT_MESSAGE( "'false' can't be parsed properly", !result );
+ }
+
+ // '0' test
+ {
+ bool result = libcmis::parseBool( string( "0" ) );
+ CPPUNIT_ASSERT_MESSAGE( "'0' can't be parsed properly", !result );
+ }
+
+ // Error test
+ {
+ try
+ {
+ libcmis::parseBool( string( "boolcheat" ) );
+ CPPUNIT_FAIL( "Exception should be thrown" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad exception message",
+ string( "Invalid xsd:boolean input: boolcheat" ), string( e.what() ) );
+ }
+ }
+}
+
+void XmlTest::parseIntegerTest( )
+{
+ // Positive value test
+ {
+ long result = libcmis::parseInteger( string( "123" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Positive integer can't be parsed properly", 123L, result );
+ }
+
+ // Negative value test
+ {
+ long result = libcmis::parseInteger( string( "-123" ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Negative integer can't be parsed properly", -123L, result );
+ }
+
+ // Overflow error test
+ {
+ try
+ {
+ libcmis::parseInteger( string( "9999999999999999999" ) );
+ CPPUNIT_FAIL( "Exception should be thrown" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad exception message",
+ string( "xsd:integer input can't fit to long: 9999999999999999999" ), string( e.what() ) );
+ }
+ }
+
+ // Non integer test
+ {
+ try
+ {
+ libcmis::parseInteger( string( "123bad" ) );
+ CPPUNIT_FAIL( "Exception should be thrown" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad exception message",
+ string( "Invalid xsd:integer input: 123bad" ), string( e.what() ) );
+ }
+ }
+}
+
+void XmlTest::parseDoubleTest( )
+{
+ // Positive value test
+ {
+ double result = libcmis::parseDouble( string( "123.456" ) );
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Positive decimal can't be parsed properly", 123.456, result, 0.000001 );
+ }
+
+ // Negative value test
+ {
+ double result = libcmis::parseDouble( string( "-123.456" ) );
+ CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE( "Negative decimal can't be parsed properly", -123.456, result, 0.000001 );
+ }
+
+ // Non integer test
+ {
+ try
+ {
+ libcmis::parseDouble( string( "123.456bad" ) );
+ CPPUNIT_FAIL( "Exception should be thrown" );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Bad exception message",
+ string( "Invalid xsd:decimal input: 123.456bad" ), string( e.what() ) );
+ }
+ }
+}
+
+void XmlTest::parsePropertyStringTest( )
+{
+ stringstream buf;
+ buf << "<cmis:propertyString " << getXmlns( )
+ << "propertyDefinitionId=\"STR-ID\">"
+ << "<cmis:value>VALUE 1</cmis:value>"
+ << "<cmis:value>VALUE 2</cmis:value>"
+ << "</cmis:propertyString>";
+ libcmis::ObjectTypePtr dummy( new ObjectTypeDummy( ) );
+ libcmis::PropertyPtr actual = libcmis::parseProperty( getXmlNode( buf.str( ) ), dummy );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id parsed", string( "STR-ID" ), actual->getPropertyType( )->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of values parsed", vector<string>::size_type( 2 ), actual->getStrings( ).size( ) );
+}
+
+void XmlTest::parsePropertyIntegerTest( )
+{
+ stringstream buf;
+ buf << "<cmis:propertyInteger " << getXmlns( )
+ << "propertyDefinitionId=\"INT-ID\">"
+ << "<cmis:value>12345</cmis:value>"
+ << "<cmis:value>67890</cmis:value>"
+ << "</cmis:propertyInteger>";
+ libcmis::ObjectTypePtr dummy( new ObjectTypeDummy( ) );
+ libcmis::PropertyPtr actual = libcmis::parseProperty( getXmlNode( buf.str( ) ), dummy );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id parsed", string( "INT-ID" ), actual->getPropertyType()->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of values parsed", vector<string>::size_type( 2 ), actual->getLongs( ).size( ) );
+}
+
+void XmlTest::parsePropertyDateTimeTest( )
+{
+ stringstream buf;
+ buf << "<cmis:propertyDateTime " << getXmlns( )
+ << "propertyDefinitionId=\"DATE-ID\">"
+ << "<cmis:value>2012-01-19T09:06:57.388Z</cmis:value>"
+ << "<cmis:value>2011-01-19T09:06:57.388Z</cmis:value>"
+ << "</cmis:propertyDateTime>";
+ libcmis::ObjectTypePtr dummy( new ObjectTypeDummy( ) );
+ libcmis::PropertyPtr actual = libcmis::parseProperty( getXmlNode( buf.str( ) ), dummy );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id parsed", string( "DATE-ID" ), actual->getPropertyType()->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of values parsed", vector<string>::size_type( 2 ), actual->getDateTimes( ).size( ) );
+}
+
+void XmlTest::parsePropertyBoolTest( )
+{
+ stringstream buf;
+ buf << "<cmis:propertyBoolean " << getXmlns( )
+ << "propertyDefinitionId=\"BOOL-ID\">"
+ << "<cmis:value>true</cmis:value>"
+ << "</cmis:propertyBoolean>";
+ libcmis::ObjectTypePtr dummy( new ObjectTypeDummy( ) );
+ libcmis::PropertyPtr actual = libcmis::parseProperty( getXmlNode( buf.str( ) ), dummy );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id parsed", string( "BOOL-ID" ), actual->getPropertyType()->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of values parsed", vector<string>::size_type( 1 ), actual->getBools( ).size( ) );
+}
+
+void XmlTest::parseEmptyPropertyTest( )
+{
+ stringstream buf;
+ buf << "<cmis:propertyId " << getXmlns( ) << "propertyDefinitionId=\"STR-ID\" />";
+ libcmis::ObjectTypePtr dummy( new ObjectTypeDummy( ) );
+ libcmis::PropertyPtr actual = libcmis::parseProperty( getXmlNode( buf.str( ) ), dummy );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id parsed", string( "STR-ID" ), actual->getPropertyType()->getId( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Should have no value", actual->getStrings( ).empty( ) );
+}
+
+void XmlTest::parsePropertyNoTypeTest( )
+{
+ stringstream buf;
+ buf << "<cmis:propertyDateTime " << getXmlns( )
+ << "propertyDefinitionId=\"DATE-ID\">"
+ << "<cmis:value>2012-01-19T09:06:57.388Z</cmis:value>"
+ << "<cmis:value>2011-01-19T09:06:57.388Z</cmis:value>"
+ << "</cmis:propertyDateTime>";
+ libcmis::ObjectTypePtr noType;
+ libcmis::PropertyPtr actual = libcmis::parseProperty( getXmlNode( buf.str( ) ), noType );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong id parsed", string( "DATE-ID" ), actual->getPropertyType()->getId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong number of values parsed", vector<string>::size_type( 2 ), actual->getDateTimes( ).size( ) );
+}
+
+void XmlTest::parseRenditionTest( )
+{
+ stringstream buf;
+ buf << "<cmis:rendition " << getXmlns( ) << ">"
+ << "<cmis:streamId>STREAM-ID</cmis:streamId>"
+ << "<cmis:mimetype>MIME</cmis:mimetype>"
+ << "<cmis:length>123456</cmis:length>"
+ << "<cmis:kind>KIND</cmis:kind>"
+ << "<cmis:title>TITLE</cmis:title>"
+ << "<cmis:height>123</cmis:height>"
+ << "<cmis:width>456</cmis:width>"
+ << "<cmis:renditionDocumentId>DOC-ID</cmis:renditionDocumentId>"
+ << "</cmis:rendition>";
+ libcmis::RenditionPtr actual( new libcmis::Rendition( getXmlNode( buf.str( ) ) ) );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong stream id parsed", string( "STREAM-ID" ), actual->getStreamId( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong mime type parsed", string( "MIME" ), actual->getMimeType( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong length parsed", long( 123456 ), actual->getLength( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong kind parsed", string( "KIND" ), actual->getKind( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong title parsed", string( "TITLE" ), actual->getTitle( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong height parsed", long( 123 ), actual->getHeight( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong width parsed", long( 456 ), actual->getWidth( ) );
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Wrong rendition doc id parsed", string( "DOC-ID" ), actual->getRenditionDocumentId( ) );
+}
+
+string lcl_findCapability( map< libcmis::Repository::Capability, string > store, libcmis::Repository::Capability capability )
+{
+ string result;
+ map< libcmis::Repository::Capability, string >::iterator it = store.find( capability );
+ if ( it != store.end( ) )
+ result = it->second;
+
+ return result;
+}
+
+void XmlTest::parseRepositoryCapabilitiesTest( )
+{
+ stringstream buf;
+ buf << "<cmis:capabilities " << getXmlns( ) << ">"
+ << "<cmis:capabilityACL>manage</cmis:capabilityACL>"
+ << "<cmis:capabilityAllVersionsSearchable>false</cmis:capabilityAllVersionsSearchable>"
+ << "<cmis:capabilityChanges>none</cmis:capabilityChanges>"
+ << "<cmis:capabilityContentStreamUpdatability>anytime</cmis:capabilityContentStreamUpdatability>"
+ << "<cmis:capabilityGetDescendants>true</cmis:capabilityGetDescendants>"
+ << "<cmis:capabilityGetFolderTree>true</cmis:capabilityGetFolderTree>"
+ << "<cmis:capabilityOrderBy>common</cmis:capabilityOrderBy>"
+ << "<cmis:capabilityMultifiling>true</cmis:capabilityMultifiling>"
+ << "<cmis:capabilityPWCSearchable>false</cmis:capabilityPWCSearchable>"
+ << "<cmis:capabilityPWCUpdatable>true</cmis:capabilityPWCUpdatable>"
+ << "<cmis:capabilityQuery>bothcombined</cmis:capabilityQuery>"
+ << "<cmis:capabilityRenditions>read</cmis:capabilityRenditions>"
+ << "<cmis:capabilityUnfiling>false</cmis:capabilityUnfiling>"
+ << "<cmis:capabilityVersionSpecificFiling>false</cmis:capabilityVersionSpecificFiling>"
+ << "<cmis:capabilityJoin>none</cmis:capabilityJoin>"
+ << "</cmis:capabilities>";
+
+ map< libcmis::Repository::Capability, string > capabilities = libcmis::Repository::parseCapabilities( getXmlNode( buf.str( ) ) );
+
+ CPPUNIT_ASSERT_EQUAL( string( "manage" ), lcl_findCapability( capabilities, libcmis::Repository::ACL ) );
+ CPPUNIT_ASSERT_EQUAL( string( "false" ), lcl_findCapability( capabilities, libcmis::Repository::AllVersionsSearchable ) );
+ CPPUNIT_ASSERT_EQUAL( string( "none" ), lcl_findCapability( capabilities, libcmis::Repository::Changes ) );
+ CPPUNIT_ASSERT_EQUAL( string( "anytime" ), lcl_findCapability( capabilities, libcmis::Repository::ContentStreamUpdatability ) );
+ CPPUNIT_ASSERT_EQUAL( string( "true" ), lcl_findCapability( capabilities, libcmis::Repository::GetDescendants ) );
+ CPPUNIT_ASSERT_EQUAL( string( "true" ), lcl_findCapability( capabilities, libcmis::Repository::GetFolderTree ) );
+ CPPUNIT_ASSERT_EQUAL( string( "common" ), lcl_findCapability( capabilities, libcmis::Repository::OrderBy ) );
+ CPPUNIT_ASSERT_EQUAL( string( "true" ), lcl_findCapability( capabilities, libcmis::Repository::Multifiling ) );
+ CPPUNIT_ASSERT_EQUAL( string( "false" ), lcl_findCapability( capabilities, libcmis::Repository::PWCSearchable ) );
+ CPPUNIT_ASSERT_EQUAL( string( "true" ), lcl_findCapability( capabilities, libcmis::Repository::PWCUpdatable ) );
+ CPPUNIT_ASSERT_EQUAL( string( "bothcombined" ), lcl_findCapability( capabilities, libcmis::Repository::Query ) );
+ CPPUNIT_ASSERT_EQUAL( string( "read" ), lcl_findCapability( capabilities, libcmis::Repository::Renditions ) );
+ CPPUNIT_ASSERT_EQUAL( string( "false" ), lcl_findCapability( capabilities, libcmis::Repository::Unfiling ) );
+ CPPUNIT_ASSERT_EQUAL( string( "false" ), lcl_findCapability( capabilities, libcmis::Repository::VersionSpecificFiling ) );
+ CPPUNIT_ASSERT_EQUAL( string( "none" ), lcl_findCapability( capabilities, libcmis::Repository::Join ) );
+}
+
+void XmlTest::propertyStringAsXmlTest( )
+{
+ vector< string > values;
+ values.push_back( string( "Value 1" ) );
+ values.push_back( string( "Value 2" ) );
+
+ ObjectTypeDummy factory;
+ map< string, libcmis::PropertyTypePtr >::iterator it = factory.getPropertiesTypes( ).find( "STR-ID" );
+ CPPUNIT_ASSERT_MESSAGE( "Missing property type to setup fixture", it != factory.getPropertiesTypes( ).end() );
+ libcmis::PropertyPtr property( new libcmis::Property( it->second, values ) );
+
+ string actual = writeXml( property );
+
+ stringstream expected;
+ expected << "<?xml version=\"1.0\"?>\n"
+ << "<cmis:propertyString propertyDefinitionId=\"STR-ID\" localName=\"LOCAL\" displayName=\"DISPLAY\" queryName=\"QUERY\">"
+ << "<cmis:value>Value 1</cmis:value>"
+ << "<cmis:value>Value 2</cmis:value>"
+ << "</cmis:propertyString>\n";
+
+ CPPUNIT_ASSERT_EQUAL( expected.str( ), actual );
+}
+
+void XmlTest::propertyIntegerAsXmlTest( )
+{
+ vector< string > values;
+ values.push_back( string( "123" ) );
+ values.push_back( string( "456" ) );
+
+ ObjectTypeDummy factory;
+ map< string, libcmis::PropertyTypePtr >::iterator it = factory.getPropertiesTypes( ).find( "INT-ID" );
+ CPPUNIT_ASSERT_MESSAGE( "Missing property type to setup fixture", it != factory.getPropertiesTypes( ).end() );
+ libcmis::PropertyPtr property( new libcmis::Property( it->second, values ) );
+
+ string actual = writeXml( property );
+
+ stringstream expected;
+ expected << "<?xml version=\"1.0\"?>\n"
+ << "<cmis:propertyInteger propertyDefinitionId=\"INT-ID\" localName=\"LOCAL\" displayName=\"DISPLAY\" queryName=\"QUERY\">"
+ << "<cmis:value>123</cmis:value>"
+ << "<cmis:value>456</cmis:value>"
+ << "</cmis:propertyInteger>\n";
+
+ CPPUNIT_ASSERT_EQUAL( expected.str( ), actual );
+}
+
+void XmlTest::sha1Test( )
+{
+ {
+ string actual = libcmis::sha1( "Hello" );
+ CPPUNIT_ASSERT_EQUAL( string( "f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0" ), actual );
+ }
+
+ {
+ // check correct width
+ string actual = libcmis::sha1( "35969137" );
+ CPPUNIT_ASSERT_EQUAL( string( "0d93546909cfeb5c00089202104df3980000ec9f" ), actual );
+ }
+}
+
+void XmlTest::propertyTypeUpdateTest( )
+{
+ libcmis::PropertyType propDef( "datetime", "DATE-ID", "", "", "" );
+
+ libcmis::ObjectTypePtr dummy( new ObjectTypeDummy( ) );
+ vector< libcmis::ObjectTypePtr > typeDefs;
+ typeDefs.push_back( dummy );
+
+ propDef.update( typeDefs );
+
+ CPPUNIT_ASSERT_EQUAL_MESSAGE( "Not updated",
+ string( "LOCAL" ), propDef.getLocalName( ) );
+ CPPUNIT_ASSERT_MESSAGE( "Property Type still marked temporary",
+ !propDef.m_temporary );
+}
+
+void XmlTest::escapeTest( )
+{
+ string actual = libcmis::escape("something to escape$");
+ CPPUNIT_ASSERT_EQUAL( string("something%20to%20escape%24"), actual);
+}
+
+void XmlTest::unescapeTest( )
+{
+ string actual = libcmis::unescape("something%20to%20escape%24");
+ CPPUNIT_ASSERT_EQUAL( string("something to escape$"), actual);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION( XmlTest );
diff --git a/qa/mockup/Makefile.am b/qa/mockup/Makefile.am
new file mode 100644
index 0000000..ef34e12
--- /dev/null
+++ b/qa/mockup/Makefile.am
@@ -0,0 +1,15 @@
+if !OS_WIN32
+noinst_LTLIBRARIES = libcmis-mockup.la
+
+libcmis_mockup_la_SOURCES = \
+ curl-mockup.cxx \
+ internals.hxx \
+ mockup-config.cxx \
+ mockup-config.h \
+ curl/curl.h
+
+libcmis_mockup_la_LIBADD = \
+ $(top_builddir)/src/libcmis/libcmis.la
+
+libcmis_mockup_la_LDFLAGS = -export-dynamic -no-undefined
+endif
diff --git a/qa/mockup/curl-mockup.cxx b/qa/mockup/curl-mockup.cxx
new file mode 100644
index 0000000..0a74a64
--- /dev/null
+++ b/qa/mockup/curl-mockup.cxx
@@ -0,0 +1,504 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sstream>
+
+#include "curl/curl.h"
+#include "internals.hxx"
+
+using namespace std;
+
+namespace mockup
+{
+ extern Configuration* config;
+}
+
+/** Code mostly coming from curl
+ */
+struct curl_slist *curl_slist_append( struct curl_slist * list, const char * data )
+{
+ struct curl_slist* new_item = ( struct curl_slist* ) malloc( sizeof( struct curl_slist ) );
+
+ if( new_item )
+ {
+ char *dupdata = strdup(data);
+ if ( dupdata )
+ {
+ new_item->next = NULL;
+ new_item->data = dupdata;
+ }
+ else
+ {
+ free(new_item);
+ return NULL;
+ }
+ }
+ else
+ return NULL;
+
+ if ( list )
+ {
+ curl_slist* last = list;
+ while ( last->next )
+ last = last->next;
+ last->next = new_item;
+ return list;
+ }
+
+ /* if this is the first item, then new_item *is* the list */
+ return new_item;
+}
+
+void curl_slist_free_all( struct curl_slist * list )
+{
+ if ( list )
+ {
+ struct curl_slist* item = list;
+ struct curl_slist* next = NULL;
+ do
+ {
+ next = item->next;
+ if ( item->data )
+ free( item->data );
+ free(item);
+ item = next;
+ } while ( next );
+ }
+}
+
+void curl_free( void * p )
+{
+ free( p );
+}
+
+CURLcode curl_global_init( long )
+{
+ return CURLE_OK;
+}
+
+CURL *curl_easy_init( void )
+{
+ return new CurlHandle();
+}
+
+void curl_easy_cleanup( CURL * curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle* >( curl );
+ delete( handle );
+}
+
+void curl_easy_reset( CURL * curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle * >( curl );
+ handle->reset( );
+}
+
+char *curl_easy_escape( CURL *, const char *string, int length )
+{
+ return strndup( string, length );
+}
+
+char *curl_unescape( const char *string, int length )
+{
+ return strndup( string, length );
+}
+
+char *curl_easy_unescape( CURL *, const char *string, int length, int * )
+{
+ return curl_unescape( string, length );
+}
+
+CURLcode curl_easy_setopt( CURL * curl, long option, ... )
+{
+ CurlHandle* handle = static_cast< CurlHandle * >( curl );
+
+ va_list arg;
+ va_start( arg, option );
+ switch ( option )
+ {
+ /* TODO Add support for more options */
+ case CURLOPT_POST:
+ {
+ if ( va_arg( arg, long ) )
+ handle->m_method = string( "POST" );
+ break;
+ }
+ case CURLOPT_UPLOAD:
+ {
+ if ( 0 != va_arg( arg, long ) )
+ handle->m_method = string( "PUT" );
+ break;
+ }
+ case CURLOPT_CUSTOMREQUEST:
+ handle->m_method = string( va_arg( arg, char* ) );
+ break;
+ case CURLOPT_URL:
+ {
+ handle->m_url = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_WRITEFUNCTION:
+ {
+ handle->m_writeFn = va_arg( arg, write_callback );
+ break;
+ }
+ case CURLOPT_WRITEDATA:
+ {
+ handle->m_writeData = va_arg( arg, void* );
+ break;
+ }
+ case CURLOPT_READFUNCTION:
+ {
+ handle->m_readFn = va_arg( arg, read_callback );
+ break;
+ }
+ case CURLOPT_READDATA:
+ {
+ handle->m_readData = va_arg( arg, void* );
+ break;
+ }
+ case CURLOPT_INFILESIZE:
+ {
+ handle->m_readSize = va_arg( arg, long );
+ break;
+ }
+ case CURLOPT_HEADERFUNCTION:
+ {
+ handle->m_headersFn = va_arg( arg, headers_callback );
+ break;
+ }
+ case CURLOPT_WRITEHEADER:
+ {
+ handle->m_headersData = va_arg( arg, void* );
+ break;
+ }
+ case CURLOPT_USERNAME:
+ {
+ handle->m_username = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_PASSWORD:
+ {
+ handle->m_password = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_USERPWD:
+ {
+ string userpwd( va_arg( arg, char* ) );
+ size_t pos = userpwd.find( ':' );
+ if ( pos != string::npos )
+ {
+ handle->m_username = userpwd.substr( 0, pos );
+ handle->m_password = userpwd.substr( pos + 1 );
+ }
+ break;
+ }
+ case CURLOPT_PROXY:
+ {
+ // FIXME curl does some more complex things with port and type
+ handle->m_proxy = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_NOPROXY:
+ {
+ handle->m_noProxy = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_PROXYUSERNAME:
+ {
+ handle->m_proxyUser = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_PROXYPASSWORD:
+ {
+ handle->m_proxyPass = string( va_arg( arg, char* ) );
+ break;
+ }
+ case CURLOPT_PROXYUSERPWD:
+ {
+ string userpwd( va_arg( arg, char* ) );
+ size_t pos = userpwd.find( ':' );
+ if ( pos != string::npos )
+ {
+ handle->m_proxyUser = userpwd.substr( 0, pos );
+ handle->m_proxyPass = userpwd.substr( pos + 1 );
+ }
+ break;
+ }
+ case CURLOPT_SSL_VERIFYHOST:
+ {
+ handle->m_verifyHost = va_arg( arg, long ) != 0;
+ break;
+ }
+ case CURLOPT_SSL_VERIFYPEER:
+ {
+ handle->m_verifyPeer = va_arg( arg, long ) != 0;
+ break;
+ }
+ case CURLOPT_CERTINFO:
+ {
+ handle->m_certInfo = va_arg( arg, long );
+ break;
+ }
+ case CURLOPT_HTTPHEADER:
+ {
+ handle->m_headers.clear();
+ struct curl_slist* headers = va_arg( arg, struct curl_slist* );
+ while ( headers != NULL )
+ {
+ handle->m_headers.push_back( string( headers->data ) );
+ headers = headers->next;
+ }
+ break;
+ }
+ default:
+ {
+ // We surely don't want to break the test for that.
+ }
+ }
+ va_end( arg );
+
+ return CURLE_OK;
+}
+
+CURLcode curl_easy_perform( CURL * curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle * >( curl );
+
+ /* Fake a bad SSL Certificate? */
+ if ( !mockup::config->m_badSSLCertificate.empty( ) && handle->m_verifyPeer && handle->m_verifyHost )
+ {
+ return CURLE_SSL_CACERT;
+ }
+
+ /* Populate the certificate infos */
+ if ( handle->m_certInfo && !mockup::config->m_badSSLCertificate.empty( ) )
+ {
+ curl_slist * certData = NULL;
+ string cert( "Cert:" + mockup::config->m_badSSLCertificate );
+ char* c_cert = strdup( cert.c_str( ) );
+ certData = curl_slist_append( certData, c_cert );
+ free( c_cert );
+
+ handle->m_certs.num_of_certs = 1;
+ handle->m_certs.certinfo = ( struct curl_slist** )calloc( ( size_t )1, sizeof( struct curl_slist * ) );
+ handle->m_certs.certinfo[0] = certData;
+ }
+
+ /* Check the credentials */
+ if ( mockup::config->hasCredentials( ) &&
+ ( handle->m_username != mockup::config->m_username ||
+ handle->m_password != mockup::config->m_password ) )
+ {
+ // Send HTTP 401
+ handle->m_httpError = 401;
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+
+ // Store the requests for later verifications
+ stringstream body;
+ if ( handle->m_readFn && handle->m_readData )
+ {
+ size_t bufSize = 2048;
+ char* buf = new char[bufSize];
+
+ size_t read = 0;
+ do
+ {
+ read = handle->m_readFn( buf, 1, bufSize, handle->m_readData );
+ body.write( buf, read );
+ } while ( read == bufSize );
+
+ delete[] buf;
+ }
+
+ mockup::config->m_requests.push_back( mockup::Request( handle->m_url, handle->m_method, body.str( ), handle->m_headers ) );
+
+
+ return mockup::config->writeResponse( handle );
+}
+
+CURLcode curl_easy_getinfo( CURL * curl, long info, ... )
+{
+ CurlHandle* handle = static_cast< CurlHandle * >( curl );
+
+ va_list arg;
+ va_start( arg, info );
+ switch ( info )
+ {
+ case CURLINFO_RESPONSE_CODE:
+ {
+ long* buf = va_arg( arg, long* );
+ *buf = handle->m_httpError;
+ break;
+ }
+ case CURLINFO_CERTINFO:
+ {
+ struct curl_slist** param = va_arg( arg, struct curl_slist** );
+ if ( NULL != param )
+ {
+ union
+ {
+ struct curl_certinfo * to_certinfo;
+ struct curl_slist * to_slist;
+ } ptr;
+
+ // Fill it
+ ptr.to_certinfo = &handle->m_certs;
+ *param = ptr.to_slist;
+ }
+ break;
+ }
+ default:
+ {
+ // We surely don't want to break the test for that.
+ }
+ }
+ va_end( arg );
+
+ return CURLE_OK;
+}
+
+CurlHandle::CurlHandle( ) :
+ m_url( ),
+ m_writeFn( NULL ),
+ m_writeData( NULL ),
+ m_readFn( NULL ),
+ m_readData( NULL ),
+ m_readSize( 0 ),
+ m_headersFn( NULL ),
+ m_headersData( NULL ),
+ m_username( ),
+ m_password( ),
+ m_proxy( ),
+ m_noProxy( ),
+ m_proxyUser( ),
+ m_proxyPass( ),
+ m_verifyHost( true ),
+ m_verifyPeer( true ),
+ m_certInfo( false ),
+ m_certs( ),
+ m_httpError( 0 ),
+ m_method( "GET" ),
+ m_headers( )
+{
+}
+
+CurlHandle::CurlHandle( const CurlHandle& copy ) :
+ m_url( copy.m_url ),
+ m_writeFn( copy.m_writeFn ),
+ m_writeData( copy.m_writeData ),
+ m_readFn( copy.m_readFn ),
+ m_readData( copy.m_readData ),
+ m_readSize( copy.m_readSize ),
+ m_headersFn( copy.m_headersFn ),
+ m_headersData( copy.m_headersData ),
+ m_username( copy.m_username ),
+ m_password( copy.m_password ),
+ m_proxy( copy.m_proxy ),
+ m_noProxy( copy.m_noProxy ),
+ m_proxyUser( copy.m_proxyUser ),
+ m_proxyPass( copy.m_proxyPass ),
+ m_verifyHost( copy.m_verifyHost ),
+ m_verifyPeer( copy.m_verifyPeer ),
+ m_certInfo( copy.m_certInfo ),
+ m_certs( copy.m_certs ),
+ m_httpError( copy.m_httpError ),
+ m_method( copy.m_method ),
+ m_headers( copy.m_headers )
+{
+}
+
+CurlHandle& CurlHandle::operator=( const CurlHandle& copy )
+{
+ if ( this != &copy )
+ {
+ m_url = copy.m_url;
+ m_writeFn = copy.m_writeFn;
+ m_writeData = copy.m_writeData;
+ m_readFn = copy.m_readFn;
+ m_readData = copy.m_readData;
+ m_readSize = copy.m_readSize;
+ m_headersFn = copy.m_headersFn;
+ m_headersData = copy.m_headersData;
+ m_username = copy.m_username;
+ m_password = copy.m_password;
+ m_proxy = copy.m_proxy;
+ m_noProxy = copy.m_noProxy;
+ m_proxyUser = copy.m_proxyUser;
+ m_proxyPass = copy.m_proxyPass;
+ m_verifyHost = copy.m_verifyHost;
+ m_verifyPeer = copy.m_verifyPeer;
+ m_certInfo = copy.m_certInfo;
+ m_certs = copy.m_certs;
+ m_httpError = copy.m_httpError;
+ m_method = copy.m_method;
+ m_headers = copy.m_headers;
+ }
+ return *this;
+}
+
+CurlHandle::~CurlHandle( )
+{
+ reset();
+}
+
+void CurlHandle::reset( )
+{
+ m_url = string( );
+ m_writeFn = NULL;
+ m_writeData = NULL;
+ m_readFn = NULL;
+ m_readData = NULL;
+ m_readSize = 0;
+ m_username = string( );
+ m_password = string( );
+ m_proxy = string( );
+ m_noProxy = string( );
+ m_proxyUser = string( );
+ m_proxyPass = string( );
+ m_verifyHost = true;
+ m_verifyPeer = true;
+ m_certInfo = false;
+
+ for ( int i = 0; i < m_certs.num_of_certs; ++i )
+ {
+ curl_slist_free_all( m_certs.certinfo[i] );
+ m_certs.certinfo[i] = NULL;
+ }
+ free( m_certs.certinfo );
+ m_certs.certinfo = NULL;
+ m_certs.num_of_certs = 0;
+
+ m_method = "GET";
+ m_headers.clear( );
+}
diff --git a/qa/mockup/curl/curl.h b/qa/mockup/curl/curl.h
new file mode 100644
index 0000000..50f1cfe
--- /dev/null
+++ b/qa/mockup/curl/curl.h
@@ -0,0 +1,153 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _MOCKUP_CURL_CURL_H_
+#define _MOCKUP_CURL_CURL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Curl used symbols to mockup */
+
+typedef void CURL;
+
+typedef enum
+{
+ CURLIOE_OK, /* I/O operation successful */
+ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
+ CURLIOE_FAILRESTART, /* failed to restart the read */
+ CURLIOE_LAST /* never use */
+} curlioerr;
+
+#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_WIN32 (1<<1)
+#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
+
+#define CURLOPTTYPE_LONG 0
+#define CURLOPTTYPE_OBJECTPOINT 10000
+#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T 30000
+
+typedef enum
+{
+ CURLOPT_WRITEFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 11,
+ CURLOPT_READFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 12,
+ CURLOPT_WRITEDATA = CURLOPTTYPE_OBJECTPOINT + 1,
+ CURLOPT_HEADERFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 79,
+ CURLOPT_WRITEHEADER = CURLOPTTYPE_OBJECTPOINT + 29,
+ CURLOPT_FOLLOWLOCATION = CURLOPTTYPE_LONG + 52,
+ CURLOPT_MAXREDIRS = CURLOPTTYPE_LONG + 68,
+ CURLOPT_INFILESIZE = CURLOPTTYPE_LONG + 14,
+ CURLOPT_READDATA = CURLOPTTYPE_OBJECTPOINT + 9,
+ CURLOPT_UPLOAD = CURLOPTTYPE_LONG + 46,
+ CURLOPT_IOCTLFUNCTION = CURLOPTTYPE_FUNCTIONPOINT + 130,
+ CURLOPT_IOCTLDATA = CURLOPTTYPE_OBJECTPOINT + 131,
+ CURLOPT_HTTPHEADER = CURLOPTTYPE_OBJECTPOINT + 23,
+ CURLOPT_POSTFIELDSIZE = CURLOPTTYPE_LONG + 60,
+ CURLOPT_POST = CURLOPTTYPE_LONG + 47,
+ CURLOPT_CUSTOMREQUEST = CURLOPTTYPE_OBJECTPOINT + 36,
+ CURLOPT_URL = CURLOPTTYPE_OBJECTPOINT + 2,
+ CURLOPT_HTTPAUTH = CURLOPTTYPE_LONG + 107,
+ CURLOPT_USERNAME = CURLOPTTYPE_OBJECTPOINT + 173,
+ CURLOPT_PASSWORD = CURLOPTTYPE_OBJECTPOINT + 174,
+ CURLOPT_USERPWD = CURLOPTTYPE_OBJECTPOINT + 5,
+ CURLOPT_ERRORBUFFER = CURLOPTTYPE_OBJECTPOINT + 10,
+ CURLOPT_FAILONERROR = CURLOPTTYPE_LONG + 45,
+ CURLOPT_VERBOSE = CURLOPTTYPE_LONG + 41,
+ CURLOPT_PROXY = CURLOPTTYPE_OBJECTPOINT + 4,
+ CURLOPT_PROXYUSERPWD = CURLOPTTYPE_OBJECTPOINT + 6,
+ CURLOPT_PROXYAUTH = CURLOPTTYPE_LONG + 111,
+ CURLOPT_PROXYUSERNAME = CURLOPTTYPE_OBJECTPOINT + 175,
+ CURLOPT_PROXYPASSWORD = CURLOPTTYPE_OBJECTPOINT + 176,
+ CURLOPT_NOPROXY = CURLOPTTYPE_OBJECTPOINT + 177,
+ CURLOPT_SSL_VERIFYPEER = CURLOPTTYPE_LONG + 64,
+ CURLOPT_SSL_VERIFYHOST = CURLOPTTYPE_LONG + 81,
+ CURLOPT_CERTINFO = CURLOPTTYPE_LONG + 172
+} CURLoption;
+
+#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
+#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE)
+
+typedef enum
+{
+ CURLE_OK = 0,
+ CURLE_HTTP_RETURNED_ERROR = 22,
+ CURLE_SSL_CACERT = 60,
+ /* TODO Add some more error codes from curl? */
+ CURL_LAST
+} CURLcode;
+
+struct curl_slist
+{
+ char *data;
+ struct curl_slist *next;
+};
+
+struct curl_slist *curl_slist_append( struct curl_slist *, const char * );
+void curl_slist_free_all( struct curl_slist * );
+
+void curl_free( void *p );
+CURLcode curl_global_init( long flags );
+
+CURL *curl_easy_init( void );
+void curl_easy_cleanup( CURL *curl );
+CURLcode curl_easy_setopt( CURL *curl, long option, ... );
+char *curl_easy_escape( CURL *handle, const char *string, int length );
+char *curl_unescape( const char *string, int length );
+char *curl_easy_unescape( CURL *handle, const char *string, int length, int *outlength );
+CURLcode curl_easy_perform( CURL *curl );
+void curl_easy_reset( CURL *curl );
+
+struct curl_certinfo
+{
+ int num_of_certs;
+ struct curl_slist **certinfo;
+};
+
+#define CURLINFO_LONG 0x200000
+#define CURLINFO_SLIST 0x400000
+
+typedef enum
+{
+ CURLINFO_NONE,
+ CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2,
+ CURLINFO_CERTINFO = CURLINFO_SLIST + 34,
+ CURLINFO_LASTONE = 42
+} CURLINFO;
+
+CURLcode curl_easy_getinfo( CURL *curl, long info, ... );
+
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 26
+#define LIBCURL_VERSION_PATCH 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/qa/mockup/internals.hxx b/qa/mockup/internals.hxx
new file mode 100644
index 0000000..43c001e
--- /dev/null
+++ b/qa/mockup/internals.hxx
@@ -0,0 +1,133 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef INCLUDED_QA_MOCKUP_INTERNALS_HXX
+#define INCLUDED_QA_MOCKUP_INTERNALS_HXX
+
+#include <map>
+#include <string>
+#include <vector>
+
+typedef size_t ( *write_callback )( char *ptr, size_t size, size_t nmemb, void *userdata );
+typedef size_t ( *read_callback )( char *ptr, size_t size, size_t nmemb, void *userdata );
+typedef size_t ( *headers_callback )( char *ptr, size_t size, size_t nmemb, void *userdata );
+
+class CurlHandle
+{
+ public:
+ CurlHandle( );
+ CurlHandle( const CurlHandle& copy );
+ CurlHandle& operator=( const CurlHandle& copy );
+ ~CurlHandle( );
+
+ std::string m_url;
+
+ write_callback m_writeFn;
+ void* m_writeData;
+ read_callback m_readFn;
+ void* m_readData;
+ long m_readSize;
+ headers_callback m_headersFn;
+ void* m_headersData;
+
+ std::string m_username;
+ std::string m_password;
+ std::string m_proxy;
+ std::string m_noProxy;
+ std::string m_proxyUser;
+ std::string m_proxyPass;
+
+ bool m_verifyHost;
+ bool m_verifyPeer;
+ bool m_certInfo;
+
+ struct curl_certinfo m_certs;
+
+ long m_httpError;
+ std::string m_method;
+ std::vector< std::string > m_headers;
+
+ void reset( );
+};
+
+namespace mockup
+{
+ class Response
+ {
+ public:
+ Response( std::string response, unsigned int status, bool isFilePath,
+ std::string headers );
+
+ std::string m_response;
+ unsigned int m_status;
+ bool m_isFilePath;
+ std::string m_headers;
+ };
+
+ class Request
+ {
+ public:
+ Request( std::string url, std::string method, std::string body,
+ std::vector< std::string > headers );
+
+ std::string m_url;
+ std::string m_method;
+ std::string m_body;
+ std::vector< std::string > m_headers;
+ };
+
+ class RequestMatcher
+ {
+ public:
+ RequestMatcher( std::string baseUrl, std::string matchParam,
+ std::string method, std::string matchBody );
+ bool operator< ( const RequestMatcher& compare ) const;
+
+ std::string m_baseUrl;
+ std::string m_matchParam;
+ std::string m_method;
+ std::string m_matchBody;
+ };
+
+ class Configuration
+ {
+ public:
+ Configuration( );
+
+ bool hasCredentials( );
+ CURLcode writeResponse( CurlHandle* handle );
+
+ std::map< RequestMatcher, Response > m_responses;
+ std::vector< Request > m_requests;
+ std::string m_username;
+ std::string m_password;
+ std::string m_badSSLCertificate;
+ };
+}
+
+#endif
diff --git a/qa/mockup/mockup-config.cxx b/qa/mockup/mockup-config.cxx
new file mode 100644
index 0000000..7678518
--- /dev/null
+++ b/qa/mockup/mockup-config.cxx
@@ -0,0 +1,409 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "mockup-config.h"
+
+#include <memory>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+
+#include <boost/algorithm/string.hpp>
+
+#include "internals.hxx"
+
+using namespace std;
+
+namespace
+{
+ void lcl_splitUrl( const string& url, string& urlBase, string& params )
+ {
+ size_t pos = url.find( "?" );
+ urlBase = url;
+ if ( pos != string::npos )
+ {
+ urlBase = url.substr( 0, pos );
+ params = url.substr( pos + 1 );
+ }
+ }
+
+ const char** lcl_toStringArray( const vector< string >& vect )
+ {
+ const char** array = new const char*[vect.size() + 1];
+ for ( size_t i = 0; i < vect.size( ); i++ )
+ array[i] = vect[i].c_str();
+ array[vect.size()] = NULL;
+ return array;
+ }
+}
+
+namespace mockup
+{
+ Response::Response( string response, unsigned int status, bool isFilePath, string headers ) :
+ m_response( response ),
+ m_status( status ),
+ m_isFilePath( isFilePath ),
+ m_headers( headers )
+ {
+ }
+
+ Request::Request( string url, string method, string body, vector< string > headers ) :
+ m_url( url ),
+ m_method( method ),
+ m_body( body ),
+ m_headers( headers )
+ {
+ }
+
+ RequestMatcher::RequestMatcher( string baseUrl, string matchParam, string method, string matchBody ) :
+ m_baseUrl( baseUrl ),
+ m_matchParam( matchParam ),
+ m_method( method ),
+ m_matchBody( matchBody )
+ {
+ }
+
+ bool RequestMatcher::operator< ( const RequestMatcher& compare ) const
+ {
+ int cmpBaseUrl = m_baseUrl.compare( compare.m_baseUrl ) ;
+ if ( cmpBaseUrl != 0 )
+ return cmpBaseUrl < 0;
+
+ int cmpMatchParam = m_matchParam.compare( compare.m_matchParam );
+ if ( cmpMatchParam != 0 )
+ return cmpMatchParam < 0;
+
+ int cmpMatchMethod = m_method.compare( compare.m_method );
+ if ( cmpMatchMethod != 0 )
+ return cmpMatchMethod < 0;
+
+ int cmpMatchBody = m_matchBody.compare( compare.m_matchBody );
+ return cmpMatchBody < 0;
+ }
+
+ Configuration::Configuration( ) :
+ m_responses( ),
+ m_requests( ),
+ m_username( ),
+ m_password( ),
+ m_badSSLCertificate( )
+ {
+ }
+
+ bool Configuration::hasCredentials( )
+ {
+ return !m_username.empty( ) && !m_password.empty( );
+ }
+
+ /** Find a suitable response
+ * using the request as a search key
+ */
+ CURLcode Configuration::writeResponse( CurlHandle* handle )
+ {
+ CURLcode code = CURLE_OK;
+
+ string headers;
+ string response;
+ bool foundResponse = false;
+ bool isFilePath = true;
+ const string& url = handle->m_url;
+
+ string urlBase = url;
+ string params;
+ lcl_splitUrl( url, urlBase, params );
+ string method = handle->m_method;
+ string body = m_requests.back().m_body;
+
+ for ( map< RequestMatcher, Response >::iterator it = m_responses.begin( );
+ it != m_responses.end( ) && response.empty( ); ++it )
+ {
+ RequestMatcher matcher = it->first;
+ string& paramFind = matcher.m_matchParam;
+ bool matchBaseUrl = matcher.m_baseUrl.empty() || ( urlBase == matcher.m_baseUrl );
+ bool matchParams = paramFind.empty( ) || ( params.find( paramFind ) != string::npos );
+ bool matchMethod = it->first.m_method.empty( ) || ( it->first.m_method == method );
+ bool matchBody = matcher.m_matchBody.empty( ) || ( body.find( matcher.m_matchBody ) != string::npos );
+
+ if ( matchBaseUrl && matchParams && matchMethod && matchBody )
+ {
+ foundResponse = true;
+ response = it->second.m_response;
+ handle->m_httpError = it->second.m_status;
+ isFilePath = it->second.m_isFilePath;
+ headers = it->second.m_headers;
+ }
+ }
+
+ // Output headers is any
+ if ( !headers.empty() )
+ {
+ char* buf = strdup( headers.c_str() );
+ handle->m_headersFn( buf, 1, headers.size( ), handle->m_headersData );
+ free( buf );
+ }
+
+ // If nothing matched, then send a 404 HTTP error instead
+ if ( !foundResponse || ( foundResponse && isFilePath && response.empty() ) )
+ handle->m_httpError = 404;
+ else
+ {
+ if ( isFilePath )
+ {
+ FILE* fd = fopen( response.c_str( ), "r" );
+ if ( !fd ) {
+ cerr << "Missing test file: " << response << endl;
+ handle->m_httpError = 500;
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+
+
+ size_t bufSize = 2048;
+ char* buf = new char[bufSize];
+
+ size_t read = 0;
+ size_t written = 0;
+ do
+ {
+ read = fread( buf, 1, bufSize, fd );
+ written = handle->m_writeFn( buf, 1, read, handle->m_writeData );
+ } while ( read == bufSize && written == read );
+
+ fclose( fd );
+ delete[] buf;
+ }
+ else
+ {
+ if ( !response.empty() )
+ {
+ char* buf = strdup( response.c_str() );
+ handle->m_writeFn( buf, 1, response.size( ), handle->m_writeData );
+ free( buf );
+ }
+ }
+ }
+
+ // What curl error code to give?
+ if ( handle->m_httpError == 0 )
+ handle->m_httpError = 200;
+
+ if ( handle->m_httpError < 200 || handle->m_httpError >= 300 )
+ code = CURLE_HTTP_RETURNED_ERROR;
+
+ return code;
+ }
+
+ unique_ptr<Configuration> config{ new Configuration( ) };
+}
+
+void curl_mockup_reset( )
+{
+ mockup::config.reset( new mockup::Configuration( ) );
+}
+
+void curl_mockup_addResponse( const char* urlBase, const char* matchParam, const char* method,
+ const char* response, unsigned int status, bool isFilePath,
+ const char* headers, const char* matchBody )
+{
+ string matchBodyStr;
+ if ( matchBody )
+ matchBodyStr = matchBody;
+ mockup::RequestMatcher matcher( urlBase, matchParam, method, matchBodyStr );
+ map< mockup::RequestMatcher, mockup::Response >::iterator it = mockup::config->m_responses.find( matcher );
+ if ( it != mockup::config->m_responses.end( ) )
+ mockup::config->m_responses.erase( it );
+
+ string headersStr;
+ if ( headers != NULL )
+ headersStr = headers;
+ mockup::Response responseDesc( response, status, isFilePath, headersStr );
+ mockup::config->m_responses.insert( pair< mockup::RequestMatcher, mockup::Response >( matcher, responseDesc ) );
+}
+
+void curl_mockup_setResponse( const char* filepath )
+{
+ mockup::config->m_responses.clear( );
+ curl_mockup_addResponse( "", "", "", filepath );
+}
+
+void curl_mockup_setCredentials( const char* username, const char* password )
+{
+ mockup::config->m_username = string( username );
+ mockup::config->m_password = string( password );
+}
+
+const struct HttpRequest* curl_mockup_getRequest( const char* urlBase,
+ const char* matchParam,
+ const char* method,
+ const char* matchBody )
+{
+ struct HttpRequest* request = NULL;
+
+ string urlBaseString( urlBase );
+ string matchParamString( matchParam );
+
+ string matchBodyStr;
+ if ( matchBody )
+ matchBodyStr = matchBody;
+
+ for ( vector< mockup::Request >::iterator it = mockup::config->m_requests.begin( );
+ it != mockup::config->m_requests.end( ) && request == NULL; ++it )
+ {
+ string url;
+ string params;
+ if ( it->m_method == string( method ) )
+ {
+ lcl_splitUrl( it->m_url, url, params );
+
+ bool matchBaseUrl = urlBaseString.empty() || boost::starts_with( url, urlBaseString );
+ bool matchParams = matchParamString.empty( ) || ( params.find( matchParamString ) != string::npos );
+ bool matchBodyPart = !matchBody || ( it->m_body.find( matchBodyStr ) != string::npos );
+
+ if ( matchBaseUrl && matchParams && matchBodyPart )
+ {
+ request = new HttpRequest;
+ request->url = it->m_url.c_str();
+ request->body = it->m_body.c_str();
+ request->headers = lcl_toStringArray( it->m_headers );
+ }
+ }
+ }
+
+ return request;
+}
+
+const char* curl_mockup_getRequestBody( const char* urlBase,
+ const char* matchParam,
+ const char* method,
+ const char* matchBody )
+{
+ const struct HttpRequest* request = curl_mockup_getRequest( urlBase, matchParam, method, matchBody );
+ if ( request )
+ {
+ const char* body = request->body;
+ curl_mockup_HttpRequest_free( request );
+ return body;
+ }
+ return NULL;
+}
+
+int curl_mockup_getRequestsCount( const char* urlBase,
+ const char* matchParam,
+ const char* method,
+ const char* matchBody )
+{
+ int count = 0;
+
+ string urlBaseString( urlBase );
+ string matchParamString( matchParam );
+ string matchBodyStr( matchBody );
+
+ for ( vector< mockup::Request >::iterator it = mockup::config->m_requests.begin( );
+ it != mockup::config->m_requests.end( ); ++it )
+ {
+ string url;
+ string params;
+ if ( it->m_method == string( method ) )
+ {
+ lcl_splitUrl( it->m_url, url, params );
+
+ bool matchBaseUrl = urlBaseString.empty() || boost::starts_with( url, urlBaseString );
+ bool matchParams = matchParamString.empty( ) ||
+ ( params.find( matchParamString ) != string::npos );
+ bool matchBodyPart = matchBodyStr.empty() ||
+ ( it->m_body.find( matchBodyStr ) != string::npos );
+
+ if ( matchBaseUrl && matchParams && matchBodyPart )
+ {
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+void curl_mockup_HttpRequest_free( const struct HttpRequest* request )
+{
+ delete[] request->headers;
+ delete request;
+}
+
+char* curl_mockup_HttpRequest_getHeader( const struct HttpRequest* request, const char* name )
+{
+ char* value = NULL;
+ size_t i = 0;
+ while ( request->headers[i] != NULL && value == NULL )
+ {
+ string header = request->headers[i];
+ const string prefix = string( name ) + ":";
+ size_t pos = header.find( prefix );
+ if ( pos == 0 )
+ {
+ value = strdup( header.substr( prefix.size() ).c_str() );
+ }
+ ++i;
+ }
+ return value;
+}
+
+const char* curl_mockup_getProxy( CURL* curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle* >( curl );
+ if ( NULL != handle )
+ return handle->m_proxy.c_str();
+ return NULL;
+}
+
+const char* curl_mockup_getNoProxy( CURL* curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle* >( curl );
+ if ( NULL != handle )
+ return handle->m_noProxy.c_str();
+ return NULL;
+}
+
+const char* curl_mockup_getProxyUser( CURL* curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle* >( curl );
+ if ( NULL != handle )
+ return handle->m_proxyUser.c_str();
+ return NULL;
+}
+
+const char* curl_mockup_getProxyPass( CURL* curl )
+{
+ CurlHandle* handle = static_cast< CurlHandle* >( curl );
+ if ( NULL != handle )
+ return handle->m_proxyPass.c_str();
+ return NULL;
+}
+
+void curl_mockup_setSSLBadCertificate( const char* certificate )
+{
+ mockup::config->m_badSSLCertificate = string( certificate );
+}
diff --git a/qa/mockup/mockup-config.h b/qa/mockup/mockup-config.h
new file mode 100644
index 0000000..d0fc3bb
--- /dev/null
+++ b/qa/mockup/mockup-config.h
@@ -0,0 +1,113 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <curl/curl.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Mockup behavior configuration functions */
+void curl_mockup_reset( );
+
+/** Add a new HTTP response the server should send.
+
+ \param baseURL
+ the base URL of the request without parameters
+ \param matchParam
+ a string to find in the parameters part of the URL to match
+ \param method
+ HTTP method to match like PUT, GET, POST or DELETE. An empty
+ string matches any method.
+ \param response
+ a string corresponding either to the file path of the request
+ body to send or directly the content to send. This value has
+ a different meaning depending on isFilePath parameter.
+ \param status
+ the HTTP status to return. 0 means HTTP OK (200).
+ \param isFilePath
+ if this value is true the response value is used as a file path,
+ otherwise, the response value is used as the body of the HTTP
+ response to send.
+ \param headers
+ the HTTP headers block to send with the response. By default
+ no header is sent.
+ \param matchBody
+ a string to find in the request body to match
+ */
+void curl_mockup_addResponse( const char* baseUrl, const char* matchParam, const char* method,
+ const char* response, unsigned int status = 0, bool isFilePath = true,
+ const char* headers = 0, const char* matchBody = 0 );
+
+/** Set the HTTP response the server is supposed to send.
+ This will reset all already defined responses.
+ */
+void curl_mockup_setResponse( const char* filepath );
+void curl_mockup_setCredentials( const char* username, const char* password );
+
+struct HttpRequest
+{
+ const char* url;
+ const char* body;
+ ///< NULL terminated array of headers.
+ const char** headers;
+};
+
+const struct HttpRequest* curl_mockup_getRequest( const char* baseUrl,
+ const char* matchParam,
+ const char* method,
+ const char* matchBody = 0 );
+const char* curl_mockup_getRequestBody( const char* baseUrl,
+ const char* matchParam,
+ const char* method,
+ const char* matchBody = 0 );
+int curl_mockup_getRequestsCount( const char* urlBase,
+ const char* matchParam,
+ const char* method,
+ const char* matchBody = "" );
+
+void curl_mockup_HttpRequest_free( const struct HttpRequest* request );
+
+/** The resulting value is either NULL (no such header found) or the value
+ of the header. In such a case, the result needs to be freed by the caller.
+ */
+char* curl_mockup_HttpRequest_getHeader( const struct HttpRequest* request, const char* name );
+
+const char* curl_mockup_getProxy( CURL* handle );
+const char* curl_mockup_getNoProxy( CURL* handle );
+const char* curl_mockup_getProxyUser( CURL* handle );
+const char* curl_mockup_getProxyPass( CURL* handle );
+
+/** Set a fake invalid certificate to raise CURLE_SSL_CACERT. Setting it
+ to an empty string will reset to no certificate.
+ */
+void curl_mockup_setSSLBadCertificate( const char* certificate );
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/samples/populate.sh b/samples/populate.sh
new file mode 100644
index 0000000..8a47359
--- /dev/null
+++ b/samples/populate.sh
@@ -0,0 +1,168 @@
+#!/bin/sh
+# libcmis
+# Version: MPL 1.1 / GPLv2+ / LGPLv2+
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License or as specified alternatively below. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# Major Contributor(s):
+# Copyright (C) 2012 SUSE <cbosdonnat@suse.com>
+#
+#
+# All Rights Reserved.
+#
+# For minor contributions see the git repository.
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+# the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+# in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+# instead of those above.
+
+function usage ( )
+{
+ echo "$0 --url http://binding/url [-u|--username user -p|--password pass] [-r|--repository repo] path/to/local/folder /path/to/remote/folder"
+}
+
+
+# Utility function to call cmis-client
+function cmis_client ( )
+{
+ repo_opt=
+ if test "z$REPO" != "z"; then
+ repo_opt=" -r \"$REPO\""
+ fi
+ $CMIS_CLIENT --url "$BINDING_URL" -u "$USER" -p "$PASS"$repo_opt "$@"
+}
+
+
+BASE_FOLDER=
+SERVER_FOLDER=
+BINDING_URL=
+USER=
+PASS=
+REPO=
+
+# Parse the arguments into variables
+while test -n "$1"; do
+ case $1 in
+ --url)
+ shift
+ BINDING_URL="$1"
+ shift
+ ;;
+ --username|-u)
+ shift
+ USER="$1"
+ shift
+ ;;
+ --password|-p)
+ shift
+ PASS="$1"
+ shift
+ ;;
+ --repository|-r)
+ shift
+ REPO="$1"
+ shift
+ ;;
+ --help|-h)
+ usage
+ exit 1
+ ;;
+ *)
+ if test -z "$BASE_FOLDER"; then
+ BASE_FOLDER="$1"
+ shift
+ elif test -z "$SERVER_FOLDER"; then
+ SERVER_FOLDER="$1"
+ shift
+ fi
+ ;;
+ esac
+done
+
+# Check that we had the input we need
+if test ! -d "$BASE_FOLDER"; then
+ usage
+ echo ""
+ echo "Missing or invalid local folder path"
+ exit 1
+fi
+
+if test -z "$BINDING_URL"; then
+ usage
+ echo ""
+ echo "Missing CMIS binding URL"
+ exit 1
+fi
+
+# Look for cmis-client in PATH
+CMIS_CLIENT=`which cmis-client 2>/dev/null`
+if test -z $CMIS_CLIENT; then
+ echo "cmis-client executable isn't in the PATH"
+ exit 1
+fi
+
+# Make sure the SERVER_FOLDER is existing
+SERVER_FOLDER_ID=`cmis_client show-by-path "$SERVER_FOLDER" 2>&1 | grep '^Id:' | sed -e 's/^[^:]*: \(.*\)$/\1/'`
+if test -z $SERVER_FOLDER_ID; then
+ echo "Server folder '$SERVER_FOLDER' doesn't exist, please indicate an existing folder"
+ exit 1
+fi
+
+SERVER_FOLDER_BASE_TYPE=`cmis_client show-by-path "$SERVER_FOLDER" 2>&1 | grep '^Base type:' | sed -e 's/^[^:]*: \(.*\)$/\1/'`
+if test "$SERVER_FOLDER_BASE_TYPE" != "cmis:folder"; then
+ echo "'$SERVER_FOLDER' isn't a folder, please indicate an existing folder"
+ exit 1
+fi
+
+# Make sure that SERVER_FOLDER has no trailing slash
+SERVER_FOLDER=${SERVER_FOLDER%/}
+
+cd $BASE_FOLDER/..
+BASE_FOLDER_NAME=`basename "$BASE_FOLDER"`
+find $BASE_FOLDER_NAME -print0 | while read -d $'\0' FILE_PATH
+do
+ FILE_NAME=`basename "$FILE_PATH"`
+ DIRNAME=`dirname "$FILE_PATH"`
+ DIRNAME=${DIRNAME#.}
+ SERVER_PARENT=$SERVER_FOLDER/$DIRNAME
+ if test -z "$DIRNAME"; then
+ SERVER_PARENT=$SERVER_FOLDER
+ fi
+
+ PARENT_ID=`cmis_client show-by-path "$SERVER_PARENT" 2>&1 | grep '^Id:' | sed -e 's/^[^:]*: \(.*\)$/\1/'`
+
+ # We couldn't find the parent id, then we need to create the folder on the server
+ if test -z "$PARENT_ID"; then
+ PARENT_NAME=`basename "$SERVER_PARENT"`
+ PARENT_PARENT_PATH=`dirname "$SERVER_PARENT"`
+ PARENT_PARENT_ID=`cmis_client show-by-path "$PARENT_PARENT_PATH" 2>&1 | grep '^Id:' | sed -e 's/^[^:]*: \(.*\)$/\1/'`
+ PARENT_ID=`cmis_client create-folder $PARENT_PARENT_ID $PARENT_NAME 2>&1 | grep '^Id:' | sed -e 's/^[^:]*: \(.*\)$/\1/'`
+ fi
+
+ if test -d "$FILE_PATH"; then
+ cmis_client create-folder "$PARENT_ID" "$FILE_NAME" >/dev/null
+ else
+ FILE_MIME=`file --mime-type "$FILE_PATH" | cut -d ' ' -f 2`
+
+ cmis_client --input-file "$FILE_PATH" --input-type $FILE_MIME \
+ create-document "$PARENT_ID" "$FILE_NAME" >/dev/null
+ fi
+
+ if test "x$?" == "x0";
+ then
+ echo -ne "OK\t"
+ else
+ echo -ne "Failed\t"
+ fi
+ echo $SERVER_PARENT/$FILE_NAME
+done
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..01c3d19
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = libcmis libcmis-c
+
+if ENABLE_CLIENT
+AM_CXXFLAGS = \
+ -I$(top_srcdir)/inc \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+bin_PROGRAMS = cmis-client
+
+cmis_client_SOURCES = cmis-client.cxx
+cmis_client_LDADD = $(top_builddir)/src/libcmis/libcmis-@LIBCMIS_API_VERSION@.la \
+ $(XML2_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(BOOST_DATE_TIME_LIBS) \
+ $(JSON_LIBS)
+endif
diff --git a/src/cmis-client.cxx b/src/cmis-client.cxx
new file mode 100644
index 0000000..73b6f42
--- /dev/null
+++ b/src/cmis-client.cxx
@@ -0,0 +1,1158 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <stdio.h>
+
+#include <exception>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+
+#include <boost/program_options.hpp>
+
+#include <libcmis/libcmis.hxx>
+
+using namespace std;
+using namespace boost::program_options;
+using libcmis::PropertyPtrMap;
+
+namespace
+{
+ char* lcl_queryAuthCode( const char* url, const char* /*username*/, const char* /*password*/ )
+ {
+ string code;
+ cout << "Copy the following link to your browser and take the code: " << endl << endl << url << endl << endl;
+ cout << "Enter the code:" << endl;
+ cin >> code;
+
+ return strdup( code.c_str() );
+ }
+
+ class AuthCodeProvider
+ {
+ private:
+ static string m_authCode;
+
+ public:
+ static void setAuthCode( string authCode );
+ static char* getAuthCode( const char* /*url*/, const char* /*username*/, const char* /*password*/ );
+ };
+
+ string AuthCodeProvider::m_authCode = string( );
+ void AuthCodeProvider::setAuthCode( string authCode )
+ {
+ m_authCode = authCode;
+ }
+
+ char* AuthCodeProvider::getAuthCode( const char* /*url*/, const char* /*username*/, const char* /*password*/ )
+ {
+ return strdup( m_authCode.c_str( ) );
+ }
+
+ class CinAuthProvider : public libcmis::AuthProvider
+ {
+ private:
+ string m_user;
+ string m_pass;
+
+ public:
+ CinAuthProvider( ) : m_user( ), m_pass( ) { }
+ ~CinAuthProvider( ) { }
+
+ virtual bool authenticationQuery( string& username, string& password );
+ };
+
+ bool CinAuthProvider::authenticationQuery( string& username, string& password )
+ {
+ bool cancelled = false;
+ bool askUsername = username.empty();
+
+ if ( askUsername )
+ {
+ if ( m_user.empty() )
+ {
+ cout << "Username (empty to cancel): ";
+ getline( cin, m_user );
+ }
+
+ cancelled = m_user.empty();
+ username = m_user;
+ }
+
+ if ( !cancelled && ( askUsername || password.empty( ) ) )
+ {
+ if ( m_pass.empty() )
+ {
+ cout << "Password (empty to cancel): ";
+ getline( cin, m_pass );
+ }
+
+ cancelled = m_pass.empty();
+ password = m_pass;
+ }
+
+ return !cancelled;
+ }
+
+ class CinCertValidationHandler : public libcmis::CertValidationHandler
+ {
+ private:
+ map< string, bool > m_answers;
+
+ public:
+ CinCertValidationHandler( ) : m_answers( ) { }
+ ~CinCertValidationHandler( ) { }
+
+ virtual bool validateCertificate( vector< string > certificates )
+ {
+ if ( certificates.empty( ) )
+ return false; // Should never happen
+
+ // Show the first certificate (even base64-encoded)
+ string cert = certificates.front();
+ map< string, bool >::iterator it = m_answers.find( cert );
+ if ( it != m_answers.end( ) )
+ return it->second;
+
+ cout << "Invalid SSL certificate:" << endl << cert << endl;
+ cout << "'openssl x509 -noout -text' can show you the details of this certificate." << endl << endl;
+
+ // Ask whether to validate
+ cout << "Do you want to ignore this problem and go on? yes/no [default: no]: ";
+ string answer;
+ getline( cin, answer );
+
+ m_answers[cert] = answer == "yes";
+
+ return answer == "yes";
+ }
+ };
+}
+
+class CommandException : public exception
+{
+ private:
+ string m_msg;
+
+ public:
+ CommandException( string msg ) : m_msg( msg ) { }
+ ~CommandException( ) noexcept { }
+ CommandException( const CommandException& copy ) : m_msg( copy.m_msg ) { }
+
+ CommandException& operator=( const CommandException& copy )
+ {
+ if ( this != &copy )
+ m_msg = copy.m_msg;
+ return *this;
+ }
+
+ virtual const char* what() const noexcept { return m_msg.c_str(); }
+};
+
+class CmisClient
+{
+ private:
+ variables_map& m_vm;
+ public:
+ CmisClient( variables_map& vm ) : m_vm( vm ) { }
+
+ libcmis::Session* getSession( bool inGetRepositories = false );
+
+ void execute( );
+
+ void printHelp( );
+
+ static options_description getOptionsDescription( );
+
+ private:
+ map< int, string > getSessionParams();
+ map< string, string > getObjectProperties( );
+};
+
+map< string, string > CmisClient::getObjectProperties( )
+{
+ map< string, string > result;
+ if ( m_vm.count( "object-property" ) > 0 )
+ {
+ vector< string > params = m_vm["object-property"].as< vector< string > >( );
+ for ( vector< string >::iterator it = params.begin( ); it != params.end( ); ++it )
+ {
+ size_t pos = it->find( "=" );
+ if ( pos != string::npos )
+ {
+ string name = it->substr( 0, pos );
+ string value = it->substr( pos + 1 );
+ result.insert( pair< string, string >( name, value ) );
+ }
+ }
+ }
+
+ return result;
+}
+
+libcmis::Session* CmisClient::getSession( bool inGetRepositories )
+{
+ if ( m_vm.count( "url" ) == 0 )
+ throw CommandException( "Missing binding URL" );
+
+ // Setup the authentication provider in case we have missing credentials
+ libcmis::AuthProviderPtr provider( new CinAuthProvider( ) );
+ libcmis::SessionFactory::setAuthenticationProvider( provider );
+
+ libcmis::CertValidationHandlerPtr certValidator( new CinCertValidationHandler( ) );
+ libcmis::SessionFactory::setCertificateValidationHandler( certValidator );
+
+ string url = m_vm["url"].as<string>();
+
+ // Look for the credentials
+ string username;
+ string password;
+ if ( m_vm.count( "username" ) > 0 )
+ {
+ username = m_vm["username"].as< string >();
+
+ if ( m_vm.count( "password" ) > 0 )
+ password = m_vm["password"].as< string >();
+ }
+
+ // Look for proxy settings
+ string proxyUrl;
+ string proxyUser;
+ string proxyPass;
+ string noproxy;
+ if ( m_vm.count( "proxy" ) > 0 )
+ {
+ proxyUrl = m_vm["proxy"].as< string >();
+
+ if ( m_vm.count( "proxy-user" ) > 0 )
+ proxyUser = m_vm["proxy-user"].as< string >();
+
+ if ( m_vm.count( "proxy-password" ) > 0 )
+ proxyPass = m_vm["proxy-password"].as< string >();
+
+ if ( m_vm.count( "noproxy" ) > 0 )
+ noproxy = m_vm["noproxy"].as< string >();
+
+ libcmis::SessionFactory::setProxySettings( proxyUrl, noproxy, proxyUser, proxyPass );
+ }
+
+ bool verbose = m_vm.count( "verbose" ) > 0;
+
+ libcmis::Session* session = NULL;
+ string repoId;
+ // The repository ID is needed to initiate a session
+ if ( m_vm.count( "repository" ) == 0 && !inGetRepositories )
+ {
+ // Do we have a single repository on the server?
+ session = getSession( true );
+ if ( session != NULL )
+ {
+ vector< libcmis::RepositoryPtr > repos = session->getRepositories();
+ if ( repos.size() == 1 )
+ {
+ repoId = repos.front( )->getId( );
+ session->setRepository( repoId );
+ }
+ }
+
+ // We couldn't auto-guess the repository, then throw an error
+ if ( repoId.empty( ) )
+ {
+ delete session;
+ throw CommandException( "Missing repository ID" );
+ }
+ }
+ else if ( m_vm.count( "repository" ) > 0 )
+ {
+ repoId = m_vm["repository"].as< string >();
+ }
+
+ if ( session == NULL )
+ {
+ bool noSslCheck = m_vm.count( "no-ssl-check" ) > 0;
+
+ // Should we use OAuth2?
+ string oauth2ClientId;
+ string oauth2ClientSecret;
+ string oauth2AuthUrl;
+ string oauth2TokenUrl;
+ string oauth2RedirectUri;
+ string oauth2Scope;
+ if ( m_vm.count( "oauth2-client-id" ) > 0 )
+ oauth2ClientId = m_vm["oauth2-client-id"].as< string >();
+ if ( m_vm.count( "oauth2-client-secret" ) > 0 )
+ oauth2ClientSecret = m_vm["oauth2-client-secret"].as< string >();
+ if ( m_vm.count( "oauth2-auth-url" ) > 0 )
+ oauth2AuthUrl = m_vm["oauth2-auth-url"].as< string >();
+ if ( m_vm.count( "oauth2-token-url" ) > 0 )
+ oauth2TokenUrl = m_vm["oauth2-token-url"].as< string >();
+ if ( m_vm.count( "oauth2-redirect-uri" ) > 0 )
+ oauth2RedirectUri = m_vm["oauth2-redirect-uri"].as< string >();
+ if ( m_vm.count( "oauth2-scope" ) > 0 )
+ oauth2Scope = m_vm["oauth2-scope"].as< string >();
+ if ( m_vm.count( "oauth2-auth-code" ) > 0 )
+ AuthCodeProvider::setAuthCode( m_vm["oauth2-auth-code"].as< string >() );
+
+ libcmis::OAuth2DataPtr oauth2Data( new libcmis::OAuth2Data( oauth2AuthUrl, oauth2TokenUrl,
+ oauth2Scope, oauth2RedirectUri, oauth2ClientId, oauth2ClientSecret) );
+
+ if ( oauth2Data->isComplete( ) )
+ {
+ // Set the fallback AuthCode provider
+ if ( m_vm.count( "oauth2-auth-code" ) > 0 )
+ {
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( AuthCodeProvider::getAuthCode );
+ }
+ else
+ {
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( lcl_queryAuthCode );
+ }
+ }
+ else
+ {
+ oauth2Data.reset( );
+ }
+
+ session = libcmis::SessionFactory::createSession( url, username, password, repoId, noSslCheck, oauth2Data, verbose );
+ }
+
+ return session;
+}
+
+void CmisClient::execute( )
+{
+ if ( ( m_vm.count( "help" ) > 0 ) || m_vm.count( "command" ) != 1 )
+ {
+ printHelp();
+ return;
+ }
+
+ if ( m_vm.count( "command" ) == 1 )
+ {
+ string command = m_vm["command"].as<string>();
+ if ( "list-repos" == command )
+ {
+ libcmis::Session* session = getSession( true );
+ if ( session != NULL )
+ {
+ vector< libcmis::RepositoryPtr > repos = session->getRepositories();
+
+ cout << "Repositories: name (id)" << endl;
+ for ( vector< libcmis::RepositoryPtr >::iterator it = repos.begin(); it != repos.end(); ++it )
+ cout << "\t" << ( *it )->getName( ) << " (" << ( *it )->getId( ) << ")" << endl;
+ }
+ else
+ {
+ cerr << "Couldn't create a session for some reason" << endl;
+ }
+ }
+ else if ( "show-root" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ libcmis::FolderPtr root = session->getRootFolder();
+ if ( root.get() )
+ {
+ cout << "------------------------------------------------" << endl;
+ cout << root->toString() << endl;
+ }
+ }
+ else if ( "repo-infos" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+ libcmis::RepositoryPtr repo = session->getRepository( );
+
+ if ( repo )
+ {
+ cout << "------------------------------------------------" << endl;
+ cout << repo->toString() << endl;
+ }
+ else
+ throw CommandException( "Please select a repository" );
+ }
+ else if ( "type-by-id" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the types to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node ids to show as command args" );
+
+ vector< string > ids = m_vm["args"].as< vector< string > >( );
+
+
+ for ( vector< string >::iterator it = ids.begin(); it != ids.end(); ++it )
+ {
+ cout << "------------------------------------------------" << endl;
+ try
+ {
+ libcmis::ObjectTypePtr type = session->getType( *it );
+ cout << type->toString() << endl;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ cout << e.what() << endl;
+ }
+ }
+ }
+ else if ( "show-by-id" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node ids to show as command args" );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+
+
+ for ( vector< string >::iterator it = objIds.begin(); it != objIds.end(); ++it )
+ {
+ libcmis::ObjectPtr cmisObj = session->getObject( *it );
+ cout << "------------------------------------------------" << endl;
+ if ( cmisObj.get() )
+ cout << cmisObj->toString() << endl;
+ else
+ cout << "No such node: " << *it << endl;
+ }
+ }
+ else if ( "show-by-path" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the paths of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node paths to show as command args" );
+
+ vector< string > objPaths = m_vm["args"].as< vector< string > >( );
+
+
+ for ( vector< string >::iterator it = objPaths.begin(); it != objPaths.end(); ++it )
+ {
+ libcmis::ObjectPtr cmisObj = session->getObjectByPath( *it );
+ cout << "------------------------------------------------" << endl;
+ if ( cmisObj.get() )
+ cout << cmisObj->toString() << endl;
+ else
+ cout << "No such node: " << *it << endl;
+ }
+ }
+ else if ( "get-content" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+ if ( objIds.empty( ) )
+ throw CommandException( "Please provide a content object Id" );
+
+ libcmis::ObjectPtr cmisObj = session->getObject( objIds.front() );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( cmisObj.get() );
+ if ( NULL != document )
+ {
+ // TODO Handle name clashes
+ string streamId;
+ if ( m_vm.count( "stream-id" ) > 0 )
+ streamId = m_vm["stream-id"].as<string>();
+
+ boost::shared_ptr< istream > in = document->getContentStream( streamId );
+ ofstream out( document->getContentFilename().c_str() );
+ out << in->rdbuf();
+ out.close();
+ }
+ else
+ throw CommandException( string( "Not a document object id: " ) + objIds.front() );
+ }
+ else if ( "set-content" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+ if ( objIds.empty( ) )
+ throw CommandException( "Please provide a content object Id" );
+
+ libcmis::ObjectPtr cmisObj = session->getObject( objIds.front() );
+ libcmis::Document* document = dynamic_cast< libcmis::Document* >( cmisObj.get() );
+ if ( NULL != document )
+ {
+ if ( m_vm.count( "input-file" ) == 0 )
+ throw CommandException( "Missing --input-file" );
+ if ( m_vm.count( "input-type" ) == 0 )
+ throw CommandException( "Missing --input-type" );
+
+ string type = m_vm["input-type"].as<string>();
+ string filename;
+ if ( m_vm.count( "input-name" ) > 0 )
+ filename = m_vm["input-name"].as<string>();
+ string file = m_vm["input-file"].as<string>();
+ ifstream is( file.c_str(), ifstream::in );
+ boost::shared_ptr< ostream > os ( new ostream ( is.rdbuf( ) ) );
+ if ( is.fail( ) )
+ throw CommandException( string( "Unable to open file " ) + file );
+
+ document->setContentStream( os, type, filename );
+
+ is.close( );
+ }
+ else
+ throw CommandException( string( "Not a document object id: " ) + objIds.front() );
+ }
+ else if ( "create-folder" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ vector< string > args = m_vm["args"].as< vector< string > >( );
+ if ( args.size() < 2 )
+ throw CommandException( "Please provide a parent Id and folder name" );
+
+ libcmis::FolderPtr parent = session->getFolder( args[0] );
+
+ // Get the folder type to create
+ string folderType( "cmis:folder" );
+ if ( m_vm.count( "object-type" ) != 0 )
+ folderType = m_vm["object-type"].as<string>( );
+
+ libcmis::ObjectTypePtr type = session->getType( folderType );
+ if ( "cmis:folder" != type->getBaseType( )->getId( ) )
+ throw CommandException( string( "Not a folder type: " ) + folderType );
+
+ PropertyPtrMap properties;
+ map< string, libcmis::PropertyTypePtr >& propertiesTypes = type->getPropertiesTypes( );
+
+ // Set the name
+ map< string, libcmis::PropertyTypePtr >::iterator typeIt = propertiesTypes.find( string( "cmis:name" ) );
+ if ( typeIt == propertiesTypes.end( ) )
+ throw CommandException( string( "No cmis:name on the object type... weird" ) );
+ vector< string > nameValues;
+ string newFolderName = args[1];
+ for ( unsigned int i = 2; i < args.size( ); i++ )
+ {
+ newFolderName += " " + args[i];
+ }
+ nameValues.push_back( newFolderName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( typeIt->second, nameValues ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // Set the objectTypeId
+ typeIt = propertiesTypes.find( string( "cmis:objectTypeId" ) );
+ if ( typeIt == propertiesTypes.end( ) )
+ throw CommandException( string( "No cmis:objectTypeId on the object type... weird" ) );
+ vector< string > typeIdValues;
+ typeIdValues.push_back( folderType );
+ libcmis::PropertyPtr typeIdProperty( new libcmis::Property( typeIt->second, typeIdValues ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeIdProperty ) );
+
+ // Checks for the properties to set if any
+ map< string, string > propsToSet = getObjectProperties( );
+ for ( map< string, string >::iterator it = propsToSet.begin(); it != propsToSet.end(); ++it )
+ {
+ // Create the CMIS property if it exists
+ typeIt = propertiesTypes.find( it->first );
+ if ( typeIt != propertiesTypes.end( ) )
+ {
+ vector< string > values;
+ values.push_back( it->second );
+ libcmis::PropertyPtr cmisProperty( new libcmis::Property( typeIt->second, values ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( it->first, cmisProperty ) );
+ }
+ }
+
+ libcmis::FolderPtr created = parent->createFolder( properties );
+
+ cout << "------------------------------------------------" << endl;
+ cout << created->toString() << endl;
+ }
+ else if ( "create-document" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ vector< string > args = m_vm["args"].as< vector< string > >( );
+ if ( args.size() < 2 )
+ throw CommandException( "Please provide a parent Id and document name" );
+
+ libcmis::FolderPtr parent = session->getFolder( args[0] );
+
+ // Get the document type to create
+ string documentType( "cmis:document" );
+ if ( m_vm.count( "object-type" ) != 0 )
+ documentType = m_vm["object-type"].as<string>( );
+
+ libcmis::ObjectTypePtr type = session->getType( documentType );
+ if ( "cmis:document" != type->getBaseType( )->getId( ) )
+ throw CommandException( string( "Not a document type: " ) + documentType );
+
+ PropertyPtrMap properties;
+ map< string, libcmis::PropertyTypePtr >& propertiesTypes = type->getPropertiesTypes( );
+
+ // Set the name
+ map< string, libcmis::PropertyTypePtr >::iterator typeIt = propertiesTypes.find( string( "cmis:name" ) );
+ if ( typeIt == propertiesTypes.end( ) )
+ throw CommandException( string( "No cmis:name on the object type... weird" ) );
+ vector< string > nameValues;
+ string newDocumentName = args[1];
+ for ( unsigned int i = 2; i < args.size( ); i++ )
+ {
+ newDocumentName += " " + args[i];
+ }
+ nameValues.push_back( newDocumentName );
+ libcmis::PropertyPtr nameProperty( new libcmis::Property( typeIt->second, nameValues ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:name" ), nameProperty ) );
+
+ // Set the objectTypeId
+ typeIt = propertiesTypes.find( string( "cmis:objectTypeId" ) );
+ if ( typeIt == propertiesTypes.end( ) )
+ throw CommandException( string( "No cmis:objectTypeId on the object type... weird" ) );
+ vector< string > typeIdValues;
+ typeIdValues.push_back( documentType );
+ libcmis::PropertyPtr typeIdProperty( new libcmis::Property( typeIt->second, typeIdValues ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( string( "cmis:objectTypeId" ), typeIdProperty ) );
+
+ // Checks for the properties to set if any
+ map< string, string > propsToSet = getObjectProperties( );
+ for ( map< string, string >::iterator it = propsToSet.begin(); it != propsToSet.end(); ++it )
+ {
+ // Create the CMIS property if it exists
+ typeIt = propertiesTypes.find( it->first );
+ if ( typeIt != propertiesTypes.end( ) )
+ {
+ vector< string > values;
+ values.push_back( it->second );
+ libcmis::PropertyPtr cmisProperty( new libcmis::Property( typeIt->second, values ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( it->first, cmisProperty ) );
+ }
+ }
+
+ // Get the content type and stream
+ boost::shared_ptr< ostream > contentStream;
+ string contentType;
+ string filename;
+
+ bool hasInputFile = m_vm.count( "input-file" ) != 0;
+ bool hasInputType = m_vm.count( "input-type" ) != 0;
+ bool hasInputName = m_vm.count( "input-name" ) != 0;
+
+ if ( hasInputType && !hasInputFile )
+ throw CommandException( "Missing --input-file" );
+ if ( hasInputFile && !hasInputType )
+ throw CommandException( "Missing --input-type" );
+
+ if ( hasInputFile && hasInputType )
+ {
+ contentType = m_vm["input-type"].as<string>();
+ string file = m_vm["input-file"].as<string>();
+ fstream is( file.c_str() );
+ if ( is.fail( ) )
+ throw CommandException( string( "Unable to open file " ) + file );
+ contentStream.reset( new ostringstream( ios_base::out | ios_base::in ) );
+
+ *contentStream << is.rdbuf();
+ }
+
+ if ( hasInputName )
+ filename = m_vm[ "input-name" ].as< string >( );
+
+ // Actually create the document
+ libcmis::DocumentPtr created = parent->createDocument( properties, contentStream, contentType, filename );
+
+ cout << "------------------------------------------------" << endl;
+ cout << created->toString() << endl;
+ }
+ else if ( "update-object" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ vector< string > args = m_vm["args"].as< vector< string > >( );
+ if ( args.size() != 1 )
+ throw CommandException( "Please provide an object id" );
+
+ libcmis::ObjectPtr object = session->getObject( args[0] );
+ libcmis::ObjectTypePtr type = session->getType( object->getType( ) );
+ map< string, libcmis::PropertyTypePtr >& propertiesTypes = type->getPropertiesTypes( );
+
+ PropertyPtrMap properties;
+
+ // Checks for the properties to set if any
+ map< string, string > propsToSet = getObjectProperties( );
+ for ( map< string, string >::iterator it = propsToSet.begin(); it != propsToSet.end(); ++it )
+ {
+ // Create the CMIS property if it exists
+ map< string, libcmis::PropertyTypePtr >::iterator typeIt = propertiesTypes.find( it->first );
+ if ( typeIt != propertiesTypes.end( ) && typeIt->second->isUpdatable( ) )
+ {
+ vector< string > values;
+ values.push_back( it->second );
+ libcmis::PropertyPtr property( new libcmis::Property( typeIt->second, values ) );
+ properties[ it->first ] = property;
+ }
+ }
+
+ libcmis::ObjectPtr updated = object->updateProperties( properties );
+
+ cout << "------------------------------------------------" << endl;
+ // Output updated instead of object as it may be different depending on the server
+ cout << updated->toString() << endl;
+ }
+ else if ( "move-object" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ vector< string > args = m_vm["args"].as< vector< string > > ( );
+ if ( args.size() != 3 )
+ throw CommandException( "Please provide an object id and source and destination folder ids" );
+ string& objId = args[0];
+ string& srcId = args[1];
+ string& dstId = args[2];
+
+ libcmis::ObjectPtr obj = session->getObject( objId );
+
+ libcmis::ObjectPtr src = session->getObject( srcId );
+ libcmis::FolderPtr srcFolder = boost::dynamic_pointer_cast< libcmis::Folder > ( src );
+ if ( !srcFolder )
+ throw CommandException( "Source object is not a folder" );
+
+ libcmis::ObjectPtr dst = session->getObject( dstId );
+ libcmis::FolderPtr dstFolder = boost::dynamic_pointer_cast< libcmis::Folder > ( dst );
+ if ( !dstFolder )
+ throw CommandException( "Destinaton object is not a folder" );
+
+ obj->move( srcFolder, dstFolder );
+
+ cout << "------------------------------------------------" << endl;
+ cout << obj->toString( ) << endl;
+ }
+ else if ( "delete" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node ids to delete as command args" );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+
+ vector< string > errors;
+ for ( vector< string >::iterator it = objIds.begin(); it != objIds.end(); ++it )
+ {
+ libcmis::ObjectPtr cmisObj = session->getObject( *it );
+ libcmis::Folder* folder = dynamic_cast< libcmis::Folder* >( cmisObj.get() );
+ if ( NULL != folder )
+ {
+ try
+ {
+ vector< string > failed = folder->removeTree( );
+ string error;
+ for ( vector< string >::iterator dumpIt = failed.begin( );
+ dumpIt != failed.end( ); ++dumpIt )
+ {
+ if ( dumpIt == failed.begin( ) )
+ error += "Failed to remove children nodes: ";
+ else
+ error += ", ";
+ error = *dumpIt;
+ }
+ if ( !error.empty( ) )
+ errors.push_back( error );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = *it + ": " + e.what( );
+ errors.push_back( msg );
+ }
+ }
+ else if ( cmisObj.get() )
+ {
+ try
+ {
+ cmisObj->remove( );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string msg = *it + ": " + e.what( );
+ errors.push_back( msg );
+ }
+ }
+ else
+ {
+ string msg = "No such node: " + *it;
+ errors.push_back( msg );
+ }
+ }
+
+ // Show the errors
+ if ( !errors.empty( ) )
+ {
+ cout << "Errors:" << endl;
+ for ( vector< string >::iterator it = errors.begin( ); it != errors.end( ); ++it )
+ {
+ cout << "\t" << *it << endl;
+ }
+ }
+ else
+ {
+ cout << "All nodes have been removed" << endl;
+ }
+ }
+ else if ( "checkout" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node id to checkout as command args" );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+
+ libcmis::ObjectPtr cmisObj = session->getObject( objIds.front() );
+ if ( cmisObj.get() )
+ {
+ libcmis::Document* doc = dynamic_cast< libcmis::Document* >( cmisObj.get() );
+ if ( NULL != doc )
+ {
+ libcmis::DocumentPtr pwc = doc->checkOut( );
+ if ( pwc.get( ) )
+ {
+ cout << "------------------------------------------------" << endl;
+ cout << pwc->toString() << endl;
+ }
+ else
+ cout << "No Private Working Copy returned?" << endl;
+ }
+ else
+ throw CommandException( string( "Not a document object id: " ) + objIds.front() );
+ }
+ else
+ cout << "No such node: " << objIds.front() << endl;
+ }
+ else if ( "cancel-checkout" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the private working copy object id to cancel as command args" );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+
+ libcmis::ObjectPtr cmisObj = session->getObject( objIds.front() );
+ cout << "------------------------------------------------" << endl;
+ if ( cmisObj.get() )
+ {
+ libcmis::Document* doc = dynamic_cast< libcmis::Document* >( cmisObj.get() );
+ if ( NULL != doc )
+ {
+ doc->cancelCheckout( );
+ cout << "Checkout cancelled" << endl;
+ }
+ else
+ throw CommandException( string( "Not a document object id: " ) + objIds.front() );
+ }
+ else
+ cout << "No such node: " << objIds.front() << endl;
+ }
+ else if ( "checkin" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node id to checkin as command args" );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+
+ libcmis::ObjectPtr object = session->getObject( objIds.front() );
+ if ( object.get() )
+ {
+ // Create the properties map
+ PropertyPtrMap properties;
+ map< string, string > propsToSet = getObjectProperties( );
+ libcmis::ObjectTypePtr type = session->getType( object->getType( ) );
+ map< string, libcmis::PropertyTypePtr > propertyTypes = type->getPropertiesTypes( );
+ for ( map< string, string >::iterator propIt = propsToSet.begin();
+ propIt != propsToSet.end(); ++propIt )
+ {
+ string name = propIt->first;
+ map< string, libcmis::PropertyTypePtr >::iterator typeIt = propertyTypes.find( name );
+ if ( typeIt != propertyTypes.end( ) )
+ {
+ vector< string > values;
+ values.push_back( propIt->second );
+ libcmis::PropertyPtr prop( new libcmis::Property( typeIt->second, values ) );
+ properties.insert( pair< string, libcmis::PropertyPtr >( name, prop ) );
+ }
+ }
+
+ // Get the content stream if any
+ string contentType;
+ string filename;
+ boost::shared_ptr< ostream > stream;
+ if ( m_vm.count( "input-file" ) > 0 )
+ {
+ string file = m_vm["input-file"].as<string>();
+ ifstream is( file.c_str(), ios_base::in );
+ stringstream os;
+ os << is.rdbuf( );
+ if ( is.fail( ) )
+ throw CommandException( string( "Unable to open file " ) + file );
+
+ string content = os.str( );
+ stream.reset( new stringstream( content ) );
+ is.close( );
+
+ if ( m_vm.count( "input-type" ) > 0 )
+ {
+ contentType = m_vm["input-type"].as<string>();
+ }
+ if ( m_vm.count( "input-name" ) > 0 )
+ {
+ filename = m_vm["input-name"].as<string>();
+ }
+ }
+
+ bool major = false;
+ if ( m_vm.count( "major" ) > 0 )
+ major = "yes";
+
+ string comment;
+ if ( m_vm.count( "message" ) > 0 )
+ comment = m_vm["message"].as< string >( );
+
+ libcmis::Document* doc = dynamic_cast< libcmis::Document* >( object.get() );
+ if ( NULL != doc )
+ {
+ libcmis::DocumentPtr newDoc = doc->checkIn( major, comment, properties, stream, contentType, filename );
+
+ cout << "------------------------------------------------" << endl;
+ cout << newDoc->toString() << endl;
+ }
+ else
+ throw CommandException( string( "Not a document object id: " ) + objIds.front() );
+ }
+ else
+ cout << "No such node: " << objIds.front() << endl;
+ }
+ else if ( "get-versions" == command )
+ {
+ unique_ptr<libcmis::Session> session( getSession( ) );
+
+ // Get the ids of the objects to fetch
+ if ( m_vm.count( "args" ) == 0 )
+ throw CommandException( "Please provide the node id to get versions from as command args" );
+
+ vector< string > objIds = m_vm["args"].as< vector< string > >( );
+
+ libcmis::ObjectPtr object = session->getObject( objIds.front() );
+ if ( object.get() )
+ {
+ libcmis::Document* doc = dynamic_cast< libcmis::Document* >( object.get() );
+ if ( NULL != doc )
+ {
+ vector< libcmis::DocumentPtr > versions = doc->getAllVersions( );
+
+ for ( vector< libcmis::DocumentPtr >::iterator it = versions.begin( );
+ it != versions.end( ); ++it )
+ {
+ cout << "------------------------------------------------" << endl;
+ cout << ( *it )->toString() << endl;
+ }
+ }
+ else
+ throw CommandException( string( "Not a document object id: " ) + objIds.front() );
+ }
+ else
+ cout << "No such node: " << objIds.front() << endl;
+ }
+ else if ( "help" == command )
+ {
+ printHelp();
+ }
+ else
+ {
+ cerr << "------------------------------------------------" << endl;
+ cerr << "ERROR: Unknown command: " << command << endl;
+ cerr << "------------------------------------------------" << endl;
+ printHelp( );
+ }
+
+ // TODO Add some more useful commands here
+ }
+}
+
+options_description CmisClient::getOptionsDescription( )
+{
+ options_description desc( "Allowed options" );
+ desc.add_options( )
+ ( "help", "Produce help message and exists" )
+ ( "verbose,v", "Show loads of useful messages for debugging" )
+ ( "url", value< string >(), "URL of the binding of the server" )
+ ( "repository,r", value< string >(), "Name of the repository to use" )
+ ( "username,u", value< string >(), "Username used to authenticate to the repository" )
+ ( "password,p", value< string >(), "Password used to authenticate to the repository" )
+ ( "no-ssl-check", "Disable the verification of SSL certificates. This may come handy"
+ "for self-signed certificates for example, though it lowers the security" )
+ ( "proxy", value< string >(), "HTTP proxy url to override the system settings" )
+ ( "noproxy", value< string >(), "Coma separated list if host and domain names not going"
+ "through the proxy" )
+ ( "proxy-username", value< string >(), "Username to authenticate on the proxy" )
+ ( "proxy-password", value< string >(), "Password to authenticate on the proxy" )
+ ( "oauth2-client-id", value< string >(), "OAuth2 application client_id" )
+ ( "oauth2-client-secret", value< string >(), "OAuth2 application client_secret" )
+ ( "oauth2-auth-url", value< string >(), "URL to authenticate in the OAuth2 flow" )
+ ( "oauth2-token-url", value< string >(), "URL to convert code to tokens in the OAuth2 flow" )
+ ( "oauth2-redirect-uri", value< string >(), "redirect URI indicating that the authentication is finished in OAuth2 flow" )
+ ( "oauth2-scope", value< string >(), "The authentication scope in OAuth2" )
+ ( "oauth2-auth-code", value< string >(), "The authentication code required to get the access token" )
+ ;
+
+ options_description setcontentOpts( "modification operations options" );
+ setcontentOpts.add_options( )
+ ( "input-file", value< string >(), "File to push to the repository" )
+ ( "input-type", value< string >(), "Mime type of the file to push to the repository" )
+ ( "input-name", value< string >(), "Name of the file to push to the repository"
+ "(may be different from the local name)" )
+ ( "object-type", value< string >(), "CMIS type of the object to create" )
+ ( "object-property", value< vector< string > >(), "under the form prop-id=prop-value, defines a property"
+ "to be set on the object" )
+ ( "message,m", value< string >(), "Check in message" )
+ ( "major", "The version to create during the check in will be a major version." )
+ ( "stream-id", value< string >(), "streamId of the rendition to get content." )
+ ;
+
+ desc.add( setcontentOpts );
+ return desc;
+}
+
+void CmisClient::printHelp( )
+{
+ cerr << "cmis-client [options] [command] arguments" << endl;
+
+ cerr << endl << "Commands" << endl;
+ cerr << " list-repos\n"
+ " Lists the repositories available on the server" << endl;
+ cerr << " repo-infos\n"
+ " Show the informations and capabilities of the selected repository" << endl;
+ cerr << " show-root\n"
+ " Dump the root node of the repository." << endl;
+ cerr << " type-by-id <Type Id 1> [... <Type Id N>]\n"
+ " Dumps the type informations for all the ids." << endl;
+ cerr << " show-by-id <Object Id 1> [... <Object Id N>]\n"
+ " Dumps the objects informations for all the ids." << endl;
+ cerr << " show-by-path <Object Path 1> [... <Object Path N>]\n"
+ " Dumps the objects informations for all the paths." << endl;
+ cerr << " get-content <Object Id>\n"
+ " Saves the stream of the content object in the\n"
+ " current folder. Any existing file is overwritten.\n"
+ " streamId can be used to get the desired rendition with --stream-id"<< endl;
+ cerr << " set-content <Object Id>\n"
+ " Replaces the stream of the content object by the\n"
+ " file selected with --input-file." << endl;
+ cerr << " create-folder <Parent Id> <Folder Name>\n"
+ " Creates a new folder inside the folder <Parent Id> named <Folder Name>." << endl;
+ cerr << " create-document <Parent Id> <Document Name>\n"
+ " Creates a new document inside the folder <Parent Id>\n"
+ " named <Document Name>.\n"
+ " Note that --input-file and --input-type may be requested if\n"
+ " the server requires a content stream." << endl;
+ cerr << " update-object <Object Id>\n"
+ " Update the object matching id <Object Id> with the properties\n"
+ " defined with --object-property." << endl;
+ cerr << " move-object <Object Id> <Source Folder Id> <Destination Folder Id>\n"
+ " Move the object matching id <Object Id> from the\n"
+ " folder <Source Folder Id> to the folder <Destination Folder Id>." << endl;
+ cerr << " delete <Object Id 1> [... <Object Id N>]\n"
+ " Delete the objects corresponding to the ids. If the node\n"
+ " is a folder, its content will be removed as well." << endl;
+ cerr << " checkout <Object Id>\n"
+ " Check out the document corresponding to the id and shows the\n"
+ " Private Working Copy document infos." << endl;
+ cerr << " cancel-checkout <Object Id>\n"
+ " Cancel the Private Working Copy corresponding to the id" << endl;
+ cerr << " checkin <Object Id>\n"
+ " Check in the Private Working copy corresponding to the id.\n"
+ " Use the --message and --major parameters to give more\n"
+ " details about the new version.\n"
+ " The modification options may be needed to set the new\n"
+ " version properties and content stream if the repository\n"
+ " doesn't allow to change the private working copies." << endl;
+ cerr << " get-versions <Object-Id>\n"
+ " Show all the versions of a document." << endl;
+ cerr << " help\n"
+ " Prints this help message and exits (like --help option)." << endl;
+
+ cerr << endl << getOptionsDescription() << endl;
+}
+
+int main ( int argc, char* argv[] )
+{
+ options_description hidden( "Hidden options" );
+ hidden.add_options( )
+ ( "command", value< string >(), "Command" )
+ ( "args", value< vector< string > >(), "Arguments for the command" )
+ ;
+
+ options_description allOptions = CmisClient::getOptionsDescription( );
+ allOptions.add( hidden );
+
+ positional_options_description pd;
+ pd.add( "command", 1 );
+ pd.add( "args", -1 );
+
+ variables_map vm;
+ store( command_line_parser( argc, argv ).options( allOptions ).positional( pd ).run( ), vm );
+ notify( vm );
+
+ CmisClient client( vm );
+ try
+ {
+ client.execute( );
+ }
+ catch ( const CommandException& e )
+ {
+ cerr << "------------------------------------------------" << endl;
+ cerr << "ERROR: " << e.what() << endl;
+ cerr << "------------------------------------------------" << endl;
+ client.printHelp();
+ return 1;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ cerr << "------------------------------------------------" << endl;
+ cerr << "ERROR: " << e.what() << endl;
+ cerr << "------------------------------------------------" << endl;
+ return 1;
+ }
+ catch ( const exception& e )
+ {
+ cerr << "------------------------------------------------" << endl;
+ cerr << "ERROR: " << e.what() << endl;
+ cerr << "------------------------------------------------" << endl;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/src/libcmis-c/Makefile.am b/src/libcmis-c/Makefile.am
new file mode 100644
index 0000000..1510272
--- /dev/null
+++ b/src/libcmis-c/Makefile.am
@@ -0,0 +1,39 @@
+
+libcmis_c_@LIBCMIS_API_VERSION@_la_CXXFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/inc/libcmis-c \
+ $(XML2_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+libcmis_c_@LIBCMIS_API_VERSION@_la_CPPFLAGS = -DLIBCMIS_C_BUILD
+if ENABLE_VISIBILITY
+libcmis_c_@LIBCMIS_API_VERSION@_la_CXXFLAGS += -fvisibility=hidden
+libcmis_c_@LIBCMIS_API_VERSION@_la_CPPFLAGS += -DLIBCMIS_C_VISIBILITY
+endif
+
+lib_LTLIBRARIES = libcmis-c-@LIBCMIS_API_VERSION@.la
+libcmis_c_@LIBCMIS_API_VERSION@_la_SOURCES = \
+ allowable-actions.cxx \
+ document.cxx \
+ error.cxx \
+ folder.cxx \
+ internals.hxx \
+ oauth2-data.cxx \
+ object-type.cxx \
+ object.cxx \
+ property-type.cxx \
+ property.cxx \
+ rendition.cxx \
+ repository.cxx \
+ session-factory.cxx \
+ session.cxx \
+ vectors.cxx
+
+libcmis_c_@LIBCMIS_API_VERSION@_la_LDFLAGS = -export-dynamic -no-undefined -version-info 6:0:0
+
+libcmis_c_@LIBCMIS_API_VERSION@_la_LIBADD = \
+ ../libcmis/libcmis-@LIBCMIS_API_VERSION@.la \
+ $(XML2_LIBS) \
+ $(CURL_LIBS) \
+ $(BOOST_SMART_PTR_LIBS) \
+ $(BOOST_DATE_TIME_LIBS)
diff --git a/src/libcmis-c/allowable-actions.cxx b/src/libcmis-c/allowable-actions.cxx
new file mode 100644
index 0000000..f08f366
--- /dev/null
+++ b/src/libcmis-c/allowable-actions.cxx
@@ -0,0 +1,56 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/allowable-actions.h>
+
+#include "internals.hxx"
+
+void libcmis_allowable_actions_free( libcmis_AllowableActionsPtr allowable )
+{
+ delete allowable;
+}
+
+
+bool libcmis_allowable_actions_isAllowed( libcmis_AllowableActionsPtr allowable,
+ libcmis_allowable_actions_Type action )
+{
+ bool result = false;
+ if ( allowable != NULL && allowable->handle.get( ) != NULL )
+ result = allowable->handle->isAllowed( libcmis::ObjectAction::Type( action ) );
+ return result;
+}
+
+
+bool libcmis_allowable_actions_isDefined( libcmis_AllowableActionsPtr allowable,
+ libcmis_allowable_actions_Type action )
+{
+ bool result = false;
+ if ( allowable != NULL && allowable->handle.get( ) != NULL )
+ result = allowable->handle->isDefined( libcmis::ObjectAction::Type( action ) );
+ return result;
+}
diff --git a/src/libcmis-c/document.cxx b/src/libcmis-c/document.cxx
new file mode 100644
index 0000000..74d04d9
--- /dev/null
+++ b/src/libcmis-c/document.cxx
@@ -0,0 +1,448 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/document.h>
+
+#include "internals.hxx"
+
+using namespace std;
+using libcmis::DocumentPtr;
+using libcmis::FolderPtr;
+using libcmis::PropertyPtrMap;
+using boost::dynamic_pointer_cast;
+
+void libcmis_vector_document_free( libcmis_vector_document_Ptr vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_document_size( libcmis_vector_document_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_DocumentPtr libcmis_vector_document_get( libcmis_vector_document_Ptr vector, size_t i )
+{
+ libcmis_DocumentPtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::DocumentPtr handle = vector->handle[i];
+ item = new( nothrow ) libcmis_document( );
+ item->handle = handle;
+ }
+ return item;
+}
+
+bool libcmis_is_document( libcmis_ObjectPtr object )
+{
+ bool isDocument = false;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ DocumentPtr document = dynamic_pointer_cast< libcmis::Document >( object->handle );
+ isDocument = document.get( ) != NULL;
+ }
+ return isDocument;
+}
+
+
+libcmis_DocumentPtr libcmis_document_cast( libcmis_ObjectPtr object )
+{
+ libcmis_DocumentPtr document = NULL;
+
+ if ( object != NULL && object->handle.get( ) != NULL &&
+ libcmis_is_document( object ) )
+ {
+ document = new ( nothrow ) libcmis_document( );
+ document->handle = object->handle;
+ }
+
+ return document;
+}
+
+
+void libcmis_document_free( libcmis_DocumentPtr document )
+{
+ delete document;
+}
+
+
+libcmis_vector_folder_Ptr libcmis_document_getParents( libcmis_DocumentPtr document, libcmis_ErrorPtr error )
+{
+ libcmis_vector_folder_Ptr parents = NULL;
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ {
+ vector< libcmis::FolderPtr > handles = doc->getParents( );
+ parents = new libcmis_vector_folder( );
+ parents->handle = handles;
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return parents;
+}
+
+
+void libcmis_document_getContentStream(
+ libcmis_DocumentPtr document,
+ libcmis_writeFn writeFn,
+ void* userData,
+ libcmis_ErrorPtr error )
+{
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ {
+ boost::shared_ptr< istream > stream = doc->getContentStream( );
+
+ stream->seekg( 0 );
+ int bufSize = 2048;
+ char* buf = new char[ bufSize ];
+ while ( !stream->eof( ) )
+ {
+ stream->read( buf, bufSize );
+ size_t read = stream->gcount( );
+ writeFn( ( const void * )buf, size_t( 1 ), read, userData );
+ }
+ delete[] buf;
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ catch ( const exception& e )
+ {
+ if ( error != NULL )
+ error->message = strdup( e.what() );
+ }
+ catch ( ... )
+ {
+ }
+ }
+}
+
+
+void libcmis_document_setContentStream(
+ libcmis_DocumentPtr document,
+ libcmis_readFn readFn,
+ void* userData,
+ const char* contentType,
+ const char* fileName,
+ bool overwrite,
+ libcmis_ErrorPtr error )
+{
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ boost::shared_ptr< std::ostream > stream( new stringstream( ) );
+
+ size_t bufSize = 2048;
+ char* buf = new char[ bufSize ];
+ size_t read = 0;
+ do
+ {
+ read = readFn( ( void * )buf, size_t( 1 ), bufSize, userData );
+ stream->write( buf, read );
+ } while ( read == bufSize );
+ delete[] buf;
+
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ doc->setContentStream( stream, contentType, fileName, overwrite );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ catch ( const exception& e )
+ {
+ if ( error != NULL )
+ error->message = strdup( e.what() );
+ }
+ }
+}
+
+
+char* libcmis_document_getContentType( libcmis_DocumentPtr document )
+{
+ char* value = NULL;
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ value = strdup( doc->getContentType( ).c_str( ) );
+ }
+ return value;
+}
+
+
+char* libcmis_document_getContentFilename( libcmis_DocumentPtr document )
+{
+ char* value = NULL;
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ value = strdup( doc->getContentFilename( ).c_str( ) );
+ }
+ return value;
+}
+
+
+long libcmis_document_getContentLength( libcmis_DocumentPtr document )
+{
+ long value = 0;
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ value = doc->getContentLength( );
+ }
+ return value;
+}
+
+
+libcmis_DocumentPtr libcmis_document_checkOut( libcmis_DocumentPtr document, libcmis_ErrorPtr error )
+{
+ libcmis_DocumentPtr pwc = NULL;
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ {
+ libcmis::DocumentPtr handle = doc->checkOut( );
+ pwc= new libcmis_document( );
+ pwc->handle = handle;
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ error->badAlloc = true;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ }
+ return pwc;
+}
+
+
+void libcmis_document_cancelCheckout( libcmis_DocumentPtr document, libcmis_ErrorPtr error )
+{
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ doc->cancelCheckout( );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ }
+}
+
+libcmis_DocumentPtr libcmis_document_checkIn(
+ libcmis_DocumentPtr document,
+ bool isMajor,
+ const char* comment,
+ libcmis_vector_property_Ptr properties,
+ libcmis_readFn readFn,
+ void* userData,
+ const char* contentType,
+ const char* filename,
+ libcmis_ErrorPtr error )
+{
+ libcmis_DocumentPtr newVersion = NULL;
+
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ {
+ // Create the ostream
+ boost::shared_ptr< std::ostream > stream( new stringstream( ) );
+
+ size_t bufSize = 2048;
+ char * buf = new char[ bufSize ];
+ size_t read = 0;
+ do
+ {
+ read = readFn( ( void * )buf, size_t( 1 ), bufSize, userData );
+ stream->write( buf, read );
+ } while ( read == bufSize );
+ delete[] buf;
+
+ // Create the property map
+ PropertyPtrMap propertiesMap;
+ if ( properties != NULL )
+ {
+ for ( vector< libcmis::PropertyPtr >::iterator it = properties->handle.begin( );
+ it != properties->handle.end( ); ++it )
+ {
+ string id = ( *it )->getPropertyType( )->getId( );
+ propertiesMap.insert( pair< string, libcmis::PropertyPtr >( id, *it ) );
+ }
+ }
+
+ libcmis::DocumentPtr handle = doc->checkIn( isMajor, comment, propertiesMap,
+ stream, contentType, filename );
+ newVersion = new libcmis_document( );
+ newVersion->handle = handle;
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ catch ( const exception& e )
+ {
+ if ( error != NULL )
+ error->message = strdup( e.what() );
+ }
+ }
+ return newVersion;
+}
+
+libcmis_vector_document_Ptr libcmis_document_getAllVersions(
+ libcmis_DocumentPtr document,
+ libcmis_ErrorPtr error )
+{
+ libcmis_vector_document_Ptr result = NULL;
+ if ( document != NULL && document->handle.get( ) != NULL )
+ {
+ try
+ {
+ DocumentPtr doc = dynamic_pointer_cast< libcmis::Document >( document->handle );
+ if ( doc )
+ {
+ std::vector< libcmis::DocumentPtr > handles = doc->getAllVersions( );
+ result = new libcmis_vector_document( );
+ result->handle = handles;
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return result;
+}
diff --git a/src/libcmis-c/error.cxx b/src/libcmis-c/error.cxx
new file mode 100644
index 0000000..8fdb681
--- /dev/null
+++ b/src/libcmis-c/error.cxx
@@ -0,0 +1,74 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/error.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "internals.hxx"
+
+using namespace std;
+
+libcmis_ErrorPtr libcmis_error_create( )
+{
+ libcmis_ErrorPtr error = new( nothrow ) libcmis_error( );
+ return error;
+}
+
+
+void libcmis_error_free( libcmis_ErrorPtr error )
+{
+ if ( error != NULL )
+ {
+ free( error->message );
+ free( error->type );
+ delete error;
+ }
+}
+
+const char* libcmis_error_getMessage( libcmis_ErrorPtr error )
+{
+ if ( error != NULL )
+ {
+ if ( error->badAlloc )
+ return "Failed to allocate memory";
+ else
+ return error->message;
+ }
+ else
+ return "";
+}
+
+const char* libcmis_error_getType( libcmis_ErrorPtr error )
+{
+ if ( error != NULL )
+ return error->type;
+ else
+ return NULL;
+}
diff --git a/src/libcmis-c/folder.cxx b/src/libcmis-c/folder.cxx
new file mode 100644
index 0000000..8d7555a
--- /dev/null
+++ b/src/libcmis-c/folder.cxx
@@ -0,0 +1,369 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/folder.h>
+
+#include "internals.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+using libcmis::FolderPtr;
+using boost::dynamic_pointer_cast;
+
+void libcmis_vector_folder_free( libcmis_vector_folder_Ptr vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_folder_size( libcmis_vector_folder_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_FolderPtr libcmis_vector_folder_get( libcmis_vector_folder_Ptr vector, size_t i )
+{
+ libcmis_FolderPtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::FolderPtr handle = vector->handle[i];
+ item = new ( nothrow ) libcmis_folder( );
+ if ( item )
+ item->handle = handle;
+ }
+ return item;
+}
+
+
+bool libcmis_is_folder( libcmis_ObjectPtr object )
+{
+ bool isFolder = false;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr folder = boost::dynamic_pointer_cast< libcmis::Folder >( object->handle );
+ isFolder = folder.get( ) != NULL;
+ }
+ return isFolder;
+}
+
+
+libcmis_FolderPtr libcmis_folder_cast( libcmis_ObjectPtr object )
+{
+ libcmis_FolderPtr folder = NULL;
+
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr handle = boost::dynamic_pointer_cast< libcmis::Folder >( object->handle );
+ if ( handle.get( ) != NULL )
+ {
+ folder = new ( nothrow ) libcmis_folder( );
+ if ( folder )
+ folder->handle = handle;
+ }
+ }
+
+ return folder;
+}
+
+
+void libcmis_folder_free( libcmis_FolderPtr folder )
+{
+ delete folder;
+}
+
+
+libcmis_FolderPtr libcmis_folder_getParent( libcmis_FolderPtr folder, libcmis_ErrorPtr error )
+{
+ libcmis_FolderPtr parent = NULL;
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ try
+ {
+ FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ {
+ libcmis::FolderPtr handle = folderHandle->getFolderParent( );
+ if ( handle.get( ) != NULL )
+ {
+ parent = new libcmis_folder( );
+ parent->handle = handle;
+ }
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return parent;
+}
+
+
+libcmis_vector_object_Ptr libcmis_folder_getChildren( libcmis_FolderPtr folder, libcmis_ErrorPtr error )
+{
+ libcmis_vector_object_Ptr result = NULL;
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ try
+ {
+ libcmis::FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ {
+ std::vector< libcmis::ObjectPtr > handles = folderHandle->getChildren( );
+ result = new libcmis_vector_object( );
+ result->handle = handles;
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return result;
+}
+
+
+char* libcmis_folder_getPath( libcmis_FolderPtr folder )
+{
+ char* path = NULL;
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ path = strdup( folderHandle->getPath( ).c_str( ) );
+ }
+ return path;
+}
+
+
+bool libcmis_folder_isRootFolder( libcmis_FolderPtr folder )
+{
+ bool isRoot = false;
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ isRoot = folderHandle->isRootFolder( );
+ }
+ return isRoot;
+}
+
+libcmis_FolderPtr libcmis_folder_createFolder(
+ libcmis_FolderPtr folder,
+ libcmis_vector_property_Ptr properties,
+ libcmis_ErrorPtr error )
+{
+ libcmis_FolderPtr result = NULL;
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ {
+ try
+ {
+ PropertyPtrMap mappedProperties;
+ if ( properties != NULL )
+ {
+ size_t size = properties->handle.size( );
+ for ( size_t i = 0; i < size; ++i )
+ {
+ libcmis::PropertyPtr property = properties->handle[i];
+ if ( property.get( ) != NULL )
+ {
+ string id = property->getPropertyType( )->getId( );
+ mappedProperties.insert( pair< string, libcmis::PropertyPtr >( id, property ) );
+ }
+ }
+ }
+
+ libcmis::FolderPtr handle = folderHandle->createFolder( mappedProperties );
+ result = new libcmis_folder( );
+ result->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+
+libcmis_DocumentPtr libcmis_folder_createDocument(
+ libcmis_FolderPtr folder,
+ libcmis_vector_property_Ptr properties,
+ libcmis_readFn readFn,
+ void* userData,
+ const char* contentType,
+ const char* filename,
+ libcmis_ErrorPtr error )
+{
+ libcmis_DocumentPtr created = NULL;
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ {
+ try
+ {
+ // Create the ostream
+ boost::shared_ptr< std::ostream > stream( new stringstream( ) );
+
+ size_t bufSize = 2048;
+ char* buf = new char[ bufSize ];
+ size_t read = 0;
+ do
+ {
+ read = readFn( ( void * )buf, size_t( 1 ), bufSize, userData );
+ stream->write( buf, read );
+ } while ( read == bufSize );
+ delete[] buf;
+
+ // Create the property map
+ PropertyPtrMap propertiesMap;
+ if ( properties != NULL )
+ {
+ for ( vector< libcmis::PropertyPtr >::iterator it = properties->handle.begin( );
+ it != properties->handle.end( ); ++it )
+ {
+ string id = ( *it )->getPropertyType( )->getId( );
+ propertiesMap.insert( pair< string, libcmis::PropertyPtr >( id, *it ) );
+ }
+ }
+
+ libcmis::DocumentPtr handle = folderHandle->createDocument( propertiesMap, stream, contentType, filename );
+ created = new libcmis_document( );
+ created->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ catch ( const exception& e )
+ {
+ if ( error != NULL )
+ error->message = strdup( e.what() );
+ }
+ }
+ }
+ return created;
+}
+
+
+libcmis_vector_string_Ptr libcmis_folder_removeTree( libcmis_FolderPtr folder,
+ bool allVersion,
+ libcmis_folder_UnfileObjects unfile,
+ bool continueOnError,
+ libcmis_ErrorPtr error )
+{
+ libcmis_vector_string_Ptr failed = NULL;
+ try
+ {
+ failed = new libcmis_vector_string( );
+ if ( folder != NULL && folder->handle.get( ) != NULL )
+ {
+ libcmis::FolderPtr folderHandle = dynamic_pointer_cast< libcmis::Folder >( folder->handle );
+ if ( folder )
+ {
+ vector< string > handle = folderHandle->removeTree( allVersion,
+ libcmis::UnfileObjects::Type( unfile ), continueOnError );
+ failed->handle = handle;
+ }
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ return failed;
+}
diff --git a/src/libcmis-c/internals.hxx b/src/libcmis-c/internals.hxx
new file mode 100644
index 0000000..e4a5b6b
--- /dev/null
+++ b/src/libcmis-c/internals.hxx
@@ -0,0 +1,242 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _LIBCMIS_INTERNALS_H_
+#define _LIBCMIS_INTERNALS_H_
+
+#include <vector>
+
+#include <libcmis/allowable-actions.hxx>
+#include <libcmis/document.hxx>
+#include <libcmis/exception.hxx>
+#include <libcmis/folder.hxx>
+#include <libcmis/object.hxx>
+#include <libcmis/property.hxx>
+#include <libcmis/repository.hxx>
+#include <libcmis/session.hxx>
+#include <libcmis/session-factory.hxx>
+
+std::string createString( char* str );
+
+struct libcmis_error
+{
+ char* message;
+ char* type;
+ bool badAlloc;
+
+ libcmis_error( ) : message( NULL ), type( NULL ), badAlloc( false ) { }
+};
+
+struct libcmis_session
+{
+ libcmis::Session* handle;
+ libcmis::AuthProviderPtr provider;
+
+ // Constructors
+
+ libcmis_session( ) :
+ handle( NULL ),
+ provider( )
+ {
+ }
+
+ libcmis_session( const libcmis_session& copy ) :
+ handle( copy.handle ),
+ provider( copy.provider )
+ {
+ }
+
+ libcmis_session& operator=( const libcmis_session& copy )
+ {
+ if ( this != &copy )
+ {
+ handle = copy.handle;
+ provider = copy.provider;
+ }
+ return *this;
+ }
+};
+
+struct libcmis_repository
+{
+ libcmis::RepositoryPtr handle;
+
+ libcmis_repository( ) : handle( ) { }
+};
+
+struct libcmis_object
+{
+ libcmis::ObjectPtr handle;
+
+ libcmis_object( ) : handle( ) { }
+ virtual ~libcmis_object( ) { }
+};
+
+struct libcmis_object_type
+{
+ libcmis::ObjectTypePtr handle;
+
+ libcmis_object_type( ) : handle( ) { }
+};
+
+struct libcmis_allowable_actions
+{
+ libcmis::AllowableActionsPtr handle;
+
+ libcmis_allowable_actions( ) : handle ( ) { }
+};
+
+struct libcmis_property_type
+{
+ libcmis::PropertyTypePtr handle;
+
+ libcmis_property_type( ) : handle( ) { }
+};
+
+struct libcmis_property
+{
+ libcmis::PropertyPtr handle;
+
+ libcmis_property( ) : handle( ) { }
+};
+
+struct libcmis_folder : public libcmis_object
+{
+ libcmis_folder( ) : libcmis_object( ) { }
+};
+
+struct libcmis_document : public libcmis_object
+{
+ libcmis_document( ) : libcmis_object( ) { }
+};
+
+struct libcmis_oauth2data
+{
+ libcmis::OAuth2DataPtr handle;
+
+ libcmis_oauth2data( ) : handle( ) { }
+};
+
+struct libcmis_rendition
+{
+ libcmis::RenditionPtr handle;
+
+ libcmis_rendition( ) : handle( ) { }
+};
+
+struct libcmis_vector_bool
+{
+ std::vector< bool > handle;
+
+ libcmis_vector_bool( ) : handle( ) { }
+};
+
+struct libcmis_vector_string
+{
+ std::vector< std::string > handle;
+
+ libcmis_vector_string( ) : handle( ) { }
+};
+
+struct libcmis_vector_long
+{
+ std::vector< long > handle;
+
+ libcmis_vector_long( ) : handle( ) { }
+};
+
+struct libcmis_vector_double
+{
+ std::vector< double > handle;
+
+ libcmis_vector_double( ) : handle( ) { }
+};
+
+struct libcmis_vector_time
+{
+ std::vector< boost::posix_time::ptime > handle;
+
+ libcmis_vector_time( ) : handle( ) { }
+};
+
+struct libcmis_vector_object_type
+{
+ std::vector< libcmis::ObjectTypePtr > handle;
+
+ libcmis_vector_object_type( ) : handle( ) { }
+};
+
+struct libcmis_vector_property_type
+{
+ std::vector< libcmis::PropertyTypePtr > handle;
+
+ libcmis_vector_property_type( ) : handle( ) { }
+};
+
+struct libcmis_vector_property
+{
+ std::vector< libcmis::PropertyPtr > handle;
+
+ libcmis_vector_property( ) : handle( ) { }
+};
+
+struct libcmis_vector_object
+{
+ std::vector< libcmis::ObjectPtr > handle;
+
+ libcmis_vector_object( ) : handle( ) { }
+};
+
+struct libcmis_vector_folder
+{
+ std::vector< libcmis::FolderPtr > handle;
+
+ libcmis_vector_folder( ) : handle( ) { }
+};
+
+struct libcmis_vector_document
+{
+ std::vector< libcmis::DocumentPtr > handle;
+
+ libcmis_vector_document( ) : handle( ) { }
+};
+
+struct libcmis_vector_repository
+{
+ std::vector< libcmis::RepositoryPtr > handle;
+
+ libcmis_vector_repository( ) : handle( ) { }
+};
+
+struct libcmis_vector_rendition
+{
+ std::vector< libcmis::RenditionPtr > handle;
+
+ libcmis_vector_rendition( ) : handle( ) { }
+};
+
+#endif
diff --git a/src/libcmis-c/oauth2-data.cxx b/src/libcmis-c/oauth2-data.cxx
new file mode 100644
index 0000000..9b7c69f
--- /dev/null
+++ b/src/libcmis-c/oauth2-data.cxx
@@ -0,0 +1,110 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/oauth2-data.h>
+
+#include "internals.hxx"
+
+using namespace std;
+
+
+libcmis_OAuth2DataPtr libcmis_oauth2data_create(
+ char* authUrl, char* tokenUrl, char* scope, char* redirectUri,
+ char* clientId, char* clientSecret )
+{
+ libcmis_OAuth2DataPtr data = new( nothrow ) libcmis_oauth2data( );
+
+ if ( NULL != data )
+ data->handle.reset( new libcmis::OAuth2Data(
+ authUrl, tokenUrl, scope, redirectUri,
+ clientId, clientSecret ) );
+ return data;
+}
+
+
+void libcmis_oauth2data_free( libcmis_OAuth2DataPtr oauth2 )
+{
+ delete oauth2;
+}
+
+
+bool libcmis_oauth2data_isComplete( libcmis_OAuth2DataPtr oauth2 )
+{
+ bool result = false;
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ result = oauth2->handle->isComplete();
+ return result;
+}
+
+
+const char* libcmis_oauth2data_getAuthUrl( libcmis_OAuth2DataPtr oauth2 )
+{
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ return oauth2->handle->getAuthUrl().c_str();
+ return NULL;
+}
+
+
+const char* libcmis_oauth2data_getTokenUrl( libcmis_OAuth2DataPtr oauth2 )
+{
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ return oauth2->handle->getTokenUrl().c_str();
+ return NULL;
+}
+
+
+const char* libcmis_oauth2data_getClientId( libcmis_OAuth2DataPtr oauth2 )
+{
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ return oauth2->handle->getClientId().c_str();
+ return NULL;
+}
+
+
+const char* libcmis_oauth2data_getClientSecret( libcmis_OAuth2DataPtr oauth2 )
+{
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ return oauth2->handle->getClientSecret().c_str();
+ return NULL;
+}
+
+
+const char* libcmis_oauth2data_getScope( libcmis_OAuth2DataPtr oauth2 )
+{
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ return oauth2->handle->getScope().c_str();
+ return NULL;
+}
+
+
+const char* libcmis_oauth2data_getRedirectUri( libcmis_OAuth2DataPtr oauth2 )
+{
+ if ( oauth2 != NULL && oauth2->handle != NULL )
+ return oauth2->handle->getRedirectUri().c_str();
+ return NULL;
+}
diff --git a/src/libcmis-c/object-type.cxx b/src/libcmis-c/object-type.cxx
new file mode 100644
index 0000000..f1b3b9f
--- /dev/null
+++ b/src/libcmis-c/object-type.cxx
@@ -0,0 +1,388 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/object-type.h>
+
+#include "internals.hxx"
+
+using namespace std;
+
+
+void libcmis_vector_object_type_free( libcmis_vector_object_type_Ptr vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_object_type_size( libcmis_vector_object_type_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_ObjectTypePtr libcmis_vector_object_type_get( libcmis_vector_object_type_Ptr vector, size_t i )
+{
+ libcmis_ObjectTypePtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::ObjectTypePtr type = vector->handle[i];
+ item = new ( nothrow ) libcmis_object_type( );
+ if ( item )
+ item->handle = type;
+ }
+ return item;
+}
+
+
+void libcmis_object_type_free( libcmis_ObjectTypePtr type )
+{
+ delete type;
+}
+
+
+char* libcmis_object_type_getId( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getId( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_type_getLocalName( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getLocalName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_type_getLocalNamespace( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getLocalNamespace( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_type_getQueryName( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getQueryName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_type_getDisplayName( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getDisplayName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_type_getDescription( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getDescription( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+libcmis_ObjectTypePtr libcmis_object_type_getParentType(
+ libcmis_ObjectTypePtr type,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectTypePtr result = NULL;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ try
+ {
+ libcmis::ObjectTypePtr handle = type->handle->getParentType( );
+ if ( handle.get ( ) )
+ {
+ result = new libcmis_object_type( );
+ result->handle = handle;
+ }
+ }
+ catch( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+libcmis_ObjectTypePtr libcmis_object_type_getBaseType(
+ libcmis_ObjectTypePtr type,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectTypePtr result = NULL;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ try
+ {
+ libcmis::ObjectTypePtr handle = type->handle->getBaseType( );
+ result = new libcmis_object_type( );
+ result->handle = handle;
+ }
+ catch( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+char* libcmis_object_type_getParentTypeId( libcmis_ObjectTypePtr type )
+{
+ char* result = NULL;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ result = strdup( type->handle->getParentTypeId( ).c_str() );
+ }
+
+ return result;
+}
+
+
+char* libcmis_object_type_getBaseTypeId( libcmis_ObjectTypePtr type )
+{
+ char* result = NULL;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ result = strdup( type->handle->getBaseTypeId( ).c_str() );
+ }
+
+ return result;
+}
+
+
+libcmis_vector_object_type_Ptr libcmis_object_type_getChildren(
+ libcmis_ObjectTypePtr type, libcmis_ErrorPtr error )
+{
+ libcmis_vector_object_type_Ptr children = NULL;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ try
+ {
+ std::vector< libcmis::ObjectTypePtr > types = type->handle->getChildren( );
+ children = new libcmis_vector_object_type( );
+ children->handle = types;
+ }
+ catch( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+
+ return children;
+}
+
+
+bool libcmis_object_type_isCreatable( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isCreatable( );
+ return value;
+}
+
+
+bool libcmis_object_type_isFileable( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isFileable( );
+ return value;
+}
+
+
+bool libcmis_object_type_isQueryable( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isQueryable( );
+ return value;
+}
+
+
+bool libcmis_object_type_isFulltextIndexed( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isFulltextIndexed( );
+ return value;
+}
+
+
+bool libcmis_object_type_isIncludedInSupertypeQuery( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isIncludedInSupertypeQuery( );
+ return value;
+}
+
+
+bool libcmis_object_type_isControllablePolicy( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isControllablePolicy( );
+ return value;
+}
+
+
+bool libcmis_object_type_isControllableACL( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isControllableACL( );
+ return value;
+}
+
+
+bool libcmis_object_type_isVersionable( libcmis_ObjectTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isVersionable( );
+ return value;
+}
+
+
+libcmis_object_type_ContentStreamAllowed libcmis_object_type_getContentStreamAllowed( libcmis_ObjectTypePtr type )
+{
+ libcmis_object_type_ContentStreamAllowed result = libcmis_NotAllowed;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ libcmis::ObjectType::ContentStreamAllowed value = type->handle->getContentStreamAllowed( );
+ result = libcmis_object_type_ContentStreamAllowed( value );
+ }
+ return result;
+}
+
+
+libcmis_vector_property_type_Ptr libcmis_object_type_getPropertiesTypes( libcmis_ObjectTypePtr type )
+{
+ libcmis_vector_property_type_Ptr propertyTypes = NULL;
+ if ( type != NULL && type->handle != NULL )
+ {
+ map< string, libcmis::PropertyTypePtr >& handles = type->handle->getPropertiesTypes( );
+ propertyTypes = new ( nothrow ) libcmis_vector_property_type( );
+ if ( propertyTypes )
+ {
+ int i = 0;
+ for ( map< string, libcmis::PropertyTypePtr >::iterator it = handles.begin( );
+ it != handles.end( ); ++it, ++i )
+ {
+ propertyTypes->handle.push_back( it->second );
+ }
+ }
+ }
+
+ return propertyTypes;
+}
+
+libcmis_PropertyTypePtr libcmis_object_type_getPropertyType( libcmis_ObjectTypePtr type, const char* id )
+{
+ libcmis_PropertyTypePtr propertyType = NULL;
+ if ( type != NULL && type->handle != NULL )
+ {
+ map< string, libcmis::PropertyTypePtr >& handles = type->handle->getPropertiesTypes( );
+ map< string, libcmis::PropertyTypePtr >::iterator it = handles.find( string( id ) );
+ if ( it != handles.end( ) )
+ {
+ propertyType = new ( nothrow ) libcmis_property_type( );
+ if ( propertyType )
+ propertyType->handle = it->second;
+ }
+ }
+
+ return propertyType;
+}
+
+
+char* libcmis_object_type_toString( libcmis_ObjectTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->toString( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
diff --git a/src/libcmis-c/object.cxx b/src/libcmis-c/object.cxx
new file mode 100644
index 0000000..323cb31
--- /dev/null
+++ b/src/libcmis-c/object.cxx
@@ -0,0 +1,512 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/object.h>
+
+#include <libcmis-c/folder.h>
+
+#include "internals.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+using boost::dynamic_pointer_cast;
+
+namespace
+{
+ string lcl_stdString( const char* str )
+ {
+ string result;
+ if ( str )
+ result = string( str );
+ return result;
+ }
+
+ PropertyPtrMap lcl_createPropertiesMap( libcmis_vector_property_Ptr properties )
+ {
+ PropertyPtrMap propertiesMap;
+ if ( properties )
+ {
+ for ( vector< libcmis::PropertyPtr >::iterator it = properties->handle.begin( );
+ it != properties->handle.end( ); ++it )
+ {
+ libcmis::PropertyPtr propHandle = *it;
+ propertiesMap[ propHandle->getPropertyType()->getId( ) ] = propHandle;
+ }
+ }
+ return propertiesMap;
+ }
+}
+
+void libcmis_vector_object_free( libcmis_vector_object_Ptr vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_object_size( libcmis_vector_object_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_ObjectPtr libcmis_vector_object_get( libcmis_vector_object_Ptr vector, size_t i )
+{
+ libcmis_ObjectPtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::ObjectPtr type = vector->handle[i];
+ item = new ( nothrow ) libcmis_object( );
+ if ( item )
+ item->handle = type;
+ }
+ return item;
+}
+
+
+void libcmis_object_free( libcmis_ObjectPtr object )
+{
+ delete object;
+}
+
+
+char* libcmis_object_getId( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getId( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_getName( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+libcmis_vector_string_Ptr libcmis_object_getPaths( libcmis_ObjectPtr object )
+{
+ libcmis_vector_string_Ptr c_paths = NULL;
+ if ( object != NULL && object->handle != NULL )
+ {
+ std::vector< std::string > paths = object->handle->getPaths( );
+ c_paths = new ( nothrow ) libcmis_vector_string( );
+ if ( c_paths )
+ c_paths->handle = paths;
+ }
+ return c_paths;
+}
+
+char* libcmis_object_getBaseType( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getBaseType( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_getType( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getType( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_object_getCreatedBy( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getCreatedBy( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+time_t libcmis_object_getCreationDate( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ {
+ tm time = boost::posix_time::to_tm( object->handle->getCreationDate( ) );
+ return mktime( &time );
+ }
+ else
+ return 0;
+}
+
+
+char* libcmis_object_getLastModifiedBy( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getLastModifiedBy( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+time_t libcmis_object_getLastModificationDate( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ {
+ tm time = boost::posix_time::to_tm( object->handle->getLastModificationDate( ) );
+ return mktime( &time );
+ }
+ else
+ return 0;
+}
+
+
+char* libcmis_object_getChangeToken( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getChangeToken( ).c_str( ) );
+ else
+ return NULL;
+}
+
+char* libcmis_object_getThumbnailUrl( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->getThumbnailUrl( ).c_str( ) );
+ else
+ return NULL;
+}
+
+libcmis_vector_rendition_Ptr libcmis_object_getRenditions( libcmis_ObjectPtr object,
+ libcmis_ErrorPtr error )
+{
+ libcmis_vector_rendition_Ptr result = NULL;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ try
+ {
+ std::vector< libcmis::RenditionPtr > handles = object->handle->getRenditions( );
+ result = new libcmis_vector_rendition( );
+ result->handle = handles;
+ }
+
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return result;
+}
+
+bool libcmis_object_isImmutable( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return object->handle->isImmutable( );
+ else
+ return true;
+}
+
+libcmis_vector_string_Ptr libcmis_object_getSecondaryTypes( libcmis_ObjectPtr object )
+{
+ libcmis_vector_string_Ptr c_types = NULL;
+ if ( object != NULL && object->handle != NULL )
+ {
+ vector< string > types = object->handle->getSecondaryTypes( );
+ c_types = new ( nothrow ) libcmis_vector_string( );
+ if ( c_types )
+ c_types->handle = types;
+ }
+ return c_types;
+}
+
+libcmis_ObjectPtr
+libcmis_object_addSecondaryType( libcmis_ObjectPtr object,
+ const char* id,
+ libcmis_vector_property_Ptr properties,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectPtr updated = NULL;
+ if ( object != NULL && object->handle != NULL && properties != NULL )
+ {
+ try
+ {
+ PropertyPtrMap propertiesMap = lcl_createPropertiesMap( properties );
+ libcmis::ObjectPtr result = object->handle->addSecondaryType(
+ lcl_stdString( id ),
+ propertiesMap );
+ updated = new libcmis_object( );
+ updated->handle = result;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return updated;
+}
+
+libcmis_ObjectPtr
+libcmis_object_removeSecondaryType( libcmis_ObjectPtr object,
+ const char* id,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectPtr updated = NULL;
+ if ( object != NULL && object->handle != NULL )
+ {
+ try
+ {
+ libcmis::ObjectPtr result = object->handle->removeSecondaryType(
+ lcl_stdString( id ) );
+ updated = new libcmis_object( );
+ updated->handle = result;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return updated;
+}
+
+libcmis_vector_property_Ptr libcmis_object_getProperties( libcmis_ObjectPtr object )
+{
+ libcmis_vector_property_Ptr properties = NULL;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ PropertyPtrMap& handles = object->handle->getProperties( );
+ properties = new ( nothrow ) libcmis_vector_property( );
+ if ( properties )
+ {
+ int i = 0;
+ for ( PropertyPtrMap::iterator it = handles.begin( );
+ it != handles.end( ); ++it, ++i )
+ {
+ properties->handle.push_back( it->second );
+ }
+ }
+ }
+ return properties;
+}
+
+
+libcmis_PropertyPtr libcmis_object_getProperty( libcmis_ObjectPtr object, const char* name )
+{
+ libcmis_PropertyPtr property = NULL;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ PropertyPtrMap& handles = object->handle->getProperties( );
+ PropertyPtrMap::iterator it = handles.find( lcl_stdString( name ) );
+ if ( it != handles.end( ) )
+ {
+ property = new ( nothrow ) libcmis_property( );
+ if ( property )
+ property->handle = it->second;
+ }
+ }
+ return property;
+}
+
+
+libcmis_ObjectPtr libcmis_object_updateProperties(
+ libcmis_ObjectPtr object,
+ libcmis_vector_property_Ptr properties,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectPtr result = NULL;
+ if ( object != NULL && object->handle != NULL && properties != NULL )
+ {
+ try
+ {
+ // Build the map of changed properties
+ PropertyPtrMap propertiesMap = lcl_createPropertiesMap( properties );
+ libcmis::ObjectPtr handle = object->handle->updateProperties( propertiesMap );
+ result = new libcmis_object( );
+ result->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return result;
+}
+
+
+libcmis_ObjectTypePtr libcmis_object_getTypeDescription( libcmis_ObjectPtr object )
+{
+ libcmis_ObjectTypePtr result = NULL;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ result = new ( nothrow ) libcmis_object_type( );
+ if ( result )
+ result->handle = object->handle->getTypeDescription( );
+ }
+ return result;
+}
+
+
+libcmis_AllowableActionsPtr libcmis_object_getAllowableActions( libcmis_ObjectPtr object )
+{
+ libcmis_AllowableActionsPtr result = NULL;
+ if ( object != NULL && object->handle.get( ) != NULL )
+ {
+ result = new ( nothrow ) libcmis_allowable_actions( );
+ if ( result )
+ result->handle = object->handle->getAllowableActions( );
+ }
+ return result;
+}
+
+
+void libcmis_object_refresh( libcmis_ObjectPtr object, libcmis_ErrorPtr error )
+{
+ if ( object != NULL && object->handle != NULL )
+ {
+ try
+ {
+ object->handle->refresh( );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ }
+}
+
+
+time_t libcmis_object_getRefreshTimestamp( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return object->handle->getRefreshTimestamp( );
+ else
+ return 0;
+}
+
+
+void libcmis_object_remove( libcmis_ObjectPtr object, bool allVersions, libcmis_ErrorPtr error )
+{
+ if ( object != NULL && object->handle != NULL )
+ {
+ try
+ {
+ object->handle->remove( allVersions );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ }
+}
+
+
+void libcmis_object_move( libcmis_ObjectPtr object,
+ libcmis_FolderPtr source,
+ libcmis_FolderPtr dest,
+ libcmis_ErrorPtr error )
+{
+ if ( object != NULL && object->handle != NULL )
+ {
+ try
+ {
+ libcmis::FolderPtr sourceHandle;
+ if ( source != NULL )
+ sourceHandle = dynamic_pointer_cast< libcmis::Folder >( source->handle );
+ libcmis::FolderPtr destHandle;
+ if ( dest != NULL )
+ destHandle = dynamic_pointer_cast< libcmis::Folder >( dest->handle );
+
+ object->handle->move( sourceHandle, destHandle );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ }
+}
+
+
+char* libcmis_object_toString( libcmis_ObjectPtr object )
+{
+ if ( object != NULL && object->handle != NULL )
+ return strdup( object->handle->toString( ).c_str( ) );
+ else
+ return NULL;
+}
diff --git a/src/libcmis-c/property-type.cxx b/src/libcmis-c/property-type.cxx
new file mode 100644
index 0000000..3f23939
--- /dev/null
+++ b/src/libcmis-c/property-type.cxx
@@ -0,0 +1,201 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/property-type.h>
+
+#include "internals.hxx"
+
+void libcmis_vector_property_type_free( libcmis_vector_property_type* vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_property_type_size( libcmis_vector_property_type* vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_PropertyTypePtr libcmis_vector_property_type_get( libcmis_vector_property_type* vector, size_t i )
+{
+ libcmis_PropertyTypePtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::PropertyTypePtr type = vector->handle[i];
+ item = new ( std::nothrow ) libcmis_property_type( );
+ if ( item )
+ item->handle = type;
+ }
+ return item;
+}
+
+
+void libcmis_property_type_free( libcmis_PropertyTypePtr type )
+{
+ delete type;
+}
+
+
+char* libcmis_property_type_getId( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getId( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_property_type_getLocalName( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getLocalName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_property_type_getLocalNamespace( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getLocalNamespace( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_property_type_getDisplayName( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getDisplayName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_property_type_getQueryName( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getQueryName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+libcmis_property_type_Type libcmis_property_type_getType( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return libcmis_property_type_Type( type->handle->getType( ) );
+ else
+ return libcmis_String;
+}
+
+
+char* libcmis_property_type_getXmlType( libcmis_PropertyTypePtr type )
+{
+ if ( type != NULL && type->handle.get( ) != NULL )
+ return strdup( type->handle->getXmlType( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+bool libcmis_property_type_isMultiValued( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isMultiValued( );
+ return value;
+}
+
+
+bool libcmis_property_type_isUpdatable( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isUpdatable( );
+ return value;
+}
+
+
+bool libcmis_property_type_isInherited( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isInherited( );
+ return value;
+}
+
+
+bool libcmis_property_type_isRequired( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isRequired( );
+ return value;
+}
+
+
+bool libcmis_property_type_isQueryable( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isQueryable( );
+ return value;
+}
+
+
+bool libcmis_property_type_isOrderable( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isOrderable( );
+ return value;
+}
+
+
+bool libcmis_property_type_isOpenChoice( libcmis_PropertyTypePtr type )
+{
+ bool value = false;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ value = type->handle->isOpenChoice( );
+ return value;
+}
+
+void libcmis_property_type_update( libcmis_PropertyTypePtr propDef,
+ libcmis_vector_object_type_Ptr types )
+{
+ if ( propDef != NULL && propDef->handle.get( ) != NULL && types != NULL )
+ {
+ std::vector< libcmis::ObjectTypePtr > typesHandle = types->handle;
+ propDef->handle->update( typesHandle );
+ }
+}
diff --git a/src/libcmis-c/property.cxx b/src/libcmis-c/property.cxx
new file mode 100644
index 0000000..2886d55
--- /dev/null
+++ b/src/libcmis-c/property.cxx
@@ -0,0 +1,200 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/property.h>
+
+#include "internals.hxx"
+
+using namespace std;
+
+
+libcmis_vector_property_Ptr libcmis_vector_property_create( )
+{
+ return new ( nothrow ) libcmis_vector_property( );
+}
+
+
+void libcmis_vector_property_free( libcmis_vector_property_Ptr vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_property_size( libcmis_vector_property_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_PropertyPtr libcmis_vector_property_get( libcmis_vector_property_Ptr vector, size_t i )
+{
+ libcmis_PropertyPtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::PropertyPtr type = vector->handle[i];
+ item = new ( nothrow ) libcmis_property( );
+ if ( item )
+ item->handle = type;
+ }
+ return item;
+}
+
+
+void libcmis_vector_property_append( libcmis_vector_property_Ptr vector, libcmis_PropertyPtr item )
+{
+ if ( vector != NULL &&
+ item != NULL && item->handle.get( ) != NULL )
+ {
+ vector->handle.push_back( item->handle );
+ }
+}
+
+
+libcmis_PropertyPtr libcmis_property_create( libcmis_PropertyTypePtr type, const char** strValues, size_t size )
+{
+ libcmis_PropertyPtr property = NULL;
+ if ( type != NULL && type->handle.get( ) != NULL )
+ {
+ property = new ( nothrow ) libcmis_property( );
+ if ( property )
+ {
+ vector< string > values;
+ for ( size_t i = 0; i < size; ++i )
+ values.push_back( string( strValues[i] ) );
+ libcmis::PropertyPtr prop( new ( nothrow ) libcmis::Property( type->handle, values ) );
+ property->handle = prop;
+ }
+ }
+
+ return property;
+}
+
+
+void libcmis_property_free( libcmis_PropertyPtr property )
+{
+ delete property;
+}
+
+
+libcmis_PropertyTypePtr libcmis_property_getPropertyType( libcmis_PropertyPtr property )
+{
+ libcmis_PropertyTypePtr type = NULL;
+ if ( property != NULL && property->handle.get( ) != NULL )
+ {
+ libcmis::PropertyTypePtr handle = property->handle->getPropertyType( );
+ type = new ( nothrow ) libcmis_property_type( );
+ if ( type )
+ type->handle = handle;
+ }
+ return type;
+}
+
+
+libcmis_vector_time_Ptr libcmis_property_getDateTimes( libcmis_PropertyPtr property )
+{
+ libcmis_vector_time_Ptr times = NULL;
+ if ( property != NULL && property->handle.get( ) != NULL )
+ {
+ vector< boost::posix_time::ptime > handles = property->handle->getDateTimes( );
+ times = new ( nothrow ) libcmis_vector_time( );
+ if ( times )
+ times->handle = handles;
+ }
+ return times;
+}
+
+
+libcmis_vector_bool_Ptr libcmis_property_getBools( libcmis_PropertyPtr property )
+{
+ libcmis_vector_bool_Ptr values = NULL;
+ if ( property != NULL && property->handle.get( ) != NULL )
+ {
+ vector< bool > handles = property->handle->getBools( );
+ values = new ( nothrow ) libcmis_vector_bool( );
+ if ( values )
+ values->handle = handles;
+ }
+ return values;
+}
+
+
+libcmis_vector_string_Ptr libcmis_property_getStrings( libcmis_PropertyPtr property )
+{
+ libcmis_vector_string_Ptr values = NULL;
+ if ( property != NULL && property->handle.get( ) != NULL )
+ {
+ vector< string > handles = property->handle->getStrings( );
+ values = new ( nothrow ) libcmis_vector_string( );
+ if ( values )
+ values->handle = handles;
+ }
+ return values;
+}
+
+
+libcmis_vector_long_Ptr libcmis_property_getLongs( libcmis_PropertyPtr property )
+{
+ libcmis_vector_long_Ptr values = NULL;
+ if ( property != NULL && property->handle.get( ) != NULL )
+ {
+ vector< long > handles = property->handle->getLongs( );
+ values = new ( nothrow ) libcmis_vector_long( );
+ if ( values )
+ values->handle = handles;
+ }
+ return values;
+}
+
+
+libcmis_vector_double_Ptr libcmis_property_getDoubles( libcmis_PropertyPtr property )
+{
+ libcmis_vector_double_Ptr values = NULL;
+ if ( property != NULL && property->handle.get( ) != NULL )
+ {
+ vector< double > handles = property->handle->getDoubles( );
+ values = new ( nothrow ) libcmis_vector_double( );
+ if ( values )
+ values->handle = handles;
+ }
+ return values;
+}
+
+
+void libcmis_property_setValues( libcmis_PropertyPtr property, const char** strValues, size_t size )
+{
+ if ( property != NULL && property->handle.get() != NULL )
+ {
+ vector< string > values;
+ for ( size_t i = 0; i < size; ++i )
+ values.push_back( string( strValues[i] ) );
+ property->handle->setValues( values );
+ }
+}
diff --git a/src/libcmis-c/rendition.cxx b/src/libcmis-c/rendition.cxx
new file mode 100644
index 0000000..8adfd42
--- /dev/null
+++ b/src/libcmis-c/rendition.cxx
@@ -0,0 +1,110 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/rendition.h>
+
+#include "internals.hxx"
+
+using namespace std;
+
+void libcmis_rendition_free( libcmis_RenditionPtr rendition )
+{
+ delete rendition;
+}
+
+bool libcmis_rendition_isThumbnail( libcmis_RenditionPtr rendition )
+{
+ bool result = false;
+ if ( rendition != NULL && rendition->handle != NULL )
+ result = rendition->handle->isThumbnail();
+ return result;
+}
+
+const char* libcmis_rendition_getStreamId( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getStreamId().c_str();
+ return NULL;
+}
+
+const char* libcmis_rendition_getMimeType( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getMimeType().c_str();
+ return NULL;
+}
+
+const char* libcmis_rendition_getKind( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getKind().c_str();
+ return NULL;
+}
+
+const char* libcmis_rendition_getUrl( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getUrl().c_str();
+ return NULL;
+}
+
+const char* libcmis_rendition_getTitle( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getTitle().c_str();
+ return NULL;
+}
+
+long libcmis_rendition_getLength( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getLength();
+ return -1;
+}
+
+long libcmis_rendition_getWidth( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getWidth();
+ return -1;
+}
+
+long libcmis_rendition_getHeight( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getHeight();
+ return -1;
+}
+
+const char* libcmis_rendition_getRenditionDocumentId( libcmis_RenditionPtr rendition )
+{
+ if ( rendition != NULL && rendition->handle != NULL )
+ return rendition->handle->getRenditionDocumentId().c_str();
+ return NULL;
+}
+
diff --git a/src/libcmis-c/repository.cxx b/src/libcmis-c/repository.cxx
new file mode 100644
index 0000000..41169a1
--- /dev/null
+++ b/src/libcmis-c/repository.cxx
@@ -0,0 +1,208 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/repository.h>
+
+#include "internals.hxx"
+
+using std::nothrow;
+
+void libcmis_vector_repository_free( libcmis_vector_Repository_Ptr vector )
+{
+ delete vector;
+}
+
+
+size_t libcmis_vector_repository_size( libcmis_vector_Repository_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+
+libcmis_RepositoryPtr libcmis_vector_repository_get( libcmis_vector_Repository_Ptr vector, size_t i )
+{
+ libcmis_RepositoryPtr item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ libcmis::RepositoryPtr type = vector->handle[i];
+ item = new ( nothrow ) libcmis_repository( );
+ if ( item )
+ item->handle = type;
+ }
+ return item;
+}
+
+
+libcmis_RepositoryPtr libcmis_repository_create( xmlNodePtr node )
+{
+ libcmis_RepositoryPtr repository = new ( nothrow ) libcmis_repository( );
+
+ if ( repository )
+ {
+ libcmis::RepositoryPtr handle( new ( nothrow ) libcmis::Repository( node ) );
+ repository->handle = handle;
+ }
+
+ return repository;
+}
+
+
+void libcmis_repository_free( libcmis_RepositoryPtr repository )
+{
+ delete repository;
+}
+
+
+char* libcmis_repository_getId( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getId( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getName( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getDescription( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getDescription( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getVendorName( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getVendorName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getProductName( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getProductName( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getProductVersion( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getProductVersion( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getRootId( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getRootId( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getCmisVersionSupported( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ return strdup( repository->handle->getCmisVersionSupported( ).c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getThinClientUri( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL &&
+ repository->handle->getThinClientUri( ).get( ) != NULL )
+ return strdup( repository->handle->getThinClientUri( )->c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getPrincipalAnonymous( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL &&
+ repository->handle->getPrincipalAnonymous( ).get( ) != NULL )
+ return strdup( repository->handle->getPrincipalAnonymous( )->c_str( ) );
+ else
+ return NULL;
+}
+
+
+char* libcmis_repository_getPrincipalAnyone( libcmis_RepositoryPtr repository )
+{
+ if ( repository != NULL && repository->handle != NULL &&
+ repository->handle->getPrincipalAnyone( ).get( ) != NULL )
+ return strdup( repository->handle->getPrincipalAnyone( )->c_str( ) );
+ else
+ return NULL;
+}
+
+char* libcmis_repository_getCapability(
+ libcmis_RepositoryPtr repository,
+ libcmis_repository_capability_Type capability )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ {
+ std::string value = repository->handle->getCapability( ( libcmis::Repository::Capability ) capability );
+ return strdup( value.c_str( ) );
+ }
+ else
+ return NULL;
+}
+
+bool libcmis_repository_getCapabilityAsBool(
+ libcmis_RepositoryPtr repository,
+ libcmis_repository_capability_Type capability )
+{
+ if ( repository != NULL && repository->handle != NULL )
+ {
+ return repository->handle->getCapabilityAsBool( ( libcmis::Repository::Capability ) capability );
+ }
+ else
+ return false;
+}
diff --git a/src/libcmis-c/session-factory.cxx b/src/libcmis-c/session-factory.cxx
new file mode 100644
index 0000000..cee4532
--- /dev/null
+++ b/src/libcmis-c/session-factory.cxx
@@ -0,0 +1,239 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/session-factory.h>
+
+#include <map>
+#include <string>
+#include <stdlib.h>
+
+#include <libcmis/session-factory.hxx>
+
+#include <libcmis-c/session.h>
+#include <libcmis-c/vectors.h>
+
+#include "internals.hxx"
+
+using namespace std;
+
+namespace
+{
+ size_t const CRED_MAX_LEN = 1024;
+
+ class WrapperAuthProvider : public libcmis::AuthProvider
+ {
+ private:
+ libcmis_authenticationCallback m_callback;
+
+ public:
+ WrapperAuthProvider( libcmis_authenticationCallback callback ) :
+ m_callback( callback )
+ {
+ }
+ virtual ~WrapperAuthProvider( ) { };
+
+ virtual bool authenticationQuery( string& username, string& password );
+ };
+
+ bool WrapperAuthProvider::authenticationQuery( string& username, string& password )
+ {
+ /* NOTE: As I understand this, the callback is responsible for
+ * filling the correct username and password (possibly using
+ * the passed values as defaults in some dialog or so). But then
+ * there is no guarantee that the new username/password will
+ * not be longer than the present one, in which case it will
+ * not fit into the available space! For now, use a buffer size
+ * big enough for practical purposes.
+ *
+ * It might be a better idea to change the callback's signature
+ * to bool ( * )( char** username, char** password )
+ * and make it the callee's responsibility to reallocate the
+ * strings if it needs to.
+ */
+ char user[CRED_MAX_LEN];
+ strncpy(user, username.c_str( ), sizeof( user ) );
+ user[CRED_MAX_LEN - 1] = '\0';
+ char pass[CRED_MAX_LEN];
+ strncpy(pass, password.c_str( ), sizeof( pass ) );
+ pass[CRED_MAX_LEN - 1] = '\0';
+
+ bool result = m_callback( user, pass );
+
+ // Update the username and password with the input
+ username = user;
+ password = pass;
+
+ return result;
+ }
+
+
+ class WrapperCertHandler : public libcmis::CertValidationHandler
+ {
+ private:
+ libcmis_certValidationCallback m_callback;
+ public:
+ WrapperCertHandler( libcmis_certValidationCallback callback ) :
+ m_callback( callback )
+ {
+ }
+ virtual ~WrapperCertHandler( ) { };
+
+ virtual bool validateCertificate( vector< string > certificatesChain );
+ };
+
+ bool WrapperCertHandler::validateCertificate( vector< string > certificatesChain )
+ {
+ libcmis_vector_string_Ptr chain = new ( nothrow ) libcmis_vector_string( );
+ if ( chain )
+ chain->handle = certificatesChain;
+
+ bool result = m_callback( chain );
+
+ libcmis_vector_string_free( chain );
+ return result;
+ }
+}
+
+std::string createString( char* str )
+{
+ if ( str )
+ return string( str );
+ else
+ return string( );
+}
+
+void libcmis_setAuthenticationCallback( libcmis_authenticationCallback callback )
+{
+ libcmis::AuthProviderPtr provider( new ( nothrow ) WrapperAuthProvider( callback ) );
+ if ( provider )
+ libcmis::SessionFactory::setAuthenticationProvider( provider );
+}
+
+void libcmis_setCertValidationCallback( libcmis_certValidationCallback callback )
+{
+ libcmis::CertValidationHandlerPtr handler( new ( nothrow )WrapperCertHandler( callback ) );
+ if ( handler )
+ libcmis::SessionFactory::setCertificateValidationHandler( handler );
+}
+
+void libcmis_setOAuth2AuthCodeProvider( libcmis_oauth2AuthCodeProvider callback )
+{
+ libcmis::SessionFactory::setOAuth2AuthCodeProvider( callback );
+}
+
+libcmis_oauth2AuthCodeProvider libcmis_getOAuth2AuthCodeProvider( )
+{
+ return libcmis::SessionFactory::getOAuth2AuthCodeProvider( );
+}
+
+void libcmis_setProxySettings( char* proxy, char* noProxy,
+ char* proxyUser, char* proxyPass )
+{
+ libcmis::SessionFactory::setProxySettings( string( proxy ), string( noProxy ),
+ string( proxyUser ), string( proxyPass ) );
+}
+
+const char* libcmis_getProxy( )
+{
+ return libcmis::SessionFactory::getProxy( ).c_str();
+}
+
+const char* libcmis_getNoProxy( )
+{
+ return libcmis::SessionFactory::getNoProxy( ).c_str();
+}
+
+const char* libcmis_getProxyUser( )
+{
+ return libcmis::SessionFactory::getProxyUser( ).c_str();
+}
+
+const char* libcmis_getProxyPass( )
+{
+ return libcmis::SessionFactory::getProxyPass( ).c_str();
+}
+
+libcmis_SessionPtr libcmis_createSession(
+ char* bindingUrl,
+ char* repositoryId,
+ char* username,
+ char* password,
+ bool noSslCheck,
+ libcmis_OAuth2DataPtr oauth2,
+ bool verbose,
+ libcmis_ErrorPtr error )
+{
+ libcmis_SessionPtr session = NULL;
+
+ try
+ {
+ libcmis::OAuth2DataPtr oauth2Handle;
+ if ( oauth2 != NULL )
+ oauth2Handle = oauth2->handle;
+
+ libcmis::Session* handle = libcmis::SessionFactory::createSession(
+ createString( bindingUrl ),
+ createString( username ),
+ createString( password ),
+ createString( repositoryId ), noSslCheck, oauth2Handle, verbose );
+ session = new libcmis_session( );
+ session->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+
+ return session;
+}
+
+libcmis_vector_Repository_Ptr libcmis_getRepositories(
+ char* bindingUrl,
+ char* username,
+ char* password,
+ bool verbose,
+ libcmis_ErrorPtr error )
+{
+ libcmis_SessionPtr session = libcmis_createSession(
+ bindingUrl, NULL, username, password, false, NULL, verbose, error );
+ libcmis_vector_Repository_Ptr repositories = libcmis_session_getRepositories( session );
+ libcmis_session_free( session );
+ return repositories;
+}
diff --git a/src/libcmis-c/session.cxx b/src/libcmis-c/session.cxx
new file mode 100644
index 0000000..df6b503
--- /dev/null
+++ b/src/libcmis-c/session.cxx
@@ -0,0 +1,305 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/session.h>
+
+#include <utility>
+
+#include "internals.hxx"
+
+using namespace std;
+
+void libcmis_session_free( libcmis_SessionPtr session )
+{
+ if ( session != NULL )
+ {
+ delete session->handle;
+ delete session;
+ }
+}
+
+libcmis_RepositoryPtr libcmis_session_getRepository(
+ libcmis_SessionPtr session,
+ libcmis_ErrorPtr error )
+{
+ libcmis_RepositoryPtr repository = NULL;
+
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ libcmis::RepositoryPtr handle = session->handle->getRepository( );
+ if ( handle )
+ {
+ repository = new ( nothrow ) libcmis_repository( );
+ if ( repository )
+ repository->handle = handle;
+ }
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ }
+
+ return repository;
+}
+
+libcmis_vector_Repository_Ptr libcmis_session_getRepositories( libcmis_SessionPtr session )
+{
+ libcmis_vector_Repository_Ptr result = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ vector< libcmis::RepositoryPtr > handles = session->handle->getRepositories();
+ result = new ( nothrow ) libcmis_vector_repository( );
+ if ( result )
+ result->handle = handles;
+ }
+
+ return result;
+}
+
+bool libcmis_session_setRepository( libcmis_SessionPtr session, const char* id )
+{
+ bool success = false;
+ if ( session && session->handle && id )
+ {
+ success = session->handle->setRepository( id );
+ }
+ return success;
+}
+
+libcmis_FolderPtr libcmis_session_getRootFolder(
+ libcmis_SessionPtr session,
+ libcmis_ErrorPtr error )
+{
+ libcmis_FolderPtr folder = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ libcmis::FolderPtr handle = session->handle->getRootFolder( );
+ folder = new libcmis_folder( );
+ folder->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return folder;
+}
+
+
+libcmis_ObjectPtr libcmis_session_getObject(
+ libcmis_SessionPtr session,
+ const char* id,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectPtr object = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ libcmis::ObjectPtr handle = session->handle->getObject( string( id ) );
+ object = new libcmis_object( );
+ object->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return object;
+}
+
+
+libcmis_ObjectPtr libcmis_session_getObjectByPath(
+ libcmis_SessionPtr session,
+ const char* path,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectPtr object = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ libcmis::ObjectPtr handle = session->handle->getObjectByPath( string( path ) );
+ object = new libcmis_object( );
+ object->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return object;
+}
+
+
+libcmis_FolderPtr libcmis_session_getFolder(
+ libcmis_SessionPtr session,
+ const char* id,
+ libcmis_ErrorPtr error )
+{
+ libcmis_FolderPtr folder = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ libcmis::FolderPtr handle = session->handle->getFolder( string( id ) );
+ folder = new libcmis_folder( );
+ folder->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return folder;
+}
+
+
+libcmis_ObjectTypePtr libcmis_session_getType(
+ libcmis_SessionPtr session,
+ const char* id,
+ libcmis_ErrorPtr error )
+{
+ libcmis_ObjectTypePtr type = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ libcmis::ObjectTypePtr handle = session->handle->getType( string( id ) );
+ type = new libcmis_object_type( );
+ type->handle = handle;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return type;
+}
+
+libcmis_vector_object_type_Ptr libcmis_session_getBaseTypes(
+ libcmis_SessionPtr session,
+ libcmis_ErrorPtr error )
+{
+ libcmis_vector_object_type_Ptr types = NULL;
+ if ( session != NULL && session->handle != NULL )
+ {
+ try
+ {
+ vector< libcmis::ObjectTypePtr > handles = session->handle->getBaseTypes( );
+ types = new libcmis_vector_object_type( );
+ types->handle = handles;
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->type = strdup( e.getType().c_str() );
+ }
+ }
+ catch ( const bad_alloc& e )
+ {
+ if ( error != NULL )
+ {
+ error->message = strdup( e.what() );
+ error->badAlloc = true;
+ }
+ }
+ }
+ return types;
+}
diff --git a/src/libcmis-c/vectors.cxx b/src/libcmis-c/vectors.cxx
new file mode 100644
index 0000000..e520751
--- /dev/null
+++ b/src/libcmis-c/vectors.cxx
@@ -0,0 +1,139 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis-c/vectors.h>
+
+#include "internals.hxx"
+
+void libcmis_vector_bool_free( libcmis_vector_bool_Ptr vector )
+{
+ delete vector;
+}
+
+size_t libcmis_vector_bool_size( libcmis_vector_bool_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+bool libcmis_vector_bool_get( libcmis_vector_bool_Ptr vector, size_t i )
+{
+ bool item = false;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ item = vector->handle[i];
+ return item;
+}
+
+void libcmis_vector_string_free( libcmis_vector_string_Ptr vector )
+{
+ delete vector;
+}
+
+size_t libcmis_vector_string_size( libcmis_vector_string_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+const char* libcmis_vector_string_get( libcmis_vector_string_Ptr vector, size_t i )
+{
+ const char* item = NULL;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ item = vector->handle[i].c_str( );
+ return item;
+}
+
+void libcmis_vector_long_free( libcmis_vector_long_Ptr vector )
+{
+ delete vector;
+}
+
+size_t libcmis_vector_long_size( libcmis_vector_long_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+long libcmis_vector_long_get( libcmis_vector_long_Ptr vector, size_t i )
+{
+ long item = 0;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ item = vector->handle[i];
+ return item;
+}
+
+void libcmis_vector_double_free( libcmis_vector_double_Ptr vector )
+{
+ delete vector;
+}
+
+size_t libcmis_vector_double_size( libcmis_vector_double_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+double libcmis_vector_double_get( libcmis_vector_double_Ptr vector, size_t i )
+{
+ double item = 0.0;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ item = vector->handle[i];
+ return item;
+}
+
+void libcmis_vector_time_free( libcmis_vector_time_Ptr vector )
+{
+ delete vector;
+}
+
+size_t libcmis_vector_time_size( libcmis_vector_time_Ptr vector )
+{
+ size_t size = 0;
+ if ( vector != NULL )
+ size = vector->handle.size( );
+ return size;
+}
+
+time_t libcmis_vector_time_get( libcmis_vector_time_Ptr vector, size_t i )
+{
+ time_t item = 0;
+ if ( vector != NULL && i < vector->handle.size( ) )
+ {
+ tm time = boost::posix_time::to_tm( vector->handle[i] );
+ item = mktime( &time );
+ }
+ return item;
+}
diff --git a/src/libcmis/Makefile.am b/src/libcmis/Makefile.am
new file mode 100644
index 0000000..bc924f9
--- /dev/null
+++ b/src/libcmis/Makefile.am
@@ -0,0 +1,147 @@
+AM_CXXFLAGS = \
+ -I$(top_srcdir)/inc \
+ -I$(top_srcdir)/src/libcmis \
+ $(XML2_CFLAGS) \
+ $(CURL_CFLAGS) \
+ $(BOOST_CPPFLAGS)
+
+if ENABLE_VISIBILITY
+AM_CXXFLAGS += -fvisibility=hidden
+endif
+
+noinst_LTLIBRARIES = libcmis.la
+
+lib_LTLIBRARIES = libcmis-@LIBCMIS_API_VERSION@.la
+
+libcmis_@LIBCMIS_API_VERSION@_la_SOURCES = \
+ dummy.cxx
+
+libcmis_la_CPPFLAGS = -DLIBCMIS_BUILD
+if ENABLE_VISIBILITY
+libcmis_la_CPPFLAGS += -DLIBCMIS_VISIBILITY
+endif
+
+libcmis_la_SOURCES = \
+ allowable-actions.cxx \
+ atom-document.cxx \
+ atom-document.hxx \
+ atom-folder.cxx \
+ atom-folder.hxx \
+ atom-object-type.cxx \
+ atom-object-type.hxx \
+ atom-object.cxx \
+ atom-object.hxx \
+ atom-session.cxx \
+ atom-session.hxx \
+ atom-workspace.cxx \
+ atom-workspace.hxx \
+ base-session.cxx \
+ base-session.hxx \
+ document.cxx \
+ folder.cxx \
+ gdrive-allowable-actions.hxx \
+ gdrive-document.cxx \
+ gdrive-document.hxx \
+ gdrive-folder.cxx \
+ gdrive-folder.hxx \
+ gdrive-object-type.cxx \
+ gdrive-object-type.hxx \
+ gdrive-object.cxx \
+ gdrive-object.hxx \
+ gdrive-property.cxx \
+ gdrive-property.hxx \
+ gdrive-repository.cxx \
+ gdrive-repository.hxx \
+ gdrive-session.cxx \
+ gdrive-session.hxx \
+ gdrive-utils.cxx \
+ gdrive-utils.hxx \
+ http-session.cxx \
+ http-session.hxx \
+ json-utils.cxx \
+ json-utils.hxx \
+ oauth2-data.cxx \
+ oauth2-handler.cxx \
+ oauth2-handler.hxx \
+ oauth2-providers.cxx \
+ oauth2-providers.hxx \
+ object-type.cxx \
+ object.cxx \
+ onedrive-allowable-actions.hxx \
+ onedrive-document.cxx \
+ onedrive-document.hxx \
+ onedrive-folder.cxx \
+ onedrive-folder.hxx \
+ onedrive-object-type.cxx \
+ onedrive-object-type.hxx \
+ onedrive-object.cxx \
+ onedrive-object.hxx \
+ onedrive-property.cxx \
+ onedrive-property.hxx \
+ onedrive-repository.cxx \
+ onedrive-repository.hxx \
+ onedrive-session.cxx \
+ onedrive-session.hxx \
+ onedrive-utils.cxx \
+ onedrive-utils.hxx \
+ property-type.cxx \
+ property.cxx \
+ rendition.cxx \
+ repository.cxx \
+ session-factory.cxx \
+ sharepoint-allowable-actions.hxx \
+ sharepoint-document.cxx \
+ sharepoint-document.hxx \
+ sharepoint-folder.cxx \
+ sharepoint-folder.hxx \
+ sharepoint-object-type.cxx \
+ sharepoint-object-type.hxx \
+ sharepoint-object.cxx \
+ sharepoint-object.hxx \
+ sharepoint-property.cxx \
+ sharepoint-property.hxx \
+ sharepoint-repository.cxx \
+ sharepoint-repository.hxx \
+ sharepoint-session.cxx \
+ sharepoint-session.hxx \
+ sharepoint-utils.cxx \
+ sharepoint-utils.hxx \
+ ws-document.cxx \
+ ws-document.hxx \
+ ws-folder.cxx \
+ ws-folder.hxx \
+ ws-navigationservice.cxx \
+ ws-navigationservice.hxx \
+ ws-object-type.cxx \
+ ws-object-type.hxx \
+ ws-object.cxx \
+ ws-object.hxx \
+ ws-objectservice.cxx \
+ ws-objectservice.hxx \
+ ws-relatedmultipart.cxx \
+ ws-relatedmultipart.hxx \
+ ws-repositoryservice.cxx \
+ ws-repositoryservice.hxx \
+ ws-requests.cxx \
+ ws-requests.hxx \
+ ws-session.cxx \
+ ws-session.hxx \
+ ws-soap.cxx \
+ ws-soap.hxx \
+ ws-versioningservice.cxx \
+ ws-versioningservice.hxx \
+ xml-utils.cxx
+
+# -version-info current:revision:age see https://autotools.info/libtool/version.html
+# Always increase the revision value.
+# Increase the current value whenever an interface has been added, removed or changed.
+# Increase the age value only if the changes made to the ABI are backward compatible.
+libcmis_@LIBCMIS_API_VERSION@_la_LDFLAGS = -export-dynamic -no-undefined -version-info 7:1:1
+
+libcmis_@LIBCMIS_API_VERSION@_la_LIBADD = \
+ libcmis.la \
+ $(XML2_LIBS) \
+ $(CURL_LIBS) \
+ $(BOOST_SMART_PTR_LIBS) \
+ $(BOOST_DATE_TIME_LDFLAGS) \
+ $(BOOST_DATE_TIME_LIBS)
diff --git a/src/libcmis/allowable-actions.cxx b/src/libcmis/allowable-actions.cxx
new file mode 100644
index 0000000..533069c
--- /dev/null
+++ b/src/libcmis/allowable-actions.cxx
@@ -0,0 +1,294 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/allowable-actions.hxx>
+
+#include <libcmis/object.hxx>
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ ObjectAction::ObjectAction( xmlNodePtr node ) :
+ m_type( ObjectAction::DeleteObject ),
+ m_enabled( false ),
+ m_valid( false )
+ {
+ try
+ {
+ m_type = parseType( string( ( char* ) node->name ) );
+ m_valid = true;
+ }
+ catch ( const Exception& )
+ {
+ m_valid = false;
+ }
+
+ // Invalid xsd:bool will be mean false... not sure what the spec says
+ try
+ {
+ xmlChar* content = xmlNodeGetContent( node );
+ m_enabled = parseBool( string( ( char* )content ) );
+ xmlFree( content );
+ }
+ catch ( const Exception& )
+ {
+ m_enabled = false;
+ }
+ }
+
+ ObjectAction::Type ObjectAction::parseType( string type )
+ {
+ Type value = DeleteObject;
+ if ( type == "canDeleteObject" )
+ value = DeleteObject;
+ else if ( type == "canUpdateProperties" )
+ value = UpdateProperties;
+ else if ( type == "canGetFolderTree" )
+ value = GetFolderTree;
+ else if ( type == "canGetProperties" )
+ value = GetProperties;
+ else if ( type == "canGetObjectRelationships" )
+ value = GetObjectRelationships;
+ else if ( type == "canGetObjectParents" )
+ value = GetObjectParents;
+ else if ( type == "canGetFolderParent" )
+ value = GetFolderParent;
+ else if ( type == "canGetDescendants" )
+ value = GetDescendants;
+ else if ( type == "canMoveObject" )
+ value = MoveObject;
+ else if ( type == "canDeleteContentStream" )
+ value = DeleteContentStream;
+ else if ( type == "canCheckOut" )
+ value = CheckOut;
+ else if ( type == "canCancelCheckOut" )
+ value = CancelCheckOut;
+ else if ( type == "canCheckIn" )
+ value = CheckIn;
+ else if ( type == "canSetContentStream" )
+ value = SetContentStream;
+ else if ( type == "canGetAllVersions" )
+ value = GetAllVersions;
+ else if ( type == "canAddObjectToFolder" )
+ value = AddObjectToFolder;
+ else if ( type == "canRemoveObjectFromFolder" )
+ value = RemoveObjectFromFolder;
+ else if ( type == "canGetContentStream" )
+ value = GetContentStream;
+ else if ( type == "canApplyPolicy" )
+ value = ApplyPolicy;
+ else if ( type == "canGetAppliedPolicies" )
+ value = GetAppliedPolicies;
+ else if ( type == "canRemovePolicy" )
+ value = RemovePolicy;
+ else if ( type == "canGetChildren" )
+ value = GetChildren;
+ else if ( type == "canCreateDocument" )
+ value = CreateDocument;
+ else if ( type == "canCreateFolder" )
+ value = CreateFolder;
+ else if ( type == "canCreateRelationship" )
+ value = CreateRelationship;
+ else if ( type == "canDeleteTree" )
+ value = DeleteTree;
+ else if ( type == "canGetRenditions" )
+ value = GetRenditions;
+ else if ( type == "canGetACL" )
+ value = GetACL;
+ else if ( type == "canApplyACL" )
+ value = ApplyACL;
+ else
+ throw Exception( "Invalid AllowableAction type: " + type );
+
+ return value;
+ }
+
+ AllowableActions::AllowableActions( ) :
+ m_states( )
+ {
+ }
+
+ AllowableActions::AllowableActions( xmlNodePtr node ) :
+ m_states( )
+ {
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ // Check for non text children... "\n" is also a node ;)
+ if ( !xmlNodeIsText( child ) )
+ {
+ ObjectAction action( child );
+ if ( action.isValid( ) )
+ m_states.insert( pair< libcmis::ObjectAction::Type, bool >(
+ action.getType( ),
+ action.isEnabled() ) );
+ }
+ }
+ }
+
+ AllowableActions::AllowableActions( const AllowableActions& copy ) :
+ m_states( copy.m_states )
+ {
+ }
+
+ AllowableActions::~AllowableActions( )
+ {
+ m_states.clear();
+ }
+
+ AllowableActions& AllowableActions::operator=( const AllowableActions& copy )
+ {
+ if ( this != &copy )
+ m_states = copy.m_states;
+
+ return *this;
+ }
+
+ bool AllowableActions::isAllowed( ObjectAction::Type action )
+ {
+ bool allowed = false;
+
+ map< ObjectAction::Type, bool>::iterator it = m_states.find( action );
+ if ( it != m_states.end() )
+ allowed = it->second;
+
+ return allowed;
+ }
+
+ bool AllowableActions::isDefined( ObjectAction::Type action )
+ {
+ map< ObjectAction::Type, bool>::iterator it = m_states.find( action );
+ return it != m_states.end();
+ }
+
+ // LCOV_EXCL_START
+ string AllowableActions::toString( )
+ {
+ stringstream buf;
+
+ for ( map< ObjectAction::Type, bool >::iterator it = m_states.begin( );
+ it != m_states.end( ); ++it )
+ {
+ switch ( it->first )
+ {
+ case ObjectAction::DeleteObject:
+ buf << "canDeleteObject";
+ break;
+ case ObjectAction::UpdateProperties:
+ buf << "canUpdateProperties";
+ break;
+ case ObjectAction::GetFolderTree:
+ buf << "canGetFolderTree";
+ break;
+ case ObjectAction::GetProperties:
+ buf << "canGetProperties";
+ break;
+ case ObjectAction::GetObjectRelationships:
+ buf << "canGetObjectRelationships";
+ break;
+ case ObjectAction::GetObjectParents:
+ buf << "canGetObjectParents";
+ break;
+ case ObjectAction::GetFolderParent:
+ buf << "canGetFolderParent";
+ break;
+ case ObjectAction::GetDescendants:
+ buf << "canGetDescendants";
+ break;
+ case ObjectAction::MoveObject:
+ buf << "canMoveObject";
+ break;
+ case ObjectAction::DeleteContentStream:
+ buf << "canDeleteContentStream";
+ break;
+ case ObjectAction::CheckOut:
+ buf << "canCheckOut";
+ break;
+ case ObjectAction::CancelCheckOut:
+ buf << "canCancelCheckOut";
+ break;
+ case ObjectAction::CheckIn:
+ buf << "canCheckIn";
+ break;
+ case ObjectAction::SetContentStream:
+ buf << "canSetContentStream";
+ break;
+ case ObjectAction::GetAllVersions:
+ buf << "canGetAllVersions";
+ break;
+ case ObjectAction::AddObjectToFolder:
+ buf << "canAddObjectToFolder";
+ break;
+ case ObjectAction::RemoveObjectFromFolder:
+ buf << "canRemoveObjectFromFolder";
+ break;
+ case ObjectAction::GetContentStream:
+ buf << "canGetContentStream";
+ break;
+ case ObjectAction::ApplyPolicy:
+ buf << "canApplyPolicy";
+ break;
+ case ObjectAction::GetAppliedPolicies:
+ buf << "canGetAppliedPolicies";
+ break;
+ case ObjectAction::RemovePolicy:
+ buf << "canRemovePolicy";
+ break;
+ case ObjectAction::GetChildren:
+ buf << "canGetChildren";
+ break;
+ case ObjectAction::CreateDocument:
+ buf << "canCreateDocument";
+ break;
+ case ObjectAction::CreateFolder:
+ buf << "canCreateFolder";
+ break;
+ case ObjectAction::CreateRelationship:
+ buf << "canCreateRelationship";
+ break;
+ case ObjectAction::DeleteTree:
+ buf << "canDeleteTree";
+ break;
+ case ObjectAction::GetRenditions:
+ buf << "canGetRenditions";
+ break;
+ case ObjectAction::GetACL:
+ buf << "canGetACL";
+ break;
+ case ObjectAction::ApplyACL:
+ buf << "canApplyACL";
+ break;
+ }
+ buf << ": " << it->second << endl;
+ }
+
+ return buf.str( );
+ }
+ // LCOV_EXCL_STOP
+}
diff --git a/src/libcmis/atom-document.cxx b/src/libcmis/atom-document.cxx
new file mode 100644
index 0000000..e0400b1
--- /dev/null
+++ b/src/libcmis/atom-document.cxx
@@ -0,0 +1,480 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "atom-document.hxx"
+
+#include <algorithm>
+#include <stdlib.h>
+#include <sstream>
+
+#include <curl/curl.h>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "atom-session.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+AtomDocument::AtomDocument( AtomPubSession* session ) :
+ libcmis::Object( session ),
+ libcmis::Document( session ),
+ AtomObject( session ),
+ m_contentUrl( )
+{
+}
+
+
+AtomDocument::AtomDocument( AtomPubSession* session, xmlNodePtr entryNd ) :
+ libcmis::Object( session ),
+ libcmis::Document( session ),
+ AtomObject( session ),
+ m_contentUrl( )
+{
+ xmlDocPtr doc = libcmis::wrapInDoc( entryNd );
+ refreshImpl( doc );
+ xmlFreeDoc( doc );
+}
+
+AtomDocument::~AtomDocument( )
+{
+}
+
+vector< libcmis::FolderPtr > AtomDocument::getParents( )
+{
+ AtomLink* parentsLink = getLink( "up", "" );
+
+ if ( ( NULL == parentsLink ) ||
+ ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetObjectParents ) ) )
+ throw libcmis::Exception( string( "GetObjectParents not allowed on node " ) + getId() );
+
+ vector< libcmis::FolderPtr > parents;
+
+ string buf;
+ try
+ {
+ buf = getSession()->httpGetRequest( parentsLink->getHref( ) )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), parentsLink->getHref( ).c_str(), NULL, 0 );
+ if ( NULL != doc )
+ {
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+ if ( NULL != xpathCtx )
+ {
+ const string& entriesReq( "//atom:entry" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( entriesReq.c_str() ), xpathCtx );
+
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval )
+ {
+ int size = xpathObj->nodesetval->nodeNr;
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ xmlDocPtr entryDoc = libcmis::wrapInDoc( node );
+ libcmis::ObjectPtr object = getSession()->createObjectFromEntryDoc( entryDoc );
+ libcmis::FolderPtr folder = boost::dynamic_pointer_cast< libcmis::Folder >( object );
+
+ if ( folder.get() )
+ parents.push_back( folder );
+ xmlFreeDoc( entryDoc );
+ }
+ }
+
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ {
+ throw libcmis::Exception( "Failed to parse folder infos" );
+ }
+ xmlFreeDoc( doc );
+
+ return parents;
+}
+
+boost::shared_ptr< istream > AtomDocument::getContentStream( string /*streamId*/ )
+{
+ if ( getAllowableActions().get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetContentStream ) )
+ throw libcmis::Exception( string( "GetContentStream is not allowed on document " ) + getId() );
+
+ boost::shared_ptr< istream > stream;
+ try
+ {
+ stream = getSession()->httpGetRequest( m_contentUrl )->getStream( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ return stream;
+}
+
+void AtomDocument::setContentStream( boost::shared_ptr< ostream > os, string contentType, string fileName, bool overwrite )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ if ( getAllowableActions().get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetContentStream ) )
+ throw libcmis::Exception( string( "SetContentStream is not allowed on document " ) + getId() );
+
+ string overwriteStr( "false" );
+ if ( overwrite )
+ overwriteStr = "true";
+
+ string urlPattern( m_contentUrl );
+ if ( urlPattern.find( '?' ) != string::npos )
+ urlPattern += "&";
+ else
+ urlPattern += "?";
+ urlPattern += "overwriteFlag={overwriteFlag}";
+
+ map< string, string > params;
+ params["overwriteFlag"] = overwriteStr;
+
+ // Use the changeToken if set on the object
+ if ( !getChangeToken().empty() )
+ {
+ urlPattern += "&changeToken={changeToken}";
+ params["changeToken"] = getChangeToken();
+ }
+
+ string putUrl = getSession()->createUrl( urlPattern, params );
+
+ bool tryBase64 = false;
+ do
+ {
+ try
+ {
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ if ( tryBase64 )
+ {
+ tryBase64 = false;
+
+ // Encode the content
+ stringstream* encodedIn = new stringstream( );
+ libcmis::EncodedData encoder( encodedIn );
+ encoder.setEncoding( "base64" );
+
+ int bufLength = 1000;
+ char* buf = new char[ bufLength ];
+ do
+ {
+ is->read( buf, bufLength );
+ int size = is->gcount( );
+ encoder.encode( buf, 1, size );
+ } while ( !is->eof( ) && !is->fail( ) );
+ delete[] buf;
+ encoder.finish( );
+
+ encodedIn->seekg( 0, ios_base::beg );
+ encodedIn->clear( );
+
+ is.reset( encodedIn );
+ }
+ vector< string > headers;
+ headers.push_back( string( "Content-Type: " ) + contentType );
+ if ( !fileName.empty( ) )
+ headers.push_back( string( "Content-Disposition: attachment; filename=" ) + fileName );
+ getSession()->httpPutRequest( putUrl, *is, headers );
+
+ long httpStatus = getSession( )->getHttpStatus( );
+ if ( httpStatus < 200 || httpStatus >= 300 )
+ throw libcmis::Exception( "Document content wasn't set for some reason" );
+ refresh( );
+ }
+ catch ( const CurlException& e )
+ {
+ // SharePoint wants base64 encoded content... let's try to figure out
+ // if we falled in that case.
+ if ( !tryBase64 && e.getHttpStatus() == 400 )
+ tryBase64 = true;
+ else
+ throw e.getCmisException( );
+ }
+ }
+ while ( tryBase64 );
+}
+
+libcmis::DocumentPtr AtomDocument::checkOut( )
+{
+ if ( ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::CheckOut ) ) )
+ throw libcmis::Exception( string( "CanCheckout not allowed on document " ) + getId() );
+
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ // Create a document with only the needed properties
+ PropertyPtrMap props;
+ PropertyPtrMap::iterator it = getProperties( ).find( string( "cmis:objectId" ) );
+ if ( it != getProperties( ).end( ) )
+ {
+ props.insert( *it );
+ }
+
+ boost::shared_ptr< ostream > stream;
+ AtomObject::writeAtomEntry( writer, props, stream, string( ) );
+
+ xmlTextWriterEndDocument( writer );
+ string str( ( const char * )xmlBufferContent( buf ) );
+ istringstream is( str );
+
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ libcmis::HttpResponsePtr resp;
+ string urlPattern = getSession()->getAtomRepository( )->getCollectionUrl( Collection::CheckedOut );
+ if ( urlPattern.find( "?" ) != string::npos )
+ urlPattern += "&";
+ else
+ urlPattern += "?";
+ urlPattern += "objectId={objectId}";
+
+ map< string, string > params;
+ params[ "objectId" ] = getId( );
+ string checkedOutUrl = getSession( )->createUrl( urlPattern, params );
+
+ try
+ {
+ resp = getSession( )->httpPostRequest( checkedOutUrl, is, "application/atom+xml;type=entry" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ string respBuf = resp->getStream( )->str();
+ xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), checkedOutUrl.c_str(), NULL, 0 );
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+
+ libcmis::ObjectPtr created = getSession( )->createObjectFromEntryDoc( doc, AtomPubSession::RESULT_DOCUMENT );
+ xmlFreeDoc( doc );
+
+ libcmis::DocumentPtr pwc = boost::dynamic_pointer_cast< libcmis::Document >( created );
+ if ( !pwc.get( ) )
+ throw libcmis::Exception( string( "Created object is not a document: " ) + created->getId( ) );
+
+ return pwc;
+}
+
+void AtomDocument::cancelCheckout( )
+{
+ if ( ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::CancelCheckOut ) ) )
+ throw libcmis::Exception( string( "CanCancelCheckout not allowed on document " ) + getId() );
+
+ string url = getInfosUrl( );
+
+ // Use working-copy link if provided as a workaround
+ // for some non-compliant repositories
+ AtomLink* link = getLink( "working-copy", "application/atom+xml;type=entry" );
+ if ( link )
+ url = link->getHref( );
+
+ try
+ {
+ getSession( )->httpDeleteRequest( url );
+ }
+ catch ( CurlException const& e )
+ {
+ throw e.getCmisException( );
+ }
+}
+
+libcmis::DocumentPtr AtomDocument::checkIn( bool isMajor, string comment,
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > stream, string contentType, string )
+{
+ if ( ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::CheckIn ) ) )
+ throw libcmis::Exception( string( "CanCheckIn not allowed on document " ) + getId() );
+
+ string urlPattern = getInfosUrl( );
+
+ // Use working-copy link if provided as a workaround
+ // for some non-compliant repositories
+ AtomLink* link = getLink( "working-copy", "application/atom+xml;type=entry" );
+ if ( link )
+ urlPattern = link->getHref( );
+
+ if ( urlPattern.find( "?" ) != string::npos )
+ urlPattern += "&";
+ else
+ urlPattern += "?";
+ urlPattern += "checkin=true&major={major}&checkinComment={checkinComment}";
+
+ map< string, string > params;
+
+ string majorStr = "false";
+ if ( isMajor )
+ majorStr = "true";
+ params[ "major" ] = majorStr;
+ params[ "checkinComment" ] = comment;
+ string checkInUrl = getSession( )->createUrl( urlPattern, params );
+
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ AtomObject::writeAtomEntry( writer, properties, stream, contentType );
+
+ xmlTextWriterEndDocument( writer );
+ string str( ( const char * )xmlBufferContent( buf ) );
+ istringstream is( str );
+
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ // Run the request
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ vector< string > headers;
+ headers.push_back( string( "Content-Type: application/atom+xml;type=entry" ) );
+ response = getSession( )->httpPutRequest( checkInUrl, is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ // Get the returned entry and update using it
+ string respBuf = response->getStream( )->str( );
+ xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), checkInUrl.c_str(), NULL, 0 );
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+
+
+ libcmis::ObjectPtr newVersion = getSession( )->createObjectFromEntryDoc( doc, AtomPubSession::RESULT_DOCUMENT );
+
+ if ( newVersion->getId( ) == getId( ) )
+ refreshImpl( doc );
+ xmlFreeDoc( doc );
+
+ return boost::dynamic_pointer_cast< libcmis::Document >( newVersion );
+}
+
+vector< libcmis::DocumentPtr > AtomDocument::getAllVersions( )
+{
+ if ( getAllowableActions( ).get() &&
+ !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetAllVersions ) )
+ throw libcmis::Exception( string( "GetAllVersions not allowed on node " ) + getId() );
+
+ vector< libcmis::DocumentPtr > versions;
+ AtomLink* link = getLink( "version-history", string( ) );
+ if ( link != NULL )
+ {
+ string pageUrl = link->getHref( );
+
+ string buf;
+ try
+ {
+ buf = getSession()->httpGetRequest( pageUrl )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), pageUrl.c_str(), NULL, 0 );
+ if ( NULL != doc )
+ {
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+ if ( NULL != xpathCtx )
+ {
+ // Get the entries
+ const string& entriesReq( "//atom:entry" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( entriesReq.c_str() ), xpathCtx );
+
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval )
+ {
+ int size = xpathObj->nodesetval->nodeNr;
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ xmlDocPtr entryDoc = libcmis::wrapInDoc( node );
+ libcmis::ObjectPtr cmisObject = getSession()->createObjectFromEntryDoc( entryDoc );
+ libcmis::DocumentPtr cmisDoc = boost::dynamic_pointer_cast< libcmis::Document >( cmisObject );
+
+ if ( cmisDoc.get() )
+ versions.push_back( cmisDoc );
+ xmlFreeDoc( entryDoc );
+ }
+ }
+
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ {
+ throw libcmis::Exception( "Failed to parse versions infos" );
+ }
+ xmlFreeDoc( doc );
+
+ }
+ return versions;
+}
+
+void AtomDocument::extractInfos( xmlDocPtr doc )
+{
+ AtomObject::extractInfos( doc );
+
+ // Get the content url
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ if ( NULL != doc )
+ {
+ libcmis::registerNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( "//atom:content" ), xpathCtx );
+ if ( xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 )
+ {
+ xmlNodePtr contentNd = xpathObj->nodesetval->nodeTab[0];
+ xmlChar* src = xmlGetProp( contentNd, BAD_CAST( "src" ) );
+ m_contentUrl = string( ( char* ) src );
+ xmlFree( src );
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+ xmlXPathFreeContext( xpathCtx );
+ }
+}
diff --git a/src/libcmis/atom-document.hxx b/src/libcmis/atom-document.hxx
new file mode 100644
index 0000000..40d7109
--- /dev/null
+++ b/src/libcmis/atom-document.hxx
@@ -0,0 +1,66 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ATOM_DOCUMENT_HXX_
+#define _ATOM_DOCUMENT_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "atom-object.hxx"
+
+class AtomDocument : public libcmis::Document, public AtomObject
+{
+ private:
+ std::string m_contentUrl;
+
+ public:
+ AtomDocument( AtomPubSession* session );
+ AtomDocument( AtomPubSession* session, xmlNodePtr entryNd );
+ ~AtomDocument( );
+
+ virtual std::vector< libcmis::FolderPtr > getParents( );
+
+ virtual boost::shared_ptr< std::istream > getContentStream( std::string streamId = std::string( ) );
+
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os, std::string contentType,
+ std::string fileName, bool overwrite = true );
+
+ virtual libcmis::DocumentPtr checkOut( );
+ virtual void cancelCheckout( );
+ virtual libcmis::DocumentPtr checkIn( bool isMajor, std::string comment,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType, std::string fileName );
+
+ virtual std::vector< libcmis::DocumentPtr > getAllVersions( );
+
+ protected:
+ virtual void extractInfos( xmlDocPtr doc );
+};
+
+#endif
diff --git a/src/libcmis/atom-folder.cxx b/src/libcmis/atom-folder.cxx
new file mode 100644
index 0000000..5e41194
--- /dev/null
+++ b/src/libcmis/atom-folder.cxx
@@ -0,0 +1,322 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "atom-folder.hxx"
+
+#include <sstream>
+
+#include <boost/shared_ptr.hpp>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "atom-document.hxx"
+#include "atom-session.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+namespace
+{
+}
+
+AtomFolder::AtomFolder( AtomPubSession* session, xmlNodePtr entryNd ) :
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ AtomObject( session )
+{
+ xmlDocPtr doc = libcmis::wrapInDoc( entryNd );
+ refreshImpl( doc );
+ xmlFreeDoc( doc );
+}
+
+
+AtomFolder::~AtomFolder( )
+{
+}
+
+vector< libcmis::ObjectPtr > AtomFolder::getChildren( )
+{
+ AtomLink* childrenLink = getLink( "down", "application/atom+xml;type=feed" );
+
+ // Some servers aren't giving the GetChildren properly... if not defined, we need to try
+ // as we may have the right to proceed.
+ if ( ( NULL == childrenLink ) || ( getAllowableActions( ).get() &&
+ ( !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetChildren ) &&
+ getAllowableActions()->isDefined( libcmis::ObjectAction::GetChildren ) ) ) )
+ throw libcmis::Exception( string( "GetChildren not allowed on node " ) + getId() );
+
+ vector< libcmis::ObjectPtr > children;
+
+ string pageUrl = childrenLink->getHref( );
+
+ bool hasNext = true;
+ while ( hasNext )
+ {
+ string buf;
+ try
+ {
+ buf = getSession()->httpGetRequest( pageUrl )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), pageUrl.c_str(), NULL, 0 );
+ if ( NULL != doc )
+ {
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+ if ( NULL != xpathCtx )
+ {
+ // Check if there is a next link to handled paged results
+ const string& nextReq( "/atom:feed/atom:link[@rel='next']/attribute::href" );
+ string nextHref = libcmis::getXPathValue( xpathCtx, nextReq );
+ hasNext = !nextHref.empty( );
+ if ( hasNext )
+ pageUrl = nextHref;
+
+ // Get the page entries
+ const string& entriesReq( "//atom:entry" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( entriesReq.c_str() ), xpathCtx );
+
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval )
+ {
+ int size = xpathObj->nodesetval->nodeNr;
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ xmlDocPtr entryDoc = libcmis::wrapInDoc( node );
+ libcmis::ObjectPtr cmisObject = getSession()->createObjectFromEntryDoc( entryDoc );
+
+ if ( cmisObject.get() )
+ children.push_back( cmisObject );
+ xmlFreeDoc( entryDoc );
+ }
+ }
+
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ {
+ throw libcmis::Exception( "Failed to parse folder infos" );
+ }
+ xmlFreeDoc( doc );
+ }
+
+ return children;
+}
+
+libcmis::FolderPtr AtomFolder::createFolder( const PropertyPtrMap& properties )
+{
+ AtomLink* childrenLink = getLink( "down", "application/atom+xml;type=feed" );
+
+ if ( ( NULL == childrenLink ) || ( getAllowableActions( ).get() &&
+ !getAllowableActions()->isAllowed( libcmis::ObjectAction::CreateFolder ) ) )
+ throw libcmis::Exception( string( "CreateFolder not allowed on folder " ) + getId(), "permissionDenied" );
+
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ // Copy and remove the readonly properties before serializing
+ boost::shared_ptr< ostream > stream;
+ AtomObject::writeAtomEntry( writer, properties, stream, string( ) );
+
+ xmlTextWriterEndDocument( writer );
+ string str( ( const char * )xmlBufferContent( buf ) );
+ istringstream is( str );
+
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ response = getSession( )->httpPostRequest( childrenLink->getHref( ), is, "application/atom+xml;type=entry" );
+ }
+ catch ( const CurlException& e )
+ {
+ /* 409 here is more likely to be a constraint error */
+ if ( e.getHttpStatus() == 409 ) {
+ throw libcmis::Exception( e.what(), "constraint" );
+ }
+ throw e.getCmisException( );
+ }
+
+ string respBuf = response->getStream( )->str( );
+ xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, 0 );
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+
+ libcmis::ObjectPtr created = getSession( )->createObjectFromEntryDoc( doc, AtomPubSession::RESULT_FOLDER );
+ xmlFreeDoc( doc );
+
+ libcmis::FolderPtr newFolder = boost::dynamic_pointer_cast< libcmis::Folder >( created );
+ if ( !newFolder.get( ) )
+ throw libcmis::Exception( string( "Created object is not a folder: " ) + created->getId( ), "constraint" );
+
+ return newFolder;
+}
+
+libcmis::DocumentPtr AtomFolder::createDocument( const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os, string contentType, string )
+{
+ AtomLink* childrenLink = getLink( "down", "application/atom+xml;type=feed" );
+
+ if ( ( NULL == childrenLink ) || ( getAllowableActions( ).get() &&
+ !getAllowableActions()->isAllowed( libcmis::ObjectAction::CreateDocument ) &&
+ getAllowableActions()->isDefined( libcmis::ObjectAction::CreateDocument ) ) )
+ throw libcmis::Exception( string( "CreateDocument not allowed on folder " ) + getId() );
+
+ stringstream ss;
+ xmlOutputBufferPtr buf = xmlOutputBufferCreateIO(libcmis::stringstream_write_callback, NULL, &ss, NULL);
+ xmlTextWriterPtr writer = xmlNewTextWriter(buf);
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ AtomObject::writeAtomEntry( writer, properties, os, contentType );
+
+ xmlTextWriterEndDocument( writer );
+ xmlFreeTextWriter( writer );
+
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ response = getSession( )->httpPostRequest( childrenLink->getHref( ), ss, "application/atom+xml;type=entry" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ string respBuf = response->getStream( )->str( );
+ boost::shared_ptr< xmlDoc > doc( xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, XML_PARSE_NOERROR ), xmlFreeDoc );
+ if ( !doc )
+ {
+ // We may not have the created document entry in the response body: this is
+ // the behaviour of some servers, but the standard says we need to look for
+ // the Location header.
+ map< string, string >& headers = response->getHeaders( );
+ map< string, string >::iterator it = headers.find( "Location" );
+
+ // Some servers like Lotus Live aren't sending Location header, but Content-Location
+ if ( it == headers.end( ) )
+ it = headers.find( "Content-Location" );
+
+ if ( it != headers.end() )
+ {
+ try
+ {
+ response = getSession( )->httpGetRequest( it->second );
+ respBuf = response->getStream( )->str( );
+ doc.reset( xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, XML_PARSE_NOERROR ), xmlFreeDoc );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ }
+
+ // if doc is still NULL after that, then throw an exception
+ if ( !doc )
+ throw libcmis::Exception( "Missing expected response from server" );
+ }
+
+ libcmis::ObjectPtr created = getSession( )->createObjectFromEntryDoc( doc.get(), AtomPubSession::RESULT_DOCUMENT );
+
+ libcmis::DocumentPtr newDocument = boost::dynamic_pointer_cast< libcmis::Document >( created );
+ if ( !newDocument.get( ) )
+ throw libcmis::Exception( string( "Created object is not a document: " ) + created->getId( ) );
+
+ return newDocument;
+}
+
+vector< string > AtomFolder::removeTree( bool allVersions, libcmis::UnfileObjects::Type unfile,
+ bool continueOnError )
+{
+ AtomLink* treeLink = getLink( "down", "application/cmistree+xml" );
+ if ( NULL == treeLink )
+ treeLink = getLink( "http://docs.oasis-open.org/ns/cmis/link/200908/foldertree", "application/cmistree+xml" );
+
+ if ( ( NULL == treeLink ) || ( getAllowableActions( ).get() &&
+ !getAllowableActions()->isAllowed( libcmis::ObjectAction::DeleteTree ) ) )
+ throw libcmis::Exception( string( "DeleteTree not allowed on folder " ) + getId() );
+
+ try
+ {
+ string deleteUrl = treeLink->getHref( );
+ if ( deleteUrl.find( '?' ) != string::npos )
+ deleteUrl += "&";
+ else
+ deleteUrl += "?";
+
+ // Add the all versions parameter
+ string allVersionsStr = "TRUE";
+ if ( !allVersions )
+ allVersionsStr = "FALSE";
+ deleteUrl += "allVersions=" + allVersionsStr;
+
+ // Add the unfileObjects parameter
+ string unfileStr;
+ switch ( unfile )
+ {
+ case libcmis::UnfileObjects::Delete:
+ unfileStr = "delete";
+ break;
+ case libcmis::UnfileObjects::DeleteSingleFiled:
+ unfileStr = "deletesinglefiled";
+ break;
+ case libcmis::UnfileObjects::Unfile:
+ unfileStr = "unfile";
+ break;
+ default:
+ break;
+ }
+ deleteUrl += "&unfileObjects=" + unfileStr;
+
+ // Add the continueOnFailure parameter
+ string continueOnErrorStr = "TRUE";
+ if ( !continueOnError )
+ continueOnErrorStr = "FALSE";
+ deleteUrl += "&continueOnFailure=" + continueOnErrorStr;
+
+ getSession( )->httpDeleteRequest( deleteUrl );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ // TODO Implement getting the failedIDs using a GET request on the same URL
+ return vector< string >( );
+}
diff --git a/src/libcmis/atom-folder.hxx b/src/libcmis/atom-folder.hxx
new file mode 100644
index 0000000..8137487
--- /dev/null
+++ b/src/libcmis/atom-folder.hxx
@@ -0,0 +1,56 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ATOM_FOLDER_HXX_
+#define _ATOM_FOLDER_HXX_
+
+#include <string>
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "atom-object.hxx"
+
+class AtomFolder : public libcmis::Folder, public AtomObject
+{
+ public:
+ AtomFolder( AtomPubSession* session, xmlNodePtr entryNd );
+ ~AtomFolder( );
+
+ // virtual pure methods from Folder
+ virtual std::vector< libcmis::ObjectPtr > getChildren( );
+
+ virtual libcmis::FolderPtr createFolder( const std::map< std::string, libcmis::PropertyPtr >& properties );
+ virtual libcmis::DocumentPtr createDocument( const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > os, std::string contentType, std::string fileName );
+
+ virtual std::vector< std::string > removeTree( bool allVersion = true,
+ libcmis::UnfileObjects::Type unfile = libcmis::UnfileObjects::Delete,
+ bool continueOnError = false );
+};
+
+#endif
diff --git a/src/libcmis/atom-object-type.cxx b/src/libcmis/atom-object-type.cxx
new file mode 100644
index 0000000..8f50d04
--- /dev/null
+++ b/src/libcmis/atom-object-type.cxx
@@ -0,0 +1,167 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "atom-object-type.hxx"
+
+#include <sstream>
+
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+using namespace boost;
+
+
+AtomObjectType::AtomObjectType( AtomPubSession* session, string id ) :
+ libcmis::ObjectType( ),
+ m_session( session ),
+ m_selfUrl( ),
+ m_childrenUrl( )
+{
+ m_id = id;
+ refresh( );
+}
+
+AtomObjectType::AtomObjectType( AtomPubSession* session, xmlNodePtr entryNd ) :
+ libcmis::ObjectType( ),
+ m_session( session ),
+ m_selfUrl( ),
+ m_childrenUrl( )
+{
+ xmlDocPtr doc = libcmis::wrapInDoc( entryNd );
+ refreshImpl( doc );
+ xmlFreeDoc( doc );
+}
+
+AtomObjectType::AtomObjectType( const AtomObjectType& copy ) :
+ libcmis::ObjectType( copy ),
+ m_session( copy.m_session ),
+ m_selfUrl( copy.m_selfUrl ),
+ m_childrenUrl( copy.m_childrenUrl )
+{
+}
+
+AtomObjectType::~AtomObjectType( )
+{
+}
+
+AtomObjectType& AtomObjectType::operator=( const AtomObjectType& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::ObjectType::operator=( copy );
+ m_session = copy.m_session;
+ m_selfUrl = copy.m_selfUrl;
+ m_childrenUrl = copy.m_childrenUrl;
+ }
+
+ return *this;
+}
+
+libcmis::ObjectTypePtr AtomObjectType::getParentType( )
+{
+ return m_session->getType( m_parentTypeId );
+}
+
+libcmis::ObjectTypePtr AtomObjectType::getBaseType( )
+{
+ return m_session->getType( m_baseTypeId );
+}
+
+vector< libcmis::ObjectTypePtr > AtomObjectType::getChildren( )
+{
+ return m_session->getChildrenTypes( m_childrenUrl );
+}
+
+void AtomObjectType::refreshImpl( xmlDocPtr doc )
+{
+ bool createdDoc = ( NULL == doc );
+ if ( createdDoc )
+ {
+ string pattern = m_session->getAtomRepository()->getUriTemplate( UriTemplate::TypeById );
+ map< string, string > vars;
+ vars[URI_TEMPLATE_VAR_ID] = getId( );
+ string url = m_session->createUrl( pattern, vars );
+
+ string buf;
+ try
+ {
+ buf = m_session->httpGetRequest( url )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ if ( ( e.getErrorCode( ) == CURLE_HTTP_RETURNED_ERROR ) &&
+ ( e.getHttpStatus( ) == 404 ) )
+ {
+ string msg = "No such type: ";
+ msg += getId( );
+ throw libcmis::Exception( msg, "objectNotFound" );
+ }
+ else
+ throw e.getCmisException( );
+ }
+
+ doc = xmlReadMemory( buf.c_str(), buf.size(), m_selfUrl.c_str(), NULL, 0 );
+
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+ }
+
+ extractInfos( doc );
+
+ if ( createdDoc )
+ xmlFreeDoc( doc );
+}
+
+void AtomObjectType::extractInfos( xmlDocPtr doc )
+{
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+
+ // Register the Service Document namespaces
+ libcmis::registerNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ // Get the self URL
+ string selfUrlReq( "//atom:link[@rel='self']/attribute::href" );
+ m_selfUrl = libcmis::getXPathValue( xpathCtx, selfUrlReq );
+
+ // Get the children URL
+ string childrenUrlReq( "//atom:link[@rel='down' and @type='application/atom+xml;type=feed']/attribute::href" );
+ m_childrenUrl = libcmis::getXPathValue( xpathCtx, childrenUrlReq );
+
+ // Get the cmisra:type node
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( "//cmisra:type" ), xpathCtx );
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval && xpathObj->nodesetval->nodeNr )
+ {
+ xmlNodePtr typeNode = xpathObj->nodesetval->nodeTab[0];
+ initializeFromNode( typeNode );
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+ xmlXPathFreeContext( xpathCtx );
+}
diff --git a/src/libcmis/atom-object-type.hxx b/src/libcmis/atom-object-type.hxx
new file mode 100644
index 0000000..c4c80dd
--- /dev/null
+++ b/src/libcmis/atom-object-type.hxx
@@ -0,0 +1,63 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ATOM_OBJECT_TYPE_HXX_
+#define _ATOM_OBJECT_TYPE_HXX_
+
+#include <libcmis/object-type.hxx>
+
+#include "atom-session.hxx"
+
+class AtomObjectType : public libcmis::ObjectType
+{
+ private:
+ AtomPubSession* m_session;
+
+ std::string m_selfUrl;
+ std::string m_childrenUrl;
+
+ public:
+ AtomObjectType( AtomPubSession* session, std::string id );
+ AtomObjectType( AtomPubSession* session, xmlNodePtr node );
+ AtomObjectType( const AtomObjectType& copy );
+ virtual ~AtomObjectType( );
+
+ AtomObjectType& operator=( const AtomObjectType& copy );
+
+ virtual void refresh( ) { refreshImpl( NULL ); }
+
+ virtual libcmis::ObjectTypePtr getParentType( );
+ virtual libcmis::ObjectTypePtr getBaseType( );
+ virtual std::vector< libcmis::ObjectTypePtr > getChildren( );
+
+ private:
+
+ void refreshImpl( xmlDocPtr doc );
+ void extractInfos( xmlDocPtr doc );
+};
+
+#endif
diff --git a/src/libcmis/atom-object.cxx b/src/libcmis/atom-object.cxx
new file mode 100644
index 0000000..65332f6
--- /dev/null
+++ b/src/libcmis/atom-object.cxx
@@ -0,0 +1,486 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "atom-object.hxx"
+
+#include <algorithm>
+#include <locale>
+#include <sstream>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "atom-document.hxx"
+#include "atom-folder.hxx"
+#include "atom-object-type.hxx"
+#include "atom-session.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+namespace
+{
+ class MatchLink
+ {
+ private:
+ string m_rel;
+ string m_type;
+
+ public:
+ MatchLink( string rel, string type ) : m_rel( rel ), m_type( type ) { }
+ bool operator() ( const AtomLink &link )
+ {
+ bool matchesRel = link.getRel( ) == m_rel;
+
+ // Some implementations (xcmis) put extra spaces into the type attribute
+ // (e.g. "application/atom+xml; type=feed" instead of "application/atom+xml;type=feed")
+ string linkType = link.getType( );
+ linkType.erase( remove_if( linkType.begin(), linkType.end(), boost::is_space() ), linkType.end() );
+
+ // Some implementation (SharePoint) are omitting the type attribute
+ bool matchesType = m_type.empty( ) || linkType.empty() || ( linkType == m_type );
+ return matchesRel && matchesType;
+ }
+ };
+}
+
+AtomObject::AtomObject( AtomPubSession* session ) :
+ libcmis::Object( session ),
+ m_links( )
+{
+}
+
+AtomObject::AtomObject( const AtomObject& copy ) :
+ libcmis::Object( copy ),
+ m_links( copy.m_links )
+{
+}
+
+AtomObject& AtomObject::operator=( const AtomObject& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Object::operator=( copy );
+ m_links = copy.m_links;
+ }
+
+ return *this;
+}
+
+AtomObject::~AtomObject( )
+{
+}
+
+libcmis::ObjectPtr AtomObject::updateProperties( const PropertyPtrMap& properties )
+{
+ if ( getAllowableActions().get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::UpdateProperties ) )
+ throw libcmis::Exception( string( "UpdateProperties is not allowed on object " ) + getId() );
+
+ // No need to send HTTP request if there is nothing to update
+ if ( properties.empty( ) )
+ {
+ libcmis::ObjectPtr object;
+ if ( getBaseType( ) == "cmis:document" )
+ {
+ const AtomDocument& thisDoc = dynamic_cast< const AtomDocument& >( *this );
+ object.reset( new AtomDocument( thisDoc ) );
+ }
+ else if ( getBaseType( ) == "cmis:folder" )
+ {
+ const AtomFolder& thisFolder = dynamic_cast< const AtomFolder& >( *this );
+ object.reset( new AtomFolder( thisFolder ) );
+ }
+ return object;
+ }
+
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ // Copy and remove the readonly properties before serializing
+ boost::shared_ptr< ostream > stream;
+ AtomObject::writeAtomEntry( writer, properties, stream, string( ) );
+
+ xmlTextWriterEndDocument( writer );
+ string str( ( const char * )xmlBufferContent( buf ) );
+ istringstream is( str );
+
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ vector< string > headers;
+ headers.push_back( "Content-Type: application/atom+xml;type=entry" );
+ response = getSession( )->httpPutRequest( getInfosUrl( ), is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ string respBuf = response->getStream( )->str( );
+ xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, 0 );
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+
+ libcmis::ObjectPtr updated = getSession( )->createObjectFromEntryDoc( doc );
+ if ( updated->getId( ) == getId( ) )
+ refreshImpl( doc );
+ xmlFreeDoc( doc );
+
+ return updated;
+}
+
+libcmis::AllowableActionsPtr AtomObject::getAllowableActions( )
+{
+ if ( !m_allowableActions )
+ {
+ // For some reason we had no allowable actions before, get them now.
+ AtomLink* link = getLink( "http://docs.oasis-open.org/ns/cmis/link/200908/allowableactions", "application/cmisallowableactions+xml" );
+ if ( link )
+ {
+ try
+ {
+ libcmis::HttpResponsePtr response = getSession()->httpGetRequest( link->getHref() );
+ string buf = response->getStream()->str();
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), link->getHref().c_str(), NULL, 0 );
+ xmlNodePtr actionsNode = xmlDocGetRootElement( doc );
+ if ( actionsNode )
+ m_allowableActions.reset( new libcmis::AllowableActions( actionsNode ) );
+
+ xmlFreeDoc( doc );
+ }
+ catch ( CurlException& )
+ {
+ }
+ }
+ }
+
+ return libcmis::Object::getAllowableActions();
+}
+
+void AtomObject::refreshImpl( xmlDocPtr doc )
+{
+ bool createdDoc = ( NULL == doc );
+ if ( createdDoc )
+ {
+ string buf;
+ try
+ {
+ buf = getSession()->httpGetRequest( getInfosUrl() )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ doc = xmlReadMemory( buf.c_str(), buf.size(), getInfosUrl().c_str(), NULL, 0 );
+
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+
+ }
+
+ // Cleanup the structures before setting them again
+ m_typeDescription.reset( );
+ m_properties.clear( );
+ m_allowableActions.reset( );
+ m_links.clear( );
+ m_renditions.clear( );
+
+ extractInfos( doc );
+
+ if ( createdDoc )
+ xmlFreeDoc( doc );
+}
+
+void AtomObject::remove( bool allVersions )
+{
+ if ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::DeleteObject ) )
+ throw libcmis::Exception( string( "DeleteObject not allowed on object " ) + getId() );
+
+ try
+ {
+ string deleteUrl = getInfosUrl( );
+ if ( deleteUrl.find( '?' ) != string::npos )
+ deleteUrl += "&";
+ else
+ deleteUrl += "?";
+
+ string allVersionsStr = "TRUE";
+ if ( !allVersions )
+ allVersionsStr = "FALSE";
+ deleteUrl += "allVersions=" + allVersionsStr;
+
+ getSession( )->httpDeleteRequest( deleteUrl );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+}
+
+void AtomObject::move( boost::shared_ptr< libcmis::Folder > source, boost::shared_ptr< libcmis::Folder > destination )
+{
+ AtomFolder* atomDestination = dynamic_cast< AtomFolder* > ( destination.get() );
+
+ if ( NULL == atomDestination )
+ throw libcmis::Exception( string( "Destination is not an AtomFolder" ) );
+
+ AtomLink* destChildrenLink = atomDestination->getLink( "down", "application/atom+xml;type=feed" );
+
+ if ( ( NULL == destChildrenLink ) || ( getAllowableActions().get() &&
+ !getAllowableActions()->isAllowed( libcmis::ObjectAction::MoveObject ) ) )
+ throw libcmis::Exception( string( "MoveObject not allowed on object " ) + getId() );
+
+ // create object xml
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ boost::shared_ptr< ostream > stream;
+ AtomObject::writeAtomEntry( writer, getProperties( ), stream, string( ) );
+ xmlTextWriterEndDocument( writer );
+
+ string str( ( const char * )xmlBufferContent( buf ) );
+ istringstream is( str );
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ // create post url
+ string postUrl = destChildrenLink->getHref();
+ if ( postUrl.find( '?' ) != string::npos )
+ postUrl += "&";
+ else
+ postUrl += "?";
+ postUrl += "sourceFolderId={sourceFolderId}";
+ // Session::CreateUrl is used to properly escape the id
+ map< string, string > params;
+ params[ "sourceFolderId" ] = source->getId();
+ postUrl = getSession( )->createUrl( postUrl, params );
+
+ // post it
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ response = getSession( )->httpPostRequest( postUrl, is, "application/atom+xml;type=entry" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ // refresh self from response
+ string respBuf = response->getStream( )->str( );
+ xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL, 0 );
+ if ( NULL == doc )
+ throw libcmis::Exception( "Failed to parse object infos" );
+ refreshImpl( doc );
+ xmlFreeDoc( doc );
+}
+
+string AtomObject::getInfosUrl( )
+{
+ AtomLink* selfLink = getLink( "self", "application/atom+xml;type=entry" );
+ if ( NULL != selfLink )
+ return selfLink->getHref( );
+ return string( );
+}
+
+void AtomObject::extractInfos( xmlDocPtr doc )
+{
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+
+ libcmis::registerNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ m_links.clear( );
+ m_renditions.clear( );
+
+ // Get all the atom links
+ string linksReq( "//atom:link" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( linksReq.c_str() ), xpathCtx );
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval )
+ {
+ int size = xpathObj->nodesetval->nodeNr;
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ try
+ {
+ AtomLink link( node );
+ // Add to renditions if alternate link
+ if ( link.getRel( ) == "alternate" )
+ {
+ string kind;
+ map< string, string >::iterator it = link.getOthers().find( "renditionKind" );
+ if ( it != link.getOthers( ).end() )
+ kind = it->second;
+
+ string title;
+ it = link.getOthers().find( "title" );
+ if ( it != link.getOthers( ).end( ) )
+ title = it->second;
+
+ long length = -1;
+ it = link.getOthers( ).find( "length" );
+ if ( it != link.getOthers( ).end( ) )
+ length = libcmis::parseInteger( it->second );
+
+ libcmis::RenditionPtr rendition( new libcmis::Rendition(
+ string(), link.getType(), kind,
+ link.getHref( ), title, length ) );
+
+ m_renditions.push_back( rendition );
+ }
+ else
+ m_links.push_back( node );
+ }
+ catch ( const libcmis::Exception& )
+ {
+ // Broken or incomplete link... don't add it
+ }
+ }
+ }
+ xmlXPathFreeObject( xpathObj );
+
+
+ xpathObj = xmlXPathEvalExpression( BAD_CAST( "//cmisra:object" ), xpathCtx );
+ if ( xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[0];
+ initializeFromNode( node );
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ xmlXPathFreeContext( xpathCtx );
+}
+
+AtomPubSession* AtomObject::getSession( )
+{
+ return dynamic_cast< AtomPubSession* >( m_session );
+}
+
+void AtomObject::writeAtomEntry( xmlTextWriterPtr writer,
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os, string contentType )
+{
+ AtomObject tmp( NULL );
+ PropertyPtrMap propertiesCopy( properties );
+ tmp.m_properties.swap( propertiesCopy );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "atom:entry" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:atom" ), BAD_CAST( NS_ATOM_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmisra" ), BAD_CAST( NS_CMISRA_URL ) );
+
+ if ( !tmp.getCreatedBy( ).empty( ) )
+ {
+ xmlTextWriterStartElement( writer, BAD_CAST( "atom:author" ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "atom:name" ), BAD_CAST( tmp.getCreatedBy( ).c_str( ) ) );
+ xmlTextWriterEndElement( writer );
+ }
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "atom:title" ), BAD_CAST( tmp.getName( ).c_str( ) ) );
+
+ boost::posix_time::ptime now( boost::posix_time::second_clock::universal_time( ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "atom:updated" ), BAD_CAST( libcmis::writeDateTime( now ).c_str( ) ) );
+
+ if ( os.get( ) )
+ {
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmisra:content" ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmisra:mediatype" ), BAD_CAST( contentType.c_str() ) );
+ xmlTextWriterStartElement(writer, BAD_CAST( "cmisra:base64" ) );
+
+ libcmis::EncodedData encoder( writer );
+ encoder.setEncoding( "base64" );
+ istream is( os->rdbuf( ) );
+ int bufLength = 1000;
+ char* buf = new char[ bufLength ];
+ do
+ {
+ is.read( buf, bufLength );
+ int size = is.gcount( );
+ encoder.encode( buf, 1, size );
+ } while ( !is.eof( ) && !is.fail( ) );
+ delete[] buf;
+ encoder.finish( );
+ xmlTextWriterEndElement( writer ); // "cmisra:base64"
+
+ xmlTextWriterEndElement( writer );
+ }
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmisra:object" ) );
+
+ tmp.toXml( writer );
+
+ xmlTextWriterEndElement( writer ); // cmisra:object
+
+ xmlTextWriterEndElement( writer ); // atom:entry
+}
+
+AtomLink* AtomObject::getLink( std::string rel, std::string type )
+{
+ AtomLink* link = NULL;
+ vector< AtomLink >::iterator it = find_if( m_links.begin(), m_links.end(), MatchLink( rel, type ) );
+ if ( it != m_links.end() )
+ link = &( *it );
+ return link;
+}
+
+AtomLink::AtomLink( xmlNodePtr node ):
+ m_rel( ), m_type( ), m_id( ), m_href( ), m_others( )
+{
+ xmlAttrPtr prop = node->properties;
+ while ( prop != NULL )
+ {
+ xmlChar* xmlStr = xmlGetProp( node, prop->name );
+ string value( ( char * ) xmlStr );
+
+ if ( xmlStrEqual( prop->name, BAD_CAST( "id" ) ) )
+ m_id = value;
+ else if ( xmlStrEqual( prop->name, BAD_CAST( "type" ) ) )
+ m_type = value;
+ else if ( xmlStrEqual( prop->name, BAD_CAST( "rel" ) ) )
+ m_rel = value;
+ else if ( xmlStrEqual( prop->name, BAD_CAST( "href" ) ) )
+ m_href = value;
+ else
+ m_others[ string( ( char * ) prop->name ) ] = value;
+
+ free( xmlStr );
+ prop = prop->next;
+ }
+}
diff --git a/src/libcmis/atom-object.hxx b/src/libcmis/atom-object.hxx
new file mode 100644
index 0000000..5d54dab
--- /dev/null
+++ b/src/libcmis/atom-object.hxx
@@ -0,0 +1,106 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ATOM_OBJECT_HXX_
+#define _ATOM_OBJECT_HXX_
+
+#include <map>
+#include <ostream>
+
+#include <libcmis/object.hxx>
+
+class AtomPubSession;
+
+class AtomLink
+{
+ private:
+ std::string m_rel;
+ std::string m_type;
+ std::string m_id;
+ std::string m_href;
+ std::map< std::string, std::string > m_others;
+
+ public:
+ AtomLink( xmlNodePtr node );
+
+ std::string getRel( ) const { return m_rel; }
+ std::string getType( ) const { return m_type; }
+ std::string getId( ) const { return m_id; }
+ bool hasId( ) const { return !m_id.empty( ); }
+ std::string getHref( ) const { return m_href; }
+ std::map< std::string, std::string >& getOthers( ) { return m_others; }
+};
+
+class AtomObject : public virtual libcmis::Object
+{
+ private:
+
+ std::vector< AtomLink > m_links;
+
+ public:
+ AtomObject( AtomPubSession* session );
+ AtomObject( const AtomObject& copy );
+ ~AtomObject( );
+
+ AtomObject& operator=( const AtomObject& copy );
+
+ // Overridden methods from libcmis::Object
+ virtual libcmis::ObjectPtr updateProperties(
+ const std::map< std::string, libcmis::PropertyPtr >& properties );
+
+ virtual libcmis::AllowableActionsPtr getAllowableActions( );
+
+ /** Reload the data from the server.
+ */
+ virtual void refresh( ) { refreshImpl( NULL ); }
+
+ virtual void remove( bool allVersion = true );
+
+ virtual void move( boost::shared_ptr< libcmis::Folder > source, boost::shared_ptr< libcmis::Folder > destination );
+
+ static void writeAtomEntry( xmlTextWriterPtr writer,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > os, std::string contentType );
+
+ protected:
+
+ std::string getInfosUrl( );
+ virtual void refreshImpl( xmlDocPtr doc );
+ virtual void extractInfos( xmlDocPtr doc );
+
+ AtomPubSession* getSession( );
+
+ /** Get the atom link corresponding to the given relation and type or NULL
+ if no link matched those criteria.
+
+ \param rel the relation to match
+ \param type the type to match or the empty string to match all types.
+ */
+ AtomLink* getLink( std::string rel, std::string type );
+};
+
+#endif
diff --git a/src/libcmis/atom-session.cxx b/src/libcmis/atom-session.cxx
new file mode 100644
index 0000000..7478c5f
--- /dev/null
+++ b/src/libcmis/atom-session.cxx
@@ -0,0 +1,349 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "atom-session.hxx"
+
+#include <string>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "atom-document.hxx"
+#include "atom-folder.hxx"
+#include "atom-object-type.hxx"
+
+using namespace std;
+
+AtomPubSession::AtomPubSession( string atomPubUrl, string repositoryId,
+ string username, string password, bool noSslCheck,
+ libcmis::OAuth2DataPtr oauth2, bool verbose ) :
+ BaseSession( atomPubUrl, repositoryId, username, password, noSslCheck, oauth2, verbose ),
+ m_repository( )
+{
+ libcmis::HttpResponsePtr response;
+ initialize( response );
+}
+
+AtomPubSession::AtomPubSession( string atomPubUrl, string repositoryId,
+ const HttpSession& httpSession, libcmis::HttpResponsePtr response ) :
+ BaseSession( atomPubUrl, repositoryId, httpSession ),
+ m_repository( )
+{
+ initialize( response );
+}
+
+AtomPubSession::AtomPubSession( ) :
+ BaseSession( ),
+ m_repository( )
+{
+}
+
+AtomPubSession::~AtomPubSession( )
+{
+}
+
+void AtomPubSession::parseServiceDocument( const string& buf )
+{
+ // parse the content
+ const boost::shared_ptr< xmlDoc > doc( xmlReadMemory( buf.c_str(), buf.size(), m_bindingUrl.c_str(), NULL, 0 ), xmlFreeDoc );
+
+ if ( bool( doc ) )
+ {
+ // Check that we have an AtomPub service document
+ xmlNodePtr root = xmlDocGetRootElement( doc.get() );
+ if ( !xmlStrEqual( root->name, BAD_CAST( "service" ) ) )
+ throw libcmis::Exception( "Not an atompub service document" );
+
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc.get() );
+
+ // Register the Service Document namespaces
+ libcmis::registerNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ string workspacesXPath( "//app:workspace" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( workspacesXPath.c_str() ), xpathCtx );
+
+ if ( xpathObj != NULL )
+ {
+ int nbWorkspaces = 0;
+ if ( xpathObj->nodesetval )
+ nbWorkspaces = xpathObj->nodesetval->nodeNr;
+
+ for ( int i = 0; i < nbWorkspaces; i++ )
+ {
+ try
+ {
+ AtomRepositoryPtr ws( new AtomRepository( xpathObj->nodesetval->nodeTab[i] ) );
+
+ // Check if we have a repository set
+ if ( m_repositoryId.empty( ) && i == 0 )
+ m_repositoryId = ws->getId( );
+
+ // SharePoint is case insensitive for the id...
+ if ( boost::to_lower_copy( ws->getId( ) ) == boost::to_lower_copy( m_repositoryId ) )
+ m_repository = ws;
+
+ m_repositories.push_back( ws );
+ }
+ catch ( const libcmis::Exception& )
+ {
+ // Invalid repository, don't take care of this
+ }
+ }
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ throw libcmis::Exception( "Failed to parse service document" );
+}
+
+void AtomPubSession::initialize( libcmis::HttpResponsePtr response )
+{
+ if ( m_repositories.empty() )
+ {
+ // Pull the content from sAtomPubUrl
+ string buf;
+ if ( response )
+ {
+ buf = response->getStream( )->str( );
+ }
+ else
+ {
+ try
+ {
+ buf = httpGetRequest( m_bindingUrl )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ }
+
+ parseServiceDocument( buf );
+ }
+}
+
+AtomRepositoryPtr AtomPubSession::getAtomRepository( )
+{
+ return m_repository;
+}
+
+libcmis::RepositoryPtr AtomPubSession::getRepository( )
+{
+ return getAtomRepository( );
+}
+
+bool AtomPubSession::setRepository( string repositoryId )
+{
+ vector< libcmis::RepositoryPtr > repos = getRepositories( );
+ bool found = false;
+ for ( vector< libcmis::RepositoryPtr >::iterator it = repos.begin();
+ it != repos.end() && !found; ++it )
+ {
+ libcmis::RepositoryPtr repo = *it;
+ if ( repo->getId() == repositoryId )
+ {
+ AtomRepositoryPtr atomRepo = boost::dynamic_pointer_cast< AtomRepository >( repo );
+ m_repository = atomRepo;
+ m_repositoryId = repositoryId;
+ found = true;
+ }
+ }
+ return found;
+}
+
+libcmis::ObjectPtr AtomPubSession::createObjectFromEntryDoc( xmlDocPtr doc, ResultObjectType res )
+{
+ libcmis::ObjectPtr cmisObject;
+
+ if ( NULL != doc )
+ {
+ // Get the atom:entry node
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+ if ( NULL != xpathCtx )
+ {
+ const string& entriesReq( "//atom:entry" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( entriesReq.c_str() ), xpathCtx );
+
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval && ( 0 < xpathObj->nodesetval->nodeNr ) )
+ {
+ // Get the entry's base type
+ string baseTypeReq = "//atom:entry[1]//cmis:propertyId[@propertyDefinitionId='cmis:baseTypeId']/cmis:value/text()";
+ string baseType = libcmis::getXPathValue( xpathCtx, baseTypeReq );
+
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[0];
+ if ( res == RESULT_FOLDER || baseType == "cmis:folder" )
+ {
+ cmisObject.reset( new AtomFolder( this, node ) );
+ }
+ else if ( res == RESULT_DOCUMENT || baseType == "cmis:document" )
+ {
+ cmisObject.reset( new AtomDocument( this, node ) );
+ }
+ else
+ {
+ // Not a valid CMIS atom entry... weird
+ }
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+ xmlXPathFreeContext( xpathCtx );
+ }
+
+ return cmisObject;
+}
+
+libcmis::ObjectPtr AtomPubSession::getObject( string id )
+{
+ string pattern = getAtomRepository()->getUriTemplate( UriTemplate::ObjectById );
+ map< string, string > vars;
+ vars[URI_TEMPLATE_VAR_ID] = id;
+ vars[string( "includeAllowableActions" )] = string( "true" );
+ string url = createUrl( pattern, vars );
+
+ try
+ {
+ string buf = httpGetRequest( url )->getStream( )->str( );
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), url.c_str(), NULL, 0 );
+ libcmis::ObjectPtr cmisObject = createObjectFromEntryDoc( doc );
+ xmlFreeDoc( doc );
+ return cmisObject;
+ }
+ catch ( const CurlException& e )
+ {
+ if ( ( e.getErrorCode( ) == CURLE_HTTP_RETURNED_ERROR ) &&
+ ( e.getHttpStatus( ) == 404 ) )
+ {
+ string msg = "No such node: ";
+ msg += id;
+ throw libcmis::Exception( msg, "objectNotFound" );
+ }
+ else
+ throw e.getCmisException();
+ }
+}
+
+libcmis::ObjectPtr AtomPubSession::getObjectByPath( string path )
+{
+ string pattern = getAtomRepository()->getUriTemplate( UriTemplate::ObjectByPath );
+ map< string, string > vars;
+ vars[URI_TEMPLATE_VAR_PATH] = path;
+ vars[string( "includeAllowableActions" )] = string( "true" );
+ string url = createUrl( pattern, vars );
+
+ try
+ {
+ string buf = httpGetRequest( url )->getStream( )->str( );
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), url.c_str(), NULL, 0 );
+ libcmis::ObjectPtr cmisObject = createObjectFromEntryDoc( doc );
+ xmlFreeDoc( doc );
+ return cmisObject;
+ }
+ catch ( const CurlException& e )
+ {
+ if ( ( e.getErrorCode( ) == CURLE_HTTP_RETURNED_ERROR ) &&
+ ( e.getHttpStatus( ) == 404 ) )
+ {
+ string msg = "No node corresponding to path: ";
+ msg += path;
+ throw libcmis::Exception( msg, "objectNotFound" );
+ }
+ else
+ throw e.getCmisException();
+ }
+}
+
+libcmis::ObjectTypePtr AtomPubSession::getType( string id )
+{
+ libcmis::ObjectTypePtr type( new AtomObjectType( this, id ) );
+ return type;
+}
+
+vector< libcmis::ObjectTypePtr > AtomPubSession::getBaseTypes( )
+{
+ string url = getAtomRepository( )->getCollectionUrl( Collection::Types );
+ return getChildrenTypes( url );
+}
+
+vector< libcmis::ObjectTypePtr > AtomPubSession::getChildrenTypes( string url )
+{
+ vector< libcmis::ObjectTypePtr > children;
+ string buf;
+ try
+ {
+ buf = httpGetRequest( url )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), url.c_str(), NULL, 0 );
+ if ( NULL != doc )
+ {
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+ if ( NULL != xpathCtx )
+ {
+ const string& entriesReq( "//atom:entry" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( entriesReq.c_str() ), xpathCtx );
+
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval )
+ {
+ int size = xpathObj->nodesetval->nodeNr;
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ libcmis::ObjectTypePtr type( new AtomObjectType( this, node ) );
+ children.push_back( type );
+ }
+ }
+
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ {
+ throw libcmis::Exception( "Failed to parse type children infos" );
+ }
+ xmlFreeDoc( doc );
+
+ return children;
+}
diff --git a/src/libcmis/atom-session.hxx b/src/libcmis/atom-session.hxx
new file mode 100644
index 0000000..6220591
--- /dev/null
+++ b/src/libcmis/atom-session.hxx
@@ -0,0 +1,90 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ATOM_SESSION_HXX_
+#define _ATOM_SESSION_HXX_
+
+#include "base-session.hxx"
+#include "atom-workspace.hxx"
+
+class AtomPubSession : public BaseSession
+{
+ private:
+ AtomRepositoryPtr m_repository;
+
+ public:
+ enum ResultObjectType { RESULT_DYNAMIC, RESULT_FOLDER, RESULT_DOCUMENT };
+ AtomPubSession( std::string sAtomPubUrl, std::string repositoryId,
+ std::string username, std::string password, bool noSslCheck = false,
+ libcmis::OAuth2DataPtr oauth2 = libcmis::OAuth2DataPtr(),
+ bool verbose =false );
+
+ /** This constructor uses the response of an HTTP request made
+ before to spare some HTTP request. This constructor has mostly
+ been designed for the SessionFactory use.
+ */
+ AtomPubSession( std::string sAtomPubUrl, std::string repositoryId,
+ const HttpSession& httpSession,
+ libcmis::HttpResponsePtr response );
+ ~AtomPubSession( );
+
+ AtomRepositoryPtr getAtomRepository( );
+
+ // Utility methods
+
+ libcmis::ObjectPtr createObjectFromEntryDoc( xmlDocPtr doc, ResultObjectType res=RESULT_DYNAMIC );
+
+ std::vector< libcmis::ObjectTypePtr > getChildrenTypes( std::string url );
+
+ // Override session methods
+
+ virtual libcmis::RepositoryPtr getRepository( );
+
+ virtual bool setRepository( std::string repositoryId );
+
+ virtual libcmis::ObjectPtr getObject( std::string id );
+
+ virtual libcmis::ObjectPtr getObjectByPath( std::string path );
+
+ virtual libcmis::ObjectTypePtr getType( std::string id );
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
+ protected:
+
+ /** Defaults constructor shouldn't be used
+ */
+ AtomPubSession( );
+ AtomPubSession( const AtomPubSession& copy ) = delete;
+ AtomPubSession& operator=( const AtomPubSession& copy ) = delete;
+
+ void parseServiceDocument( const std::string& buf );
+
+ void initialize( libcmis::HttpResponsePtr response );
+};
+
+#endif
diff --git a/src/libcmis/atom-workspace.cxx b/src/libcmis/atom-workspace.cxx
new file mode 100644
index 0000000..fb9af8d
--- /dev/null
+++ b/src/libcmis/atom-workspace.cxx
@@ -0,0 +1,228 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Cédric Bosdonnat <cbosdo@users.sourceforge.net>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "atom-workspace.hxx"
+
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+AtomRepository::AtomRepository( xmlNodePtr wsNode ):
+ Repository( ),
+ m_collections( ),
+ m_uriTemplates( )
+{
+ if ( wsNode != NULL )
+ {
+ xmlDocPtr doc = libcmis::wrapInDoc( wsNode );
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ // Get the collections
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( "//app:collection" ), xpathCtx );
+ if ( NULL != xpathObj )
+ readCollections( xpathObj->nodesetval );
+ xmlXPathFreeObject( xpathObj );
+
+ // Get the URI templates
+ xpathObj = xmlXPathEvalExpression( BAD_CAST( "//cmisra:uritemplate" ), xpathCtx );
+ if ( NULL != xpathObj )
+ readUriTemplates( xpathObj->nodesetval );
+ xmlXPathFreeObject( xpathObj );
+
+ // Get the repository infos
+ xpathObj = xmlXPathEvalExpression( BAD_CAST( "//cmisra:repositoryInfo" ), xpathCtx );
+ if ( NULL != xpathObj )
+ initializeFromNode( xpathObj->nodesetval->nodeTab[0] );
+ xmlXPathFreeObject( xpathObj );
+
+ }
+ xmlXPathFreeContext( xpathCtx );
+ xmlFreeDoc( doc );
+ }
+}
+
+AtomRepository::AtomRepository( const AtomRepository& rCopy ) :
+ Repository( rCopy ),
+ m_collections( rCopy.m_collections ),
+ m_uriTemplates( rCopy.m_uriTemplates )
+{
+}
+
+AtomRepository::~AtomRepository( )
+{
+ m_collections.clear( );
+ m_uriTemplates.clear( );
+}
+
+AtomRepository& AtomRepository::operator= ( const AtomRepository& rCopy )
+{
+ if ( this != &rCopy )
+ {
+ m_collections = rCopy.m_collections;
+ m_uriTemplates = rCopy.m_uriTemplates;
+ }
+
+ return *this;
+}
+
+string AtomRepository::getCollectionUrl( Collection::Type type )
+{
+ return m_collections[ type ];
+}
+
+string AtomRepository::getUriTemplate( UriTemplate::Type type )
+{
+ return m_uriTemplates[ type ];
+}
+
+void AtomRepository::readCollections( xmlNodeSetPtr nodeSet )
+{
+ int size = 0;
+ if ( nodeSet )
+ size = nodeSet->nodeNr;
+
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = nodeSet->nodeTab[i];
+
+ // Look for the href property
+ xmlChar* href = xmlGetProp( node, BAD_CAST( "href" ) );
+ if ( href )
+ {
+ string collectionRef( ( char* )href );
+ xmlFree( href );
+
+ // Look for the cmisra:collectionType child
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ // SharePoint CMIS implementation doesn't follow the spec:
+ // the cmisra namespace is omitted
+ bool isCollectionType = xmlStrEqual( child->name, BAD_CAST( "collectionType" ) );
+ if ( isCollectionType )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ Collection::Type type = Collection::Root;
+ bool typeDefined = false;
+
+ if ( xmlStrEqual( content, BAD_CAST( "root" ) ) )
+ {
+ type = Collection::Root;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "types" ) ) )
+ {
+ type = Collection::Types;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "query" ) ) )
+ {
+ type = Collection::Query;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "checkedout" ) ) )
+ {
+ type = Collection::CheckedOut;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "unfiled" ) ) )
+ {
+ type = Collection::Unfiled;
+ typeDefined = true;
+ }
+
+ if ( typeDefined )
+ m_collections[ type ] = collectionRef;
+
+ xmlFree( content );
+ }
+ }
+ }
+ }
+}
+
+void AtomRepository::readUriTemplates( xmlNodeSetPtr nodeSet )
+{
+ int size = 0;
+ if ( nodeSet )
+ size = nodeSet->nodeNr;
+
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr node = nodeSet->nodeTab[i];
+
+ string templateUri;
+ UriTemplate::Type type = UriTemplate::ObjectById;
+ bool typeDefined = false;
+
+ // Look for the cmisra:template and cmisra:type children
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ bool isTemplate = xmlStrEqual( child->name, BAD_CAST( "template" ) );
+ bool isType = xmlStrEqual( child->name, BAD_CAST( "type" ) );
+
+ if ( isTemplate )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( content != NULL )
+ templateUri = string( ( char * )content );
+ xmlFree( content );
+ }
+ else if ( isType )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( xmlStrEqual( content, BAD_CAST( "objectbyid" ) ) )
+ {
+ type = UriTemplate::ObjectById;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "objectbypath" ) ) )
+ {
+ type = UriTemplate::ObjectByPath;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "query" ) ) )
+ {
+ type = UriTemplate::Query;
+ typeDefined = true;
+ }
+ else if ( xmlStrEqual( content, BAD_CAST( "typebyid" ) ) )
+ {
+ type = UriTemplate::TypeById;
+ typeDefined = true;
+ }
+ xmlFree( content );
+ }
+ }
+
+ if ( !templateUri.empty() && typeDefined )
+ m_uriTemplates[ type ] = templateUri;
+ }
+}
diff --git a/src/libcmis/atom-workspace.hxx b/src/libcmis/atom-workspace.hxx
new file mode 100644
index 0000000..fa4582c
--- /dev/null
+++ b/src/libcmis/atom-workspace.hxx
@@ -0,0 +1,91 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Cédric Bosdonnat <cbosdo@users.sourceforge.net>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ATOM_WORKSPACE_HXX_
+#define _ATOM_WORKSPACE_HXX_
+
+#include <map>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+#include <curl/curl.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/exception.hxx>
+#include <libcmis/repository.hxx>
+
+#define URI_TEMPLATE_VAR_ID std::string( "id" )
+#define URI_TEMPLATE_VAR_PATH std::string( "path" )
+
+struct Collection {
+ enum Type
+ {
+ Root,
+ Types,
+ Query,
+ CheckedOut,
+ Unfiled
+ };
+};
+
+struct UriTemplate {
+ enum Type
+ {
+ ObjectById,
+ ObjectByPath,
+ TypeById,
+ Query
+ };
+};
+
+class AtomRepository : public libcmis::Repository
+{
+ private:
+ /// Collections URLs
+ std::map< Collection::Type, std::string > m_collections;
+
+ /// URI templates
+ std::map< UriTemplate::Type, std::string > m_uriTemplates;
+
+ public:
+ AtomRepository( xmlNodePtr wsNode = NULL );
+ AtomRepository( const AtomRepository& rCopy );
+ ~AtomRepository( );
+
+ AtomRepository& operator= ( const AtomRepository& rCopy );
+
+ std::string getCollectionUrl( Collection::Type );
+ std::string getUriTemplate( UriTemplate::Type );
+
+ private:
+ void readCollections( xmlNodeSetPtr pNodeSet );
+ void readUriTemplates( xmlNodeSetPtr pNodeSet );
+};
+
+typedef boost::shared_ptr< AtomRepository > AtomRepositoryPtr;
+
+#endif
diff --git a/src/libcmis/base-session.cxx b/src/libcmis/base-session.cxx
new file mode 100644
index 0000000..a4311ca
--- /dev/null
+++ b/src/libcmis/base-session.cxx
@@ -0,0 +1,146 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "base-session.hxx"
+
+#include <cctype>
+#include <string>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/session-factory.hxx>
+#include <libcmis/xml-utils.hxx>
+
+#include "oauth2-handler.hxx"
+
+using namespace std;
+
+BaseSession::BaseSession( string bindingUrl, string repositoryId, string username,
+ string password, bool noSslCheck, libcmis::OAuth2DataPtr oauth2, bool verbose ) :
+ Session( ),
+ HttpSession( username, password, noSslCheck, oauth2, verbose ),
+ m_bindingUrl( bindingUrl ),
+ m_repositoryId( repositoryId ),
+ m_repositories( )
+{
+}
+
+BaseSession::BaseSession( string sBindingUrl, string repository,
+ const HttpSession& httpSession ) :
+ Session( ),
+ HttpSession( httpSession ),
+ m_bindingUrl( sBindingUrl ),
+ m_repositoryId( repository ),
+ m_repositories( )
+{
+}
+
+BaseSession::BaseSession( ) :
+ Session( ),
+ HttpSession( ),
+ m_bindingUrl( ),
+ m_repositoryId( ),
+ m_repositories( )
+{
+}
+
+BaseSession::~BaseSession( )
+{
+}
+
+string BaseSession::createUrl( const string& pattern, map< string, string > variables )
+{
+ string url( pattern );
+
+ // Decompose the pattern and replace the variables by their values
+ map< string, string >::iterator it = variables.begin( );
+ while ( it != variables.end( ) )
+ {
+ string name = "{";
+ name += it->first;
+ name += "}";
+ string value = it->second;
+
+ // Search and replace the variable
+ size_t pos = url.find( name );
+ if ( pos != string::npos )
+ {
+ // Escape the URL by chunks
+ url = url.replace( pos, name.size(), libcmis::escape( value ) );
+ }
+
+ ++it;
+ }
+
+ // Cleanup the remaining unset variables
+ size_t pos1 = url.find( '{' );
+ while ( pos1 != string::npos )
+ {
+ // look for the closing bracket
+ size_t pos2 = url.find( '}', pos1 );
+ if ( pos2 != string::npos )
+ url.erase( pos1, pos2 - pos1 + 1 );
+
+ pos1 = url.find( '{', pos1 - 1 );
+ }
+
+ return url;
+}
+
+
+void BaseSession::setNoSSLCertificateCheck( bool noCheck )
+{
+ HttpSession::setNoSSLCertificateCheck( noCheck );
+}
+
+void BaseSession::setOAuth2Data( libcmis::OAuth2DataPtr oauth2 )
+{
+ m_oauth2Handler = new OAuth2Handler( this, oauth2 );
+ m_oauth2Handler->setOAuth2Parser( OAuth2Providers::getOAuth2Parser( getBindingUrl( ) ) );
+
+ oauth2Authenticate( );
+}
+
+vector< libcmis::RepositoryPtr > BaseSession::getRepositories( )
+{
+ return m_repositories;
+}
+
+libcmis::FolderPtr BaseSession::getRootFolder()
+{
+ return getFolder( getRootId() );
+}
+
+libcmis::FolderPtr BaseSession::getFolder( string id )
+{
+ libcmis::ObjectPtr object = getObject( id );
+ libcmis::FolderPtr folder = boost::dynamic_pointer_cast< libcmis::Folder >( object );
+ return folder;
+}
diff --git a/src/libcmis/base-session.hxx b/src/libcmis/base-session.hxx
new file mode 100644
index 0000000..60976d4
--- /dev/null
+++ b/src/libcmis/base-session.hxx
@@ -0,0 +1,104 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _BASE_SESSION_HXX_
+#define _BASE_SESSION_HXX_
+
+#include <istream>
+#include <sstream>
+#include <vector>
+#include <map>
+#include <string>
+
+#include <curl/curl.h>
+#include <libxml/xmlstring.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/exception.hxx>
+#include <libcmis/oauth2-data.hxx>
+#include <libcmis/session.hxx>
+#include <libcmis/xml-utils.hxx>
+
+#include "http-session.hxx"
+
+class OAuth2Handler;
+
+class BaseSession : public libcmis::Session,
+ public HttpSession
+{
+ protected:
+ std::string m_bindingUrl;
+ std::string m_repositoryId;
+
+ std::vector< libcmis::RepositoryPtr > m_repositories;
+ public:
+ BaseSession( std::string sBindingUrl, std::string repository,
+ std::string username, std::string password,
+ bool noSslCheck = false,
+ libcmis::OAuth2DataPtr oauth2 = libcmis::OAuth2DataPtr(), bool verbose = false );
+
+ /** This constructor copies an existing http session.
+ This has been mostly designed for SessionFactory to save
+ a few HTTP requests when guessing the binding to use.
+ */
+ BaseSession( std::string sBindingUrl, std::string repository,
+ const HttpSession& httpSession );
+
+ ~BaseSession( );
+
+ std::string& getRepositoryId( ) { return m_repositoryId; }
+
+ // Utility methods
+
+ std::string getRootId( ) { return getRepository()->getRootId( ); }
+
+ std::string createUrl( const std::string& pattern, std::map< std::string, std::string > variables );
+
+ std::string getBindingUrl( ) { return m_bindingUrl; }
+
+ // HttpSession overridden methods
+
+ virtual void setOAuth2Data( libcmis::OAuth2DataPtr oauth2 );
+
+ // Session methods
+
+ virtual void setNoSSLCertificateCheck( bool noCheck );
+
+ virtual std::vector< libcmis::RepositoryPtr > getRepositories( );
+
+ virtual libcmis::FolderPtr getRootFolder();
+
+ virtual libcmis::FolderPtr getFolder( std::string id );
+
+ protected:
+ BaseSession( );
+
+ BaseSession( const BaseSession& copy ) = delete;
+ BaseSession& operator=( const BaseSession& copy ) = delete;
+};
+
+#endif
diff --git a/src/libcmis/document.cxx b/src/libcmis/document.cxx
new file mode 100644
index 0000000..b8a0d0d
--- /dev/null
+++ b/src/libcmis/document.cxx
@@ -0,0 +1,107 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/document.hxx>
+
+#include <libcmis/folder.hxx>
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+namespace libcmis
+{
+ vector< string > Document::getPaths( )
+ {
+ vector< string > paths;
+ try
+ {
+ vector< libcmis::FolderPtr > parents = getParents( );
+ for ( vector< libcmis::FolderPtr >::iterator it = parents.begin( );
+ it != parents.end(); ++it )
+ {
+ string path = ( *it )->getPath( );
+ if ( path.empty() )
+ continue;
+ if ( path[path.size() - 1] != '/' )
+ path += "/";
+ path += getName( );
+ paths.push_back( path );
+ }
+ }
+ catch ( const libcmis::Exception& )
+ {
+ // We may not have the permission to get the parents
+ }
+ return paths;
+ }
+
+ string Document::getContentType( )
+ {
+ return getStringProperty( "cmis:contentStreamMimeType" );
+ }
+
+ string Document::getContentFilename( )
+ {
+ return getStringProperty( "cmis:contentStreamFileName" );
+ }
+
+ long Document::getContentLength( )
+ {
+ long contentLength = 0;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( "cmis:contentStreamLength" ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getLongs( ).empty( ) )
+ contentLength = it->second->getLongs( ).front( );
+ return contentLength;
+ }
+
+ // LCOV_EXCL_START
+ string Document::toString( )
+ {
+ stringstream buf;
+
+ buf << "Document Object:" << endl << endl;
+ buf << Object::toString();
+ try
+ {
+ vector< libcmis::FolderPtr > parents = getParents( );
+ buf << "Parents ids: ";
+ for ( vector< libcmis::FolderPtr >::iterator it = parents.begin(); it != parents.end(); ++it )
+ buf << "'" << ( *it )->getId( ) << "' ";
+ buf << endl;
+ }
+ catch ( const libcmis::Exception& )
+ {
+ }
+ buf << "Content Type: " << getContentType( ) << endl;
+ buf << "Content Length: " << getContentLength( ) << endl;
+ buf << "Content Filename: " << getContentFilename( ) << endl;
+
+ return buf.str();
+ }
+ // LCOV_EXCL_STOP
+}
diff --git a/src/libcmis/dummy.cxx b/src/libcmis/dummy.cxx
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/libcmis/dummy.cxx
diff --git a/src/libcmis/folder.cxx b/src/libcmis/folder.cxx
new file mode 100644
index 0000000..d4a5acd
--- /dev/null
+++ b/src/libcmis/folder.cxx
@@ -0,0 +1,92 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/folder.hxx>
+
+#include <libcmis/session.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ vector< string > Folder::getPaths( )
+ {
+ vector< string > paths;
+ paths.push_back( getPath( ) );
+ return paths;
+ }
+
+ libcmis::FolderPtr Folder::getFolderParent( )
+ {
+ if ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::GetFolderParent ) )
+ throw libcmis::Exception( string( "GetFolderParent not allowed on node " ) + getId() );
+
+ if ( m_session == NULL )
+ throw libcmis::Exception( string( "Session not defined on the object... weird!" ) );
+
+ return m_session->getFolder( getParentId( ) );
+ }
+
+ string Folder::getParentId( )
+ {
+ return getStringProperty( "cmis:parentId" );
+ }
+
+ string Folder::getPath( )
+ {
+ return getStringProperty( "cmis:path" );
+ }
+
+ bool Folder::isRootFolder( )
+ {
+ return getParentId( ).empty( );
+ }
+
+ // LCOV_EXCL_START
+ string Folder::toString( )
+ {
+ stringstream buf;
+
+ buf << "Folder Object:" << endl << endl;
+ buf << Object::toString();
+ buf << "Path: " << getPath() << endl;
+ buf << "Folder Parent Id: " << getParentId( ) << endl;
+ buf << "Children [Name (Id)]:" << endl;
+
+ vector< libcmis::ObjectPtr > children = getChildren( );
+ for ( vector< libcmis::ObjectPtr >::iterator it = children.begin( );
+ it != children.end(); ++it )
+ {
+ libcmis::ObjectPtr child = *it;
+ buf << " " << child->getName() << " (" << child->getId() << ")" << endl;
+ }
+
+ return buf.str();
+ }
+ // LCOV_EXCL_STOP
+}
diff --git a/src/libcmis/gdrive-allowable-actions.hxx b/src/libcmis/gdrive-allowable-actions.hxx
new file mode 100644
index 0000000..1a22d5d
--- /dev/null
+++ b/src/libcmis/gdrive-allowable-actions.hxx
@@ -0,0 +1,102 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _GDRIVE_ALLOWABLE_ACTIONS_HXX_
+#define _GDRIVE_ALLOWABLE_ACTIONS_HXX_
+
+#include <libcmis/allowable-actions.hxx>
+
+class GdriveAllowableActions: public libcmis::AllowableActions
+{
+ public:
+ GdriveAllowableActions( bool isFolder ) : AllowableActions( )
+ {
+ m_states.clear( );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteObject, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::UpdateProperties, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetProperties, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetObjectRelationships, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetObjectParents, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::MoveObject, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateRelationship, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::ApplyPolicy, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetAppliedPolicies, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::RemovePolicy, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetACL, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::ApplyACL, true ) );
+
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetFolderTree, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetFolderParent, isFolder) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetDescendants, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CheckOut, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CancelCheckOut, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CheckIn, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::SetContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetAllVersions, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::AddObjectToFolder, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::RemoveObjectFromFolder, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetRenditions, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetChildren, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateDocument, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateFolder, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteTree, isFolder ) );
+ }
+};
+
+#endif
diff --git a/src/libcmis/gdrive-document.cxx b/src/libcmis/gdrive-document.cxx
new file mode 100644
index 0000000..ecb13d6
--- /dev/null
+++ b/src/libcmis/gdrive-document.cxx
@@ -0,0 +1,250 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-document.hxx"
+
+#include <libcmis/rendition.hxx>
+
+#include "gdrive-folder.hxx"
+#include "gdrive-session.hxx"
+#include "json-utils.hxx"
+#include "gdrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+GDriveDocument::GDriveDocument( GDriveSession* session ) :
+ libcmis::Object( session),
+ libcmis::Document( session ),
+ GDriveObject( session ),
+ m_isGoogleDoc( false )
+{
+}
+
+GDriveDocument::GDriveDocument( GDriveSession* session, Json json, string id, string name ) :
+ libcmis::Object( session),
+ libcmis::Document( session ),
+ GDriveObject( session, json, id, name ),
+ m_isGoogleDoc( false )
+{
+ m_isGoogleDoc = getContentType( ).find( "google" ) != string::npos;
+ getRenditions( );
+}
+
+GDriveDocument::~GDriveDocument( )
+{
+}
+
+string GDriveDocument::getDownloadUrl( string streamId )
+{
+ string streamUrl;
+ vector< RenditionPtr > renditions = getRenditions( );
+
+ if ( renditions.empty( ) )
+ return streamUrl;
+
+ if ( !streamId.empty( ) )
+ {
+ // Find the rendition associated with the streamId
+ for ( vector< RenditionPtr >::iterator it = renditions.begin( ) ;
+ it != renditions.end(); ++it )
+ {
+ if ( (*it)->getStreamId( ) == streamId )
+ {
+ streamUrl = (*it)->getUrl( );
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Automatically find the rendition
+
+ // Prefer ODF format
+ for ( vector< RenditionPtr >::iterator it = renditions.begin( ) ;
+ it != renditions.end(); ++it )
+ if ( (*it)->getMimeType( ).find( "opendocument") != string::npos )
+ return (*it)->getUrl( );
+
+ // Then MS format
+ for ( vector< RenditionPtr >::iterator it = renditions.begin( ) ;
+ it != renditions.end(); ++it )
+ if ( (*it)->getMimeType( ).find( "officedocument") != string::npos )
+ return (*it)->getUrl( );
+
+ // If not found, take the first one
+ streamUrl = renditions.front( )->getUrl( );
+
+ }
+
+ return streamUrl;
+}
+
+vector< libcmis::FolderPtr > GDriveDocument::getParents( )
+{
+ vector< libcmis::FolderPtr > parents;
+
+ vector< string > parentsId = getMultiStringProperty( "cmis:parentId" );
+
+ // Create folder objects from parent IDs
+ for ( vector< string >::iterator it = parentsId.begin( ); it != parentsId.end( ); ++it)
+ {
+ string parentId = ( *it );
+ libcmis::ObjectPtr obj = getSession( )->getObject( parentId );
+ libcmis::FolderPtr parent = boost::dynamic_pointer_cast< libcmis::Folder >( obj );
+ parents.push_back( parent );
+ }
+ return parents;
+}
+
+boost::shared_ptr< istream > GDriveDocument::getContentStream( string streamId )
+{
+ boost::shared_ptr< istream > stream;
+ string streamUrl = getDownloadUrl( streamId );
+ if ( streamUrl.empty( ) )
+ throw libcmis::Exception( "can not found stream url" );
+
+ try
+ {
+ stream = getSession( )->httpGetRequest( streamUrl )->getStream( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ return stream;
+}
+
+void GDriveDocument::uploadStream( boost::shared_ptr< ostream > os,
+ string contentType )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ string putUrl = GDRIVE_UPLOAD_LINK + getId( ) + "?uploadType=media";
+
+ // Upload stream
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ vector <string> headers;
+ headers.push_back( string( "Content-Type: " ) + contentType );
+ string res;
+ try
+ {
+ res = getSession()->httpPatchRequest( putUrl, *is, headers )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ long httpStatus = getSession( )->getHttpStatus( );
+ if ( httpStatus < 200 || httpStatus >= 300 )
+ throw libcmis::Exception( "Document content wasn't set for"
+ "some reason" );
+ refresh( );
+}
+
+void GDriveDocument::setContentStream( boost::shared_ptr< ostream > os,
+ string contentType,
+ string fileName,
+ bool /*overwrite*/ )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ // TODO: when would the filename need an update?
+ if (!fileName.empty() && fileName != getContentFilename())
+ std::cout << "filename change is not implemented in setContentStream" << std::endl;
+
+ // Upload stream
+ uploadStream( os, contentType );
+}
+
+libcmis::DocumentPtr GDriveDocument::checkOut( )
+{
+ // GDrive doesn't have CheckOut, so just return the same document here
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr checkout =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ return checkout;
+}
+
+void GDriveDocument::cancelCheckout( )
+{
+ // Don't do anything since we don't have CheckOut
+}
+
+libcmis::DocumentPtr GDriveDocument::checkIn(
+ bool /*isMajor*/,
+ std::string /*comment*/,
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string fileName )
+{
+ // GDrive doesn't have CheckIn, so just upload the properties,
+ // the content stream and fetch the new document resource.
+ updateProperties( properties );
+ setContentStream( stream, contentType, fileName );
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr checkin =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ return checkin;
+}
+
+
+vector< libcmis::DocumentPtr > GDriveDocument::getAllVersions( )
+{
+ vector< libcmis::DocumentPtr > revisions;
+ string versionUrl = GDRIVE_METADATA_LINK + getId( ) + "/revisions";
+ // Run the http request to get the properties definition
+ string res;
+ try
+ {
+ res = getSession()->httpGetRequest( versionUrl )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+ Json::JsonVector objs = jsonRes["revisions"].getList( );
+
+ string parentId = getStringProperty( "cmis:parentId" );
+
+ // Create document objects from Json objects
+ for(unsigned int i = 0; i < objs.size(); i++)
+ {
+ objs[i].add( "parents", GdriveUtils::createJsonFromParentId( parentId ) );
+ libcmis::DocumentPtr revision(
+ new GDriveDocument( getSession(), objs[i], getId( ), getName( ) ) );
+
+ revisions.push_back( revision );
+ }
+ return revisions;
+}
+
diff --git a/src/libcmis/gdrive-document.hxx b/src/libcmis/gdrive-document.hxx
new file mode 100644
index 0000000..aecf270
--- /dev/null
+++ b/src/libcmis/gdrive-document.hxx
@@ -0,0 +1,90 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _GDRIVE_DOCUMENT_HXX_
+#define _GDRIVE_DOCUMENT_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+#include <libcmis/rendition.hxx>
+
+#include "gdrive-object.hxx"
+#include "json-utils.hxx"
+
+class GDriveDocument : public libcmis::Document, public GDriveObject
+{
+ public:
+ GDriveDocument( GDriveSession* session );
+
+ // Create a GDrive document from Json properties.
+ // In case it's a revision, keep the ID and the name of the original file.
+ GDriveDocument( GDriveSession* session, Json json,
+ std::string id = std::string( ),
+ std::string name = std::string( ) );
+ ~GDriveDocument( );
+
+ std::string getType( ) { return std::string( "cmis:document" );}
+ std::string getBaseType( ) { return std::string( "cmis:document" );}
+
+ bool isGoogleDoc( ) { return m_isGoogleDoc; }
+
+ /* Get the download Url associated to streamId,
+ automatically find ODF then MS format if no streamId is specified.
+ */
+ std::string getDownloadUrl( std::string streamId = std::string( ) );
+
+ void uploadStream( boost::shared_ptr< std::ostream > os,
+ std::string contentType );
+
+ virtual std::vector< libcmis::FolderPtr > getParents( );
+ virtual boost::shared_ptr< std::istream > getContentStream(
+ std::string streamId = std::string( ) );
+
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os,
+ std::string contentType,
+ std::string fileName,
+ bool overwrite = true );
+
+ virtual libcmis::DocumentPtr checkOut( );
+ virtual void cancelCheckout( );
+ virtual libcmis::DocumentPtr checkIn(
+ bool isMajor,
+ std::string comment,
+ const std::map< std::string,libcmis::PropertyPtr >&
+ properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string fileName );
+
+ virtual std::vector< libcmis::DocumentPtr > getAllVersions( );
+
+ private:
+ bool m_isGoogleDoc;
+};
+
+#endif
diff --git a/src/libcmis/gdrive-folder.cxx b/src/libcmis/gdrive-folder.cxx
new file mode 100644
index 0000000..26de89b
--- /dev/null
+++ b/src/libcmis/gdrive-folder.cxx
@@ -0,0 +1,192 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-folder.hxx"
+
+#include "gdrive-session.hxx"
+#include "gdrive-document.hxx"
+#include "gdrive-property.hxx"
+#include "gdrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+GDriveFolder::GDriveFolder( GDriveSession* session ):
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ GDriveObject( session )
+{
+}
+
+GDriveFolder::GDriveFolder( GDriveSession* session, Json json ):
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ GDriveObject( session, json )
+{
+}
+
+GDriveFolder::~GDriveFolder( )
+{
+}
+
+vector< libcmis::ObjectPtr > GDriveFolder::getChildren( )
+{
+ vector< libcmis::ObjectPtr > children;
+
+ // GDrive doesn't support fetch all the children in one query.
+ // Instead of sending multiple queries for children,
+ // we send a single query to search for objects where parents
+ // include the folderID.
+ string query = GDRIVE_METADATA_LINK + "?q=\"" + getId( ) + "\"+in+parents+and+trashed+=+false" +
+ "&fields=files(kind,id,name,parents,mimeType,createdTime,modifiedTime,thumbnailLink,size)";
+
+ string res;
+ try
+ {
+ res = getSession( )->httpGetRequest( query )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ Json jsonRes = Json::parse( res );
+ Json::JsonVector objs = jsonRes["files"].getList( );
+
+ // Create children objects from Json objects
+ for(unsigned int i = 0; i < objs.size(); i++)
+ {
+ ObjectPtr child;
+ if ( objs[i]["mimeType"].toString( ) == GDRIVE_FOLDER_MIME_TYPE )
+ child.reset( new GDriveFolder( getSession( ), objs[i] ) );
+ else
+ child.reset( new GDriveDocument( getSession( ), objs[i] ) );
+ children.push_back( child );
+ }
+
+ return children;
+}
+
+string GDriveFolder::uploadProperties( Json properties )
+{
+ // URL for uploading meta data
+ string metaUrl = GDRIVE_METADATA_LINK + "?fields=kind,id,name,parents,mimeType,createdTime,modifiedTime";
+
+ // add parents to the properties
+ properties.add( "parents", GdriveUtils::createJsonFromParentId( getId( ) ) );
+
+ //upload metadata
+ std::istringstream is( properties.toString( ) );
+ string response;
+ try
+ {
+ response = getSession()->httpPostRequest( metaUrl, is, "application/json" )
+ ->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ return response;
+}
+
+libcmis::FolderPtr GDriveFolder::createFolder(
+ const PropertyPtrMap& properties )
+{
+ Json propsJson = GdriveUtils::toGdriveJson( properties );
+
+ // GDrive folder is a file with a different mime type.
+ string mimeType = GDRIVE_FOLDER_MIME_TYPE;
+
+ // Add mimetype to the propsJson
+ Json jsonMimeType( mimeType.c_str( ) );
+ propsJson.add( "mimeType", jsonMimeType );
+
+ // Upload meta-datas
+ string response = uploadProperties( propsJson );
+
+ Json jsonRes = Json::parse( response );
+ libcmis::FolderPtr folderPtr( new GDriveFolder( getSession( ), jsonRes ) );
+
+ return folderPtr;
+}
+
+libcmis::DocumentPtr GDriveFolder::createDocument(
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os,
+ string contentType, string fileName )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ Json propsJson = GdriveUtils::toGdriveJson( properties );
+
+ if(!fileName.empty()) {
+ // use provided filename
+ Json jsonFilename( fileName.c_str( ) );
+
+ propsJson.add( "name", jsonFilename );
+ }
+ if(!contentType.empty()) {
+ propsJson.add( "mimeType", Json(contentType.c_str()));
+ }
+
+ // Upload meta-datas
+ string res = uploadProperties( propsJson);
+
+ // parse the document
+ Json jsonRes = Json::parse( res );
+
+ boost::shared_ptr< GDriveDocument >
+ gDocument( new GDriveDocument( getSession( ), jsonRes ) );
+
+ // Upload stream
+ gDocument->uploadStream( os, contentType);
+
+ return gDocument;
+}
+
+vector< string > GDriveFolder::removeTree(
+ bool /*allVersions*/,
+ libcmis::UnfileObjects::Type /*unfile*/,
+ bool /*continueOnError*/ )
+{
+ try
+ {
+ getSession( )->httpDeleteRequest( GDRIVE_METADATA_LINK + getId( ) );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ // Nothing to return here
+ return vector< string >( );
+}
+
diff --git a/src/libcmis/gdrive-folder.hxx b/src/libcmis/gdrive-folder.hxx
new file mode 100644
index 0000000..aff4737
--- /dev/null
+++ b/src/libcmis/gdrive-folder.hxx
@@ -0,0 +1,66 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _GDRIVE_FOLDER_HXX_
+#define _GDRIVE_FOLDER_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "gdrive-object.hxx"
+#include "json-utils.hxx"
+
+class GDriveFolder : public libcmis::Folder, public GDriveObject
+{
+ public:
+ GDriveFolder( GDriveSession* session );
+ GDriveFolder( GDriveSession* session, Json json );
+ ~GDriveFolder( );
+
+ std::string getType( ) { return std::string( "cmis:folder" );}
+ std::string getBaseType( ) { return std::string( "cmis:folder" );}
+ virtual std::vector< libcmis::ObjectPtr > getChildren( );
+
+ virtual libcmis::FolderPtr createFolder(
+ const libcmis::PropertyPtrMap& properties );
+
+ virtual libcmis::DocumentPtr createDocument(
+ const libcmis::PropertyPtrMap& properties,
+ boost::shared_ptr< std::ostream > os,
+ std::string contentType,
+ std::string fileName );
+
+ virtual std::vector< std::string > removeTree(
+ bool allVersion = true,
+ libcmis::UnfileObjects::Type unfile = libcmis::UnfileObjects::Delete,
+ bool continueOnError = false );
+
+ std::string uploadProperties( Json properties );
+};
+
+#endif
diff --git a/src/libcmis/gdrive-object-type.cxx b/src/libcmis/gdrive-object-type.cxx
new file mode 100644
index 0000000..75df2a2
--- /dev/null
+++ b/src/libcmis/gdrive-object-type.cxx
@@ -0,0 +1,141 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-object-type.hxx"
+
+GdriveObjectType::GdriveObjectType( const std::string& id ): ObjectType( )
+{
+ m_id = id;
+ m_localName = "GoogleDrive Object Type";
+ m_localNamespace = "GoogleDrive Object Type";
+ m_displayName = "GoogleDrive Object Type";
+ m_queryName = "GoogleDrive Object Type";
+ m_description = "GoogleDrive Object Type";
+ m_parentTypeId = id;
+ m_baseTypeId = id;
+ m_creatable = true;
+ m_versionable = true;
+ m_fulltextIndexed = true;
+
+ libcmis::PropertyTypePtr idType(new libcmis::PropertyType( ) );
+ idType->setId( "cmis:objectTypeId" );
+ idType->setType( libcmis::PropertyType::String );
+ m_propertiesTypes[ idType->getId( ) ] = idType;
+
+ // create PropertyTypes which are updatable.
+
+ // title
+ libcmis::PropertyTypePtr nameType( new libcmis::PropertyType( ) );
+ nameType->setId( "cmis:name" );
+ nameType->setType( libcmis::PropertyType::String );
+ nameType->setUpdatable( true );
+ m_propertiesTypes[ nameType->getId( ) ] = nameType;
+
+ // mimeType
+ libcmis::PropertyTypePtr mimeType( new libcmis::PropertyType( ) );
+ mimeType->setId( "cmis:contentStreamMimeType" );
+ mimeType->setType( libcmis::PropertyType::String );
+ mimeType->setUpdatable( false );
+ m_propertiesTypes[ mimeType->getId( ) ] = mimeType;
+
+ // parents
+ libcmis::PropertyTypePtr parentsType( new libcmis::PropertyType( ) );
+ parentsType->setId( "cmis:parentId" );
+ parentsType->setType( libcmis::PropertyType::String );
+ parentsType->setUpdatable( false );
+ parentsType->setMultiValued( true );
+ m_propertiesTypes[ parentsType->getId( ) ] = parentsType;
+
+ // labels
+ libcmis::PropertyTypePtr labelsType( new libcmis::PropertyType( ) );
+ labelsType->setId( "labels" );
+ labelsType->setType( libcmis::PropertyType::String );
+ labelsType->setUpdatable( false );
+ labelsType->setMultiValued( true );
+ m_propertiesTypes[ labelsType->getId( ) ] = labelsType;
+
+ // ownerNames
+ libcmis::PropertyTypePtr ownerNamesType( new libcmis::PropertyType( ) );
+ ownerNamesType->setId( "ownerNames" );
+ ownerNamesType->setType( libcmis::PropertyType::String );
+ ownerNamesType->setUpdatable( false );
+ ownerNamesType->setMultiValued( true );
+ m_propertiesTypes[ ownerNamesType->getId( ) ] = ownerNamesType;
+
+ // owners
+ libcmis::PropertyTypePtr ownersType( new libcmis::PropertyType( ) );
+ ownersType->setId( "owners" );
+ ownersType->setType( libcmis::PropertyType::String );
+ ownersType->setUpdatable( false );
+ ownersType->setMultiValued( true );
+ m_propertiesTypes[ ownersType->getId( ) ] = ownersType;
+
+ // export links
+ libcmis::PropertyTypePtr exportLinksType( new libcmis::PropertyType( ) );
+ exportLinksType->setId( "exportLinks" );
+ exportLinksType->setType( libcmis::PropertyType::String );
+ exportLinksType->setUpdatable( false );
+ exportLinksType->setMultiValued( true );
+ m_propertiesTypes[ exportLinksType->getId( ) ] = exportLinksType;
+
+ // description
+ libcmis::PropertyTypePtr descriptionType( new libcmis::PropertyType( ) );
+ descriptionType->setId( "cmis:description" );
+ descriptionType->setType( libcmis::PropertyType::String );
+ descriptionType->setUpdatable( true );
+ m_propertiesTypes[ descriptionType->getId( ) ] = descriptionType;
+
+ // modifiedDate
+ libcmis::PropertyTypePtr modifiedDateType( new libcmis::PropertyType( ) );
+ modifiedDateType->setId( "cmis:lastModificationDate" );
+ modifiedDateType->setType( libcmis::PropertyType::DateTime );
+ modifiedDateType->setUpdatable( true );
+ m_propertiesTypes[ modifiedDateType->getId( ) ] = modifiedDateType;
+
+ // lastViewedByMeDate
+ libcmis::PropertyTypePtr lastViewedByMeDateType( new libcmis::PropertyType( ) );
+ lastViewedByMeDateType->setId( "lastViewedByMeDate" );
+ lastViewedByMeDateType->setType( libcmis::PropertyType::DateTime );
+ lastViewedByMeDateType->setUpdatable( true );
+ m_propertiesTypes[ lastViewedByMeDateType->getId( ) ] = lastViewedByMeDateType;
+
+}
+
+
+libcmis::ObjectTypePtr GdriveObjectType::getParentType( )
+{
+ libcmis::ObjectTypePtr parentTypePtr( new GdriveObjectType( m_parentTypeId ) );
+ return parentTypePtr;
+}
+
+libcmis::ObjectTypePtr GdriveObjectType::getBaseType( )
+{
+ libcmis::ObjectTypePtr baseTypePtr( new GdriveObjectType( m_baseTypeId ) );
+ return baseTypePtr;
+}
+
diff --git a/src/libcmis/gdrive-object-type.hxx b/src/libcmis/gdrive-object-type.hxx
new file mode 100644
index 0000000..3f1a258
--- /dev/null
+++ b/src/libcmis/gdrive-object-type.hxx
@@ -0,0 +1,46 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _GDRIVE_OBJECT_TYPE_HXX_
+#define _GDRIVE_OBJECT_TYPE_HXX_
+
+#include <libcmis/object-type.hxx>
+
+#include "json-utils.hxx"
+
+class GdriveObjectType: public libcmis::ObjectType
+{
+ public:
+ GdriveObjectType( const std::string& id );
+
+ virtual libcmis::ObjectTypePtr getParentType( );
+
+ virtual libcmis::ObjectTypePtr getBaseType( );
+};
+
+#endif
diff --git a/src/libcmis/gdrive-object.cxx b/src/libcmis/gdrive-object.cxx
new file mode 100644
index 0000000..b472e2f
--- /dev/null
+++ b/src/libcmis/gdrive-object.cxx
@@ -0,0 +1,276 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 SUSE <cbosdonnat@suse.com>
+ * 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-object.hxx"
+
+#include "gdrive-property.hxx"
+#include "gdrive-allowable-actions.hxx"
+#include "gdrive-repository.hxx"
+#include "gdrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+GDriveObject::GDriveObject( GDriveSession* session ) :
+ libcmis::Object( session )
+{
+}
+
+GDriveObject::GDriveObject( GDriveSession* session, Json json, string id, string name ) :
+ libcmis::Object( session )
+{
+ initializeFromJson( json, id, name );
+}
+
+GDriveObject::GDriveObject( const GDriveObject& copy ) :
+ libcmis::Object( copy )
+{
+}
+
+GDriveObject& GDriveObject::operator=( const GDriveObject& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Object::operator=( copy );
+ }
+ return *this;
+}
+
+void GDriveObject::initializeFromJson ( Json json, string id, string name )
+{
+ Json::JsonObject objs = json.getObjects( );
+ Json::JsonObject::iterator it;
+ for ( it = objs.begin( ); it != objs.end( ); ++it)
+ {
+ PropertyPtr property;
+
+ // in case of a revision, get the ID and name of the original file
+ if ( !id.empty( ) && it->first == "id" )
+ {
+ Json idJson( id.c_str( ) );
+ property.reset( new GDriveProperty( "id", idJson ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ property.reset( new GDriveProperty( "revisionId", it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+
+ Json nameJson( name.c_str( ) );
+ property.reset( new GDriveProperty( "cmis:name", nameJson) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ property.reset( new GDriveProperty( "cmis:contentStreamFileName", nameJson) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+ else
+ {
+ property.reset( new GDriveProperty( it->first, it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+
+ // we map "name" to both "cmis:name" and "cmis:getContentStreamFileName"
+ if ( it->first == "name" )
+ {
+ property.reset( new GDriveProperty( "cmis:name", it->second) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+
+ // some revision keep the original file name.
+ if ( it->first == "originalFilename" )
+ {
+ property.reset( new GDriveProperty( "cmis:name", it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ property.reset( new GDriveProperty( "cmis:contentStreamFileName", it->second) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+
+ // In case of a revision, get the modified date as creation date
+ if ( it->first == "modifiedDate" && !id.empty( ) )
+ {
+ property.reset( new GDriveProperty( "cmis:creationDate", it->second) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+ // In case of a revision, get the last modifying user and the creator
+ if ( it->first == "lastModifyingUserName" && !id.empty( ) )
+ {
+ property.reset( new GDriveProperty( "cmis:createdBy", it->second) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+ }
+ }
+ m_refreshTimestamp = time( NULL );
+
+ // Create AllowableActions
+ bool isFolder = json["mimeType"].toString( ) == GDRIVE_FOLDER_MIME_TYPE;
+ m_allowableActions.reset( new GdriveAllowableActions( isFolder ) );
+}
+
+GDriveSession* GDriveObject::getSession( )
+{
+ return dynamic_cast< GDriveSession* > ( m_session );
+}
+
+void GDriveObject::refreshImpl( Json json )
+{
+ m_typeDescription.reset( );
+ m_properties.clear( );
+ initializeFromJson( json );
+}
+
+vector< RenditionPtr> GDriveObject::getRenditions( string /* filter */ )
+{
+ if ( m_renditions.empty( ) )
+ {
+ string downloadUrl = GDRIVE_METADATA_LINK + getId( ) + "?alt=media";
+ string mimeType = getStringProperty( "cmis:contentStreamMimeType" );
+ if ( !mimeType.empty( ) )
+ {
+ RenditionPtr rendition(
+ new Rendition( mimeType, mimeType, mimeType, downloadUrl ));
+ m_renditions.push_back( rendition );
+ }
+
+ vector< string > exportLinks = getMultiStringProperty( "exportLinks" );
+ for ( vector<string>::iterator it = exportLinks.begin( ); it != exportLinks.end( ); ++it)
+ {
+ int pos = (*it).find(":\"");
+ if ( pos == -1 ) continue;
+ mimeType = (*it).substr( 0, pos );
+ string url = (*it).substr( pos + 2, (*it).length( ) - pos - 3 );
+ RenditionPtr rendition(
+ new Rendition( mimeType, mimeType, mimeType, url ) );
+ m_renditions.push_back( rendition );
+ }
+
+ // thumbnail link
+ string thumbnailLink = getStringProperty( "thumbnailLink" );
+ if ( !thumbnailLink.empty( ) )
+ {
+ mimeType = "cmis:thumbnail";
+ RenditionPtr rendition(
+ new Rendition( mimeType, mimeType, mimeType, thumbnailLink ));
+ m_renditions.push_back( rendition );
+ }
+ }
+ return m_renditions;
+}
+
+libcmis::ObjectPtr GDriveObject::updateProperties(
+ const PropertyPtrMap& properties )
+{
+ // Make Json object from properties
+ Json json = GdriveUtils::toGdriveJson( properties );
+
+ istringstream is( json.toString( ));
+
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ vector< string > headers;
+ headers.push_back( "Content-Type: application/json" );
+ response = getSession( )->httpPatchRequest( getUrl( ), is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ string res = response->getStream( )->str( );
+ Json jsonRes = Json::parse( res );
+ libcmis::ObjectPtr updated( new GDriveObject ( getSession( ), jsonRes ) );
+
+ if ( updated->getId( ) == getId( ) )
+ refreshImpl( jsonRes );
+
+ return updated;
+}
+
+void GDriveObject::refresh( )
+{
+ string res;
+ try
+ {
+ res = getSession()->httpGetRequest( getUrl( ) )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json json = Json::parse( res );
+ refreshImpl( json );
+}
+
+void GDriveObject::remove( bool /*allVersions*/ )
+{
+ try
+ {
+ getSession( )->httpDeleteRequest( GDRIVE_METADATA_LINK + getId( ) );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+}
+
+void GDriveObject::move( FolderPtr /*source*/, FolderPtr destination )
+{
+ Json parentsJson;
+ parentsJson.add( "addParents", Json(destination->getId( ).c_str()) );
+ parentsJson.add( "removeParents", Json(getStringProperty( "cmis:parentId" ).c_str()) );
+
+ istringstream is( parentsJson.toString( ) );
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ vector< string > headers;
+ headers.push_back( "Content-Type: application/json" );
+ response = getSession( )->httpPatchRequest( getUrl( ), is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ string res = response->getStream( )->str( );
+ Json jsonRes = Json::parse( res );
+
+ refreshImpl( jsonRes );
+}
+
+string GDriveObject::getUrl( )
+{
+ // thumbnailLink causes some operations to fail with internal server error,
+ // see https://issuetracker.google.com/issues/36760667
+ return GDRIVE_METADATA_LINK + getId( ) +
+ "?fields=kind,id,name,parents,mimeType,createdTime,modifiedTime,size";
+}
+
+vector< string> GDriveObject::getMultiStringProperty( const string& propertyName )
+{
+ vector< string > values;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( propertyName ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getStrings( ).empty( ) )
+ values = it->second->getStrings( );
+ return values;
+}
+
diff --git a/src/libcmis/gdrive-object.hxx b/src/libcmis/gdrive-object.hxx
new file mode 100644
index 0000000..4a2225f
--- /dev/null
+++ b/src/libcmis/gdrive-object.hxx
@@ -0,0 +1,87 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _GDRIVE_OBJECT_HXX_
+#define _GDRIVE_OBJECT_HXX_
+
+#include <libcmis/object.hxx>
+
+#include "gdrive-session.hxx"
+#include "json-utils.hxx"
+
+/** Class representing an object for Google Drive protocol.
+
+ This class overrides quite a number of its parent class methods to
+ git the Google Drive API into the libcmis API.
+
+ In order to reuse more of the base Object class, this class needs
+ to map the main properties (like id, name, etc) to CMIS property
+ ids (cmis:id, cmis:name, etc).
+ */
+class GDriveObject : public virtual libcmis::Object
+{
+ public:
+ GDriveObject( GDriveSession* session );
+
+ // Create a GDrive document from Json properties.
+ // In case it's a revision, keep the ID and the name of the original file.
+ GDriveObject( GDriveSession* session, Json json,
+ std::string id = std::string( ),
+ std::string name = std::string( ) );
+ GDriveObject( const GDriveObject& copy );
+ virtual ~GDriveObject( ) { }
+
+ GDriveObject& operator=( const GDriveObject& copy );
+
+ void initializeFromJson( Json json, std::string id = std::string( ),
+ std::string name = std::string( ) );
+ void refreshImpl( Json json );
+ Json createJsonFromParentId( const std::string& parentId );
+
+ std::string getUrl( );
+ std::string getUploadUrl( );
+ std::vector< std::string > getMultiStringProperty(
+ const std::string& propertyName );
+
+ virtual std::vector< libcmis::RenditionPtr> getRenditions( std::string filter = std::string( ) );
+
+ virtual boost::shared_ptr< Object > updateProperties(
+ const libcmis::PropertyPtrMap& properties );
+
+ virtual void refresh( );
+
+ virtual void remove( bool allVersions = true );
+
+ virtual void move( boost::shared_ptr< libcmis::Folder > source,
+ boost::shared_ptr< libcmis::Folder > destination );
+
+ protected:
+ GDriveSession* getSession( );
+
+};
+
+#endif
diff --git a/src/libcmis/gdrive-property.cxx b/src/libcmis/gdrive-property.cxx
new file mode 100644
index 0000000..f75c2ed
--- /dev/null
+++ b/src/libcmis/gdrive-property.cxx
@@ -0,0 +1,79 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-property.hxx"
+
+#include <libcmis/property-type.hxx>
+
+#include "gdrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+GDriveProperty::GDriveProperty( )
+{
+}
+
+GDriveProperty::~GDriveProperty( )
+{
+}
+
+GDriveProperty::GDriveProperty( const string& key, Json json ):
+ Property( )
+{
+ PropertyTypePtr propertyType( new PropertyType( ) );
+ string convertedKey = GdriveUtils::toCmisKey( key );
+ propertyType->setId( convertedKey );
+ propertyType->setLocalName( convertedKey );
+ propertyType->setLocalNamespace( convertedKey );
+ propertyType->setQueryName( convertedKey );
+ propertyType->setDisplayName( key );
+ propertyType->setTypeFromJsonType( json.getStrType( ) );
+ propertyType->setUpdatable( GdriveUtils::checkUpdatable( key ) );
+ propertyType->setMultiValued( GdriveUtils::checkMultiValued( key ) );
+
+ setPropertyType( propertyType );
+
+ vector< string > values = GdriveUtils::parseGdriveProperty( key, json );
+ setValues( values );
+}
+
+GDriveProperty::GDriveProperty( const GDriveProperty& copy ) :
+ libcmis::Property( copy )
+{
+}
+
+GDriveProperty& GDriveProperty::operator=( const GDriveProperty& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Property::operator=( copy );
+ }
+ return *this;
+}
+
diff --git a/src/libcmis/gdrive-property.hxx b/src/libcmis/gdrive-property.hxx
new file mode 100644
index 0000000..4edab78
--- /dev/null
+++ b/src/libcmis/gdrive-property.hxx
@@ -0,0 +1,51 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _GDRIVE_PROPERTY_HXX_
+#define _GDRIVE_PROPERTY_HXX_
+
+#include <libcmis/property.hxx>
+
+#include "json-utils.hxx"
+
+class GDriveProperty : public libcmis::Property
+{
+ public :
+ // Create a GDrive Property from a Json property with its key
+ GDriveProperty( const std::string& key, Json json);
+ ~GDriveProperty( );
+ GDriveProperty( const GDriveProperty& copy);
+ GDriveProperty& operator=( const GDriveProperty& copy );
+
+ // Check if the property is updatable
+ bool checkUpdatable( const std::string& key );
+ private :
+ // Avoid calling default constructor
+ GDriveProperty( );
+};
+#endif /* _GDRIVE_PROPERTY_HXX_ */
diff --git a/src/libcmis/gdrive-repository.cxx b/src/libcmis/gdrive-repository.cxx
new file mode 100644
index 0000000..24b42b5
--- /dev/null
+++ b/src/libcmis/gdrive-repository.cxx
@@ -0,0 +1,55 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-repository.hxx"
+
+GdriveRepository::GdriveRepository( ) :
+ Repository( )
+{
+ m_id = "GoogleDrive";
+ m_name = "Google Drive";
+ m_description = "Google Drive repository";
+ m_productName = "Google Drive";
+ m_productVersion = "v3";
+ m_rootId = "root";
+
+ m_capabilities[ ACL ] = "discover";
+ m_capabilities[ AllVersionsSearchable ] = "true";
+ m_capabilities[ Changes ] = "all";
+ m_capabilities[ GetDescendants ] = "true";
+ m_capabilities[ GetFolderTree ] = "true";
+ m_capabilities[ OrderBy ] = "custom";
+ m_capabilities[ Multifiling ] = "true";
+ m_capabilities[ PWCSearchable ] = "true";
+ m_capabilities[ PWCUpdatable ] = "true";
+ m_capabilities[ Query ] = "bothcombined";
+ m_capabilities[ Renditions ] = "read";
+ m_capabilities[ Unfiling ] = "false";
+ m_capabilities[ VersionSpecificFiling ] = "false";
+ m_capabilities[ Join ] = "none";
+}
diff --git a/src/libcmis/gdrive-repository.hxx b/src/libcmis/gdrive-repository.hxx
new file mode 100644
index 0000000..215a13c
--- /dev/null
+++ b/src/libcmis/gdrive-repository.hxx
@@ -0,0 +1,41 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _GDRIVE_REPOSITORY_HXX_
+#define _GDRIVE_REPOSITORY_HXX_
+
+#include <libcmis/repository.hxx>
+
+class GdriveRepository: public libcmis::Repository
+{
+ public:
+ GdriveRepository( );
+};
+
+#endif
+
diff --git a/src/libcmis/gdrive-session.cxx b/src/libcmis/gdrive-session.cxx
new file mode 100644
index 0000000..1ee748e
--- /dev/null
+++ b/src/libcmis/gdrive-session.cxx
@@ -0,0 +1,254 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-session.hxx"
+
+#include <libcmis/object-type.hxx>
+
+#include "oauth2-handler.hxx"
+#include "gdrive-document.hxx"
+#include "gdrive-folder.hxx"
+#include "gdrive-repository.hxx"
+#include "gdrive-object-type.hxx"
+#include "gdrive-utils.hxx"
+
+using namespace std;
+
+GDriveSession::GDriveSession ( string baseUrl,
+ string username,
+ string password,
+ libcmis::OAuth2DataPtr oauth2,
+ bool verbose ) :
+ BaseSession( baseUrl, string(), username, password, false,
+ libcmis::OAuth2DataPtr(), verbose )
+
+{
+ // Add the dummy repository, even if we don't have OAuth2
+ m_repositories.push_back( getRepository( ) );
+
+ if ( oauth2 && oauth2->isComplete( ) ){
+ setOAuth2Data( oauth2 );
+ }
+}
+
+GDriveSession::GDriveSession() :
+ BaseSession()
+{
+}
+
+GDriveSession::~GDriveSession()
+{
+}
+
+
+void GDriveSession::setOAuth2Data( libcmis::OAuth2DataPtr oauth2 )
+{
+ m_oauth2Handler = new OAuth2Handler( this, oauth2 );
+ m_oauth2Handler->setOAuth2Parser( OAuth2Providers::getOAuth2Parser( getBindingUrl( ) ) );
+
+ oauth2Authenticate( );
+}
+
+void GDriveSession::oauth2Authenticate()
+{
+ // treat the supplied password as refresh token
+ if (!m_password.empty())
+ {
+ try
+ {
+ m_inOAuth2Authentication = true;
+
+ m_oauth2Handler->setRefreshToken(m_password);
+ // Try to get new access tokens using the stored refreshtoken
+ m_oauth2Handler->refresh();
+ m_inOAuth2Authentication = false;
+ }
+ catch (const CurlException &e)
+ {
+ m_inOAuth2Authentication = false;
+ // refresh token expired or invalid, trigger initial auth (that in turn will hit the fallback with copy'n'paste method)
+ BaseSession::oauth2Authenticate();
+ }
+ }
+ else
+ {
+ BaseSession::oauth2Authenticate();
+ }
+}
+
+string GDriveSession::getRefreshToken() {
+ return HttpSession::getRefreshToken();
+}
+
+libcmis::RepositoryPtr GDriveSession::getRepository( )
+{
+ // Return a dummy repository since GDrive doesn't have that notion
+ libcmis::RepositoryPtr repo( new GdriveRepository( ) );
+ return repo;
+}
+
+bool GDriveSession::setRepository( std::string )
+{
+ return true;
+}
+
+libcmis::ObjectPtr GDriveSession::getObject( string objectId )
+{
+ if(objectId == "root") {
+ return getRootFolder();
+ }
+ // Run the http request to get the properties definition
+ string res;
+ string objectLink = GDRIVE_METADATA_LINK + objectId +
+ "?fields=kind,id,name,parents,mimeType,createdTime,modifiedTime,thumbnailLink,size";
+ try
+ {
+ res = httpGetRequest( objectLink )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+
+ // If we have a folder, then convert the object
+ // into a GDriveFolder otherwise, convert it
+ // into a GDriveDocument
+ libcmis::ObjectPtr object;
+ string kind = jsonRes["kind"].toString( );
+ if ( kind == "drive#file" )
+ {
+ string mimeType = jsonRes["mimeType"].toString( );
+
+ // Folder is a file with a special mimeType
+ if ( mimeType == GDRIVE_FOLDER_MIME_TYPE )
+ object.reset( new GDriveFolder( this, jsonRes ) );
+ else
+ object.reset( new GDriveDocument( this, jsonRes ) );
+ } else if ( kind == "drive#revision" ) // A revision is a document too
+ {
+ object.reset( new GDriveDocument( this, jsonRes ) );
+ }
+ else // not a folder nor file, maybe a permission or changes,...
+ object.reset( new GDriveObject( this, jsonRes ) );
+
+ return object;
+}
+
+libcmis::ObjectPtr GDriveSession::getObjectByPath( string path )
+{
+ size_t pos = 0;
+ size_t endpos = 0;
+ string objectId;
+ libcmis::ObjectPtr object;
+
+ do
+ {
+ endpos = path.find( "/", pos );
+ size_t len = path.length( ) - pos;
+ if ( endpos != string::npos )
+ len = endpos - pos;
+
+ string segment = path.substr( pos, len );
+ if ( segment.empty( ) )
+ {
+ // Root case or ignore double slashes
+ if ( pos == 0 )
+ objectId = "root";
+ else
+ continue;
+ }
+ else
+ {
+ // Normal child case
+ // Ask for the ID of the child if there is any
+ // somewhat flawed as names are not necessarily unique in GDrive...
+ string query = libcmis::escape("'" + objectId + "' in parents and trashed = false and name='" + segment + "'");
+
+ string childIdUrl = m_bindingUrl + "/files/?q=" + query + "&fields=files(id)";
+
+ string res;
+ try
+ {
+ res = httpGetRequest( childIdUrl )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+
+ // Did we get an id?
+ Json::JsonVector items = jsonRes["files"].getList();
+ if ( items.empty( ) )
+ throw libcmis::Exception( "Object not found: " + path, "objectNotFound" );
+
+ objectId = items[0]["id"].toString( );
+ if ( objectId.empty( ) )
+ throw libcmis::Exception( "Object not found: " + path, "objectNotFound" );
+ }
+
+ pos = endpos + 1;
+ } while ( endpos != string::npos );
+
+ return getObject( objectId );
+}
+
+libcmis::FolderPtr GDriveSession::getRootFolder()
+{
+ // permissions/scope with just drive.file don't allow to get it with the "root" alias/by its actual object-ID
+ Json propsJson;
+
+ // GDrive folder is a file with a different mime type.
+ string mimeType = GDRIVE_FOLDER_MIME_TYPE;
+
+ // Add mimetype to the propsJson
+ Json jsonMimeType( mimeType.c_str( ) );
+ propsJson.add( "mimeType", jsonMimeType );
+ propsJson.add( "id", "root" );
+
+ // Upload meta-datas
+ propsJson.add("cmis:name", "VirtualRoot");
+
+ libcmis::FolderPtr folderPtr( new GDriveFolder( this, propsJson ) );
+
+ return folderPtr;
+}
+
+libcmis::ObjectTypePtr GDriveSession::getType( string id )
+{
+ libcmis::ObjectTypePtr type( new GdriveObjectType( id ) );
+ return type;
+}
+
+vector< libcmis::ObjectTypePtr > GDriveSession::getBaseTypes( )
+{
+ vector< libcmis::ObjectTypePtr > types;
+ // TODO Implement me
+ return types;
+}
diff --git a/src/libcmis/gdrive-session.hxx b/src/libcmis/gdrive-session.hxx
new file mode 100644
index 0000000..d29d454
--- /dev/null
+++ b/src/libcmis/gdrive-session.hxx
@@ -0,0 +1,72 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _GDRIVE_SESSION_HXX_
+#define _GDRIVE_SESSION_HXX_
+
+#include <libcmis/repository.hxx>
+
+#include "base-session.hxx"
+
+class GDriveSession : public BaseSession
+{
+ public:
+ GDriveSession( std::string baseUrl,
+ std::string username,
+ std::string password,
+ libcmis::OAuth2DataPtr oauth2,
+ bool verbose = false );
+
+ ~GDriveSession ( );
+
+ virtual libcmis::RepositoryPtr getRepository( );
+
+ virtual bool setRepository( std::string );
+
+ virtual libcmis::ObjectPtr getObject( std::string id );
+
+ virtual libcmis::ObjectPtr getObjectByPath( std::string path );
+
+ virtual libcmis::ObjectTypePtr getType( std::string id );
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
+ virtual libcmis::FolderPtr getRootFolder();
+
+ virtual std::string getRefreshToken();
+
+ private:
+ GDriveSession( );
+ GDriveSession( const GDriveSession& copy ) = delete;
+ GDriveSession& operator=( const GDriveSession& copy ) = delete;
+
+ virtual void setOAuth2Data( libcmis::OAuth2DataPtr oauth2 );
+
+ void oauth2Authenticate( );
+};
+
+#endif /* _GDRIVE_SESSION_HXX_ */
diff --git a/src/libcmis/gdrive-utils.cxx b/src/libcmis/gdrive-utils.cxx
new file mode 100644
index 0000000..3cc0288
--- /dev/null
+++ b/src/libcmis/gdrive-utils.cxx
@@ -0,0 +1,221 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "gdrive-utils.hxx"
+
+#include <libcmis/xml-utils.hxx>
+
+#include "json-utils.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+string GdriveUtils::toCmisKey( const string& key )
+{
+ string convertedKey;
+ if ( key == "id")
+ convertedKey = "cmis:objectId";
+ else if ( key == "ownerNames" )
+ convertedKey = "cmis:createdBy";
+ else if ( key == "description" )
+ convertedKey = "cmis:description";
+ else if ( key == "createdTime" )
+ convertedKey = "cmis:creationDate";
+ else if ( key == "lastModifyingUserName" )
+ convertedKey = "cmis:lastModifiedBy";
+ else if ( key == "modifiedTime" )
+ convertedKey = "cmis:lastModificationDate";
+ else if ( key == "name" )
+ convertedKey = "cmis:contentStreamFileName";
+ else if ( key == "mimeType" )
+ convertedKey = "cmis:contentStreamMimeType";
+ else if ( key == "size" )
+ convertedKey = "cmis:contentStreamLength";
+ else if ( key == "editable" )
+ convertedKey = "cmis:isImmutable";
+ else if ( key == "parents" )
+ convertedKey = "cmis:parentId";
+ else convertedKey = key;
+ return convertedKey;
+}
+
+string GdriveUtils::toGdriveKey( const string& key )
+{
+ string convertedKey;
+ if ( key == "cmis:objectId")
+ convertedKey = "id";
+ else if ( key == "cmis:createdBy" )
+ convertedKey = "ownerNames";
+ else if ( key == "cmis:creationDate" )
+ convertedKey = "createdTime";
+ else if ( key == "cmis:description" )
+ convertedKey = "description";
+ else if ( key == "cmis:lastModifiedBy" )
+ convertedKey = "lastModifyingUserName";
+ else if ( key == "cmis:lastModificationDate" )
+ convertedKey = "modifiedTime";
+ else if ( key == "cmis:contentStreamFileName" )
+ convertedKey = "name";
+ else if ( key == "cmis:name" )
+ convertedKey = "name";
+ else if ( key == "cmis:contentStreamMimeType" )
+ convertedKey = "mimeType";
+ else if ( key == "cmis:contentStreamLength" )
+ convertedKey = "size";
+ else if ( key == "cmis:isImmutable" )
+ convertedKey = "editable";
+ else if ( key == "cmis:parentId" )
+ convertedKey = "parents";
+ else convertedKey = key;
+ return convertedKey;
+}
+
+Json GdriveUtils::toGdriveJson( const PropertyPtrMap& properties )
+{
+ Json propsJson;
+
+ // check if cmis:name and cmis:contentStreamFileName has been duplicated
+ bool duplicated = false;
+ for ( PropertyPtrMap::const_iterator it = properties.begin() ;
+ it != properties.end() ; ++it )
+ {
+ string key = it->first;
+ Json value( it->second );
+
+ // Convert the key back to the gdrive key
+ // take one of the two: cmis:name and cmis:contentStreamFileName
+ const bool isName = key == "cmis:name" || key == "cmis:contentStreamFileName";
+
+ if ( !isName || !duplicated )
+ propsJson.add( toGdriveKey( key ), value );
+
+ if ( isName )
+ duplicated = true;
+ }
+
+ return propsJson;
+}
+
+bool GdriveUtils::checkUpdatable( const string& key )
+{
+ // taken from https://developers.google.com/drive/v2/reference/files
+ bool updatable = ( key == "name" ||
+ key == "description" ||
+ key == "modifiedTime" ||
+ key == "lastViewedByMeDate" );
+ return updatable;
+}
+
+bool GdriveUtils::checkMultiValued( const string& key )
+{
+ bool bMultiValued = ( key == "parents" ||
+ key == "exportLinks" ||
+ key == "labels" ||
+ key == "ownersName" ||
+ key == "owners");
+ return bMultiValued;
+}
+
+Json GdriveUtils::createJsonFromParentId( const string& parentId )
+{
+ // parents is a Json array
+ Json firstParent;
+ firstParent.add( Json( parentId.c_str() ) );
+
+ return firstParent;
+}
+
+vector< string > GdriveUtils::parseGdriveProperty( string key, Json json )
+{
+ vector< string > values;
+ if ( key == "owners" )
+ {
+ Json::JsonVector owners = json.getList( );
+ for ( Json::JsonVector::iterator it = owners.begin( );
+ it != owners.end( ); ++it )
+ {
+ string ownerName = ( *it )["displayName"].toString( );
+ values.push_back( ownerName);
+ }
+ }
+ else if ( key == "lastModifyingUser" )
+ {
+ string ownerName = json["displayName"].toString( );
+ values.push_back( ownerName);
+ }
+ else if ( key == "userPermission" )
+ {
+ string ownerName = json["role"].toString( );
+ values.push_back( ownerName);
+ }
+ else if ( key == "ownerNames" )
+ {
+ Json::JsonVector owners = json.getList( );
+ for ( Json::JsonVector::iterator it = owners.begin( );
+ it != owners.end( ); ++it )
+ {
+ string ownerName = ( *it )[""].toString( );
+ values.push_back( ownerName);
+ }
+ }
+ else if ( key == "parents" )
+ {
+ Json::JsonVector owners = json.getList( );
+ for ( Json::JsonVector::iterator it = owners.begin( );
+ it != owners.end( ); ++it )
+ {
+ string ownerName = ( *it )["id"].toString( );
+ values.push_back( ownerName);
+ }
+ }
+ else if ( key == "exportLinks" )
+ {
+ Json::JsonObject exportLinks = json.getObjects( );
+ for ( Json::JsonObject::iterator it = exportLinks.begin( );
+ it != exportLinks.end( ); ++it )
+ {
+ string mimeType = it->first;
+ string link = it->second.toString( );
+ values.push_back( mimeType + ":\"" + link +"\"");
+ }
+ }
+ else if ( key == "labels" )
+ {
+ Json::JsonObject labels = json.getObjects( );
+ for ( Json::JsonObject::iterator it = labels.begin( );
+ it != labels.end( ); ++it )
+ {
+ string label = it->first;
+ string isSet = it->second.toString( );
+ values.push_back( label + ": " + isSet );
+ }
+ }
+ else values.push_back( json.toString( ) );
+ return values;
+}
+
diff --git a/src/libcmis/gdrive-utils.hxx b/src/libcmis/gdrive-utils.hxx
new file mode 100644
index 0000000..06ad568
--- /dev/null
+++ b/src/libcmis/gdrive-utils.hxx
@@ -0,0 +1,67 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _GDRIVE_UTILS_HXX_
+#define _GDRIVE_UTILS_HXX_
+
+#include <string>
+
+#include <libcmis/property.hxx>
+
+#include "json-utils.hxx"
+
+static const std::string GDRIVE_FOLDER_MIME_TYPE = "application/vnd.google-apps.folder" ;
+static const std::string GDRIVE_UPLOAD_LINK = "https://www.googleapis.com/upload/drive/v3/files/";
+static const std::string GDRIVE_METADATA_LINK = "https://www.googleapis.com/drive/v3/files/";
+
+class GdriveUtils
+{
+ public :
+
+ // Convert a GDrive Property key to a CMIS key
+ static std::string toCmisKey( const std::string& key);
+
+ // Convert a CMIS key to GDrive key
+ static std::string toGdriveKey( const std::string& key );
+
+ // Convert CMIS properties to GDrive properties
+ static Json toGdriveJson( const libcmis::PropertyPtrMap& properties );
+
+ // Check if a property is updatable
+ static bool checkUpdatable( const std::string& key);
+
+ // Check if a property has multiple values
+ static bool checkMultiValued( const std::string& key);
+
+ // Create a Json array from a ParentId
+ static Json createJsonFromParentId( const std::string& parentId );
+
+ // Parse a Gdrive property value to CMIS values
+ static std::vector< std::string > parseGdriveProperty( std::string key, Json jsonValue );
+};
+
+#endif
diff --git a/src/libcmis/http-session.cxx b/src/libcmis/http-session.cxx
new file mode 100644
index 0000000..f690914
--- /dev/null
+++ b/src/libcmis/http-session.cxx
@@ -0,0 +1,994 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "http-session.hxx"
+
+#include <cctype>
+#include <memory>
+#include <string>
+#include <assert.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/session-factory.hxx>
+#include <libcmis/xml-utils.hxx>
+
+#include "oauth2-handler.hxx"
+
+using namespace std;
+
+namespace
+{
+ size_t lcl_getHeaders( void *ptr, size_t size, size_t nmemb, void *userdata )
+ {
+ libcmis::HttpResponse* response = static_cast< libcmis::HttpResponse* >( userdata );
+
+ string buf( ( const char* ) ptr, size * nmemb );
+
+ size_t sepPos = buf.find( ':' );
+ if ( sepPos != string::npos )
+ {
+ string name( buf, 0, sepPos );
+ string value = buf.substr( sepPos + 1 );
+ value = libcmis::trim( value );
+
+ response->getHeaders()[name] = value;
+
+ if ( "Content-Transfer-Encoding" == name )
+ response->getData( )->setEncoding( value );
+ }
+
+ return nmemb;
+ }
+
+ size_t lcl_bufferData( void* buffer, size_t size, size_t nmemb, void* data )
+ {
+ libcmis::EncodedData* encoded = static_cast< libcmis::EncodedData* >( data );
+ encoded->decode( buffer, size, nmemb );
+ return nmemb;
+ }
+
+ size_t lcl_readStream( void* buffer, size_t size, size_t nmemb, void* data )
+ {
+ istream& is = *( static_cast< istream* >( data ) );
+ char* out = ( char * ) buffer;
+ is.read( out, size * nmemb );
+
+ return is.gcount( ) / size;
+ }
+
+#if (LIBCURL_VERSION_MAJOR < 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR < 85)
+ curlioerr lcl_ioctlStream( CURL* /*handle*/, int cmd, void* data )
+ {
+ curlioerr errCode = CURLIOE_OK;
+
+ switch ( cmd )
+ {
+ case CURLIOCMD_RESTARTREAD:
+ {
+ istream& is = *( static_cast< istream* >( data ) );
+ is.clear( );
+ is.seekg( 0, ios::beg );
+
+ if ( !is.good() )
+ {
+ fprintf ( stderr, "rewind failed\n" );
+ errCode = CURLIOE_FAILRESTART;
+ }
+ }
+ break;
+ case CURLIOCMD_NOP:
+ break;
+ default:
+ errCode = CURLIOE_UNKNOWNCMD;
+ }
+ return errCode;
+ }
+#endif
+
+ int lcl_seekStream(void* data, curl_off_t offset, int origin)
+ {
+ std::ios_base::seekdir dir = {};
+ switch (origin)
+ {
+ case SEEK_SET: dir = std::ios_base::beg; break;
+ case SEEK_CUR: dir = std::ios_base::cur; break;
+ case SEEK_END: dir = std::ios_base::end; break;
+ default: assert(false); break;
+ }
+ istream& is = *(static_cast<istream*>(data));
+ is.clear();
+ is.seekg(offset, dir);
+ if (!is.good())
+ {
+ fprintf(stderr, "rewind failed\n");
+ return CURL_SEEKFUNC_FAIL;
+ }
+ return CURL_SEEKFUNC_OK;
+ }
+
+ template<typename T>
+ class ScopeGuard
+ {
+ public:
+ ScopeGuard(T &var, T newValue)
+ : m_var(var)
+ , m_origValue(var)
+ {
+ m_var = newValue;
+ }
+
+ ~ScopeGuard()
+ {
+ m_var = m_origValue;
+ }
+
+ private:
+ T& m_var;
+ const T m_origValue;
+ };
+}
+
+HttpSession::HttpSession( string username, string password, bool noSslCheck,
+ libcmis::OAuth2DataPtr oauth2, bool verbose,
+ libcmis::CurlInitProtocolsFunction initProtocolsFunction) :
+ m_curlHandle( NULL ),
+ m_CurlInitProtocolsFunction(initProtocolsFunction),
+ m_no100Continue( false ),
+ m_oauth2Handler( NULL ),
+ m_username( username ),
+ m_password( password ),
+ m_authProvided( false ),
+ m_verbose( verbose ),
+ m_noHttpErrors( false ),
+ m_noSSLCheck( noSslCheck ),
+ m_refreshedToken( false ),
+ m_inOAuth2Authentication( false ),
+ m_authMethod( CURLAUTH_ANY )
+{
+ curl_global_init( CURL_GLOBAL_ALL );
+ m_curlHandle = curl_easy_init( );
+
+ if ( oauth2 && oauth2->isComplete( ) ){
+ setOAuth2Data( oauth2 );
+ }
+}
+
+HttpSession::HttpSession( const HttpSession& copy ) :
+ m_curlHandle( NULL ),
+ m_no100Continue( copy.m_no100Continue ),
+ m_oauth2Handler( copy.m_oauth2Handler ),
+ m_username( copy.m_username ),
+ m_password( copy.m_password ),
+ m_authProvided( copy.m_authProvided ),
+ m_verbose( copy.m_verbose ),
+ m_noHttpErrors( copy.m_noHttpErrors ),
+ m_noSSLCheck( copy.m_noSSLCheck ),
+ m_refreshedToken( false ),
+ m_inOAuth2Authentication( false ),
+ m_authMethod( copy.m_authMethod )
+{
+ // Not sure how sharing curl handles is safe.
+ curl_global_init( CURL_GLOBAL_ALL );
+ m_curlHandle = curl_easy_init( );
+}
+
+HttpSession::HttpSession( ) :
+ m_curlHandle( NULL ),
+ m_no100Continue( false ),
+ m_oauth2Handler( NULL ),
+ m_username( ),
+ m_password( ),
+ m_authProvided( false ),
+ m_verbose( false ),
+ m_noHttpErrors( false ),
+ m_noSSLCheck( false ),
+ m_refreshedToken( false ),
+ m_inOAuth2Authentication( false ),
+ m_authMethod( CURLAUTH_ANY )
+{
+ curl_global_init( CURL_GLOBAL_ALL );
+ m_curlHandle = curl_easy_init( );
+}
+
+HttpSession& HttpSession::operator=( const HttpSession& copy )
+{
+ if ( this != &copy )
+ {
+ curl_easy_cleanup( m_curlHandle );
+ m_curlHandle = NULL;
+ m_no100Continue = copy.m_no100Continue;
+ m_oauth2Handler = copy.m_oauth2Handler;
+ m_username = copy.m_username;
+ m_password = copy.m_password;
+ m_authProvided = copy.m_authProvided;
+ m_verbose = copy.m_verbose;
+ m_noHttpErrors = copy.m_noHttpErrors;
+ m_noSSLCheck = copy.m_noSSLCheck;
+ m_refreshedToken = copy.m_refreshedToken;
+ m_inOAuth2Authentication = copy.m_inOAuth2Authentication;
+ m_authMethod = copy.m_authMethod;
+
+ // Not sure how sharing curl handles is safe.
+ curl_global_init( CURL_GLOBAL_ALL );
+ m_curlHandle = curl_easy_init( );
+ }
+
+ return *this;
+}
+
+HttpSession::~HttpSession( )
+{
+ if ( NULL != m_curlHandle )
+ curl_easy_cleanup( m_curlHandle );
+ delete( m_oauth2Handler );
+}
+
+string& HttpSession::getUsername( )
+{
+ checkCredentials( );
+ return m_username;
+}
+
+string& HttpSession::getPassword( )
+{
+ checkCredentials( );
+ return m_password;
+}
+
+libcmis::HttpResponsePtr HttpSession::httpGetRequest( string url )
+{
+ checkOAuth2( url );
+
+ // Reset the handle for the request
+ curl_easy_reset( m_curlHandle );
+ initProtocols( );
+
+ libcmis::HttpResponsePtr response( new libcmis::HttpResponse( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, lcl_bufferData );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, response->getData( ).get( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_HEADERFUNCTION, &lcl_getHeaders );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEHEADER, response.get() );
+
+ // fix Cloudoku too many redirects error
+ // note: though curl doc says -1 is the default for MAXREDIRS, the error i got
+ // said it was 0
+ curl_easy_setopt( m_curlHandle, CURLOPT_MAXREDIRS, 20);
+
+ try
+ {
+ httpRunRequest( url );
+ response->getData( )->finish( );
+ }
+ catch ( const CurlException& )
+ {
+ // If the access token is expired, we get 401 error,
+ // Need to use the refresh token to get a new one.
+ if ( getHttpStatus( ) == 401 && !getRefreshToken( ).empty( ) && !m_refreshedToken )
+ {
+ // Refresh the token
+ oauth2Refresh();
+
+ // Resend the query
+ try
+ {
+ // Avoid infinite recursive call
+ m_refreshedToken = true;
+ response = httpGetRequest( url );
+ m_refreshedToken = false;
+ }
+ catch (const CurlException& )
+ {
+ throw;
+ }
+ m_refreshedToken = false;
+ }
+ else throw;
+ }
+ m_refreshedToken = false;
+
+ return response;
+}
+
+libcmis::HttpResponsePtr HttpSession::httpPatchRequest( string url, istream& is, vector< string > headers )
+{
+ checkOAuth2( url );
+
+ // Duplicate istream in case we need to retry
+ string isStr( static_cast< stringstream const&>( stringstream( ) << is.rdbuf( ) ).str( ) );
+
+ istringstream isOriginal( isStr ), isBackup( isStr );
+
+ // Reset the handle for the request
+ curl_easy_reset( m_curlHandle );
+ initProtocols( );
+
+ libcmis::HttpResponsePtr response( new libcmis::HttpResponse( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, lcl_bufferData );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, response->getData( ).get( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_HEADERFUNCTION, &lcl_getHeaders );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEHEADER, response.get() );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_MAXREDIRS, 20);
+
+ // Get the stream length
+ is.seekg( 0, ios::end );
+ long size = is.tellg( );
+ is.seekg( 0, ios::beg );
+ curl_easy_setopt( m_curlHandle, CURLOPT_INFILESIZE, size );
+ curl_easy_setopt( m_curlHandle, CURLOPT_READDATA, &isOriginal );
+ curl_easy_setopt( m_curlHandle, CURLOPT_READFUNCTION, lcl_readStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_UPLOAD, 1 );
+ curl_easy_setopt( m_curlHandle, CURLOPT_CUSTOMREQUEST, "PATCH" );
+#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 85)
+ curl_easy_setopt( m_curlHandle, CURLOPT_SEEKFUNCTION, lcl_seekStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_SEEKDATA, &isOriginal );
+#else
+ curl_easy_setopt( m_curlHandle, CURLOPT_IOCTLFUNCTION, lcl_ioctlStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_IOCTLDATA, &isOriginal );
+#endif
+
+ // If we know for sure that 100-Continue won't be accepted,
+ // don't even try with it to save one HTTP request.
+ if ( m_no100Continue )
+ headers.push_back( "Expect:" );
+ try
+ {
+ httpRunRequest( url, headers );
+ response->getData( )->finish();
+ }
+ catch ( const CurlException& )
+ {
+ long status = getHttpStatus( );
+ /** If we had a HTTP 417 response, this is likely to be due to some
+ HTTP 1.0 proxy / server not accepting the "Expect: 100-continue"
+ header. Try to disable this header and try again.
+ */
+ if ( status == 417 && !m_no100Continue)
+ {
+ // Remember that we don't want 100-Continue for the future requests
+ m_no100Continue = true;
+ response = httpPutRequest( url, isBackup, headers );
+ }
+
+ // If the access token is expired, we get 401 error,
+ // Need to use the refresh token to get a new one.
+ if ( status == 401 && !getRefreshToken( ).empty( ) && !m_refreshedToken )
+ {
+
+ // Refresh the token
+ oauth2Refresh();
+
+ // Resend the query
+ try
+ {
+ // Avoid infinite recursive call
+ m_refreshedToken = true;
+ response = httpPutRequest( url, isBackup, headers );
+ m_refreshedToken = false;
+ }
+ catch (const CurlException&)
+ {
+ m_refreshedToken = false;
+ throw;
+ }
+ }
+ // Has tried but failed
+ if ( ( status != 417 || m_no100Continue ) &&
+ ( status != 401 || getRefreshToken( ).empty( ) || m_refreshedToken ) ) throw;
+ }
+ m_refreshedToken = false;
+ return response;
+}
+
+libcmis::HttpResponsePtr HttpSession::httpPutRequest( string url, istream& is, vector< string > headers )
+{
+ checkOAuth2( url );
+
+ // Duplicate istream in case we need to retry
+ string isStr( static_cast< stringstream const&>( stringstream( ) << is.rdbuf( ) ).str( ) );
+
+ istringstream isOriginal( isStr ), isBackup( isStr );
+
+ // Reset the handle for the request
+ curl_easy_reset( m_curlHandle );
+ initProtocols( );
+
+ libcmis::HttpResponsePtr response( new libcmis::HttpResponse( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, lcl_bufferData );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, response->getData( ).get( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_HEADERFUNCTION, &lcl_getHeaders );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEHEADER, response.get() );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_MAXREDIRS, 20);
+
+ // Get the stream length
+ is.seekg( 0, ios::end );
+ long size = is.tellg( );
+ is.seekg( 0, ios::beg );
+ curl_easy_setopt( m_curlHandle, CURLOPT_INFILESIZE, size );
+ curl_easy_setopt( m_curlHandle, CURLOPT_READDATA, &isOriginal );
+ curl_easy_setopt( m_curlHandle, CURLOPT_READFUNCTION, lcl_readStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_UPLOAD, 1 );
+#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 85)
+ curl_easy_setopt( m_curlHandle, CURLOPT_SEEKFUNCTION, lcl_seekStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_SEEKDATA, &isOriginal );
+#else
+ curl_easy_setopt( m_curlHandle, CURLOPT_IOCTLFUNCTION, lcl_ioctlStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_IOCTLDATA, &isOriginal );
+#endif
+
+ // If we know for sure that 100-Continue won't be accepted,
+ // don't even try with it to save one HTTP request.
+ if ( m_no100Continue )
+ headers.push_back( "Expect:" );
+ try
+ {
+ httpRunRequest( url, headers );
+ response->getData( )->finish();
+ }
+ catch ( const CurlException& )
+ {
+ long status = getHttpStatus( );
+ /** If we had a HTTP 417 response, this is likely to be due to some
+ HTTP 1.0 proxy / server not accepting the "Expect: 100-continue"
+ header. Try to disable this header and try again.
+ */
+ if ( status == 417 && !m_no100Continue)
+ {
+ // Remember that we don't want 100-Continue for the future requests
+ m_no100Continue = true;
+ response = httpPutRequest( url, isBackup, headers );
+ }
+
+ // If the access token is expired, we get 401 error,
+ // Need to use the refresh token to get a new one.
+ if ( status == 401 && !getRefreshToken( ).empty( ) && !m_refreshedToken )
+ {
+
+ // Refresh the token
+ oauth2Refresh();
+
+ // Resend the query
+ try
+ {
+ // Avoid infinite recursive call
+ m_refreshedToken = true;
+ response = httpPutRequest( url, isBackup, headers );
+ m_refreshedToken = false;
+ }
+ catch (const CurlException& )
+ {
+ m_refreshedToken = false;
+ throw;
+ }
+ }
+ // Has tried but failed
+ if ( ( status != 417 || m_no100Continue ) &&
+ ( status != 401 || getRefreshToken( ).empty( ) || m_refreshedToken ) ) throw;
+ }
+ m_refreshedToken = false;
+ return response;
+}
+
+libcmis::HttpResponsePtr HttpSession::httpPostRequest( const string& url, istream& is,
+ const string& contentType, bool redirect )
+{
+ checkOAuth2( url );
+
+ // Duplicate istream in case we need to retry
+ string isStr( static_cast< stringstream const&>( stringstream( ) << is.rdbuf( ) ).str( ) );
+
+ istringstream isOriginal( isStr ), isBackup( isStr );
+
+ // Reset the handle for the request
+ curl_easy_reset( m_curlHandle );
+ initProtocols( );
+
+ libcmis::HttpResponsePtr response( new libcmis::HttpResponse( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, lcl_bufferData );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, response->getData( ).get( ) );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_HEADERFUNCTION, &lcl_getHeaders );
+ curl_easy_setopt( m_curlHandle, CURLOPT_WRITEHEADER, response.get() );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_MAXREDIRS, 20);
+
+ // Get the stream length
+ is.seekg( 0, ios::end );
+ long size = is.tellg( );
+ is.seekg( 0, ios::beg );
+ curl_easy_setopt( m_curlHandle, CURLOPT_POSTFIELDSIZE, size );
+ curl_easy_setopt( m_curlHandle, CURLOPT_READDATA, &isOriginal );
+ curl_easy_setopt( m_curlHandle, CURLOPT_READFUNCTION, lcl_readStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_POST, 1 );
+#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 85)
+ curl_easy_setopt( m_curlHandle, CURLOPT_SEEKFUNCTION, lcl_seekStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_SEEKDATA, &isOriginal );
+#else
+ curl_easy_setopt( m_curlHandle, CURLOPT_IOCTLFUNCTION, lcl_ioctlStream );
+ curl_easy_setopt( m_curlHandle, CURLOPT_IOCTLDATA, &isOriginal );
+#endif
+
+ vector< string > headers;
+ headers.push_back( string( "Content-Type:" ) + contentType );
+
+ // If we know for sure that 100-Continue won't be accepted,
+ // don't even try with it to save one HTTP request.
+ if ( m_no100Continue )
+ headers.push_back( "Expect:" );
+ try
+ {
+ httpRunRequest( url, headers, redirect );
+ response->getData( )->finish();
+ }
+ catch ( const CurlException& )
+ {
+
+ long status = getHttpStatus( );
+ /** If we had a HTTP 417 response, this is likely to be due to some
+ HTTP 1.0 proxy / server not accepting the "Expect: 100-continue"
+ header. Try to disable this header and try again.
+ */
+ if ( status == 417 && !m_no100Continue )
+ {
+ // Remember that we don't want 100-Continue for the future requests
+ m_no100Continue = true;
+ response = httpPostRequest( url, isBackup, contentType, redirect );
+ }
+
+ // If the access token is expired, we get 401 error,
+ // Need to use the refresh token to get a new one.
+ if ( status == 401 && !getRefreshToken( ).empty( ) && !m_refreshedToken )
+ {
+ // Refresh the token
+ oauth2Refresh();
+
+ // Resend the query
+ try
+ {
+ // Avoid infinite recursive call
+ m_refreshedToken = true;
+ response = httpPostRequest( url, isBackup, contentType, redirect );
+ m_refreshedToken = false;
+ }
+ catch (const CurlException& )
+ {
+ m_refreshedToken = false;
+ throw;
+ }
+ }
+
+ // Has tried but failed
+ if ( ( status != 417 || m_no100Continue ) &&
+ ( status != 401 || getRefreshToken( ).empty( ) || m_refreshedToken ) ) throw;
+ }
+ m_refreshedToken = false;
+
+ return response;
+}
+
+void HttpSession::httpDeleteRequest( string url )
+{
+ checkOAuth2( url );
+
+ // Reset the handle for the request
+ curl_easy_reset( m_curlHandle );
+ initProtocols( );
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_CUSTOMREQUEST, "DELETE" );
+ try
+ {
+ httpRunRequest( url );
+ }
+ catch ( const CurlException& )
+ {
+ // If the access token is expired, we get 401 error,
+ // Need to use the refresh token to get a new one.
+ if ( getHttpStatus( ) == 401 && !getRefreshToken( ).empty( ) && !m_refreshedToken )
+ {
+
+ // Refresh the token
+ oauth2Refresh();
+
+ // Resend the query
+ try
+ {
+ // Avoid infinite recursive call
+ m_refreshedToken = true;
+ httpDeleteRequest( url );
+ m_refreshedToken = false;
+ }
+ catch (const CurlException& )
+ {
+ m_refreshedToken = false;
+ throw;
+ }
+ }
+ else throw;
+ }
+ m_refreshedToken = false;
+}
+
+void HttpSession::checkCredentials( )
+{
+ // Check that we have the complete credentials
+ libcmis::AuthProviderPtr authProvider = libcmis::SessionFactory::getAuthenticationProvider();
+ if ( authProvider && !m_authProvided && ( m_username.empty() || m_password.empty() ) )
+ {
+ m_authProvided = authProvider->authenticationQuery( m_username, m_password );
+ if ( !m_authProvided )
+ {
+ throw CurlException( "User cancelled authentication request" );
+ }
+ }
+}
+
+void HttpSession::httpRunRequest( string url, vector< string > headers, bool redirect )
+{
+ // Redirect
+ curl_easy_setopt( m_curlHandle, CURLOPT_FOLLOWLOCATION, redirect);
+
+ // Activate the cookie engine
+ curl_easy_setopt( m_curlHandle, CURLOPT_COOKIEFILE, "" );
+
+ // Grab something from the web
+ curl_easy_setopt( m_curlHandle, CURLOPT_URL, url.c_str() );
+
+ // Set the headers
+ struct curl_slist *headers_slist = NULL;
+ for ( vector< string >::iterator it = headers.begin( ); it != headers.end( ); ++it )
+ headers_slist = curl_slist_append( headers_slist, it->c_str( ) );
+
+ // If we are using OAuth2, then add the proper header with token to authenticate
+ // Otherwise, just set the credentials normally using in libcurl options
+ if ( m_oauth2Handler != NULL && !m_oauth2Handler->getHttpHeader( ).empty() )
+ {
+ headers_slist = curl_slist_append( headers_slist,
+ m_oauth2Handler->getHttpHeader( ).c_str( ) );
+ }
+ else if ( !getUsername().empty() )
+ {
+ curl_easy_setopt( m_curlHandle, CURLOPT_HTTPAUTH, m_authMethod );
+#if LIBCURL_VERSION_VALUE >= 0x071301
+ curl_easy_setopt( m_curlHandle, CURLOPT_USERNAME, getUsername().c_str() );
+ curl_easy_setopt( m_curlHandle, CURLOPT_PASSWORD, getPassword().c_str() );
+#else
+ string userpwd = getUsername() + ":" + getPassword();
+ curl_easy_setopt( m_curlHandle, CURLOPT_USERPWD, userpwd.c_str( ) );
+#endif
+ }
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, headers_slist );
+
+ // Set the proxy configuration if any
+ if ( !libcmis::SessionFactory::getProxy( ).empty() )
+ {
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, libcmis::SessionFactory::getProxy( ).c_str() );
+#if LIBCURL_VERSION_VALUE >= 0x071304
+ curl_easy_setopt( m_curlHandle, CURLOPT_NOPROXY, libcmis::SessionFactory::getNoProxy( ).c_str() );
+#endif
+ const string& proxyUser = libcmis::SessionFactory::getProxyUser( );
+ const string& proxyPass = libcmis::SessionFactory::getProxyPass( );
+ if ( !proxyUser.empty( ) && !proxyPass.empty( ) )
+ {
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
+#if LIBCURL_VERSION_VALUE >= 0X071301
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERNAME, proxyUser.c_str( ) );
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYPASSWORD, proxyPass.c_str( ) );
+#else
+ string userpwd = proxyUser + ":" + proxyPass;
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, userpwd.c_str( ) );
+#endif
+ }
+ }
+
+ // Get some feedback when something wrong happens
+ char errBuff[CURL_ERROR_SIZE];
+ errBuff[0] = 0;
+ curl_easy_setopt( m_curlHandle, CURLOPT_ERRORBUFFER, errBuff );
+
+ // We want to get the response even if there is an Http error
+ if ( !m_noHttpErrors )
+ curl_easy_setopt( m_curlHandle, CURLOPT_FAILONERROR, 1 );
+
+ if ( m_verbose )
+ curl_easy_setopt( m_curlHandle, CURLOPT_VERBOSE, 1 );
+
+ // We want to get the certificate infos in error cases
+#if LIBCURL_VERSION_VALUE >= 0X071301
+ curl_easy_setopt( m_curlHandle, CURLOPT_CERTINFO, 1 );
+#endif
+
+ if ( m_noSSLCheck )
+ {
+#if LIBCURL_VERSION_VALUE >= 0x070801
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+#if LIBCURL_VERSION_VALUE >= 0x070402
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYPEER, 0);
+#endif
+ }
+
+ // Perform the query
+ CURLcode errCode = curl_easy_perform( m_curlHandle );
+
+ // Free the headers list
+ curl_slist_free_all( headers_slist );
+
+ // Process the response
+ bool isHttpError = errCode == CURLE_HTTP_RETURNED_ERROR;
+ if ( CURLE_OK != errCode && !( m_noHttpErrors && isHttpError ) )
+ {
+ long httpError = 0;
+ curl_easy_getinfo( m_curlHandle, CURLINFO_RESPONSE_CODE, &httpError );
+
+ bool errorFixed = false;
+#if LIBCURL_VERSION_VALUE >= 0X071301
+ // If we had a bad certificate, then try to get more details
+ if ( CURLE_SSL_CACERT == errCode )
+ {
+ vector< string > certificates;
+
+ // We somehow need to rerun the request to get the certificate
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYPEER, 0);
+ errCode = curl_easy_perform( m_curlHandle );
+
+ union {
+ struct curl_slist *to_info;
+ struct curl_certinfo *to_certinfo;
+ } ptr;
+
+ ptr.to_info = NULL;
+
+ CURLcode res = curl_easy_getinfo(m_curlHandle, CURLINFO_CERTINFO, &ptr.to_info);
+
+ if ( !res && ptr.to_info )
+ {
+ // We need the first certificate in the chain only
+ if ( ptr.to_certinfo->num_of_certs > 0 )
+ {
+ struct curl_slist *slist;
+
+ string certStart( "Cert:" );
+ for ( slist = ptr.to_certinfo->certinfo[0]; slist; slist = slist->next )
+ {
+ string data( slist->data );
+ size_t startPos = data.find( certStart );
+ if ( startPos == 0 )
+ {
+ startPos = certStart.length();
+ data = data.substr( startPos );
+ certificates.push_back( data );
+ }
+ }
+ }
+ }
+
+ if ( !certificates.empty() )
+ {
+ libcmis::CertValidationHandlerPtr validationHandler =
+ libcmis::SessionFactory::getCertificateValidationHandler( );
+ bool ignoreCert = validationHandler && validationHandler->validateCertificate( certificates );
+ if ( ignoreCert )
+ {
+ m_noSSLCheck = true;
+
+ isHttpError = errCode == CURLE_HTTP_RETURNED_ERROR;
+ errorFixed = ( CURLE_OK == errCode || ( m_noHttpErrors && isHttpError ) );
+ if ( !errorFixed )
+ curl_easy_getinfo( m_curlHandle, CURLINFO_RESPONSE_CODE, &httpError );
+ }
+ else
+ {
+ throw CurlException( "Invalid SSL certificate" );
+ }
+ }
+ }
+#endif
+
+ if ( !errorFixed )
+ throw CurlException( string( errBuff ), errCode, url, httpError );
+ }
+}
+
+
+void HttpSession::checkOAuth2( string url )
+try
+{
+ if ( m_oauth2Handler )
+ {
+ m_oauth2Handler->setOAuth2Parser( OAuth2Providers::getOAuth2Parser( url ) );
+ if ( m_oauth2Handler->getAccessToken().empty() && !m_inOAuth2Authentication )
+ oauth2Authenticate( );
+ }
+}
+catch ( const libcmis::Exception& e )
+{
+ throw CurlException( e.what( ) );
+}
+
+long HttpSession::getHttpStatus( )
+{
+ long status = 0;
+ curl_easy_getinfo( m_curlHandle, CURLINFO_RESPONSE_CODE, &status );
+
+ return status;
+}
+
+void HttpSession::setOAuth2Data( libcmis::OAuth2DataPtr oauth2 )
+{
+ m_oauth2Handler = new OAuth2Handler( this, oauth2 );
+}
+
+void HttpSession::oauth2Authenticate( )
+{
+ string authCode;
+
+ const ScopeGuard<bool> inOauth2Guard(m_inOAuth2Authentication, true);
+
+ try
+ {
+ // Try to get the authentication code using the given provider.
+ authCode = m_oauth2Handler->oauth2Authenticate( );
+
+ // If that didn't work, call the fallback provider from SessionFactory
+ if ( authCode.empty( ) )
+ {
+ libcmis::OAuth2AuthCodeProvider fallbackProvider = libcmis::SessionFactory::getOAuth2AuthCodeProvider( );
+ if ( fallbackProvider != NULL )
+ {
+ unique_ptr< char, void (*)( void * ) > code{
+ fallbackProvider( m_oauth2Handler->getAuthURL().c_str(), getUsername().c_str(), getPassword().c_str() ),
+ free };
+ if ( code )
+ authCode = string( code.get() );
+ }
+ }
+ }
+ catch ( const CurlException& e )
+ {
+ // Thrown by getUsername() and getPassword() if user cancels the credentials request
+ throw e.getCmisException( );
+ }
+
+ // If still no auth code, then raise an exception
+ if ( authCode.empty( ) )
+ throw libcmis::Exception( "Couldn't get OAuth authentication code", "permissionDenied" );
+
+ m_oauth2Handler->fetchTokens( string( authCode ) );
+}
+
+void HttpSession::setNoSSLCertificateCheck( bool noCheck )
+{
+ m_noSSLCheck = noCheck;
+}
+
+string HttpSession::getRefreshToken( )
+{
+ string refreshToken;
+ if ( m_oauth2Handler )
+ refreshToken = m_oauth2Handler->getRefreshToken( );
+ return refreshToken;
+}
+
+void HttpSession::oauth2Refresh( )
+try
+{
+ const ScopeGuard<bool> inOauth2Guard(m_inOAuth2Authentication, true);
+ m_oauth2Handler->refresh( );
+}
+catch ( const libcmis::Exception& e )
+{
+ throw CurlException( e.what() );
+}
+
+void HttpSession::initProtocols( )
+{
+#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 85)
+ auto const protocols = "https,http";
+ curl_easy_setopt(m_curlHandle, CURLOPT_PROTOCOLS_STR, protocols);
+ curl_easy_setopt(m_curlHandle, CURLOPT_REDIR_PROTOCOLS_STR, protocols);
+#else
+ const unsigned long protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS;
+ curl_easy_setopt(m_curlHandle, CURLOPT_PROTOCOLS, protocols);
+ curl_easy_setopt(m_curlHandle, CURLOPT_REDIR_PROTOCOLS, protocols);
+#endif
+ if (m_CurlInitProtocolsFunction)
+ {
+ (*m_CurlInitProtocolsFunction)(m_curlHandle);
+ }
+}
+
+const char* CurlException::what( ) const noexcept
+{
+ if ( !isCancelled( ) )
+ {
+ stringstream buf;
+ buf << "CURL error - " << ( unsigned int ) m_code << ": ";
+ buf << m_message;
+ m_errorMessage = buf.str( );
+
+ return m_errorMessage.c_str( );
+ }
+
+ return m_message.c_str( );
+}
+
+libcmis::Exception CurlException::getCmisException( ) const
+{
+ string msg;
+ string type( "runtime" );
+
+ switch ( m_httpStatus )
+ {
+ case 400:
+ msg = string( what() ) + string( ": " ) + m_url;
+ type = "invalidArgument";
+ break;
+ case 401:
+ msg = "Authentication failure";
+ type = "permissionDenied";
+ break;
+ case 403:
+ msg = "Invalid credentials";
+ type = "permissionDenied";
+ break;
+ case 404:
+ msg = "Invalid URL: " + m_url;
+ type = "objectNotFound";
+ break;
+ case 405:
+ msg = string( what() ) + string( ": " ) + m_url;
+ type = "notSupported";
+ break;
+ case 409:
+ msg = "Editing conflict error";
+ type = "updateConflict";
+ break;
+ default:
+ msg = what();
+ if ( !isCancelled( ) )
+ msg += ": " + m_url;
+ else
+ type = "permissionDenied";
+ break;
+ }
+
+ return libcmis::Exception( msg, type );
+}
diff --git a/src/libcmis/http-session.hxx b/src/libcmis/http-session.hxx
new file mode 100644
index 0000000..34223b2
--- /dev/null
+++ b/src/libcmis/http-session.hxx
@@ -0,0 +1,179 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _HTTP_SESSION_HXX_
+#define _HTTP_SESSION_HXX_
+
+#include <istream>
+#include <sstream>
+#include <vector>
+#include <string>
+
+#include <curl/curl.h>
+#include <libxml/xmlstring.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/exception.hxx>
+#include <libcmis/oauth2-data.hxx>
+#include <libcmis/xml-utils.hxx>
+
+class OAuth2Handler;
+
+namespace libcmis {
+ typedef void(*CurlInitProtocolsFunction)(CURL *);
+}
+
+class CurlException : public std::exception
+{
+ private:
+ std::string m_message;
+ CURLcode m_code;
+ std::string m_url;
+ long m_httpStatus;
+
+ bool m_cancelled;
+
+ mutable std::string m_errorMessage;
+
+ public:
+ CurlException( std::string message, CURLcode code, std::string url, long httpStatus ) :
+ exception( ),
+ m_message( message ),
+ m_code( code ),
+ m_url( url ),
+ m_httpStatus( httpStatus ),
+ m_cancelled( false ),
+ m_errorMessage( )
+ {
+ }
+
+ CurlException( std::string message ) :
+ exception( ),
+ m_message( message ),
+ m_code( CURLE_OK ),
+ m_url( ),
+ m_httpStatus( 0 ),
+ m_cancelled( true ),
+ m_errorMessage( )
+ {
+ }
+
+ ~CurlException( ) noexcept { }
+ virtual const char* what( ) const noexcept;
+
+ CURLcode getErrorCode( ) const { return m_code; }
+ std::string getErrorMessage( ) const { return m_message; }
+ bool isCancelled( ) const { return m_cancelled; }
+ long getHttpStatus( ) const { return m_httpStatus; }
+
+ libcmis::Exception getCmisException ( ) const;
+};
+
+class HttpSession
+{
+ protected:
+ CURL* m_curlHandle;
+ libcmis::CurlInitProtocolsFunction m_CurlInitProtocolsFunction = nullptr;
+ private:
+ bool m_no100Continue;
+ protected:
+ OAuth2Handler* m_oauth2Handler;
+ std::string m_username;
+ std::string m_password;
+ bool m_authProvided;
+
+ bool m_verbose;
+ bool m_noHttpErrors;
+ bool m_noSSLCheck;
+ bool m_refreshedToken;
+ bool m_inOAuth2Authentication;
+ unsigned long m_authMethod;
+ public:
+ HttpSession( std::string username, std::string password,
+ bool noSslCheck = false,
+ libcmis::OAuth2DataPtr oauth2 = libcmis::OAuth2DataPtr(),
+ bool verbose = false,
+ libcmis::CurlInitProtocolsFunction = nullptr);
+
+ HttpSession( const HttpSession& copy );
+ virtual ~HttpSession( );
+
+ HttpSession& operator=( const HttpSession& copy );
+
+ std::string& getUsername( );
+
+ std::string& getPassword( );
+
+ /** Don't throw the HTTP errors as CurlExceptions.
+ */
+ void setNoHttpErrors( bool noHttpErrors ) { m_noHttpErrors = noHttpErrors; }
+
+
+ /** Set the OAuth2 data and get the access / refresh tokens.
+ */
+ virtual void setOAuth2Data( libcmis::OAuth2DataPtr oauth2 );
+
+ libcmis::HttpResponsePtr httpGetRequest( std::string url );
+ libcmis::HttpResponsePtr httpPatchRequest( std::string url,
+ std::istream& is,
+ std::vector< std::string > headers );
+ libcmis::HttpResponsePtr httpPutRequest( std::string url,
+ std::istream& is,
+ std::vector< std::string > headers );
+ libcmis::HttpResponsePtr httpPostRequest( const std::string& url,
+ std::istream& is,
+ const std::string& contentType,
+ bool redirect = true );
+ void httpDeleteRequest( std::string url );
+
+ long getHttpStatus( );
+
+ void setNoSSLCertificateCheck( bool noCheck );
+
+ virtual std::string getRefreshToken( );
+
+ protected:
+ HttpSession( );
+
+ /** Helper function actually handling the oauth2 process.
+ This function is provided for BaseSession to customize
+ the OAuth2 login parser.
+ */
+ void oauth2Authenticate( );
+ void setAuthMethod( unsigned long authMethod ) { m_authMethod = authMethod; }
+ virtual void httpRunRequest( std::string url,
+ std::vector< std::string > headers = std::vector< std::string > ( ),
+ bool redirect = true );
+
+ private:
+ void checkCredentials( );
+ void checkOAuth2( std::string url );
+ void oauth2Refresh( );
+ void initProtocols( );
+};
+
+#endif
diff --git a/src/libcmis/json-utils.cxx b/src/libcmis/json-utils.cxx
new file mode 100644
index 0000000..52b036a
--- /dev/null
+++ b/src/libcmis/json-utils.cxx
@@ -0,0 +1,306 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "json-utils.hxx"
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
+#include <libcmis/exception.hxx>
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+using namespace libcmis;
+using namespace boost;
+using boost::property_tree::ptree;
+using boost::property_tree::json_parser::read_json;
+using boost::property_tree::json_parser::write_json;
+
+Json::Json( ) :
+ m_tJson( ptree( ) ),
+ m_type( json_object )
+{
+}
+
+Json::Json( const char *str ) :
+ m_tJson( ptree( ) ),
+ m_type( json_string )
+{
+ m_tJson.put_value( str );
+ m_type = parseType( );
+}
+
+Json::Json( ptree tJson ) :
+ m_tJson( tJson ),
+ m_type( json_object )
+{
+ m_type = parseType( );
+}
+
+Json::Json( const PropertyPtr& property ):
+ m_tJson( ),
+ m_type( json_object )
+{
+ string str = property->toString( );
+ m_tJson.put("", str );
+}
+
+Json::Json( const PropertyPtrMap& properties ) :
+ m_tJson( ptree( ) ),
+ m_type( json_array )
+{
+ for ( PropertyPtrMap::const_iterator it = properties.begin() ;
+ it != properties.end() ; ++it )
+ {
+ string key = it->first;
+ string value = it->second->toString( );
+ m_tJson.put( key, value );
+ }
+}
+
+Json::Json( const Json& copy ) :
+ m_tJson( copy.m_tJson ),
+ m_type( copy.m_type )
+{
+}
+
+Json::Json( const JsonObject& obj ) :
+ m_tJson( ptree( ) ),
+ m_type( json_array )
+{
+ for ( JsonObject::const_iterator i = obj.begin() ; i != obj.end() ; ++i )
+ add( i->first, i->second ) ;
+}
+
+Json::Json( const JsonVector& arr ) :
+ m_tJson( ptree( ) ),
+ m_type( json_array )
+{
+ for ( std::vector<Json>::const_iterator i = arr.begin(); i != arr.end(); ++i )
+ add( *i ) ;
+}
+
+
+Json::~Json( )
+{
+}
+
+Json& Json::operator=( const Json& rhs )
+{
+ if ( this != &rhs )
+ {
+ m_tJson = rhs.m_tJson;
+ m_type = rhs.m_type;
+ }
+ return *this ;
+}
+
+void Json::swap( Json& rhs )
+{
+ std::swap( m_tJson, rhs.m_tJson );
+ std::swap( m_type, rhs.m_type );
+}
+
+Json Json::operator[]( string key ) const
+{
+ ptree tJson;
+ try
+ {
+ tJson = m_tJson.get_child( key );
+ }
+ catch ( boost::exception const& )
+ {
+ return Json( "" );
+ }
+
+ Json childJson( tJson );
+
+ return childJson ;
+}
+
+void Json::add( const std::string& key, const Json& json )
+{
+ try
+ {
+ m_tJson.add_child( key, json.getTree( ) );
+ }
+ catch ( boost::exception const& )
+ {
+ throw libcmis::Exception( "Couldn't add Json object" );
+ }
+}
+
+Json::JsonVector Json::getList()
+{
+ JsonVector list;
+ for ( const auto &v: m_tJson.get_child("") )
+ {
+ list.push_back( Json( v.second ) );
+ }
+ return list ;
+}
+
+void Json::add( const Json& json )
+{
+ try
+ {
+ m_tJson.push_back( ptree::value_type( "", json.getTree( )) );
+ }
+ catch ( boost::exception const& )
+ {
+ throw libcmis::Exception( "Couldn't add Json object" );
+ }
+}
+
+Json Json::parse( const string& str )
+{
+ ptree pTree;
+ std::stringstream ss( str );
+ if ( ss.good( ) )
+ {
+ try
+ {
+ property_tree::json_parser::read_json( ss, pTree );
+ }
+ catch ( boost::exception const& )
+ {
+ return Json( str.c_str( ) );
+ }
+ }
+ return Json( pTree );
+}
+
+Json::JsonObject Json::getObjects( )
+{
+ JsonObject objs;
+ for ( const auto &v: m_tJson.get_child("") )
+ {
+ Json jsonValue( v.second );
+ objs.insert( JsonObject::value_type(v.first, jsonValue ) );
+ }
+ return objs ;
+}
+
+Json::Type Json::parseType( )
+{
+ Type type = json_string;
+ string str = toString( );
+ if ( str.empty( ) )
+ return type;
+ try
+ {
+ boost::posix_time::ptime time = libcmis::parseDateTime( str );
+ if ( !time.is_not_a_date_time( ) )
+ return json_datetime;
+ }
+ catch (...)
+ {
+ // Try other types
+ }
+ Type backupType = type;
+ type = json_bool;
+ try
+ {
+ parseBool( str );
+ }
+ catch (...)
+ {
+ type = backupType;
+ }
+ if ( type != json_bool )
+ {
+ if ( str.find('.') == string::npos )
+ {
+ backupType = type;
+ type = json_int;
+ try
+ {
+ parseInteger( str );
+ }
+ catch(...)
+ {
+ type = backupType;
+ }
+ }
+ else
+ {
+ backupType = type;
+ type = json_double;
+ try
+ {
+ parseDouble( str );
+ }
+ catch(...)
+ {
+ type = backupType;
+ }
+ }
+ }
+ return type;
+}
+
+Json::Type Json::getDataType( ) const
+{
+ return m_type;
+}
+
+string Json::getStrType( ) const
+{
+ switch ( m_type )
+ {
+ case json_null: return "json_null";
+ case json_bool: return "json_bool";
+ case json_int: return "json_int";
+ case json_double: return "json_double";
+ case json_string: return "json_string";
+ case json_datetime: return "json_datetime";
+ case json_object: return "json_object";
+ case json_array: return "json_array";
+ }
+ return "json_string";
+}
+
+string Json::toString( ) const
+{
+ string str;
+ try
+ {
+ stringstream ss;
+ write_json( ss, m_tJson );
+ str = ss.str( );
+ }
+ catch ( boost::exception const& )
+ {
+ str = m_tJson.get_value<string>( );
+ }
+ // empty json
+ if ( str == "{\n}\n" ) str = "";
+ return str;
+}
+
diff --git a/src/libcmis/json-utils.hxx b/src/libcmis/json-utils.hxx
new file mode 100644
index 0000000..ef3ae55
--- /dev/null
+++ b/src/libcmis/json-utils.hxx
@@ -0,0 +1,87 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _JSON_UTILS_HXX_
+#define _JSON_UTILS_HXX_
+
+#include <string>
+#include <map>
+#include <vector>
+
+#include <boost/property_tree/ptree.hpp>
+
+#include <libcmis/exception.hxx>
+#include <libcmis/property.hxx>
+
+class Json
+{
+ public :
+ typedef std::map< std::string, Json > JsonObject ;
+ typedef std::vector< Json > JsonVector ;
+ enum Type { json_null, json_bool, json_double, json_int, json_object,
+ json_array, json_string, json_datetime } ;
+
+ Json( );
+ Json( const Json& copy );
+ Json( const char *str );
+ Json( const libcmis::PropertyPtr& property );
+ Json( const libcmis::PropertyPtrMap& properties );
+ Json( const JsonVector& arr );
+ Json( const JsonObject& obj );
+
+ ~Json( ) ;
+
+ Json operator[]( std::string key ) const;
+
+ Json& operator=( const Json& rhs ) ;
+
+ void swap( Json& other ) ;
+
+ void add( const Json& json);
+
+ void add( const std::string& key, const Json& json);
+
+ static Json parse( const std::string& str );
+
+ std::string toString( ) const;
+ Type getDataType( ) const ;
+ std::string getStrType( ) const ;
+
+ JsonObject getObjects();
+ JsonVector getList();
+
+ boost::property_tree::ptree getTree( ) const{ return m_tJson; }
+ private :
+ Json( boost::property_tree::ptree tJson ) ;
+ boost::property_tree::ptree m_tJson ;
+ Type m_type;
+ Type parseType( );
+} ;
+
+#endif /* _JSON_UTILS_HXX_ */
+
diff --git a/src/libcmis/oauth2-data.cxx b/src/libcmis/oauth2-data.cxx
new file mode 100644
index 0000000..a56251f
--- /dev/null
+++ b/src/libcmis/oauth2-data.cxx
@@ -0,0 +1,95 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/oauth2-data.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ OAuth2Data::OAuth2Data( ) :
+ m_authUrl( ),
+ m_tokenUrl( ),
+ m_clientId( ),
+ m_clientSecret( ),
+ m_scope( ),
+ m_redirectUri( )
+ {
+ }
+
+ OAuth2Data::OAuth2Data( const string& authUrl, const string& tokenUrl,
+ const string& scope, const string& redirectUri,
+ const string& clientId, const string& clientSecret ):
+ m_authUrl( authUrl ),
+ m_tokenUrl( tokenUrl ),
+ m_clientId( clientId ),
+ m_clientSecret( clientSecret ),
+ m_scope( scope ),
+ m_redirectUri( redirectUri )
+ {
+ }
+
+ OAuth2Data::OAuth2Data( const OAuth2Data& copy ) :
+ m_authUrl( copy.m_authUrl ),
+ m_tokenUrl( copy.m_tokenUrl ),
+ m_clientId( copy.m_clientId ),
+ m_clientSecret( copy.m_clientSecret ),
+ m_scope( copy.m_scope ),
+ m_redirectUri( copy.m_redirectUri )
+ {
+ }
+
+ OAuth2Data::~OAuth2Data( )
+ {
+ }
+
+ OAuth2Data& OAuth2Data::operator=( const OAuth2Data& copy )
+ {
+ if ( this != &copy )
+ {
+ m_authUrl = copy.m_authUrl;
+ m_tokenUrl = copy.m_tokenUrl;
+ m_clientId = copy.m_clientId;
+ m_clientSecret = copy.m_clientSecret;
+ m_scope = copy.m_scope;
+ m_redirectUri = copy.m_redirectUri;
+ }
+
+ return *this;
+ }
+
+ bool OAuth2Data::isComplete()
+ {
+ return !m_authUrl.empty() &&
+ !m_tokenUrl.empty() &&
+ !m_clientId.empty() &&
+ !m_clientSecret.empty() &&
+ !m_scope.empty() &&
+ !m_redirectUri.empty();
+ }
+}
diff --git a/src/libcmis/oauth2-handler.cxx b/src/libcmis/oauth2-handler.cxx
new file mode 100644
index 0000000..a340b80
--- /dev/null
+++ b/src/libcmis/oauth2-handler.cxx
@@ -0,0 +1,196 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <boost/algorithm/string.hpp>
+
+#include "oauth2-handler.hxx"
+
+#include <libcmis/session-factory.hxx>
+#include <libcmis/xml-utils.hxx>
+
+#include "json-utils.hxx"
+#include "oauth2-providers.hxx"
+
+using namespace std;
+
+OAuth2Handler::OAuth2Handler(HttpSession* session, libcmis::OAuth2DataPtr data) :
+ m_session( session ),
+ m_data( data ),
+ m_access( ),
+ m_refresh( ),
+ m_oauth2Parser( )
+{
+ if ( !m_data )
+ m_data.reset( new libcmis::OAuth2Data() );
+
+}
+
+OAuth2Handler::OAuth2Handler( const OAuth2Handler& copy ) :
+ m_session( copy.m_session ),
+ m_data( copy.m_data ),
+ m_access( copy.m_access ),
+ m_refresh( copy.m_refresh ),
+ m_oauth2Parser( copy.m_oauth2Parser )
+{
+}
+
+OAuth2Handler::OAuth2Handler( ):
+ m_session( NULL ),
+ m_data( ),
+ m_access( ),
+ m_refresh( ),
+ m_oauth2Parser( )
+{
+ m_data.reset( new libcmis::OAuth2Data() );
+}
+
+OAuth2Handler& OAuth2Handler::operator=( const OAuth2Handler& copy )
+{
+ if ( this != &copy )
+ {
+ m_session = copy.m_session;
+ m_data = copy.m_data;
+ m_access = copy.m_access;
+ m_refresh = copy.m_refresh;
+ m_oauth2Parser = copy.m_oauth2Parser;
+ }
+
+ return *this;
+}
+
+OAuth2Handler::~OAuth2Handler( )
+{
+
+}
+
+void OAuth2Handler::fetchTokens( string authCode )
+{
+ string post =
+ "code=" + authCode +
+ "&client_id=" + m_data->getClientId() +
+ "&redirect_uri=" + m_data->getRedirectUri() +
+ "&grant_type=authorization_code" ;
+ if(boost::starts_with(m_data->getTokenUrl(), "https://oauth2.googleapis.com/"))
+ post += "&client_secret=" + m_data->getClientSecret();
+ else
+ post += "&scope=" + libcmis::escape( m_data->getScope() );
+
+ istringstream is( post );
+
+ libcmis::HttpResponsePtr resp;
+
+ try
+ {
+ resp = m_session->httpPostRequest ( m_data->getTokenUrl(), is,
+ "application/x-www-form-urlencoded" );
+ }
+ catch ( const CurlException& e)
+ {
+ throw libcmis::Exception(
+ "Couldn't get tokens from the authorization code ");
+ }
+
+ Json jresp = Json::parse( resp->getStream( )->str( ) );
+ m_access = jresp[ "access_token" ].toString( );
+ m_refresh = jresp[ "refresh_token" ].toString( );
+}
+
+void OAuth2Handler::refresh( )
+{
+ m_access = string( );
+ string post =
+ "refresh_token=" + m_refresh +
+ "&client_id=" + m_data->getClientId() +
+ "&grant_type=refresh_token" ;
+ if(boost::starts_with(m_data->getTokenUrl(), "https://oauth2.googleapis.com/"))
+ post += "&client_secret=" + m_data->getClientSecret();
+
+ istringstream is( post );
+ libcmis::HttpResponsePtr resp;
+ try
+ {
+ resp = m_session->httpPostRequest( m_data->getTokenUrl( ), is,
+ "application/x-www-form-urlencoded" );
+ }
+ catch (const CurlException& e )
+ {
+ throw libcmis::Exception( "Couldn't refresh token ");
+ }
+
+ Json jresp = Json::parse( resp->getStream( )->str( ) );
+ m_access = jresp[ "access_token" ].toString();
+}
+
+string OAuth2Handler::getAuthURL( )
+{
+ return m_data->getAuthUrl() +
+ "?scope=" + libcmis::escape( m_data->getScope( ) ) +
+ "&redirect_uri="+ m_data->getRedirectUri( ) +
+ "&response_type=code" +
+ "&client_id=" + m_data->getClientId( );
+}
+
+string OAuth2Handler::getAccessToken( )
+{
+ return m_access;
+}
+
+string OAuth2Handler::getRefreshToken( )
+{
+ return m_refresh;
+}
+
+void OAuth2Handler::setRefreshToken( string refreshToken )
+{
+ m_refresh = refreshToken;
+}
+
+string OAuth2Handler::getHttpHeader( )
+{
+ string header;
+ if ( !m_access.empty() )
+ header = "Authorization: Bearer " + m_access ;
+ return header;
+}
+
+string OAuth2Handler::oauth2Authenticate( )
+{
+ string code;
+ if ( m_oauth2Parser )
+ {
+ code = m_oauth2Parser( m_session, getAuthURL( ),
+ m_session->getUsername( ),
+ m_session->getPassword( ) );
+ }
+ return code;
+}
+
+void OAuth2Handler::setOAuth2Parser( OAuth2Parser parser )
+{
+ m_oauth2Parser = parser;
+}
diff --git a/src/libcmis/oauth2-handler.hxx b/src/libcmis/oauth2-handler.hxx
new file mode 100644
index 0000000..bb9a394
--- /dev/null
+++ b/src/libcmis/oauth2-handler.hxx
@@ -0,0 +1,97 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _OAUTH2_HANDLER_HXX_
+#define _OAUTH2_HANDLER_HXX_
+
+#include <string>
+#include "http-session.hxx"
+#include "oauth2-providers.hxx"
+
+namespace libcmis
+{
+ class OAuth2Data;
+}
+
+class OAuth2Handler
+{
+ private:
+ HttpSession* m_session;
+ libcmis::OAuth2DataPtr m_data;
+
+ std::string m_access;
+ std::string m_refresh;
+
+ OAuth2Parser m_oauth2Parser;
+
+ public:
+
+ OAuth2Handler( HttpSession* session, libcmis::OAuth2DataPtr data );
+
+ OAuth2Handler( const OAuth2Handler& copy );
+ ~OAuth2Handler( );
+
+ OAuth2Handler& operator=( const OAuth2Handler& copy );
+
+ std::string getAuthURL();
+
+ std::string getAccessToken( ) ;
+ std::string getRefreshToken( ) ;
+ void setRefreshToken( std::string refreshToken ) ;
+
+ // adding HTTP auth header
+ std::string getHttpHeader( ) ;
+
+ /** Exchange the previously obtained authentication code with the
+ access/refresh tokens.
+
+ \param authCode
+ the authentication code normally obtained from authenticate
+ method.
+ */
+ void fetchTokens( std::string authCode );
+ void refresh( );
+
+ /** Get the authentication code given credentials.
+
+ This method should be overridden to parse the authentication URL response,
+ authenticate using the form and get the token to avoid asking the user
+ to launch a web browser and do it himself.
+
+ \return
+ the authentication code to transform into access/refresh tokens.
+ If no code is found, an empty string is returned.
+ */
+ std::string oauth2Authenticate( );
+
+ void setOAuth2Parser( OAuth2Parser parser );
+
+ protected:
+ OAuth2Handler( );
+};
+
+#endif /* _OAUTH2_HANDLER_HXX_ */
diff --git a/src/libcmis/oauth2-providers.cxx b/src/libcmis/oauth2-providers.cxx
new file mode 100644
index 0000000..1c8d3cc
--- /dev/null
+++ b/src/libcmis/oauth2-providers.cxx
@@ -0,0 +1,246 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "oauth2-providers.hxx"
+
+#include <memory>
+
+#include <boost/algorithm/string.hpp>
+
+#include <libxml/HTMLparser.h>
+#include <libxml/xmlreader.h>
+
+#include <libcmis/session-factory.hxx>
+
+#include "http-session.hxx"
+
+#define CHALLENGE_PAGE_ACTION "/signin"
+#define CHALLENGE_PAGE_ACTION_LEN sizeof( CHALLENGE_PAGE_ACTION ) - 1
+#define PIN_FORM_ACTION "/signin/challenge/ipp"
+#define PIN_FORM_ACTION_LEN sizeof( PIN_FORM_ACTION ) - 1
+#define PIN_INPUT_NAME "Pin"
+
+using namespace std;
+
+string OAuth2Providers::OAuth2Dummy( HttpSession* /*session*/, const string& /*authUrl*/,
+ const string& /*username*/, const string& /*password*/ )
+{
+ return string( );
+}
+
+string OAuth2Providers::OAuth2Alfresco( HttpSession* session, const string& authUrl,
+ const string& username, const string& password )
+{
+ static const string CONTENT_TYPE( "application/x-www-form-urlencoded" );
+
+ // Log in
+ string res;
+ try
+ {
+ res = session->httpGetRequest( authUrl )->getStream( )->str( );
+ }
+ catch ( const CurlException& )
+ {
+ return string( );
+ }
+
+ string loginPost, loginLink;
+
+ if ( !parseResponse( res.c_str( ), loginPost, loginLink ) )
+ return string( );
+
+ loginPost += "username=";
+ loginPost += string( username );
+ loginPost += "&password=";
+ loginPost += string( password );
+ loginPost += "&action=Grant";
+
+ istringstream loginIs( loginPost );
+
+ libcmis::HttpResponsePtr resp;
+
+ // Get the code
+ try
+ {
+ // Alfresco code is in the redirect link
+ resp = session->httpPostRequest( loginLink, loginIs, CONTENT_TYPE, false );
+ }
+ catch ( const CurlException& )
+ {
+ return string( );
+ }
+
+ string header = resp->getHeaders()["Location"];
+ string code;
+ auto start = header.find("code=");
+ if ( start != string::npos )
+ {
+ start += 5;
+ auto end = header.find("&");
+ if ( end != string::npos )
+ code = header.substr( start, end - start );
+ else code = header.substr( start );
+ }
+
+ return code;
+}
+
+OAuth2Parser OAuth2Providers::getOAuth2Parser( const std::string& url )
+{
+ if ( boost::starts_with( url, "https://api.alfresco.com/" ) )
+ // For Alfresco in the cloud, only match the hostname as there can be several
+ // binding URLs created with it.
+ return OAuth2Alfresco;
+
+ return OAuth2Dummy;
+}
+
+int OAuth2Providers::parseResponse ( const char* response, string& post, string& link )
+{
+ xmlDoc *doc = htmlReadDoc ( BAD_CAST( response ), NULL, 0,
+ HTML_PARSE_NOWARNING | HTML_PARSE_RECOVER | HTML_PARSE_NOERROR );
+ if ( doc == NULL ) return 0;
+ xmlTextReaderPtr reader = xmlReaderWalker( doc );
+ if ( reader == NULL ) return 0;
+
+ bool readInputField = false;
+ bool bIsRightForm = false;
+ bool bHasPinField = false;
+
+ while ( true )
+ {
+ // Go to the next node, quit if not found
+ if ( xmlTextReaderRead ( reader ) != 1) break;
+ xmlChar* nodeName = xmlTextReaderName ( reader );
+ if ( nodeName == NULL ) continue;
+ // Find the redirect link
+ if ( xmlStrEqual( nodeName, BAD_CAST( "form" ) ) )
+ {
+ // 2FA: Don't add fields form other forms not having pin field
+ if ( bIsRightForm && !bHasPinField )
+ post = string( "" );
+ if ( bIsRightForm && bHasPinField )
+ break;
+
+ xmlChar* action = xmlTextReaderGetAttribute( reader,
+ BAD_CAST( "action" ));
+
+ // GDrive pin code page contains many forms.
+ // We have to parse only the form with pin field.
+ if ( action != NULL )
+ {
+ bool bChallengePage = ( strncmp( (char*)action,
+ CHALLENGE_PAGE_ACTION,
+ CHALLENGE_PAGE_ACTION_LEN ) == 0 );
+ bIsRightForm = ( strncmp( (char*)action,
+ PIN_FORM_ACTION,
+ PIN_FORM_ACTION_LEN ) == 0 );
+ if ( ( xmlStrlen( action ) > 0 )
+ && ( ( bChallengePage && bIsRightForm ) || !bChallengePage ) )
+ {
+ link = string ( (char*) action);
+ readInputField = true;
+ }
+ else
+ readInputField = false;
+ xmlFree (action);
+ }
+ }
+ // Find input values
+ if ( readInputField && !xmlStrcmp( nodeName, BAD_CAST( "input" ) ) )
+ {
+ xmlChar* name = xmlTextReaderGetAttribute( reader,
+ BAD_CAST( "name" ));
+ xmlChar* value = xmlTextReaderGetAttribute( reader,
+ BAD_CAST( "value" ));
+ if ( name != NULL && strcmp( (char*)name, PIN_INPUT_NAME ) == 0 )
+ bHasPinField = true;
+ if ( ( name != NULL ) && ( value!= NULL ) )
+ {
+ if ( ( xmlStrlen( name ) > 0) && ( xmlStrlen( value ) > 0) )
+ {
+ post += libcmis::escape( ( char * ) name );
+ post += string ( "=" );
+ post += libcmis::escape( ( char * ) value );
+ post += string ( "&" );
+ }
+ }
+ xmlFree( name );
+ xmlFree( value );
+ }
+ xmlFree( nodeName );
+ }
+ xmlFreeTextReader( reader );
+ xmlFreeDoc( doc );
+ if ( link.empty( ) || post.empty () )
+ return 0;
+ return 1;
+}
+
+string OAuth2Providers::parseCode( const char* response )
+{
+ string authCode;
+ xmlDoc *doc = htmlReadDoc ( BAD_CAST( response ), NULL, 0,
+ HTML_PARSE_NOWARNING | HTML_PARSE_RECOVER | HTML_PARSE_NOERROR );
+ if ( doc == NULL ) return authCode;
+ xmlTextReaderPtr reader = xmlReaderWalker( doc );
+ if ( reader == NULL ) return authCode;
+
+ while ( true )
+ {
+ // Go to the next node, quit if not found
+ if ( xmlTextReaderRead ( reader ) != 1) break;
+ xmlChar* nodeName = xmlTextReaderName ( reader );
+ if ( nodeName == NULL ) continue;
+ // Find the code
+ if ( xmlStrEqual( nodeName, BAD_CAST ( "input" ) ) )
+ {
+ xmlChar* id = xmlTextReaderGetAttribute( reader, BAD_CAST( "id" ));
+ if ( id != NULL )
+ {
+ if ( xmlStrEqual( id, BAD_CAST ( "code" ) ) )
+ {
+ xmlChar* code = xmlTextReaderGetAttribute(
+ reader, BAD_CAST("value") );
+ if ( code!= NULL )
+ {
+ authCode = string ( (char*) code );
+ xmlFree( code );
+ }
+ }
+ xmlFree ( id );
+ }
+ }
+ xmlFree( nodeName );
+ }
+ xmlFreeTextReader( reader );
+ xmlFreeDoc( doc );
+
+ return authCode;
+}
+
diff --git a/src/libcmis/oauth2-providers.hxx b/src/libcmis/oauth2-providers.hxx
new file mode 100644
index 0000000..eaeb1c4
--- /dev/null
+++ b/src/libcmis/oauth2-providers.hxx
@@ -0,0 +1,63 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _OAUTH2_PROVIDERS_HXX_
+#define _OAUTH2_PROVIDERS_HXX_
+
+#include <string>
+
+class HttpSession;
+
+typedef std::string ( *OAuth2Parser ) ( HttpSession* session, const std::string& authUrl,
+ const std::string& username, const std::string& password );
+
+class OAuth2Providers
+{
+ public :
+ static std::string OAuth2Dummy( HttpSession* session, const std::string& authUrl,
+ const std::string& username, const std::string& password );
+ static std::string OAuth2Alfresco( HttpSession* session, const std::string& authUrl,
+ const std::string& username, const std::string& password );
+
+ static OAuth2Parser getOAuth2Parser( const std::string& baseUrl );
+
+ /*
+ * Parse the authorization code from the response page
+ * in the input tag, with id = code
+ */
+ static std::string parseCode ( const char* response );
+
+ /*
+ * Parse input values and redirect link from the response page
+ */
+ static int parseResponse ( const char* response,
+ std::string& post,
+ std::string& link );
+};
+
+#endif /* _OAUTH2_PROVIDERS_HXX_ */
diff --git a/src/libcmis/object-type.cxx b/src/libcmis/object-type.cxx
new file mode 100644
index 0000000..868ec56
--- /dev/null
+++ b/src/libcmis/object-type.cxx
@@ -0,0 +1,368 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+*/
+
+#include <libcmis/object-type.hxx>
+
+#include <libcmis/xml-utils.hxx>
+#include <libcmis/property.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ ObjectType::ObjectType( ) :
+ m_refreshTimestamp( 0 ),
+ m_id( ),
+ m_localName( ),
+ m_localNamespace( ),
+ m_displayName( ),
+ m_queryName( ),
+ m_description( ),
+ m_parentTypeId( ),
+ m_baseTypeId( ),
+ m_creatable( false ),
+ m_fileable( false ),
+ m_queryable( false ),
+ m_fulltextIndexed( false ),
+ m_includedInSupertypeQuery( false ),
+ m_controllablePolicy( false ),
+ m_controllableAcl( false ),
+ m_versionable( false ),
+ m_contentStreamAllowed( libcmis::ObjectType::Allowed ),
+ m_propertiesTypes( )
+ {
+ }
+
+ ObjectType::ObjectType( xmlNodePtr node ) :
+ m_refreshTimestamp( 0 ),
+ m_id( ),
+ m_localName( ),
+ m_localNamespace( ),
+ m_displayName( ),
+ m_queryName( ),
+ m_description( ),
+ m_parentTypeId( ),
+ m_baseTypeId( ),
+ m_creatable( false ),
+ m_fileable( false ),
+ m_queryable( false ),
+ m_fulltextIndexed( false ),
+ m_includedInSupertypeQuery( false ),
+ m_controllablePolicy( false ),
+ m_controllableAcl( false ),
+ m_versionable( false ),
+ m_contentStreamAllowed( libcmis::ObjectType::Allowed ),
+ m_propertiesTypes( )
+ {
+ initializeFromNode( node );
+ }
+
+ ObjectType::ObjectType( const ObjectType& copy ) :
+ m_refreshTimestamp( copy.m_refreshTimestamp ),
+ m_id( copy.m_id ),
+ m_localName( copy.m_localName ),
+ m_localNamespace( copy.m_localNamespace ),
+ m_displayName( copy.m_displayName ),
+ m_queryName( copy.m_queryName ),
+ m_description( copy.m_description ),
+ m_parentTypeId( copy.m_parentTypeId ),
+ m_baseTypeId( copy.m_baseTypeId ),
+ m_creatable( copy.m_creatable ),
+ m_fileable( copy.m_fileable ),
+ m_queryable( copy.m_queryable ),
+ m_fulltextIndexed( copy.m_fulltextIndexed ),
+ m_includedInSupertypeQuery( copy.m_includedInSupertypeQuery ),
+ m_controllablePolicy( copy.m_controllablePolicy ),
+ m_controllableAcl( copy.m_controllableAcl ),
+ m_versionable( copy.m_versionable ),
+ m_contentStreamAllowed( copy.m_contentStreamAllowed ),
+ m_propertiesTypes( copy.m_propertiesTypes )
+ {
+ }
+
+ ObjectType& ObjectType::operator=( const ObjectType& copy )
+ {
+ if ( this != &copy )
+ {
+ m_refreshTimestamp = copy.m_refreshTimestamp;
+ m_id = copy.m_id;
+ m_localName = copy.m_localName;
+ m_localNamespace = copy.m_localNamespace;
+ m_displayName = copy.m_displayName;
+ m_queryName = copy.m_queryName;
+ m_description = copy.m_description;
+ m_parentTypeId = copy.m_parentTypeId;
+ m_baseTypeId = copy.m_baseTypeId;
+ m_creatable = copy.m_creatable;
+ m_fileable = copy.m_fileable;
+ m_queryable = copy.m_queryable;
+ m_fulltextIndexed = copy.m_fulltextIndexed;
+ m_includedInSupertypeQuery = copy.m_includedInSupertypeQuery;
+ m_controllablePolicy = copy.m_controllablePolicy;
+ m_controllableAcl = copy.m_controllableAcl;
+ m_versionable = copy.m_versionable;
+ m_contentStreamAllowed = copy.m_contentStreamAllowed;
+ m_propertiesTypes = copy.m_propertiesTypes;
+ }
+ return *this;
+ }
+
+ time_t ObjectType::getRefreshTimestamp( ) const
+ {
+ return m_refreshTimestamp;
+ }
+
+ string ObjectType::getId( ) const
+ {
+ return m_id;
+ }
+
+ string ObjectType::getLocalName( ) const
+ {
+ return m_localName;
+ }
+
+ string ObjectType::getLocalNamespace( ) const
+ {
+ return m_localNamespace;
+ }
+
+ string ObjectType::getDisplayName( ) const
+ {
+ return m_displayName;
+ }
+
+ string ObjectType::getQueryName( ) const
+ {
+ return m_queryName;
+ }
+
+ string ObjectType::getDescription( ) const
+ {
+ return m_description;
+ }
+
+ string ObjectType::getParentTypeId( ) const
+ {
+ return m_parentTypeId;
+ }
+
+ string ObjectType::getBaseTypeId( ) const
+ {
+ return m_baseTypeId;
+ }
+
+ bool ObjectType::isCreatable( ) const
+ {
+ return m_creatable;
+ }
+
+ bool ObjectType::isFileable( ) const
+ {
+ return m_fileable;
+ }
+
+ bool ObjectType::isQueryable( ) const
+ {
+ return m_queryable;
+ }
+
+ bool ObjectType::isFulltextIndexed( ) const
+ {
+ return m_fulltextIndexed;
+ }
+
+ bool ObjectType::isIncludedInSupertypeQuery( ) const
+ {
+ return m_includedInSupertypeQuery;
+ }
+
+ bool ObjectType::isControllablePolicy( ) const
+ {
+ return m_controllablePolicy;
+ }
+
+ bool ObjectType::isControllableACL( ) const
+ {
+ return m_controllableAcl;
+ }
+
+ bool ObjectType::isVersionable( ) const
+ {
+ return m_versionable;
+ }
+
+ ObjectType::ContentStreamAllowed ObjectType::getContentStreamAllowed( ) const
+ {
+ return m_contentStreamAllowed;
+ }
+
+ map< string, PropertyTypePtr >& ObjectType::getPropertiesTypes( )
+ {
+ return m_propertiesTypes;
+ }
+
+
+ void ObjectType::initializeFromNode( xmlNodePtr typeNode )
+ {
+ if ( typeNode != NULL )
+ {
+ for ( xmlNodePtr child = typeNode->children; child; child = child->next )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( content != NULL )
+ {
+ string value( ( const char * ) content, xmlStrlen( content ) );
+
+ if ( xmlStrEqual( child->name, BAD_CAST( "id" ) ) )
+ m_id = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "localName" ) ) )
+ m_localName = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "localNamespace" ) ) )
+ m_localNamespace = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "displayName" ) ) )
+ m_displayName = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "queryName" ) ) )
+ m_queryName = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "description" ) ) )
+ m_description = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "baseId" ) ) )
+ m_baseTypeId = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "parentId" ) ) )
+ m_parentTypeId = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "creatable" ) ) )
+ m_creatable = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "fileable" ) ) )
+ m_fileable = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "queryable" ) ) )
+ m_queryable = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "fulltextIndexed" ) ) )
+ m_fulltextIndexed = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "includedInSupertypeQuery" ) ) )
+ m_includedInSupertypeQuery = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "controllablePolicy" ) ) )
+ m_controllablePolicy = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "controllableACL" ) ) )
+ m_controllableAcl = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "versionable" ) ) )
+ m_versionable = libcmis::parseBool( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "contentStreamAllowed" ) ) )
+ {
+ libcmis::ObjectType::ContentStreamAllowed streamAllowed = libcmis::ObjectType::Allowed;
+ if ( value == "notallowed" )
+ streamAllowed = libcmis::ObjectType::NotAllowed;
+ else if ( value == "required" )
+ streamAllowed = libcmis::ObjectType::Required;
+
+ m_contentStreamAllowed = streamAllowed;
+ }
+ else
+ {
+ libcmis::PropertyTypePtr type( new libcmis::PropertyType( child ) );
+ m_propertiesTypes[ type->getId() ] = type;
+ }
+
+ xmlFree( content );
+ }
+ }
+ m_refreshTimestamp = time( NULL );
+ }
+ }
+
+ void ObjectType::refresh( )
+ {
+ throw Exception( "ObjectType::refresh() shouldn't be called" );
+ }
+
+ ObjectTypePtr ObjectType::getParentType( )
+ {
+ throw Exception( "ObjectType::getParentType() shouldn't be called" );
+ }
+
+ ObjectTypePtr ObjectType::getBaseType( )
+ {
+ throw Exception( "ObjectType::getBaseType() shouldn't be called" );
+ }
+
+ vector< ObjectTypePtr > ObjectType::getChildren( )
+ {
+ throw Exception( "ObjectType::getChildren() shouldn't be called" );
+ }
+
+ // LCOV_EXCL_START
+ string ObjectType::toString( )
+ {
+ stringstream buf;
+
+ buf << "Type Description:" << endl << endl;
+ buf << "Id: " << getId( ) << endl;
+ buf << "Display name: " << getDisplayName( ) << endl;
+
+ buf << "Parent type: " << m_parentTypeId << endl;
+ buf << "Base type: " << m_baseTypeId << endl;
+ buf << "Children types [(id) Name]: " << endl;
+ try
+ {
+ vector< libcmis::ObjectTypePtr > children = getChildren( );
+ for ( vector< libcmis::ObjectTypePtr >::iterator it = children.begin(); it != children.end(); ++it )
+ {
+ libcmis::ObjectTypePtr type = *it;
+ buf << " (" << type->getId( ) << ")\t" << type->getDisplayName( ) << endl;
+ }
+ }
+ catch ( const libcmis::Exception& )
+ {
+ // Ignore it
+ }
+
+ buf << "Creatable: " << isCreatable( ) << endl;
+ buf << "Fileable: " << isFileable( ) << endl;
+ buf << "Queryable: " << isQueryable( ) << endl;
+ buf << "Full text indexed: " << isFulltextIndexed( ) << endl;
+ buf << "Included in supertype query: " << isIncludedInSupertypeQuery( ) << endl;
+ buf << "Controllable policy: " << isControllablePolicy( ) << endl;
+ buf << "Controllable ACL: " << isControllableACL( ) << endl;
+ buf << "Versionable: " << isVersionable( ) << endl;
+
+ buf << "Property Definitions [RO/RW (id) Name]: " << endl;
+ map< string, libcmis::PropertyTypePtr > propsTypes = getPropertiesTypes( );
+ for ( map< string, libcmis::PropertyTypePtr >::iterator it = propsTypes.begin( ); it != propsTypes.end( ); ++it )
+ {
+ libcmis::PropertyTypePtr propType = it->second;
+ string updatable( "RO" );
+ if ( propType->isUpdatable( ) )
+ updatable = string( "RW" );
+
+ buf << " " << updatable << "\t (" << propType->getId( ) << ")\t"
+ << propType->getDisplayName( ) << endl;
+ }
+
+ return buf.str();
+ }
+ // LCOV_EXCL_STOP
+}
diff --git a/src/libcmis/object.cxx b/src/libcmis/object.cxx
new file mode 100644
index 0000000..cd67f76
--- /dev/null
+++ b/src/libcmis/object.cxx
@@ -0,0 +1,398 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/object.hxx>
+
+#include <algorithm>
+
+#include <libcmis/session.hxx>
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ Object::Object( Session* session ) :
+ m_session( session ),
+ m_typeDescription( ),
+ m_refreshTimestamp( 0 ),
+ m_typeId( ),
+ m_properties( ),
+ m_allowableActions( ),
+ m_renditions( )
+ {
+ }
+
+ Object::Object( Session* session, xmlNodePtr node ) :
+ m_session( session ),
+ m_typeDescription( ),
+ m_refreshTimestamp( 0 ),
+ m_typeId( ),
+ m_properties( ),
+ m_allowableActions( ),
+ m_renditions( )
+ {
+ initializeFromNode( node );
+ }
+
+ Object::Object( const Object& copy ) :
+ m_session( copy.m_session ),
+ m_typeDescription( copy.m_typeDescription ),
+ m_refreshTimestamp( copy.m_refreshTimestamp ),
+ m_typeId( copy.m_typeId ),
+ m_properties( copy.m_properties ),
+ m_allowableActions( copy.m_allowableActions ),
+ m_renditions( copy.m_renditions )
+ {
+ }
+
+ Object& Object::operator=( const Object& copy )
+ {
+ if ( this != &copy )
+ {
+ m_session = copy.m_session;
+ m_typeDescription = copy.m_typeDescription;
+ m_refreshTimestamp = copy.m_refreshTimestamp;
+ m_typeId = copy.m_typeId;
+ m_properties = copy.m_properties;
+ m_allowableActions = copy.m_allowableActions;
+ m_renditions = copy.m_renditions;
+ }
+
+ return *this;
+ }
+
+ void Object::initializeFromNode( xmlNodePtr node )
+ {
+ // Even if node is NULL we'll have an empty doc, so no need
+ // to worry about it.
+ xmlDocPtr doc = wrapInDoc( node );
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+
+ libcmis::registerNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ // Get the allowableActions
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( "//cmis:allowableActions" ), xpathCtx );
+ if ( xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 )
+ {
+ xmlNodePtr actionsNode = xpathObj->nodesetval->nodeTab[0];
+ m_allowableActions.reset( new libcmis::AllowableActions( actionsNode ) );
+ }
+ xmlXPathFreeObject( xpathObj );
+
+ // TODO Get rid of this request:
+ // * Too time consuming
+ // * Makes secondary aspect properties annoying to create
+ // * Prevents from getting Alfresco additional properties
+ // First get the type id as it will give us the property definitions
+ string typeIdReq( "/*/cmis:properties/cmis:propertyId[@propertyDefinitionId='cmis:objectTypeId']/cmis:value/text()" );
+ m_typeId = libcmis::getXPathValue( xpathCtx, typeIdReq );
+
+ string propertiesReq( "/*/cmis:properties/*" );
+ xpathObj = xmlXPathEvalExpression( BAD_CAST( propertiesReq.c_str() ), xpathCtx );
+ if ( NULL != xpathObj && NULL != xpathObj->nodesetval )
+ {
+ int size = xpathObj->nodesetval->nodeNr;
+ for ( int i = 0; i < size; i++ )
+ {
+ xmlNodePtr propertyNode = xpathObj->nodesetval->nodeTab[i];
+ libcmis::PropertyPtr property = libcmis::parseProperty( propertyNode, getTypeDescription( ) );
+ if ( property != NULL )
+ m_properties[ property->getPropertyType( )->getId() ] = property;
+ }
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ xmlXPathFreeContext( xpathCtx );
+ xmlFreeDoc( doc );
+
+ m_refreshTimestamp = time( NULL );
+ }
+
+ string Object::getStringProperty( const string& propertyName )
+ {
+ string name;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( propertyName ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getStrings( ).empty( ) )
+ name = it->second->getStrings( ).front( );
+ return name;
+ }
+
+ string Object::getId( )
+ {
+ return getStringProperty( "cmis:objectId" );
+ }
+
+ string Object::getName( )
+ {
+ return getStringProperty( "cmis:name" );
+ }
+
+ string Object::getBaseType( )
+ {
+ return getStringProperty( "cmis:baseTypeId" );
+ }
+
+ string Object::getType( )
+ {
+ string value = getStringProperty( "cmis:objectTypeId" );
+ if ( value.empty( ) )
+ value = m_typeId;
+ return value;
+ }
+
+ string Object::getCreatedBy( )
+ {
+ return getStringProperty( "cmis:createdBy" );
+ }
+
+ string Object::getLastModifiedBy( )
+ {
+ return getStringProperty( "cmis:lastModifiedBy" );
+ }
+
+ string Object::getChangeToken( )
+ {
+ return getStringProperty( "cmis:changeToken" );
+ }
+
+ vector< string > Object::getPaths( )
+ {
+ return vector< string > ( );
+ }
+
+ boost::posix_time::ptime Object::getCreationDate( )
+ {
+ boost::posix_time::ptime value;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( "cmis:creationDate" ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getDateTimes( ).empty( ) )
+ value = it->second->getDateTimes( ).front( );
+ return value;
+ }
+
+ boost::posix_time::ptime Object::getLastModificationDate( )
+ {
+ boost::posix_time::ptime value;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( "cmis:lastModificationDate" ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getDateTimes( ).empty( ) )
+ value = it->second->getDateTimes( ).front( );
+ return value;
+ }
+
+ bool Object::isImmutable( )
+ {
+ bool value = false;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( "cmis:isImmutable" ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getBools( ).empty( ) )
+ value = it->second->getBools( ).front( );
+ return value;
+ }
+
+ vector< string > Object::getSecondaryTypes( )
+ {
+ vector< string > types;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( "cmis:secondaryObjectTypeIds" ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL )
+ types = it->second->getStrings( );
+
+ return types;
+ }
+
+ ObjectPtr Object::addSecondaryType( string id, PropertyPtrMap properties )
+ {
+ // First make sure the cmis:secondaryObjectTypeIds property can be defined
+ map< string, PropertyTypePtr >& propertyTypes = getTypeDescription( )->
+ getPropertiesTypes();
+
+ map< string, PropertyTypePtr >::iterator it = propertyTypes.find( "cmis:secondaryObjectTypeIds" );
+ if ( it == propertyTypes.end() )
+ throw ( Exception( "Secondary Types not supported", "constraint" ) );
+
+ // Copy all the new properties without checking they are
+ // defined in the secondary type definition: that would
+ // require one more HTTP request and the server will complain
+ // anyway if it's not good.
+ PropertyPtrMap newProperties( properties );
+
+ // Prepare the new cmis:secondaryObjectTypeIds property
+ vector< string > secTypes = getSecondaryTypes( );
+ if ( find( secTypes.begin(), secTypes.end(), id ) == secTypes.end( ) )
+ {
+ secTypes.push_back( id );
+ PropertyPtr newSecTypes( new Property( it->second, secTypes ) );
+ newProperties["cmis:secondaryObjectTypeIds"] = newSecTypes;
+ }
+ return updateProperties( newProperties );
+ }
+
+ ObjectPtr Object::removeSecondaryType( string id )
+ {
+ // First make sure the cmis:secondaryObjectTypeIds property can be defined
+ map< string, PropertyTypePtr >& propertyTypes = getTypeDescription( )->
+ getPropertiesTypes();
+
+ map< string, PropertyTypePtr >::iterator it = propertyTypes.find( "cmis:secondaryObjectTypeIds" );
+ if ( it == propertyTypes.end() )
+ throw ( Exception( "Secondary Types not supported", "constraint" ) );
+
+ // Prepare the new cmis:secondaryObjectTypeIds property
+ PropertyPtrMap newProperties;
+ vector< string > secTypes = getSecondaryTypes( );
+ vector< string > newSecTypes;
+ for ( vector< string >::iterator idIt = secTypes.begin( );
+ idIt != secTypes.end( ); ++idIt )
+ {
+ if ( *idIt != id )
+ newSecTypes.push_back( *idIt );
+ }
+
+ // No need to update the property if it didn't change
+ if ( newSecTypes.size( ) != secTypes.size( ) )
+ {
+ PropertyPtr property ( new Property( it->second, newSecTypes ) );
+ newProperties["cmis:secondaryObjectTypeIds"] = property;
+ }
+
+ return updateProperties( newProperties );
+ }
+
+ PropertyPtrMap& Object::getProperties( )
+ {
+ return m_properties;
+ }
+
+ libcmis::ObjectTypePtr Object::getTypeDescription( )
+ {
+ if ( !m_typeDescription.get( ) && m_session != NULL )
+ m_typeDescription = m_session->getType( getType( ) );
+
+ return m_typeDescription;
+ }
+
+ vector< RenditionPtr> Object::getRenditions( string /*filter*/ )
+ {
+ return m_renditions;
+ }
+
+ string Object::getThumbnailUrl( )
+ {
+ string url;
+ vector< RenditionPtr > renditions = getRenditions( );
+ for ( vector< RenditionPtr >::iterator it = renditions.begin( );
+ it != renditions.end( ); ++it)
+
+ {
+ if ( (*it)->getKind( ) == "cmis:thumbnail" ) return (*it)->getUrl( );
+ }
+
+ return url;
+ }
+
+ // LCOV_EXCL_START
+ string Object::toString( )
+ {
+ stringstream buf;
+
+ buf << "Id: " << getId() << endl;
+ buf << "Name: " << getName() << endl;
+ buf << "Type: " << getType() << endl;
+ buf << "Base type: " << getBaseType() << endl;
+ buf << "Created on " << boost::posix_time::to_simple_string( getCreationDate() )
+ << " by " << getCreatedBy() << endl;
+ buf << "Last modified on " << boost::posix_time::to_simple_string( getLastModificationDate() )
+ << " by " << getLastModifiedBy() << endl;
+ buf << "Change token: " << getChangeToken() << endl;
+
+ // Write Allowable Actions
+ if ( getAllowableActions( ) )
+ buf << endl << getAllowableActions( )->toString( ) << endl;
+
+ // Write remaining properties
+ static const char* skippedProps[] = {
+ "cmis:name", "cmis:baseTypeId", "cmis:objectTypeId", "cmis:createdBy",
+ "cmis:creationDate", "cmis:lastModifiedBy", "cmis:lastModificationDate",
+ "cmis::changeToken"
+ };
+ int skippedCount = sizeof( skippedProps ) / sizeof( char* );
+
+ for ( PropertyPtrMap::iterator it = getProperties( ).begin();
+ it != getProperties( ).end( ); ++it )
+ {
+ string propId = it->first;
+ bool toSkip = false;
+ for ( int i = 0; i < skippedCount && !toSkip; ++i )
+ {
+ toSkip = propId == skippedProps[i];
+ }
+
+ if ( !toSkip )
+ {
+ libcmis::PropertyPtr prop = it->second;
+ if ( prop != NULL && prop->getPropertyType( ) != NULL )
+ {
+ buf << prop->getPropertyType( )->getDisplayName( ) << "( " << prop->getPropertyType()->getId( ) << " ): " << endl;
+ vector< string > strValues = prop->getStrings( );
+ for ( vector< string >::iterator valueIt = strValues.begin( );
+ valueIt != strValues.end( ); ++valueIt )
+ {
+ buf << "\t" << *valueIt << endl;
+ }
+ }
+ }
+ }
+
+ vector< libcmis::RenditionPtr > renditions = getRenditions( );
+ if ( !renditions.empty() )
+ {
+ buf << "Renditions: " << endl;
+ for ( vector< libcmis::RenditionPtr >::iterator it = renditions.begin();
+ it != renditions.end(); ++it )
+ {
+ buf << ( *it )->toString( ) << endl;
+ }
+ }
+
+ return buf.str();
+ }
+ // LCOV_EXCL_STOP
+
+ void Object::toXml( xmlTextWriterPtr writer )
+ {
+ // Output the properties
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmis:properties" ) );
+ for ( PropertyPtrMap::iterator it = getProperties( ).begin( );
+ it != getProperties( ).end( ); ++it )
+ {
+ it->second->toXml( writer );
+ }
+ xmlTextWriterEndElement( writer ); // cmis:properties
+ }
+}
diff --git a/src/libcmis/onedrive-allowable-actions.hxx b/src/libcmis/onedrive-allowable-actions.hxx
new file mode 100644
index 0000000..fbdba9c
--- /dev/null
+++ b/src/libcmis/onedrive-allowable-actions.hxx
@@ -0,0 +1,102 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Varga Mihai <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _ONEDRIVE_ALLOWABLE_ACTIONS_HXX_
+#define _ONEDRIVE_ALLOWABLE_ACTIONS_HXX_
+
+#include <libcmis/allowable-actions.hxx>
+
+class OneDriveAllowableActions: public libcmis::AllowableActions
+{
+ public:
+ OneDriveAllowableActions( bool isFolder ) : AllowableActions( )
+ {
+ m_states.clear( );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteObject, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::UpdateProperties, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetProperties, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetObjectRelationships, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetObjectParents, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::MoveObject, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateRelationship, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::ApplyPolicy, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetAppliedPolicies, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::RemovePolicy, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetACL, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::ApplyACL, false ) );
+
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetFolderTree, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetFolderParent, isFolder) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetDescendants, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CheckOut, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CancelCheckOut, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CheckIn, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::SetContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetAllVersions, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::AddObjectToFolder, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::RemoveObjectFromFolder, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetRenditions, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetChildren, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateDocument, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateFolder, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteTree, isFolder ) );
+ }
+};
+
+#endif
diff --git a/src/libcmis/onedrive-document.cxx b/src/libcmis/onedrive-document.cxx
new file mode 100644
index 0000000..863a92f
--- /dev/null
+++ b/src/libcmis/onedrive-document.cxx
@@ -0,0 +1,177 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-document.hxx"
+
+#include <libcmis/rendition.hxx>
+
+#include "onedrive-folder.hxx"
+#include "onedrive-session.hxx"
+#include "onedrive-utils.hxx"
+#include "json-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+OneDriveDocument::OneDriveDocument( OneDriveSession* session ) :
+ libcmis::Object( session),
+ libcmis::Document( session ),
+ OneDriveObject( session )
+{
+}
+
+OneDriveDocument::OneDriveDocument( OneDriveSession* session, Json json, string id, string name ) :
+ libcmis::Object( session),
+ libcmis::Document( session ),
+ OneDriveObject( session, json, id, name )
+{
+}
+
+OneDriveDocument::~OneDriveDocument( )
+{
+}
+
+vector< libcmis::FolderPtr > OneDriveDocument::getParents( )
+{
+ vector< libcmis::FolderPtr > parents;
+
+ string parentId = getStringProperty( "cmis:parentId" );
+
+ libcmis::ObjectPtr obj = getSession( )->getObject( parentId );
+ libcmis::FolderPtr parent = boost::dynamic_pointer_cast< libcmis::Folder >( obj );
+ parents.push_back( parent );
+ return parents;
+}
+
+boost::shared_ptr< istream > OneDriveDocument::getContentStream( string /*streamId*/ )
+{
+ boost::shared_ptr< istream > stream;
+ string streamUrl = getStringProperty( "source" );
+ if ( streamUrl.empty( ) )
+ throw libcmis::Exception( "could not find stream url" );
+
+ try
+ {
+ stream = getSession( )->httpGetRequest( streamUrl )->getStream( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ return stream;
+}
+
+void OneDriveDocument::setContentStream( boost::shared_ptr< ostream > os,
+ string /*contentType*/,
+ string fileName,
+ bool bReplaceExisting )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ string metaUrl = getUrl( );
+
+ // Update file name meta information
+ if ( bReplaceExisting && !fileName.empty( ) && fileName != getContentFilename( ) )
+ {
+ Json metaJson;
+ Json fileJson( fileName.c_str( ) );
+ metaJson.add("name", fileJson );
+
+ std::istringstream is( metaJson.toString( ) );
+ vector<string> headers;
+ headers.push_back( "Content-Type: application/json" );
+ try
+ {
+ getSession()->httpPatchRequest( metaUrl, is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ }
+
+ fileName = libcmis::escape( getStringProperty( "cmis:name" ) );
+ string putUrl = getSession( )->getBindingUrl( ) + "/me/drive/items/" +
+ getStringProperty( "cmis:parentId" ) + ":/" +
+ fileName + ":/content";
+
+ // Upload stream
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ vector <string> headers;
+ try
+ {
+ getSession()->httpPutRequest( putUrl, *is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ long httpStatus = getSession( )->getHttpStatus( );
+ if ( httpStatus < 200 || httpStatus >= 300 )
+ throw libcmis::Exception( "Document content wasn't set for"
+ "some reason" );
+ refresh( );
+}
+
+libcmis::DocumentPtr OneDriveDocument::checkOut( )
+{
+ // OneDrive doesn't have CheckOut, so just return the same document here
+ // TODO: no longer true - onedrive now has checkout/checkin
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr checkout =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ return checkout;
+}
+
+void OneDriveDocument::cancelCheckout( )
+{
+ // Don't do anything since we don't have CheckOut
+}
+
+libcmis::DocumentPtr OneDriveDocument::checkIn( bool /*isMajor*/,
+ std::string /*comment*/,
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string fileName )
+{
+ // OneDrive doesn't have CheckIn, so just upload the properties,
+ // the content stream and fetch the new document resource.
+ updateProperties( properties );
+ setContentStream( stream, contentType, fileName );
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr checkin =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ return checkin;
+}
+
+vector< libcmis::DocumentPtr > OneDriveDocument::getAllVersions( )
+{
+ return vector< libcmis::DocumentPtr > ( );
+}
diff --git a/src/libcmis/onedrive-document.hxx b/src/libcmis/onedrive-document.hxx
new file mode 100644
index 0000000..d70cede
--- /dev/null
+++ b/src/libcmis/onedrive-document.hxx
@@ -0,0 +1,75 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _ONEDRIVE_DOCUMENT_HXX_
+#define _ONEDRIVE_DOCUMENT_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+#include <libcmis/rendition.hxx>
+
+#include "onedrive-object.hxx"
+#include "json-utils.hxx"
+
+class OneDriveDocument : public libcmis::Document, public OneDriveObject
+{
+ public:
+ OneDriveDocument( OneDriveSession* session );
+
+ OneDriveDocument( OneDriveSession* session, Json json,
+ std::string id = std::string( ),
+ std::string name = std::string( ) );
+ ~OneDriveDocument( );
+
+ std::string getType( ) { return std::string( "cmis:document" );}
+ std::string getBaseType( ) { return std::string( "cmis:document" );}
+
+ virtual std::vector< libcmis::FolderPtr > getParents( );
+
+ virtual boost::shared_ptr< std::istream > getContentStream( std::string streamId = std::string( ) );
+
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os,
+ std::string contentType,
+ std::string fileName,
+ bool overwrite = true );
+
+ virtual libcmis::DocumentPtr checkOut( );
+ virtual void cancelCheckout( );
+
+ virtual libcmis::DocumentPtr checkIn( bool isMajor,
+ std::string comment,
+ const std::map< std::string,libcmis::PropertyPtr >&
+ properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string fileName );
+
+ virtual std::vector< libcmis::DocumentPtr > getAllVersions( );
+};
+
+#endif
diff --git a/src/libcmis/onedrive-folder.cxx b/src/libcmis/onedrive-folder.cxx
new file mode 100644
index 0000000..c1980c8
--- /dev/null
+++ b/src/libcmis/onedrive-folder.cxx
@@ -0,0 +1,167 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-folder.hxx"
+
+#include "onedrive-document.hxx"
+#include "onedrive-session.hxx"
+#include "onedrive-property.hxx"
+#include "onedrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+OneDriveFolder::OneDriveFolder( OneDriveSession* session ):
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ OneDriveObject( session )
+{
+}
+
+OneDriveFolder::OneDriveFolder( OneDriveSession* session, Json json ):
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ OneDriveObject( session, json )
+{
+}
+
+OneDriveFolder::~OneDriveFolder( )
+{
+}
+
+vector< libcmis::ObjectPtr > OneDriveFolder::getChildren( )
+{
+ vector< libcmis::ObjectPtr > children;
+ // TODO: limited to 200 items by default - to get more one would have to
+ // follow @odata.nextLink or change pagination size
+ string query = getSession( )->getBindingUrl( ) + "/me/drive/items/" + getId( ) + "/children";
+
+ string res;
+ try
+ {
+ res = getSession( )->httpGetRequest( query )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ Json jsonRes = Json::parse( res );
+ Json::JsonVector objs = jsonRes["value"].getList( );
+
+ // Create children objects from Json objects
+ for(unsigned int i = 0; i < objs.size(); i++)
+ {
+ children.push_back( getSession( )->getObjectFromJson( objs[i] ) );
+ }
+
+ return children;
+}
+
+libcmis::FolderPtr OneDriveFolder::createFolder(
+ const PropertyPtrMap& properties )
+{
+ Json propsJson = OneDriveUtils::toOneDriveJson( properties );
+ string uploadUrl = getSession( )->getBindingUrl( ) + "/me/drive/items/" + getId( ) + "/children";
+
+ std::istringstream is( propsJson.toString( ) );
+ string response;
+ try
+ {
+ response = getSession()->httpPostRequest( uploadUrl, is, "application/json" )
+ ->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( response );
+ libcmis::FolderPtr folderPtr( new OneDriveFolder( getSession( ), jsonRes ) );
+
+ refresh( );
+ return folderPtr;
+}
+
+libcmis::DocumentPtr OneDriveFolder::createDocument(
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os,
+ string /*contentType*/, string fileName )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ if (fileName.empty( ) )
+ {
+ for ( PropertyPtrMap::const_iterator it = properties.begin( ) ;
+ it != properties.end( ) ; ++it )
+ {
+ if ( it->first == "cmis:name" )
+ {
+ fileName = it->second->toString( );
+ }
+ }
+ }
+
+ // TODO: limited to 4MB, larger uploads need dedicated UploadSession
+ fileName = libcmis::escape( fileName );
+ string newDocUrl = getSession( )->getBindingUrl( ) + "/me/drive/items/" +
+ getId( ) + ":/" + fileName + ":/content";
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ vector< string > headers;
+ string res;
+ // this will only create the file and return it's id, name and source url
+ try
+ {
+ res = getSession( )->httpPutRequest( newDocUrl, *is, headers )
+ ->getStream( )->str( );
+ }
+ catch (const CurlException& e)
+ {
+ throw e.getCmisException( );
+ }
+
+ Json jsonRes = Json::parse( res );
+ DocumentPtr document( new OneDriveDocument( getSession( ), jsonRes ) );
+
+ // Upload the properties
+ ObjectPtr object = document->updateProperties( properties );
+ document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+
+ refresh( );
+ return document;
+}
+
+vector< string > OneDriveFolder::removeTree(
+ bool /*allVersions*/,
+ libcmis::UnfileObjects::Type /*unfile*/,
+ bool /*continueOnError*/ )
+{
+ remove( );
+ // Nothing to return here
+ return vector< string >( );
+}
diff --git a/src/libcmis/onedrive-folder.hxx b/src/libcmis/onedrive-folder.hxx
new file mode 100644
index 0000000..fc47ab3
--- /dev/null
+++ b/src/libcmis/onedrive-folder.hxx
@@ -0,0 +1,64 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _ONEDRIVE_FOLDER_HXX_
+#define _ONEDRIVE_FOLDER_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "onedrive-object.hxx"
+#include "json-utils.hxx"
+
+class OneDriveFolder : public libcmis::Folder, public OneDriveObject
+{
+ public:
+ OneDriveFolder( OneDriveSession* session );
+ OneDriveFolder( OneDriveSession* session, Json json );
+ ~OneDriveFolder( );
+
+ std::string getType( ) { return std::string( "cmis:folder" );}
+ std::string getBaseType( ) { return std::string( "cmis:folder" );}
+ virtual std::vector< libcmis::ObjectPtr > getChildren( );
+
+ virtual libcmis::FolderPtr createFolder(
+ const libcmis::PropertyPtrMap& properties );
+
+ virtual libcmis::DocumentPtr createDocument(
+ const libcmis::PropertyPtrMap& properties,
+ boost::shared_ptr< std::ostream > os,
+ std::string contentType,
+ std::string fileName );
+
+ virtual std::vector< std::string > removeTree(
+ bool allVersion = true,
+ libcmis::UnfileObjects::Type unfile = libcmis::UnfileObjects::Delete,
+ bool continueOnError = false );
+};
+
+#endif
diff --git a/src/libcmis/onedrive-object-type.cxx b/src/libcmis/onedrive-object-type.cxx
new file mode 100644
index 0000000..a88aef8
--- /dev/null
+++ b/src/libcmis/onedrive-object-type.cxx
@@ -0,0 +1,118 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-object-type.hxx"
+
+OneDriveObjectType::OneDriveObjectType( const std::string& id ): ObjectType( )
+{
+ m_id = id;
+ m_localName = "OneDrive Object Type";
+ m_localNamespace = "OneDrive Object Type";
+ m_displayName = "OneDrive Object Type";
+ m_queryName = id;
+ m_description = "OneDrive Object Type";
+ m_parentTypeId = "";
+ m_baseTypeId = id;
+ m_creatable = true;
+ m_versionable = false;
+ m_fileable = true;
+ m_fulltextIndexed = ( id == "cmis:document" );
+ m_queryable = true;
+ if ( id == "cmis:document" )
+ m_contentStreamAllowed = libcmis::ObjectType::Allowed;
+ else
+ m_contentStreamAllowed = libcmis::ObjectType::NotAllowed;
+
+ libcmis::PropertyTypePtr idType(new libcmis::PropertyType( ) );
+ idType->setId( "cmis:objectTypeId" );
+ idType->setType( libcmis::PropertyType::String );
+ m_propertiesTypes[ idType->getId( ) ] = idType;
+
+ // create PropertyTypes which are updatable.
+
+ // name
+ libcmis::PropertyTypePtr nameType( new libcmis::PropertyType( ) );
+ nameType->setId( "cmis:name" );
+ nameType->setType( libcmis::PropertyType::String );
+ nameType->setUpdatable( true );
+ m_propertiesTypes[ nameType->getId( ) ] = nameType;
+
+ // description
+ libcmis::PropertyTypePtr descriptionType( new libcmis::PropertyType( ) );
+ descriptionType->setId( "cmis:description" );
+ descriptionType->setType( libcmis::PropertyType::String );
+ descriptionType->setUpdatable( true );
+ m_propertiesTypes[ descriptionType->getId( ) ] = descriptionType;
+
+ // modifiedDate
+ libcmis::PropertyTypePtr modifiedDateType( new libcmis::PropertyType( ) );
+ modifiedDateType->setId( "cmis:lastModificationDate" );
+ modifiedDateType->setType( libcmis::PropertyType::DateTime );
+ modifiedDateType->setUpdatable( false );
+ m_propertiesTypes[ modifiedDateType->getId( ) ] = modifiedDateType;
+
+ // creationDate
+ libcmis::PropertyTypePtr creationDateType( new libcmis::PropertyType( ) );
+ creationDateType->setId( "cmis:creationDate" );
+ creationDateType->setType( libcmis::PropertyType::DateTime );
+ creationDateType->setUpdatable( false );
+ m_propertiesTypes[ creationDateType->getId( ) ] = creationDateType;
+
+
+ if ( id == "cmis:document" )
+ {
+ // size
+ libcmis::PropertyTypePtr contentStreamLength( new libcmis::PropertyType( ) );
+ contentStreamLength->setId( "cmis:contentStreamLength" );
+ contentStreamLength->setType( libcmis::PropertyType::Integer );
+ contentStreamLength->setUpdatable( false );
+ m_propertiesTypes[ contentStreamLength->getId( ) ] = contentStreamLength;
+
+ // streamFileName
+ libcmis::PropertyTypePtr streamFileNameType( new libcmis::PropertyType( ) );
+ streamFileNameType->setId( "cmis:contentStreamFileName" );
+ streamFileNameType->setType( libcmis::PropertyType::String );
+ streamFileNameType->setUpdatable( true );
+ m_propertiesTypes[ streamFileNameType->getId( ) ] = streamFileNameType;
+ }
+}
+
+libcmis::ObjectTypePtr OneDriveObjectType::getParentType( )
+{
+ libcmis::ObjectTypePtr parentTypePtr;
+ if ( m_parentTypeId != "" ) {
+ parentTypePtr.reset( new OneDriveObjectType( m_parentTypeId ) );
+ }
+ return parentTypePtr;
+}
+
+libcmis::ObjectTypePtr OneDriveObjectType::getBaseType( )
+{
+ libcmis::ObjectTypePtr baseTypePtr( new OneDriveObjectType( m_baseTypeId ) );
+ return baseTypePtr;
+}
diff --git a/src/libcmis/onedrive-object-type.hxx b/src/libcmis/onedrive-object-type.hxx
new file mode 100644
index 0000000..34b65f6
--- /dev/null
+++ b/src/libcmis/onedrive-object-type.hxx
@@ -0,0 +1,46 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _ONEDRIVE_OBJECT_TYPE_HXX_
+#define _ONEDRIVE_OBJECT_TYPE_HXX_
+
+#include <libcmis/object-type.hxx>
+
+#include "json-utils.hxx"
+
+class OneDriveObjectType: public libcmis::ObjectType
+{
+ public:
+ OneDriveObjectType( const std::string& id );
+
+ virtual libcmis::ObjectTypePtr getParentType( );
+
+ virtual libcmis::ObjectTypePtr getBaseType( );
+};
+
+#endif
diff --git a/src/libcmis/onedrive-object.cxx b/src/libcmis/onedrive-object.cxx
new file mode 100644
index 0000000..8deb591
--- /dev/null
+++ b/src/libcmis/onedrive-object.cxx
@@ -0,0 +1,198 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-object.hxx"
+
+#include "onedrive-allowable-actions.hxx"
+#include "onedrive-property.hxx"
+#include "onedrive-repository.hxx"
+#include "onedrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+OneDriveObject::OneDriveObject( OneDriveSession* session ) :
+ libcmis::Object( session )
+{
+}
+
+OneDriveObject::OneDriveObject( OneDriveSession* session, Json json, string id, string name ) :
+ libcmis::Object( session )
+{
+ initializeFromJson( json, id, name );
+}
+
+OneDriveObject::OneDriveObject( const OneDriveObject& copy ) :
+ libcmis::Object( copy )
+{
+}
+
+OneDriveObject& OneDriveObject::operator=( const OneDriveObject& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Object::operator=( copy );
+ }
+ return *this;
+}
+
+void OneDriveObject::initializeFromJson ( Json json, string /*id*/, string /*name*/ )
+{
+ Json::JsonObject objs = json.getObjects( );
+ Json::JsonObject::iterator it;
+ PropertyPtr property;
+ bool isFolder = json["folder"].toString( ) != "";
+ for ( it = objs.begin( ); it != objs.end( ); ++it)
+ {
+ property.reset( new OneDriveProperty( it->first, it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ if ( it->first == "name" && !isFolder )
+ {
+ property.reset( new OneDriveProperty( "cmis:contentStreamFileName", it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ } else if ( it->first == "parentReference" ) {
+ if (it->second["id"].toString() != "") {
+ property.reset( new OneDriveProperty( "cmis:parentId", it->second["id"] ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+ }
+ }
+
+ m_refreshTimestamp = time( NULL );
+ m_allowableActions.reset( new OneDriveAllowableActions( isFolder ) );
+}
+
+OneDriveSession* OneDriveObject::getSession( )
+{
+ return dynamic_cast< OneDriveSession* > ( m_session );
+}
+
+void OneDriveObject::refreshImpl( Json json )
+{
+ m_typeDescription.reset( );
+ m_properties.clear( );
+ initializeFromJson( json );
+}
+
+void OneDriveObject::refresh( )
+{
+ string res;
+ try
+ {
+ res = getSession()->httpGetRequest( getUrl( ) )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json json = Json::parse( res );
+ refreshImpl( json );
+}
+
+void OneDriveObject::remove( bool /*allVersions*/ )
+{
+ try
+ {
+ getSession( )->httpDeleteRequest( getUrl( ) );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+}
+
+string OneDriveObject::getUrl( )
+{
+ return getSession( )->getBindingUrl( ) + "/me/drive/items/" + getId( );
+}
+
+string OneDriveObject::getUploadUrl( )
+{
+ return getUrl( ) + "/files";
+}
+
+vector< string> OneDriveObject::getMultiStringProperty( const string& propertyName )
+{
+ vector< string > values;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( propertyName ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getStrings( ).empty( ) )
+ values = it->second->getStrings( );
+ return values;
+}
+
+libcmis::ObjectPtr OneDriveObject::updateProperties(
+ const PropertyPtrMap& properties )
+{
+ // Make Json object from properties
+ Json json = OneDriveUtils::toOneDriveJson( properties );
+
+ istringstream is( json.toString( ));
+
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ vector< string > headers;
+ headers.push_back( "Content-Type: application/json" );
+ response = getSession( )->httpPatchRequest( getUrl( ), is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ string res = response->getStream( )->str( );
+ Json jsonRes = Json::parse( res );
+ libcmis::ObjectPtr updated = getSession()->getObjectFromJson( jsonRes );
+
+ if ( updated->getId( ) == getId( ) )
+ refreshImpl( jsonRes );
+
+ return updated;
+}
+
+void OneDriveObject::move( FolderPtr /*source*/, FolderPtr destination )
+{
+ Json destJson;
+ Json destId( destination->getId( ).c_str( ) );
+ destJson.add( "destination", destId );
+
+ istringstream is( destJson.toString( ) );
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ string url = getUrl( ) + "?method=MOVE";
+ response = getSession( )->httpPostRequest( url, is, "application/json" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ string res = response->getStream( )->str( );
+ Json jsonRes = Json::parse( res );
+
+ refreshImpl( jsonRes );
+}
diff --git a/src/libcmis/onedrive-object.hxx b/src/libcmis/onedrive-object.hxx
new file mode 100644
index 0000000..8ad46b3
--- /dev/null
+++ b/src/libcmis/onedrive-object.hxx
@@ -0,0 +1,76 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ONEDRIVE_OBJECT_HXX_
+#define _ONEDRIVE_OBJECT_HXX_
+
+#include <libcmis/object.hxx>
+
+#include "onedrive-session.hxx"
+#include "json-utils.hxx"
+
+// Class representing an object for OneDrive protocol.
+class OneDriveObject : public virtual libcmis::Object
+{
+ public:
+ OneDriveObject( OneDriveSession* session );
+
+ // Create a OneDrive document from Json properties.
+ OneDriveObject( OneDriveSession* session, Json json,
+ std::string id = std::string( ),
+ std::string name = std::string( ) );
+ OneDriveObject( const OneDriveObject& copy );
+ virtual ~OneDriveObject( ) { }
+
+ OneDriveObject& operator=( const OneDriveObject& copy );
+
+ void initializeFromJson( Json json, std::string id = std::string( ),
+ std::string name = std::string( ) );
+
+ void refreshImpl( Json json );
+ virtual void refresh( );
+ virtual void remove( bool allVersions = true );
+
+ std::string getUrl( );
+ std::string getUploadUrl( );
+ std::vector< std::string > getMultiStringProperty(
+ const std::string& propertyName );
+
+ virtual boost::shared_ptr< Object > updateProperties(
+ const libcmis::PropertyPtrMap& properties );
+
+ virtual std::vector< libcmis::RenditionPtr> getRenditions( std::string /*filter = std::string( )*/ )
+ {return std::vector< libcmis::RenditionPtr>( );}
+
+ virtual void move( boost::shared_ptr< libcmis::Folder > source,
+ boost::shared_ptr< libcmis::Folder > destination );
+
+ protected:
+ OneDriveSession* getSession( );
+
+};
+#endif
diff --git a/src/libcmis/onedrive-property.cxx b/src/libcmis/onedrive-property.cxx
new file mode 100644
index 0000000..a9aa72a
--- /dev/null
+++ b/src/libcmis/onedrive-property.cxx
@@ -0,0 +1,78 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-property.hxx"
+
+#include <libcmis/property-type.hxx>
+
+#include "onedrive-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+OneDriveProperty::OneDriveProperty( )
+{
+}
+
+OneDriveProperty::~OneDriveProperty( )
+{
+}
+
+OneDriveProperty::OneDriveProperty( const string& key, Json json ):
+ Property( )
+{
+ PropertyTypePtr propertyType( new PropertyType( ) );
+ string convertedKey = OneDriveUtils::toCmisKey( key );
+ propertyType->setId( convertedKey );
+ propertyType->setLocalName( convertedKey );
+ propertyType->setLocalNamespace( convertedKey );
+ propertyType->setQueryName( convertedKey );
+ propertyType->setDisplayName( key );
+ propertyType->setTypeFromJsonType( json.getStrType( ) );
+ propertyType->setUpdatable( OneDriveUtils::checkUpdatable( key ) );
+ propertyType->setMultiValued( OneDriveUtils::checkMultiValued( key ) );
+
+ setPropertyType( propertyType );
+
+ vector< string > values = OneDriveUtils::parseOneDriveProperty( key, json );
+ setValues( values );
+}
+
+OneDriveProperty::OneDriveProperty( const OneDriveProperty& copy ) :
+ libcmis::Property( copy )
+{
+}
+
+OneDriveProperty& OneDriveProperty::operator=( const OneDriveProperty& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Property::operator=( copy );
+ }
+ return *this;
+}
diff --git a/src/libcmis/onedrive-property.hxx b/src/libcmis/onedrive-property.hxx
new file mode 100644
index 0000000..9d45316
--- /dev/null
+++ b/src/libcmis/onedrive-property.hxx
@@ -0,0 +1,52 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _ONEDRIVE_PROPERTY_HXX_
+#define _ONEDRIVE_PROPERTY_HXX_
+
+#include <libcmis/property.hxx>
+
+#include "json-utils.hxx"
+
+// reference: http://msdn.microsoft.com/en-us/library/hh243648.aspx
+class OneDriveProperty : public libcmis::Property
+{
+ public :
+ // Create a OneDrive Property from a Json property with its key
+ OneDriveProperty( const std::string& key, Json json);
+ ~OneDriveProperty( );
+ OneDriveProperty( const OneDriveProperty& copy);
+ OneDriveProperty& operator=( const OneDriveProperty& copy );
+
+ // Check if the property is updatable
+ bool checkUpdatable( const std::string& key );
+ private :
+ // Avoid calling default constructor
+ OneDriveProperty( );
+};
+#endif
diff --git a/src/libcmis/onedrive-repository.cxx b/src/libcmis/onedrive-repository.cxx
new file mode 100644
index 0000000..b01f5c2
--- /dev/null
+++ b/src/libcmis/onedrive-repository.cxx
@@ -0,0 +1,54 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#include "onedrive-repository.hxx"
+
+OneDriveRepository::OneDriveRepository( ) :
+ Repository( )
+{
+ m_id = "OneDrive";
+ m_name = "One Drive";
+ m_description = "One Drive repository";
+ m_productName = "One Drive";
+ m_productVersion = "v5";
+ m_rootId = "/me/drive/root";
+
+ m_capabilities[ ACL ] = "discover";
+ m_capabilities[ AllVersionsSearchable ] = "true";
+ m_capabilities[ Changes ] = "all";
+ m_capabilities[ GetDescendants ] = "true";
+ m_capabilities[ GetFolderTree ] = "true";
+ m_capabilities[ OrderBy ] = "custom";
+ m_capabilities[ Multifiling ] = "true";
+ m_capabilities[ PWCSearchable ] = "true";
+ m_capabilities[ PWCUpdatable ] = "true";
+ m_capabilities[ Query ] = "bothcombined";
+ m_capabilities[ Renditions ] = "read";
+ m_capabilities[ Unfiling ] = "false";
+ m_capabilities[ VersionSpecificFiling ] = "false";
+ m_capabilities[ Join ] = "none";
+}
diff --git a/src/libcmis/onedrive-repository.hxx b/src/libcmis/onedrive-repository.hxx
new file mode 100644
index 0000000..e1a8dc4
--- /dev/null
+++ b/src/libcmis/onedrive-repository.hxx
@@ -0,0 +1,40 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ONEDRIVE_REPOSITORY_HXX_
+#define _ONEDRIVE_REPOSITORY_HXX_
+
+#include <libcmis/repository.hxx>
+
+class OneDriveRepository: public libcmis::Repository
+{
+ public:
+ OneDriveRepository( );
+};
+
+#endif
+
diff --git a/src/libcmis/onedrive-session.cxx b/src/libcmis/onedrive-session.cxx
new file mode 100644
index 0000000..375cd2e
--- /dev/null
+++ b/src/libcmis/onedrive-session.cxx
@@ -0,0 +1,207 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-session.hxx"
+
+#include "oauth2-handler.hxx"
+#include "onedrive-object-type.hxx"
+#include "onedrive-document.hxx"
+#include "onedrive-folder.hxx"
+#include "onedrive-object.hxx"
+#include "onedrive-repository.hxx"
+
+using namespace std;
+
+OneDriveSession::OneDriveSession ( string baseUrl,
+ string username,
+ string password,
+ libcmis::OAuth2DataPtr oauth2,
+ bool verbose ) :
+ BaseSession( baseUrl, string(), username, password, false,
+ libcmis::OAuth2DataPtr(), verbose )
+
+{
+ // Add the dummy repository
+ m_repositories.push_back( getRepository( ) );
+
+ if ( oauth2 && oauth2->isComplete( ) ){
+ setOAuth2Data( oauth2 );
+ }
+}
+
+OneDriveSession::OneDriveSession() :
+ BaseSession()
+{
+}
+
+OneDriveSession::~OneDriveSession()
+{
+}
+
+void OneDriveSession::setOAuth2Data( libcmis::OAuth2DataPtr oauth2 )
+{
+ m_oauth2Handler = new OAuth2Handler( this, oauth2 );
+ m_oauth2Handler->setOAuth2Parser( OAuth2Providers::getOAuth2Parser( getBindingUrl( ) ) );
+
+ oauth2Authenticate( );
+}
+
+void OneDriveSession::oauth2Authenticate()
+{
+ // treat the supplied password as refresh token
+ if (!m_password.empty())
+ {
+ try
+ {
+ m_inOAuth2Authentication = true;
+
+ m_oauth2Handler->setRefreshToken(m_password);
+ // Try to get new access tokens using the stored refreshtoken
+ m_oauth2Handler->refresh();
+ m_inOAuth2Authentication = false;
+ }
+ catch (const CurlException &e)
+ {
+ m_inOAuth2Authentication = false;
+ // refresh token expired or invalid, trigger initial auth (that in turn will hit the fallback with copy'n'paste method)
+ BaseSession::oauth2Authenticate();
+ }
+ }
+ else
+ {
+ BaseSession::oauth2Authenticate();
+ }
+}
+
+string OneDriveSession::getRefreshToken() {
+ return HttpSession::getRefreshToken();
+}
+
+libcmis::RepositoryPtr OneDriveSession::getRepository( )
+{
+ // Return a dummy repository since OneDrive doesn't have that notion
+ libcmis::RepositoryPtr repo( new OneDriveRepository( ) );
+ return repo;
+}
+
+libcmis::ObjectPtr OneDriveSession::getObject( string objectId )
+{
+ // Run the http request to get the properties definition
+ string res;
+ string objectLink = m_bindingUrl + "/me/drive/items/" + objectId;
+ if (objectId == getRootId())
+ objectLink = m_bindingUrl + objectId;
+ try
+ {
+ res = httpGetRequest( objectLink )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+ return getObjectFromJson( jsonRes );
+}
+
+libcmis::ObjectPtr OneDriveSession::getObjectFromJson( Json& jsonRes )
+{
+ libcmis::ObjectPtr object;
+ if ( jsonRes["folder"].toString() != "" )
+ {
+ object.reset( new OneDriveFolder( this, jsonRes ) );
+ }
+ else if ( jsonRes["file"].toString() != "" )
+ {
+ object.reset( new OneDriveDocument( this, jsonRes ) );
+ }
+ else
+ {
+ object.reset( new OneDriveObject( this, jsonRes ) );
+ }
+ return object;
+}
+
+libcmis::ObjectPtr OneDriveSession::getObjectByPath( string path )
+{
+ string res;
+ string objectQuery = m_bindingUrl + "/me/drive/root:" + libcmis::escape( path );
+ try
+ {
+ res = httpGetRequest( objectQuery )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw libcmis::Exception( "No file could be found for path " + path + ": " + e.what() );
+ }
+ Json jsonRes = Json::parse( res );
+ return getObjectFromJson( jsonRes );
+}
+
+bool OneDriveSession::isAPathMatch( Json objectJson, string path )
+{
+ string parentId = objectJson["parent_id"].toString( );
+ string objectName = objectJson["name"].toString( );
+ size_t pos = path.rfind("/");
+ string pathName = path.substr( pos + 1, path.size( ) );
+ string truncatedPath = path.substr( 0, pos );
+
+ if ( truncatedPath.empty( ) && parentId == "null" && objectName == pathName )
+ {
+ // match
+ return true;
+ }
+ if ( truncatedPath.empty( ) || parentId == "null" || objectName != pathName )
+ {
+ return false;
+ }
+
+ string res;
+ string parentUrl = m_bindingUrl + "/" + parentId;
+ try
+ {
+ res = httpGetRequest( parentUrl )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+ return isAPathMatch( jsonRes, truncatedPath );
+}
+
+libcmis::ObjectTypePtr OneDriveSession::getType( string id )
+{
+ libcmis::ObjectTypePtr type( new OneDriveObjectType( id ) );
+ return type;
+}
+
+vector< libcmis::ObjectTypePtr > OneDriveSession::getBaseTypes( )
+{
+ vector< libcmis::ObjectTypePtr > types;
+ return types;
+}
diff --git a/src/libcmis/onedrive-session.hxx b/src/libcmis/onedrive-session.hxx
new file mode 100644
index 0000000..3c30c04
--- /dev/null
+++ b/src/libcmis/onedrive-session.hxx
@@ -0,0 +1,75 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ONEDRIVE_SESSION_HXX_
+#define _ONEDRIVE_SESSION_HXX_
+
+#include <libcmis/repository.hxx>
+
+#include "base-session.hxx"
+#include "json-utils.hxx"
+
+class OneDriveSession : public BaseSession
+{
+ public:
+ OneDriveSession( std::string baseUrl,
+ std::string username,
+ std::string password,
+ libcmis::OAuth2DataPtr oauth2,
+ bool verbose = false );
+
+ ~OneDriveSession ( );
+
+ virtual libcmis::RepositoryPtr getRepository( );
+
+ virtual bool setRepository( std::string ) { return true; }
+
+ virtual libcmis::ObjectPtr getObject( std::string id );
+
+ virtual libcmis::ObjectPtr getObjectByPath( std::string path );
+
+ virtual libcmis::ObjectTypePtr getType( std::string id );
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
+ libcmis::ObjectPtr getObjectFromJson( Json& jsonRes );
+
+ bool isAPathMatch( Json objectJson, std::string path );
+
+ virtual std::string getRefreshToken();
+
+ private:
+ OneDriveSession( );
+ OneDriveSession( const OneDriveSession& copy ) = delete;
+ OneDriveSession& operator=( const OneDriveSession& copy ) = delete;
+
+ virtual void setOAuth2Data( libcmis::OAuth2DataPtr oauth2 );
+
+ void oauth2Authenticate( );
+};
+
+#endif /* _ONEDRIVE_SESSION_HXX_ */
diff --git a/src/libcmis/onedrive-utils.cxx b/src/libcmis/onedrive-utils.cxx
new file mode 100644
index 0000000..17ed324
--- /dev/null
+++ b/src/libcmis/onedrive-utils.cxx
@@ -0,0 +1,131 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "onedrive-utils.hxx"
+
+#include <libcmis/xml-utils.hxx>
+
+#include "json-utils.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+string OneDriveUtils::toCmisKey( const string& key )
+{
+ string convertedKey;
+ if ( key == "id")
+ convertedKey = "cmis:objectId";
+ else if ( key == "from" )
+ convertedKey = "cmis:createdBy";
+ else if ( key == "description" )
+ convertedKey = "cmis:description";
+ else if ( key == "createdDateTime" )
+ convertedKey = "cmis:creationDate";
+ else if ( key == "lastModifiedDateTime" )
+ convertedKey = "cmis:lastModificationDate";
+ else if ( key == "name" )
+ convertedKey = "cmis:name";
+ else if ( key == "size" )
+ convertedKey = "cmis:contentStreamLength";
+ else if ( key == "@microsoft.graph.downloadUrl" )
+ convertedKey = "source";
+ else convertedKey = key;
+ return convertedKey;
+}
+
+string OneDriveUtils::toOneDriveKey( const string& key )
+{
+ string convertedKey;
+ if ( key == "cmis:objectId")
+ convertedKey = "id";
+ else if ( key == "cmis:createdBy" )
+ convertedKey = "from";
+ else if ( key == "cmis:creationDate" )
+ convertedKey = "created_time";
+ else if ( key == "cmis:description" )
+ convertedKey = "description";
+ else if ( key == "cmis:lastModificationDate" )
+ convertedKey = "updated_time";
+ else if ( key == "cmis:name" )
+ convertedKey = "name";
+ else if ( key == "cmis:contentStreamLength" )
+ convertedKey = "file_size";
+ else convertedKey = key;
+ return convertedKey;
+}
+
+bool OneDriveUtils::checkUpdatable( const std::string& key)
+{
+ bool updatable = ( key == "name" ||
+ key == "description" );
+ return updatable;
+}
+
+bool OneDriveUtils::checkMultiValued( const string& key )
+{
+ bool bMultiValued = ( key == "from" ||
+ key == "shared_with" );
+ return bMultiValued;
+}
+
+vector< string > OneDriveUtils::parseOneDriveProperty( string key, Json json )
+{
+ vector< string > values;
+ if ( key == "from" )
+ {
+ string ownerName = json["name"].toString( );
+ values.push_back( ownerName);
+ }
+ else if ( key == "shared_with" )
+ {
+ string sharedWith = json["access"].toString( );
+ values.push_back( sharedWith );
+ }
+ else values.push_back( json.toString( ) );
+ return values;
+}
+
+Json OneDriveUtils::toOneDriveJson( const PropertyPtrMap& properties )
+{
+ Json propsJson;
+
+ for ( PropertyPtrMap::const_iterator it = properties.begin() ;
+ it != properties.end() ; ++it )
+ {
+ string key = toOneDriveKey( it->first );
+ Json value( it->second );
+
+ // Convert the key back to the onedrive key
+ if ( checkUpdatable( key ) )
+ {
+ propsJson.add( key, value );
+ }
+ }
+
+ return propsJson;
+}
diff --git a/src/libcmis/onedrive-utils.hxx b/src/libcmis/onedrive-utils.hxx
new file mode 100644
index 0000000..eb9fa6e
--- /dev/null
+++ b/src/libcmis/onedrive-utils.hxx
@@ -0,0 +1,60 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _ONEDRIVE_UTILS_HXX_
+#define _ONEDRIVE_UTILS_HXX_
+
+#include <string>
+
+#include <libcmis/property.hxx>
+
+#include "json-utils.hxx"
+
+class OneDriveUtils
+{
+ public :
+
+ // Convert a OneDrive Property key to a CMIS key
+ static std::string toCmisKey( const std::string& key);
+
+ // Convert a CMIS key to OneDrive key
+ static std::string toOneDriveKey( const std::string& key );
+
+ // Check if a property is updatable
+ static bool checkUpdatable( const std::string& key);
+
+ // Check if a property has multiple values
+ static bool checkMultiValued( const std::string& key);
+
+ // Parse a OneDrive property value to CMIS values
+ static std::vector< std::string > parseOneDriveProperty( std::string key, Json jsonValue );
+
+ // Convert CMIS properties to OneDrive properties
+ static Json toOneDriveJson( const libcmis::PropertyPtrMap& properties );
+};
+
+#endif
diff --git a/src/libcmis/property-type.cxx b/src/libcmis/property-type.cxx
new file mode 100644
index 0000000..42af61d
--- /dev/null
+++ b/src/libcmis/property-type.cxx
@@ -0,0 +1,254 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/property-type.hxx>
+
+#include <libcmis/object-type.hxx>
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ PropertyType::PropertyType( ) :
+ m_id( ),
+ m_localName( ),
+ m_localNamespace( ),
+ m_displayName( ),
+ m_queryName( ),
+ m_type( String ),
+ m_xmlType( "String" ),
+ m_multiValued( false ),
+ m_updatable( false ),
+ m_inherited( false ),
+ m_required( false ),
+ m_queryable( false ),
+ m_orderable( false ),
+ m_openChoice( false ),
+ m_temporary( false )
+ {
+ }
+
+ PropertyType::PropertyType( xmlNodePtr node ) :
+ m_id( ),
+ m_localName( ),
+ m_localNamespace( ),
+ m_displayName( ),
+ m_queryName( ),
+ m_type( String ),
+ m_xmlType( "String" ),
+ m_multiValued( false ),
+ m_updatable( false ),
+ m_inherited( false ),
+ m_required( false ),
+ m_queryable( false ),
+ m_orderable( false ),
+ m_openChoice( false ),
+ m_temporary( false )
+ {
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ string value( ( const char * ) content );
+ xmlFree( content );
+
+ if ( xmlStrEqual( child->name, BAD_CAST( "id" ) ) )
+ setId( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "localName" ) ) )
+ setLocalName( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "localNamespace" ) ) )
+ setLocalNamespace( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "displayName" ) ) )
+ setDisplayName( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "queryName" ) ) )
+ setQueryName( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "propertyType" ) ) )
+ setTypeFromXml( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "cardinality" ) ) )
+ setMultiValued( value == "multi" );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "updatability" ) ) )
+ setUpdatable( value == "readwrite" );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "inherited" ) ) )
+ setInherited( libcmis::parseBool( value ) );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "required" ) ) )
+ setRequired( libcmis::parseBool( value ) );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "queryable" ) ) )
+ setQueryable( libcmis::parseBool( value ) );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "orderable" ) ) )
+ setOrderable( libcmis::parseBool( value ) );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "openChoice" ) ) )
+ setOpenChoice( libcmis::parseBool( value ) );
+ }
+ }
+
+ PropertyType::PropertyType( const PropertyType& copy ) :
+ m_id ( copy.m_id ),
+ m_localName ( copy.m_localName ),
+ m_localNamespace ( copy.m_localNamespace ),
+ m_displayName ( copy.m_displayName ),
+ m_queryName ( copy.m_queryName ),
+ m_type ( copy.m_type ),
+ m_xmlType( copy.m_xmlType ),
+ m_multiValued ( copy.m_multiValued ),
+ m_updatable ( copy.m_updatable ),
+ m_inherited ( copy.m_inherited ),
+ m_required ( copy.m_required ),
+ m_queryable ( copy.m_queryable ),
+ m_orderable ( copy.m_orderable ),
+ m_openChoice ( copy.m_openChoice ),
+ m_temporary( copy.m_temporary )
+ {
+ }
+
+ PropertyType::PropertyType( string type,
+ string id,
+ string localName,
+ string displayName,
+ string queryName ) :
+ m_id ( id ),
+ m_localName ( localName ),
+ m_localNamespace ( ),
+ m_displayName ( displayName ),
+ m_queryName ( queryName ),
+ m_type ( ),
+ m_xmlType( type ),
+ m_multiValued( false ),
+ m_updatable( false ),
+ m_inherited( false ),
+ m_required( false ),
+ m_queryable( false ),
+ m_orderable( false ),
+ m_openChoice( false ),
+ m_temporary( true )
+ {
+ setTypeFromXml( m_xmlType );
+ }
+
+ PropertyType& PropertyType::operator=( const PropertyType& copy )
+ {
+ if ( this != &copy )
+ {
+ m_id = copy.m_id;
+ m_localName = copy.m_localName;
+ m_localNamespace = copy.m_localNamespace;
+ m_displayName = copy.m_displayName;
+ m_queryName = copy.m_queryName;
+ m_type = copy.m_type;
+ m_xmlType = copy.m_xmlType;
+ m_multiValued = copy.m_multiValued;
+ m_updatable = copy.m_updatable;
+ m_inherited = copy.m_inherited;
+ m_required = copy.m_required;
+ m_queryable = copy.m_queryable;
+ m_orderable = copy.m_orderable;
+ m_openChoice = copy.m_openChoice;
+ m_temporary = copy.m_temporary;
+ }
+
+ return *this;
+ }
+
+ void PropertyType::setTypeFromJsonType( string jsonType )
+ {
+ if ( jsonType == "json_bool" )
+ m_type = Bool;
+ else if ( jsonType == "json_double" )
+ m_type = Decimal;
+ else if ( jsonType == "json_int" )
+ m_type = Integer;
+ else if ( jsonType == "json_datetime" )
+ m_type = DateTime;
+ else m_type = String;
+ }
+
+ void PropertyType::setTypeFromXml( string typeStr )
+ {
+ // Default to string
+ m_xmlType = string( "String" );
+ m_type = String;
+
+ if ( typeStr == "datetime" )
+ {
+ m_xmlType = string( "DateTime" );
+ m_type = DateTime;
+ }
+ else if ( typeStr == "integer" )
+ {
+ m_xmlType = string( "Integer" );
+ m_type = Integer;
+ }
+ else if ( typeStr == "decimal" )
+ {
+ m_xmlType = string( "Decimal" );
+ m_type = Decimal;
+ }
+ else if ( typeStr == "boolean" )
+ {
+ m_xmlType = string( "Boolean" );
+ m_type = Bool;
+ }
+ // Special kinds of String
+ else if ( typeStr == "html" )
+ m_xmlType = string( "Html" );
+ else if ( typeStr == "id" )
+ m_xmlType = string( "Id" );
+ else if ( typeStr == "uri" )
+ m_xmlType = string( "Uri" );
+ }
+
+ void PropertyType::update( vector< ObjectTypePtr > typesDefs )
+ {
+ for ( vector< ObjectTypePtr >::iterator it = typesDefs.begin();
+ it != typesDefs.end( ) && m_temporary; ++it )
+ {
+ map< string, PropertyTypePtr >& propertyTypes =
+ ( *it )->getPropertiesTypes( );
+ map< string, PropertyTypePtr >::iterator propIt =
+ propertyTypes.find( getId( ) );
+ if ( propIt != propertyTypes.end() )
+ {
+ PropertyTypePtr complete = propIt->second;
+
+ m_localName = complete->m_localName;
+ m_localNamespace = complete->m_localNamespace;
+ m_displayName = complete->m_displayName;
+ m_queryName = complete->m_queryName;
+ m_type = complete->m_type;
+ m_xmlType = complete->m_xmlType;
+ m_multiValued = complete->m_multiValued;
+ m_updatable = complete->m_updatable;
+ m_inherited = complete->m_inherited;
+ m_required = complete->m_required;
+ m_queryable = complete->m_queryable;
+ m_orderable = complete->m_orderable;
+ m_openChoice = complete->m_openChoice;
+ m_temporary = false;
+ }
+ }
+ }
+}
diff --git a/src/libcmis/property.cxx b/src/libcmis/property.cxx
new file mode 100644
index 0000000..41c181b
--- /dev/null
+++ b/src/libcmis/property.cxx
@@ -0,0 +1,232 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/property.hxx>
+
+#include <boost/algorithm/string.hpp>
+
+#include <libcmis/object-type.hxx>
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ Property::Property( ):
+ m_propertyType( ),
+ m_strValues( ),
+ m_boolValues( ),
+ m_longValues( ),
+ m_doubleValues( ),
+ m_dateTimeValues( )
+ {
+ }
+
+ Property::Property( PropertyTypePtr propertyType, std::vector< std::string > strValues ) :
+ m_propertyType( propertyType ),
+ m_strValues( ),
+ m_boolValues( ),
+ m_longValues( ),
+ m_doubleValues( ),
+ m_dateTimeValues( )
+ {
+ setValues( strValues );
+ }
+
+ void Property::setValues( vector< string > strValues )
+ {
+ m_strValues = strValues;
+ m_boolValues.clear( );
+ m_longValues.clear( );
+ m_doubleValues.clear( );
+ m_dateTimeValues.clear( );
+
+ for ( vector< string >::iterator it = strValues.begin(); it != strValues.end( ); ++it )
+ {
+ try
+ {
+ // If no PropertyType was provided at construction time, use String
+ PropertyType::Type type = PropertyType::String;
+ if ( getPropertyType( ) != NULL )
+ type = getPropertyType( )->getType( );
+
+ switch ( type )
+ {
+ case PropertyType::Integer:
+ m_longValues.push_back( parseInteger( *it ) );
+ break;
+ case PropertyType::Decimal:
+ m_doubleValues.push_back( parseDouble( *it ) );
+ break;
+ case PropertyType::Bool:
+ m_boolValues.push_back( parseBool( *it ) );
+ break;
+ case PropertyType::DateTime:
+ {
+ boost::posix_time::ptime time = parseDateTime( *it );
+ if ( !time.is_not_a_date_time( ) )
+ m_dateTimeValues.push_back( time );
+ }
+ break;
+ default:
+ case PropertyType::String:
+ // Nothing to convert for strings
+ break;
+ }
+ }
+ catch( const Exception& )
+ {
+ // Just ignore the unparsable values
+ }
+ }
+ }
+
+ void Property::setPropertyType( PropertyTypePtr propertyType)
+ {
+ m_propertyType = propertyType;
+ }
+ void Property::toXml( xmlTextWriterPtr writer )
+ {
+ // Don't write the property if we have no type for it.
+ if ( getPropertyType( ) != NULL )
+ {
+ string xmlType = string( "cmis:property" ) + getPropertyType()->getXmlType( );
+ xmlTextWriterStartElement( writer, BAD_CAST( xmlType.c_str( ) ) );
+
+ // Write the attributes
+ xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "propertyDefinitionId" ),
+ "%s", BAD_CAST( getPropertyType()->getId( ).c_str( ) ) );
+ xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "localName" ),
+ "%s", BAD_CAST( getPropertyType()->getLocalName( ).c_str( ) ) );
+ xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "displayName" ),
+ "%s", BAD_CAST( getPropertyType()->getDisplayName( ).c_str( ) ) );
+ xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "queryName" ),
+ "%s", BAD_CAST( getPropertyType()->getQueryName( ).c_str( ) ) );
+
+ // Write the values
+ for ( vector< string >::iterator it = m_strValues.begin( ); it != m_strValues.end( ); ++it )
+ {
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmis:value" ), BAD_CAST( it->c_str( ) ) );
+ }
+
+ xmlTextWriterEndElement( writer );
+ }
+ }
+
+ string Property::toString( )
+ {
+ string res;
+ if ( getPropertyType( ) != NULL )
+ {
+ for ( vector< string >::iterator it = m_strValues.begin( );
+ it != m_strValues.end( ); ++it )
+ {
+ res.append( *it );
+ }
+ }
+ return res;
+ }
+
+ PropertyPtr parseProperty( xmlNodePtr node, ObjectTypePtr objectType )
+ {
+ PropertyPtr property;
+
+ if ( node != NULL )
+ {
+ // Get the property definition Id
+ string propDefinitionId;
+ try
+ {
+ propDefinitionId = getXmlNodeAttributeValue( node, "propertyDefinitionId" );
+ }
+ catch ( const Exception& )
+ {
+ }
+
+ // Try to get the property type definition
+ PropertyTypePtr propType;
+ if ( !propDefinitionId.empty() && objectType )
+ {
+ map< string, PropertyTypePtr >::iterator it = objectType->getPropertiesTypes( ).find( propDefinitionId );
+ if ( it != objectType->getPropertiesTypes().end( ) )
+ propType = it->second;
+ }
+
+ // Try to construct a temporary type definition
+ if ( !propDefinitionId.empty( ) && !propType )
+ {
+ if ( node->name != NULL )
+ {
+ string localName = getXmlNodeAttributeValue( node,
+ "localName", "" );
+ string displayName = getXmlNodeAttributeValue( node,
+ "displayName", "" );
+ string queryName = getXmlNodeAttributeValue( node,
+ "queryName", "" );
+
+ string xmlType( ( char * )node->name );
+ string propStr( "property" );
+ size_t pos = xmlType.find( propStr );
+ if ( pos == 0 ) {
+ xmlType = xmlType.substr( propStr.length( ) );
+ boost::to_lower( xmlType );
+ }
+
+ propType.reset( new PropertyType( xmlType, propDefinitionId,
+ localName, displayName,
+ queryName ) );
+ }
+ }
+
+ if ( propType )
+ {
+ try
+ {
+ // Find the value nodes
+ vector< string > values;
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "value" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ values.push_back( string( ( char * ) content ) );
+ xmlFree( content );
+ }
+ }
+ property.reset( new Property( propType, values ) );
+ }
+ catch ( const Exception& )
+ {
+ // Ignore that non-property node
+ }
+ }
+ }
+
+ return property;
+ }
+}
diff --git a/src/libcmis/rendition.cxx b/src/libcmis/rendition.cxx
new file mode 100644
index 0000000..c68c053
--- /dev/null
+++ b/src/libcmis/rendition.cxx
@@ -0,0 +1,195 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2013 Cao Cuong Ngo <cao.cuong.ngo@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/rendition.hxx>
+
+#include <sstream>
+
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+namespace libcmis{
+
+Rendition::Rendition( ):
+ m_streamId( ),
+ m_mimeType( ),
+ m_kind( ),
+ m_href( ),
+ m_title( ),
+ m_length( -1 ),
+ m_width ( -1 ),
+ m_height( -1 ),
+ m_renditionDocumentId( )
+{
+}
+
+Rendition::Rendition( string streamId, string mimeType,
+ string kind, string href, string title, long length,
+ long width, long height, string renditionDocumentId ):
+ m_streamId( streamId ),
+ m_mimeType( mimeType ),
+ m_kind( kind ),
+ m_href( href ),
+ m_title( title ),
+ m_length( length ),
+ m_width ( width ),
+ m_height( height ),
+ m_renditionDocumentId( renditionDocumentId )
+{
+}
+
+Rendition::Rendition( xmlNodePtr node ):
+ m_streamId( ),
+ m_mimeType( ),
+ m_kind( ),
+ m_href( ),
+ m_title( ),
+ m_length( -1 ),
+ m_width ( -1 ),
+ m_height( -1 ),
+ m_renditionDocumentId( )
+{
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ string value( ( char * ) content );
+ xmlFree( content );
+
+ if ( xmlStrEqual( child->name, BAD_CAST( "streamId" ) ) )
+ m_streamId = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "mimetype" ) ) )
+ m_mimeType = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "length" ) ) )
+ m_length = libcmis::parseInteger( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "kind" ) ) )
+ m_kind = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "title" ) ) )
+ m_title = value;
+ else if ( xmlStrEqual( child->name, BAD_CAST( "height" ) ) )
+ m_height = libcmis::parseInteger( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "width" ) ) )
+ m_width = libcmis::parseInteger( value );
+ else if ( xmlStrEqual( child->name, BAD_CAST( "renditionDocumentId" ) ) )
+ m_renditionDocumentId = value;
+ }
+}
+
+Rendition::~Rendition( )
+{
+}
+
+bool Rendition::isThumbnail( )
+{
+ return m_kind == "cmis:thumbnail";
+}
+
+
+const string& Rendition::getStreamId( ) const
+{
+ return m_streamId;
+}
+
+const string& Rendition::getMimeType( ) const
+{
+ return m_mimeType;
+}
+
+const string& Rendition::getKind( ) const
+{
+ return m_kind;
+}
+
+const string& Rendition::getUrl( ) const
+{
+ return m_href;
+}
+
+const string& Rendition::getTitle( ) const
+{
+ return m_title;
+}
+
+long Rendition::getLength( ) const
+{
+ return m_length;
+}
+
+long Rendition::getWidth( ) const
+{
+ return m_width;
+}
+
+long Rendition::getHeight( ) const
+{
+ return m_height;
+}
+
+const string& Rendition::getRenditionDocumentId( )
+{
+ return m_renditionDocumentId;
+}
+
+
+// LCOV_EXCL_START
+string Rendition::toString( )
+{
+ stringstream buf;
+
+ if ( !getStreamId( ).empty( ) )
+ buf << " ID: " << getStreamId( ) << endl;
+
+ if ( !getKind().empty() )
+ buf << " Kind: " << getKind( ) << endl;
+
+ if ( !getMimeType( ).empty() )
+ buf << " MimeType: " << getMimeType( ) << endl;
+
+ if ( !getUrl().empty( ) )
+ buf << " URL: " << getUrl( ) << endl;
+
+ if ( !getTitle().empty( ) )
+ buf << " Title: " << getTitle( ) << endl;
+
+ if ( getLength( ) >= 0 )
+ buf << " Length: " << getLength( ) << endl;
+
+ if ( getWidth( ) >= 0 )
+ buf << " Width: " << getWidth( ) << endl;
+
+ if ( getHeight( ) >= 0 )
+ buf << " Height: " << getHeight( ) << endl;
+
+ if ( !getRenditionDocumentId().empty( ) )
+ buf << " Rendition Document ID: " << getRenditionDocumentId( ) << endl;
+
+ return buf.str( );
+}
+// LCOV_EXCL_STOP
+
+}
diff --git a/src/libcmis/repository.cxx b/src/libcmis/repository.cxx
new file mode 100644
index 0000000..0a7cbe6
--- /dev/null
+++ b/src/libcmis/repository.cxx
@@ -0,0 +1,294 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 Cédric Bosdonnat <cbosdo@users.sourceforge.net>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/repository.hxx>
+
+#include <sstream>
+
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+
+namespace libcmis
+{
+ Repository::Repository( ) :
+ m_id( ),
+ m_name( ),
+ m_description( ),
+ m_vendorName( ),
+ m_productName( ),
+ m_productVersion( ),
+ m_rootId( ),
+ m_cmisVersionSupported( ),
+ m_thinClientUri( ),
+ m_principalAnonymous( ),
+ m_principalAnyone( ),
+ m_capabilities( )
+ {
+ }
+
+ Repository::Repository( xmlNodePtr node ) :
+ m_id( ),
+ m_name( ),
+ m_description( ),
+ m_vendorName( ),
+ m_productName( ),
+ m_productVersion( ),
+ m_rootId( ),
+ m_cmisVersionSupported( ),
+ m_thinClientUri( ),
+ m_principalAnonymous( ),
+ m_principalAnyone( ),
+ m_capabilities( )
+ {
+ initializeFromNode( node );
+ }
+
+ string Repository::getId( ) const
+ {
+ return m_id;
+ }
+
+ string Repository::getName( ) const
+ {
+ return m_name;
+ }
+
+ string Repository::getDescription( ) const
+ {
+ return m_description;
+ }
+
+ string Repository::getVendorName( ) const
+ {
+ return m_vendorName;
+ }
+
+ string Repository::getProductName( ) const
+ {
+ return m_productName;
+ }
+
+ string Repository::getProductVersion( ) const
+ {
+ return m_productVersion;
+ }
+
+ string Repository::getRootId( ) const
+ {
+ return m_rootId;
+ }
+
+ string Repository::getCmisVersionSupported( ) const
+ {
+ return m_cmisVersionSupported;
+ }
+
+ boost::shared_ptr< string > Repository::getThinClientUri( ) const
+ {
+ return m_thinClientUri;
+ }
+
+ boost::shared_ptr< string > Repository::getPrincipalAnonymous( ) const
+ {
+ return m_principalAnonymous;
+ }
+
+ boost::shared_ptr< string > Repository::getPrincipalAnyone( ) const
+ {
+ return m_principalAnyone;
+ }
+
+
+ void Repository::initializeFromNode( xmlNodePtr node )
+ {
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ string localName( ( char* ) child->name );
+
+ xmlChar* content = xmlNodeGetContent( child );
+ string value( ( char* )content );
+ xmlFree( content );
+
+ if ( localName == "repositoryId" )
+ m_id = value;
+ else if ( localName == "repositoryName" )
+ m_name = value;
+ else if ( localName == "repositoryDescription" )
+ m_description = value;
+ else if ( localName == "vendorName" )
+ m_vendorName = value;
+ else if ( localName == "productName" )
+ m_productName = value;
+ else if ( localName == "productVersion" )
+ m_productVersion = value;
+ else if ( localName == "rootFolderId" )
+ m_rootId = value;
+ else if ( localName == "cmisVersionSupported" )
+ m_cmisVersionSupported = value;
+ else if ( localName == "thinClientURI" )
+ m_thinClientUri.reset( new string( value ) );
+ else if ( localName == "principalAnonymous" )
+ m_principalAnonymous.reset( new string( value ) );
+ else if ( localName == "principalAnyone" )
+ m_principalAnyone.reset( new string( value ) );
+ else if ( localName == "capabilities" )
+ {
+ m_capabilities = parseCapabilities( child );
+ }
+ }
+ }
+
+ string Repository::getCapability( Capability capability ) const
+ {
+ string result;
+
+ map< Capability, string >::const_iterator it = m_capabilities.find( capability );
+ if ( it != m_capabilities.end() )
+ result = it->second;
+
+ return result;
+ }
+
+ bool Repository::getCapabilityAsBool( Capability capability ) const
+ {
+ string value = getCapability( capability );
+ bool result = false;
+ try
+ {
+ result = libcmis::parseBool( value );
+ }
+ catch ( const Exception& )
+ {
+ }
+ return result;
+ }
+
+ // LCOV_EXCL_START
+ string Repository::toString( ) const
+ {
+ stringstream buf;
+
+ buf << "Id: " << getId( ) << endl;
+ buf << "Name: " << getName( ) << endl;
+ buf << "Description: " << getDescription( ) << endl;
+ buf << "Vendor: " << getVendorName( ) << endl;
+ buf << "Product: " << getProductName( ) << " - version " << getProductVersion( ) << endl;
+ buf << "Root Id: " << getRootId( ) << endl;
+ buf << "Supported CMIS Version: " << getCmisVersionSupported( ) << endl;
+ if ( getThinClientUri( ) )
+ buf << "Thin Client URI: " << *getThinClientUri( ) << endl;
+ if ( getPrincipalAnonymous( ) )
+ buf << "Anonymous user: " << *getPrincipalAnonymous( ) << endl;
+ if ( getPrincipalAnyone( ) )
+ buf << "Anyone user: " << *getPrincipalAnyone( ) << endl;
+ buf << endl;
+ buf << "Capabilities:" << endl;
+
+ static string capabilitiesNames[] =
+ {
+ "ACL",
+ "AllVersionsSearchable",
+ "Changes",
+ "ContentStreamUpdatability",
+ "GetDescendants",
+ "GetFolderTree",
+ "OrderBy",
+ "Multifiling",
+ "PWCSearchable",
+ "PWCUpdatable",
+ "Query",
+ "Renditions",
+ "Unfiling",
+ "VersionSpecificFiling",
+ "Join"
+ };
+
+ for ( int i = ACL; i < Join; ++i )
+ {
+ buf << "\t" << capabilitiesNames[i] << ": " << getCapability( ( Capability )i ) << endl;
+ }
+
+ return buf.str();
+ }
+ // LCOV_EXCL_STOP
+
+ map< Repository::Capability, string > Repository::parseCapabilities( xmlNodePtr node )
+ {
+ map< Capability, string > capabilities;
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ string localName( ( char* ) child->name );
+
+ xmlChar* content = xmlNodeGetContent( child );
+ string value( ( char* )content );
+ xmlFree( content );
+
+ Capability capability = ACL;
+ bool ignore = false;
+ if ( localName == "capabilityACL" )
+ capability = ACL;
+ else if ( localName == "capabilityAllVersionsSearchable" )
+ capability = AllVersionsSearchable;
+ else if ( localName == "capabilityChanges" )
+ capability = Changes;
+ else if ( localName == "capabilityContentStreamUpdatability" )
+ capability = ContentStreamUpdatability;
+ else if ( localName == "capabilityGetDescendants" )
+ capability = GetDescendants;
+ else if ( localName == "capabilityGetFolderTree" )
+ capability = GetFolderTree;
+ else if ( localName == "capabilityOrderBy" )
+ capability = OrderBy;
+ else if ( localName == "capabilityMultifiling" )
+ capability = Multifiling;
+ else if ( localName == "capabilityPWCSearchable" )
+ capability = PWCSearchable;
+ else if ( localName == "capabilityPWCUpdatable" )
+ capability = PWCUpdatable;
+ else if ( localName == "capabilityQuery" )
+ capability = Query;
+ else if ( localName == "capabilityRenditions" )
+ capability = Renditions;
+ else if ( localName == "capabilityUnfiling" )
+ capability = Unfiling;
+ else if ( localName == "capabilityVersionSpecificFiling" )
+ capability = VersionSpecificFiling;
+ else if ( localName == "capabilityJoin" )
+ capability = Join;
+ else
+ ignore = true;
+
+ if ( !ignore )
+ capabilities[capability] = value;
+ }
+
+ return capabilities;
+ }
+}
diff --git a/src/libcmis/session-factory.cxx b/src/libcmis/session-factory.cxx
new file mode 100644
index 0000000..47dc1c8
--- /dev/null
+++ b/src/libcmis/session-factory.cxx
@@ -0,0 +1,164 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/session-factory.hxx>
+
+#include "atom-session.hxx"
+#include "gdrive-session.hxx"
+#include "onedrive-session.hxx"
+#include "sharepoint-session.hxx"
+#include "ws-session.hxx"
+
+using namespace std;
+
+namespace libcmis
+{
+ CurlInitProtocolsFunction g_CurlInitProtocolsFunction = 0;
+ AuthProviderPtr SessionFactory::s_authProvider;
+ OAuth2AuthCodeProvider SessionFactory::s_oauth2AuthCodeProvider;
+
+ string SessionFactory::s_proxy;
+ string SessionFactory::s_noProxy;
+ string SessionFactory::s_proxyUser;
+ string SessionFactory::s_proxyPass;
+
+ CertValidationHandlerPtr SessionFactory::s_certValidationHandler;
+
+ void SessionFactory::setCurlInitProtocolsFunction(CurlInitProtocolsFunction const initProtocols)
+ {
+ g_CurlInitProtocolsFunction = initProtocols;
+ }
+
+ void SessionFactory::setProxySettings( string proxy, string noProxy,
+ string proxyUser, string proxyPass )
+ {
+ SessionFactory::s_proxy = proxy;
+ SessionFactory::s_noProxy = noProxy;
+ SessionFactory::s_proxyUser = proxyUser;
+ SessionFactory::s_proxyPass = proxyPass;
+ }
+
+ Session* SessionFactory::createSession( string bindingUrl, string username,
+ string password, string repository, bool noSslCheck,
+ libcmis::OAuth2DataPtr oauth2, bool verbose )
+ {
+ Session* session = NULL;
+
+ if ( !bindingUrl.empty( ) )
+ {
+ // Try the special cases based on the binding URL
+ if ( bindingUrl == "https://www.googleapis.com/drive/v3" )
+ {
+ session = new GDriveSession( bindingUrl, username, password,
+ oauth2, verbose );
+ }
+ else if ( bindingUrl == "https://graph.microsoft.com/v1.0" )
+ {
+ session = new OneDriveSession( bindingUrl, username, password,
+ oauth2, verbose);
+ }
+ else
+ {
+ libcmis::HttpResponsePtr response;
+ boost::shared_ptr< HttpSession> httpSession(
+ new HttpSession( username, password,
+ noSslCheck, oauth2, verbose,
+ g_CurlInitProtocolsFunction) );
+
+ try
+ {
+ response = httpSession->httpGetRequest( bindingUrl );
+ }
+ catch ( const CurlException& )
+ {
+ // Could be SharePoint - needs NTLM authentication
+ session = new SharePointSession( bindingUrl, username,
+ password, verbose );
+ }
+
+ // Try the CMIS cases: we need to autodetect the binding type
+ if ( session == NULL )
+ {
+ try
+ {
+ session = new AtomPubSession( bindingUrl, repository,
+ *httpSession, response );
+ }
+ catch ( const Exception& )
+ {
+ }
+ }
+
+ if ( session == NULL )
+ {
+ // We couldn't get an AtomSession, we may have an URL for the WebService binding
+ try
+ {
+ session = new WSSession( bindingUrl, repository,
+ *httpSession, response );
+ }
+ catch ( const Exception& )
+ {
+ }
+ }
+
+ if ( session == NULL )
+ {
+ // Maybe the first request didn't throw an exception and the authentication
+ // succeeded so we need to double check for SharePoint
+ try
+ {
+ session = new SharePointSession( bindingUrl,
+ *httpSession, response );
+ }
+ catch ( const Exception& )
+ {
+ }
+ }
+ }
+ }
+
+ return session;
+ }
+
+ vector< RepositoryPtr > SessionFactory::getRepositories( string bindingUrl,
+ string username, string password, bool verbose )
+ {
+ vector< RepositoryPtr > repos;
+
+ Session* session = createSession( bindingUrl, username, password,
+ string(), false, OAuth2DataPtr(), verbose );
+ if ( session != NULL )
+ {
+ repos = session->getRepositories( );
+ delete session;
+ }
+
+ return repos;
+ }
+}
diff --git a/src/libcmis/sharepoint-allowable-actions.hxx b/src/libcmis/sharepoint-allowable-actions.hxx
new file mode 100644
index 0000000..abc48fc
--- /dev/null
+++ b/src/libcmis/sharepoint-allowable-actions.hxx
@@ -0,0 +1,102 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Varga Mihai <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _SHAREPOINT_ALLOWABLE_ACTIONS_HXX_
+#define _SHAREPOINT_ALLOWABLE_ACTIONS_HXX_
+
+#include <libcmis/allowable-actions.hxx>
+
+class SharePointAllowableActions: public libcmis::AllowableActions
+{
+ public:
+ SharePointAllowableActions( bool isFolder ) : AllowableActions( )
+ {
+ m_states.clear( );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteObject, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::UpdateProperties, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetProperties, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetObjectRelationships, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetObjectParents, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::MoveObject, true ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateRelationship, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::ApplyPolicy, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetAppliedPolicies, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::RemovePolicy, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetACL, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::ApplyACL, false ) );
+
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetFolderTree, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetFolderParent, isFolder) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetDescendants, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CheckOut, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CancelCheckOut, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CheckIn, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::SetContentStream, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetAllVersions, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::AddObjectToFolder, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::RemoveObjectFromFolder, !isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetRenditions, false ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::GetChildren, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateDocument, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::CreateFolder, isFolder ) );
+ m_states.insert( std::pair< libcmis::ObjectAction::Type, bool> (
+ libcmis::ObjectAction::DeleteTree, isFolder ) );
+ }
+};
+
+#endif
diff --git a/src/libcmis/sharepoint-document.cxx b/src/libcmis/sharepoint-document.cxx
new file mode 100644
index 0000000..dec5527
--- /dev/null
+++ b/src/libcmis/sharepoint-document.cxx
@@ -0,0 +1,213 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-document.hxx"
+
+#include "sharepoint-session.hxx"
+#include "sharepoint-utils.hxx"
+#include "json-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+SharePointDocument::SharePointDocument( SharePointSession* session ) :
+ libcmis::Object( session),
+ libcmis::Document( session ),
+ SharePointObject( session )
+{
+}
+
+SharePointDocument::SharePointDocument( SharePointSession* session, Json json, string parentId, string name ) :
+ libcmis::Object( session),
+ libcmis::Document( session ),
+ SharePointObject( session, json, parentId, name )
+{
+}
+
+SharePointDocument::~SharePointDocument( )
+{
+}
+
+vector< libcmis::FolderPtr > SharePointDocument::getParents( )
+{
+ vector< libcmis::FolderPtr > parents;
+
+ string parentId = getStringProperty( "cmis:parentId" );
+
+ libcmis::ObjectPtr obj = getSession( )->getObject( parentId );
+ libcmis::FolderPtr parent = boost::dynamic_pointer_cast< libcmis::Folder >( obj );
+ parents.push_back( parent );
+ return parents;
+}
+
+boost::shared_ptr< istream > SharePointDocument::getContentStream( string /*streamId*/ )
+{
+ boost::shared_ptr< istream > stream;
+ // file uri + /$value
+ string streamUrl = getId( ) + "/%24value";
+ try
+ {
+ stream = getSession( )->httpGetRequest( streamUrl )->getStream( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ return stream;
+}
+
+void SharePointDocument::setContentStream( boost::shared_ptr< ostream > os,
+ string contentType,
+ string /*fileName*/,
+ bool /*overwrite*/ )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ // file uri + /$value
+ string putUrl = getId( ) + "/%24value";
+ // Upload stream
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ vector <string> headers;
+ headers.push_back( string( "Content-Type: " ) + contentType );
+ try
+ {
+ getSession()->httpPutRequest( putUrl, *is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ long httpStatus = getSession( )->getHttpStatus( );
+ if ( httpStatus < 200 || httpStatus >= 300 )
+ {
+ throw libcmis::Exception( "Document content wasn't set for"
+ "some reason" );
+ }
+ refresh( );
+}
+
+libcmis::DocumentPtr SharePointDocument::checkOut( )
+{
+ istringstream is( "" );
+ string url = getId( ) + "/checkout";
+ try
+ {
+ getSession( )->httpPostRequest( url, is, "" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr checkout =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ return checkout;
+}
+
+void SharePointDocument::cancelCheckout( )
+{
+ istringstream is( "" );
+ string url = getId( ) + "/undocheckout";
+ try
+ {
+ getSession( )->httpPostRequest( url, is, "" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+}
+
+libcmis::DocumentPtr SharePointDocument::checkIn( bool isMajor,
+ std::string comment,
+ const PropertyPtrMap& /*properties*/,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string fileName )
+{
+ setContentStream( stream, contentType, fileName );
+ comment = libcmis::escape( comment );
+ string url = getId( ) + "/checkin(comment='" + comment + "'";
+ if ( isMajor )
+ {
+ url += ",checkintype=1)";
+ }
+ else
+ {
+ url += ",checkintype=0)";
+ }
+ istringstream is( "" );
+ try
+ {
+ getSession( )->httpPostRequest( url, is, "" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr checkin =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ return checkin;
+}
+
+vector< libcmis::DocumentPtr > SharePointDocument::getAllVersions( )
+{
+ string res;
+ string url = getStringProperty( "Versions" );
+ vector< libcmis::DocumentPtr > allVersions;
+ try
+ {
+ res = getSession( )->httpGetRequest( url )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ // adding the latest version
+ libcmis::ObjectPtr obj = getSession( )->getObject( getId( ) );
+ libcmis::DocumentPtr doc =
+ boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ allVersions.push_back( doc );
+
+ Json jsonRes = Json::parse( res );
+ Json::JsonVector objs = jsonRes["d"]["results"].getList( );
+ for ( unsigned int i = 0; i < objs.size( ); i++)
+ {
+ string versionNumber = objs[i]["ID"].toString( );
+ string versionId = getId( ) + "/Versions(" + versionNumber + ")";
+ obj = getSession( )->getObject( versionId );
+ doc = boost::dynamic_pointer_cast< libcmis::Document > ( obj );
+ allVersions.push_back( doc );
+ }
+
+ return allVersions;
+}
diff --git a/src/libcmis/sharepoint-document.hxx b/src/libcmis/sharepoint-document.hxx
new file mode 100644
index 0000000..8423eb0
--- /dev/null
+++ b/src/libcmis/sharepoint-document.hxx
@@ -0,0 +1,72 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _SHAREPOINT_DOCUMENT_HXX_
+#define _SHAREPOINT_DOCUMENT_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "sharepoint-object.hxx"
+#include "json-utils.hxx"
+
+class SharePointDocument : public libcmis::Document, public SharePointObject
+{
+ public:
+ SharePointDocument( SharePointSession* session );
+
+ SharePointDocument( SharePointSession* session, Json json,
+ std::string parentId = std::string( ),
+ std::string name = std::string( ) );
+ ~SharePointDocument( );
+
+ std::string getType( ) { return std::string( "cmis:document" );}
+ std::string getBaseType( ) { return std::string( "cmis:document" );}
+
+ virtual std::vector< libcmis::FolderPtr > getParents( );
+ virtual boost::shared_ptr< std::istream > getContentStream( std::string streamId = std::string( ) );
+
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os,
+ std::string contentType,
+ std::string fileName,
+ bool overwrite = true );
+
+ virtual libcmis::DocumentPtr checkOut( );
+ virtual void cancelCheckout( );
+ virtual libcmis::DocumentPtr checkIn( bool isMajor,
+ std::string comment,
+ const std::map< std::string,libcmis::PropertyPtr >&
+ properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string fileName );
+
+ virtual std::vector< libcmis::DocumentPtr > getAllVersions( );
+};
+
+#endif
diff --git a/src/libcmis/sharepoint-folder.cxx b/src/libcmis/sharepoint-folder.cxx
new file mode 100644
index 0000000..e4da4a3
--- /dev/null
+++ b/src/libcmis/sharepoint-folder.cxx
@@ -0,0 +1,205 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-folder.hxx"
+
+#include "sharepoint-document.hxx"
+#include "sharepoint-session.hxx"
+#include "sharepoint-property.hxx"
+#include "sharepoint-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+SharePointFolder::SharePointFolder( SharePointSession* session ):
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ SharePointObject( session )
+{
+}
+
+SharePointFolder::SharePointFolder( SharePointSession* session, Json json, string parentId ):
+ libcmis::Object( session ),
+ libcmis::Folder( session ),
+ SharePointObject( session, json, parentId )
+{
+}
+
+SharePointFolder::~SharePointFolder( )
+{
+}
+
+string SharePointFolder::getParentId( )
+{
+ string parentId = getStringProperty( "cmis:parentId" );
+ if ( parentId.empty( ) )
+ {
+ string parentUrl = getStringProperty( "ParentFolder" );
+ string res;
+ try
+ {
+ res = getSession( )->httpGetRequest( parentUrl )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ Json jsonRes = Json::parse( res );
+ parentId = jsonRes["d"]["__metadata"]["uri"].toString( );
+ PropertyPtr property;
+ property.reset( new SharePointProperty( "cmis:parentId",
+ Json( parentId.c_str( ) ) ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+ return parentId;
+}
+
+vector< libcmis::ObjectPtr > SharePointFolder::getChildren( )
+{
+ vector< libcmis::ObjectPtr > children;
+ string filesUrl = getStringProperty( "Files" );
+ string foldersUrl = getStringProperty( "Folders" );
+
+ Json::JsonVector objs = getChildrenImpl( filesUrl );
+ Json::JsonVector folders = getChildrenImpl( foldersUrl );
+ objs.insert( objs.begin( ), folders.begin( ), folders.end( ) );
+
+ for ( unsigned int i = 0; i < objs.size( ); i++)
+ {
+ children.push_back( getSession( )->getObjectFromJson( objs[i], getId( ) ) );
+ }
+ return children;
+}
+
+Json::JsonVector SharePointFolder::getChildrenImpl( string url )
+{
+ string res;
+ try
+ {
+ res = getSession( )->httpGetRequest( url )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+ Json::JsonVector objs = jsonRes["d"]["results"].getList( );
+ return objs;
+}
+
+libcmis::FolderPtr SharePointFolder::createFolder( const PropertyPtrMap& properties )
+{
+ string folderName;
+ for ( PropertyPtrMap::const_iterator it = properties.begin() ;
+ it != properties.end() ; ++it )
+ {
+ if ( it->first == "cmis:name" )
+ {
+ folderName = it->second->toString( );
+ }
+ }
+ // bindingUrl/folders/add('/path/to/folder')
+ string relativeUrl;
+ if ( getStringProperty( "ServerRelativeUrl" ) == "/" )
+ {
+ relativeUrl = "/" + folderName;
+ }
+ else
+ {
+ relativeUrl = getStringProperty( "ServerRelativeUrl" ) + "/" + folderName;
+ }
+ relativeUrl = libcmis::escape( relativeUrl );
+ string folderUrl = getSession( )->getBindingUrl( );
+ folderUrl += "/folders/add('" + relativeUrl + "')";
+
+ istringstream is( "" );
+ string res;
+ try
+ {
+ res = getSession( )->httpPostRequest( folderUrl, is, "" )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+
+ libcmis::FolderPtr newFolder( new SharePointFolder( getSession( ), jsonRes, getId( ) ) );
+ return newFolder;
+}
+
+libcmis::DocumentPtr SharePointFolder::createDocument( const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os,
+ string contentType,
+ string fileName )
+{
+ if ( !os.get( ) )
+ throw libcmis::Exception( "Missing stream" );
+
+ if ( fileName.empty( ) )
+ {
+ for ( PropertyPtrMap::const_iterator it = properties.begin() ;
+ it != properties.end() ; ++it )
+ {
+ if ( it->first == "cmis:name" ||
+ it->first == "cmis:contentStreamFileName" )
+ {
+ fileName = it->second->toString( );
+ }
+ }
+ }
+ fileName = libcmis::escape( fileName );
+ string url = getId( ) + "/files/add(overwrite=true,";
+ url += "url='" + fileName + "')";
+
+ // Upload stream
+ boost::shared_ptr< istream> is ( new istream ( os->rdbuf( ) ) );
+ string res;
+ try
+ {
+ res = getSession( )->httpPostRequest( url, *is, contentType )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ Json jsonRes = Json::parse( res );
+ DocumentPtr document( new SharePointDocument( getSession( ), jsonRes, getId( ) ) );
+ return document;
+}
+
+vector< string > SharePointFolder::removeTree( bool /*allVersions*/,
+ libcmis::UnfileObjects::Type /*unfile*/,
+ bool /*continueOnError*/ )
+{
+ remove( );
+ // Nothing to return here
+ return vector< string >( );
+}
diff --git a/src/libcmis/sharepoint-folder.hxx b/src/libcmis/sharepoint-folder.hxx
new file mode 100644
index 0000000..223ed60
--- /dev/null
+++ b/src/libcmis/sharepoint-folder.hxx
@@ -0,0 +1,67 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _SHAREPOINT_FOLDER_HXX_
+#define _SHAREPOINT_FOLDER_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "sharepoint-object.hxx"
+#include "json-utils.hxx"
+
+class SharePointFolder : public libcmis::Folder, public SharePointObject
+{
+ public:
+ SharePointFolder( SharePointSession* session );
+ SharePointFolder( SharePointSession* session,
+ Json json,
+ std::string parentId = std::string( ) );
+ ~SharePointFolder( );
+
+ std::string getType( ) { return std::string( "cmis:folder" );}
+ std::string getBaseType( ) { return std::string( "cmis:folder" );}
+ virtual std::string getParentId( );
+ virtual std::vector< libcmis::ObjectPtr > getChildren( );
+
+ Json::JsonVector getChildrenImpl( std::string url );
+
+ virtual libcmis::FolderPtr createFolder( const libcmis::PropertyPtrMap& properties );
+
+ virtual libcmis::DocumentPtr createDocument( const libcmis::PropertyPtrMap& properties,
+ boost::shared_ptr< std::ostream > os,
+ std::string contentType,
+ std::string fileName );
+
+ virtual std::vector< std::string > removeTree( bool allVersion = true,
+ libcmis::UnfileObjects::Type
+ unfile = libcmis::UnfileObjects::Delete,
+ bool continueOnError = false );
+};
+
+#endif
diff --git a/src/libcmis/sharepoint-object-type.cxx b/src/libcmis/sharepoint-object-type.cxx
new file mode 100644
index 0000000..d6f405e
--- /dev/null
+++ b/src/libcmis/sharepoint-object-type.cxx
@@ -0,0 +1,105 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-object-type.hxx"
+
+SharePointObjectType::SharePointObjectType( const std::string& id ): ObjectType( )
+{
+ m_id = id;
+ m_localName = "SharePoint Object Type";
+ m_localNamespace = "SharePoint Object Type";
+ m_displayName = "SharePoint Object Type";
+ m_queryName = "SharePoint Object Type";
+ m_description = "SharePoint Object Type";
+ m_parentTypeId = id;
+ m_baseTypeId = id;
+ m_creatable = true;
+ m_versionable = true;
+ m_fulltextIndexed = true;
+
+ libcmis::PropertyTypePtr idType(new libcmis::PropertyType( ) );
+ idType->setId( "cmis:objectTypeId" );
+ idType->setType( libcmis::PropertyType::String );
+ m_propertiesTypes[ idType->getId( ) ] = idType;
+
+ // create PropertyTypes which are updatable.
+
+ // name
+ libcmis::PropertyTypePtr nameType( new libcmis::PropertyType( ) );
+ nameType->setId( "cmis:name" );
+ nameType->setType( libcmis::PropertyType::String );
+ nameType->setUpdatable( true );
+ m_propertiesTypes[ nameType->getId( ) ] = nameType;
+
+ // streamFileName
+ libcmis::PropertyTypePtr streamFileNameType( new libcmis::PropertyType( ) );
+ streamFileNameType->setId( "cmis:contentStreamFileName" );
+ streamFileNameType->setType( libcmis::PropertyType::String );
+ streamFileNameType->setUpdatable( true );
+ m_propertiesTypes[ streamFileNameType->getId( ) ] = streamFileNameType;
+
+ // modifiedDate
+ libcmis::PropertyTypePtr modifiedDateType( new libcmis::PropertyType( ) );
+ modifiedDateType->setId( "cmis:lastModificationDate" );
+ modifiedDateType->setType( libcmis::PropertyType::DateTime );
+ modifiedDateType->setUpdatable( false );
+ m_propertiesTypes[ modifiedDateType->getId( ) ] = modifiedDateType;
+
+ // creationDate
+ libcmis::PropertyTypePtr creationDateType( new libcmis::PropertyType( ) );
+ creationDateType->setId( "cmis:creationDate" );
+ creationDateType->setType( libcmis::PropertyType::DateTime );
+ creationDateType->setUpdatable( false );
+ m_propertiesTypes[ creationDateType->getId( ) ] = creationDateType;
+
+ // size
+ libcmis::PropertyTypePtr contentStreamLength( new libcmis::PropertyType( ) );
+ contentStreamLength->setId( "cmis:contentStreamLength" );
+ contentStreamLength->setType( libcmis::PropertyType::Integer );
+ contentStreamLength->setUpdatable( false );
+ m_propertiesTypes[ contentStreamLength->getId( ) ] = contentStreamLength;
+
+ // checkinComment
+ libcmis::PropertyTypePtr checkinComment( new libcmis::PropertyType( ) );
+ checkinComment->setId( "cmis:checkinComment" );
+ checkinComment->setType( libcmis::PropertyType::String );
+ checkinComment->setUpdatable( false );
+ m_propertiesTypes[ checkinComment->getId( ) ] = checkinComment;
+}
+
+libcmis::ObjectTypePtr SharePointObjectType::getParentType( )
+{
+ libcmis::ObjectTypePtr parentTypePtr( new SharePointObjectType( m_parentTypeId ) );
+ return parentTypePtr;
+}
+
+libcmis::ObjectTypePtr SharePointObjectType::getBaseType( )
+{
+ libcmis::ObjectTypePtr baseTypePtr( new SharePointObjectType( m_baseTypeId ) );
+ return baseTypePtr;
+}
diff --git a/src/libcmis/sharepoint-object-type.hxx b/src/libcmis/sharepoint-object-type.hxx
new file mode 100644
index 0000000..8ea8e3d
--- /dev/null
+++ b/src/libcmis/sharepoint-object-type.hxx
@@ -0,0 +1,46 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _SHAREPOINT_OBJECT_TYPE_HXX_
+#define _SHAREPOINT_OBJECT_TYPE_HXX_
+
+#include <libcmis/object-type.hxx>
+
+#include "json-utils.hxx"
+
+class SharePointObjectType: public libcmis::ObjectType
+{
+ public:
+ SharePointObjectType( const std::string& id );
+
+ virtual libcmis::ObjectTypePtr getParentType( );
+
+ virtual libcmis::ObjectTypePtr getBaseType( );
+};
+
+#endif
diff --git a/src/libcmis/sharepoint-object.cxx b/src/libcmis/sharepoint-object.cxx
new file mode 100644
index 0000000..1523205
--- /dev/null
+++ b/src/libcmis/sharepoint-object.cxx
@@ -0,0 +1,200 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-object.hxx"
+
+#include "sharepoint-allowable-actions.hxx"
+#include "sharepoint-property.hxx"
+#include "sharepoint-repository.hxx"
+#include "sharepoint-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+SharePointObject::SharePointObject( SharePointSession* session ) :
+ libcmis::Object( session )
+{
+}
+
+SharePointObject::SharePointObject( SharePointSession* session, Json json, string parentId, string name ) :
+ libcmis::Object( session )
+{
+ initializeFromJson( json, parentId, name );
+}
+
+SharePointObject::SharePointObject( const SharePointObject& copy ) :
+ libcmis::Object( copy )
+{
+}
+
+SharePointObject& SharePointObject::operator=( const SharePointObject& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Object::operator=( copy );
+ }
+ return *this;
+}
+
+void SharePointObject::initializeFromJson ( Json json, string parentId, string /*name*/ )
+{
+ if ( !json["d"].toString( ).empty( ) ) {
+ // Basic GET requests receive the data inside a "d" object,
+ // but child listing doesn't, so this unifies the representation
+ json = json["d"];
+ }
+ Json::JsonObject objs = json.getObjects( );
+ Json::JsonObject::iterator it;
+ PropertyPtr property;
+ bool isFolder = json["__metadata"]["type"].toString( ) == "SP.Folder";
+ for ( it = objs.begin( ); it != objs.end( ); ++it)
+ {
+ property.reset( new SharePointProperty( it->first, it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ if ( it->first == "Name" && !isFolder )
+ {
+ property.reset( new SharePointProperty( "cmis:contentStreamFileName", it->second ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+ }
+
+ if ( !parentId.empty( ) )
+ {
+ // ParentId is not provided in the response
+ property.reset( new SharePointProperty( "cmis:parentId", Json( parentId.c_str( ) ) ) );
+ m_properties[ property->getPropertyType( )->getId()] = property;
+ }
+
+ if ( !isFolder )
+ {
+ string authorUrl = getStringProperty( "Author" );
+ if ( authorUrl.empty( ) )
+ {
+ // it's a file version
+ authorUrl = getStringProperty( "CreatedBy" );
+ }
+ Json authorJson = getSession( )->getJsonFromUrl( authorUrl );
+ property.reset( new SharePointProperty( "cmis:createdBy",
+ authorJson["d"]["Title"] ) );
+ m_properties[ property->getPropertyType( )->getId( ) ] = property;
+ }
+ else
+ {
+ // we need to get the creation and lastUpdate time which aren't
+ // provided in the response
+ Json propJson = getSession( )->getJsonFromUrl( getStringProperty( "Properties" ) );
+ property.reset( new SharePointProperty( "cmis:creationDate",
+ propJson["d"]["vti_x005f_timecreated"] ) );
+ m_properties[ property->getPropertyType( )->getId( ) ] = property;
+
+ property.reset( new SharePointProperty( "cmis:lastModificationDate",
+ propJson["d"]["vti_x005f_timelastmodified"] ) );
+ m_properties[ property->getPropertyType( )->getId( ) ] = property;
+ }
+
+ m_refreshTimestamp = time( NULL );
+ m_allowableActions.reset( new SharePointAllowableActions( isFolder ) );
+}
+
+SharePointSession* SharePointObject::getSession( )
+{
+ return dynamic_cast< SharePointSession* > ( m_session );
+}
+
+void SharePointObject::refreshImpl( Json json )
+{
+ m_typeDescription.reset( );
+ m_properties.clear( );
+ initializeFromJson( json );
+}
+
+void SharePointObject::refresh( )
+{
+ string res;
+ try
+ {
+ res = getSession( )->httpGetRequest( getId( ) )->getStream( )->str( );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json json = Json::parse( res );
+ refreshImpl( json );
+}
+
+void SharePointObject::remove( bool /*allVersions*/ )
+{
+ try
+ {
+ getSession( )->httpDeleteRequest( getId( ) );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+}
+
+vector< string> SharePointObject::getMultiStringProperty( const string& propertyName )
+{
+ vector< string > values;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( propertyName ) );
+ if ( it != getProperties( ).end( ) && it->second != NULL && !it->second->getStrings( ).empty( ) )
+ values = it->second->getStrings( );
+ return values;
+}
+
+libcmis::ObjectPtr SharePointObject::updateProperties(
+ const PropertyPtrMap& /*properties*/ )
+{
+ // there are no updateable properties so just return the same object
+ libcmis::ObjectPtr updated = getSession( )->getObject( getId( ) );
+ return updated;
+}
+
+void SharePointObject::move( FolderPtr /*source*/, FolderPtr destination )
+{
+ if ( !getStringProperty( "cmis:checkinComment" ).empty( ) )
+ {
+ // only documents can be moved and only documents have this property
+ string url = getId( ) + "/moveto(newurl='";
+ url += libcmis::escape( destination->getStringProperty( "ServerRelativeUrl" ) );
+ url += "/" + getStringProperty( "cmis:name" ) + "'";
+ // overwrite flag
+ url += ",flags=1)";
+ istringstream is( "" );
+ try
+ {
+ getSession( )->httpPostRequest( url, is, "" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ refresh( );
+ }
+}
diff --git a/src/libcmis/sharepoint-object.hxx b/src/libcmis/sharepoint-object.hxx
new file mode 100644
index 0000000..ace581b
--- /dev/null
+++ b/src/libcmis/sharepoint-object.hxx
@@ -0,0 +1,74 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SHAREPOINT_OBJECT_HXX_
+#define _SHAREPOINT_OBJECT_HXX_
+
+#include <libcmis/object.hxx>
+
+#include "sharepoint-session.hxx"
+#include "json-utils.hxx"
+
+// Class representing an object for SharePoint protocol.
+class SharePointObject : public virtual libcmis::Object
+{
+ public:
+ SharePointObject( SharePointSession* session );
+
+ // Create a SharePoint document from Json properties.
+ SharePointObject( SharePointSession* session, Json json,
+ std::string parentId = std::string( ),
+ std::string name = std::string( ) );
+ SharePointObject( const SharePointObject& copy );
+ virtual ~SharePointObject( ) { }
+
+ SharePointObject& operator=( const SharePointObject& copy );
+
+ void initializeFromJson( Json json, std::string parentId = std::string( ),
+ std::string name = std::string( ) );
+
+ void refreshImpl( Json json );
+ virtual void refresh( );
+ virtual void remove( bool allVersions = true );
+
+ std::vector< std::string > getMultiStringProperty(
+ const std::string& propertyName );
+
+ virtual boost::shared_ptr< Object > updateProperties(
+ const libcmis::PropertyPtrMap& properties );
+
+ virtual std::vector< libcmis::RenditionPtr> getRenditions( std::string /*filter = std::string( )*/ )
+ {return std::vector< libcmis::RenditionPtr>( );}
+
+ virtual void move( boost::shared_ptr< libcmis::Folder > source,
+ boost::shared_ptr< libcmis::Folder > destination );
+
+ protected:
+ SharePointSession* getSession( );
+
+};
+#endif
diff --git a/src/libcmis/sharepoint-property.cxx b/src/libcmis/sharepoint-property.cxx
new file mode 100644
index 0000000..dfca7fe
--- /dev/null
+++ b/src/libcmis/sharepoint-property.cxx
@@ -0,0 +1,79 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-property.hxx"
+
+#include <libcmis/property-type.hxx>
+
+#include "sharepoint-utils.hxx"
+
+using namespace std;
+using namespace libcmis;
+
+SharePointProperty::SharePointProperty( )
+{
+}
+
+SharePointProperty::~SharePointProperty( )
+{
+}
+
+SharePointProperty::SharePointProperty( const string& key, Json json ):
+ Property( )
+{
+ PropertyTypePtr propertyType( new PropertyType( ) );
+ string convertedKey = SharePointUtils::toCmisKey( key );
+ propertyType->setId( convertedKey );
+ propertyType->setLocalName( convertedKey );
+ propertyType->setLocalNamespace( convertedKey );
+ propertyType->setQueryName( convertedKey );
+ propertyType->setDisplayName( key );
+ propertyType->setTypeFromJsonType( json.getStrType( ) );
+ propertyType->setUpdatable( false );
+ propertyType->setMultiValued( false );
+ propertyType->setType( SharePointUtils::getPropertyType( convertedKey ) );
+
+ setPropertyType( propertyType );
+
+ vector< string > values = SharePointUtils::parseSharePointProperty( key, json );
+ setValues( values );
+}
+
+SharePointProperty::SharePointProperty( const SharePointProperty& copy ) :
+ libcmis::Property( copy )
+{
+}
+
+SharePointProperty& SharePointProperty::operator=( const SharePointProperty& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Property::operator=( copy );
+ }
+ return *this;
+}
diff --git a/src/libcmis/sharepoint-property.hxx b/src/libcmis/sharepoint-property.hxx
new file mode 100644
index 0000000..2649be4
--- /dev/null
+++ b/src/libcmis/sharepoint-property.hxx
@@ -0,0 +1,50 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#ifndef _SHAREPOINT_PROPERTY_HXX_
+#define _SHAREPOINT_PROPERTY_HXX_
+
+#include <libcmis/property.hxx>
+
+#include "json-utils.hxx"
+
+// reference: http://msdn.microsoft.com/en-us/library/hh243648.aspx
+class SharePointProperty : public libcmis::Property
+{
+ public :
+ // Create a SharePoint Property from a Json property with its key
+ SharePointProperty( const std::string& key, Json json);
+ ~SharePointProperty( );
+ SharePointProperty( const SharePointProperty& copy);
+ SharePointProperty& operator=( const SharePointProperty& copy );
+
+ private :
+ // Avoid calling default constructor
+ SharePointProperty( );
+};
+#endif
diff --git a/src/libcmis/sharepoint-repository.cxx b/src/libcmis/sharepoint-repository.cxx
new file mode 100644
index 0000000..f992689
--- /dev/null
+++ b/src/libcmis/sharepoint-repository.cxx
@@ -0,0 +1,65 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#include "sharepoint-repository.hxx"
+
+SharePointRepository::SharePointRepository( std::string baseUrl ) :
+ Repository( )
+{
+ m_id = "SharePoint";
+ m_name = "SharePoint";
+ m_description = "SharePoint repository";
+ m_productName = "SharePoint";
+ m_productVersion = "2010/2013";
+ // getFolderByServerRelativeUrl() API expects path to be
+ // *server-relative*, i.e. they must include site path.
+ // Given the baseUrl like "https://sp2013/sites/mysite/_api/Web"
+ // for a site "mysite" on sharepoint server "sp2013",
+ // the site root is '/sites/mysite/', not '/'.
+ // Trying to get folder '/' results in "Value does not fall
+ // within expected range" error.
+ // Preferrable here is to extract the root path from baseUrl,
+ // stripping server and api parts. But it can be unreliable
+ // if api part (_api/Web) is different for some server.
+ // On the other side, just querying empty path '' gives the root folder.
+ m_rootId = baseUrl + "/getFolderByServerRelativeUrl('')";
+
+ m_capabilities[ ACL ] = "discover";
+ m_capabilities[ AllVersionsSearchable ] = "true";
+ m_capabilities[ Changes ] = "all";
+ m_capabilities[ GetDescendants ] = "true";
+ m_capabilities[ GetFolderTree ] = "true";
+ m_capabilities[ OrderBy ] = "custom";
+ m_capabilities[ Multifiling ] = "true";
+ m_capabilities[ PWCSearchable ] = "true";
+ m_capabilities[ PWCUpdatable ] = "true";
+ m_capabilities[ Query ] = "bothcombined";
+ m_capabilities[ Renditions ] = "read";
+ m_capabilities[ Unfiling ] = "false";
+ m_capabilities[ VersionSpecificFiling ] = "false";
+ m_capabilities[ Join ] = "none";
+}
diff --git a/src/libcmis/sharepoint-repository.hxx b/src/libcmis/sharepoint-repository.hxx
new file mode 100644
index 0000000..abf60c8
--- /dev/null
+++ b/src/libcmis/sharepoint-repository.hxx
@@ -0,0 +1,39 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SHAREPOINT_REPOSITORY_HXX_
+#define _SHAREPOINT_REPOSITORY_HXX_
+
+#include <libcmis/repository.hxx>
+
+class SharePointRepository: public libcmis::Repository
+{
+ public:
+ SharePointRepository( std::string baseUrl );
+};
+
+#endif
diff --git a/src/libcmis/sharepoint-session.cxx b/src/libcmis/sharepoint-session.cxx
new file mode 100644
index 0000000..d33bae8
--- /dev/null
+++ b/src/libcmis/sharepoint-session.cxx
@@ -0,0 +1,424 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-session.hxx"
+
+#include <libcmis/session-factory.hxx>
+
+#include "sharepoint-document.hxx"
+#include "sharepoint-folder.hxx"
+#include "sharepoint-object.hxx"
+#include "sharepoint-object-type.hxx"
+#include "sharepoint-repository.hxx"
+#include "sharepoint-utils.hxx"
+
+using namespace std;
+
+SharePointSession::SharePointSession ( string baseUrl,
+ string username,
+ string password,
+ bool verbose ) :
+ BaseSession( baseUrl, string(), username, password, false,
+ libcmis::OAuth2DataPtr(), verbose ),
+ m_digestCode( string( ) )
+
+{
+ setAuthMethod( CURLAUTH_NTLM );
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ response = httpGetRequest( baseUrl + "/currentuser" );
+ }
+ catch ( const CurlException& e )
+ {
+ // It's not SharePoint or wrong username/passwd provided
+ throw e.getCmisException( );
+ }
+
+ // Add the dummy repository
+ m_repositories.push_back( getRepository( ) );
+ fetchDigestCode( );
+}
+
+SharePointSession::SharePointSession( string baseUrl,
+ const HttpSession& httpSession,
+ libcmis::HttpResponsePtr response ) :
+ BaseSession( baseUrl, string(), httpSession ),
+ m_digestCode( string( ) )
+{
+ if ( !SharePointUtils::isSharePoint( response->getStream( )->str( ) ) )
+ {
+ throw libcmis::Exception( "Not a SharePoint service" );
+ }
+ // Add the dummy repository
+ m_repositories.push_back( getRepository( ) );
+ fetchDigestCode( );
+}
+
+SharePointSession::SharePointSession() :
+ BaseSession(), m_digestCode( string( ) )
+{
+}
+
+SharePointSession::~SharePointSession()
+{
+}
+
+bool SharePointSession::setRepository( string )
+{
+ return true;
+}
+
+libcmis::RepositoryPtr SharePointSession::getRepository( )
+{
+ // Return a dummy repository since SharePoint doesn't have that notion
+ libcmis::RepositoryPtr repo( new SharePointRepository( getBindingUrl( ) ) );
+ return repo;
+}
+
+libcmis::ObjectPtr SharePointSession::getObject( string objectId )
+{
+ // objectId is uri for the file
+ string res;
+ try
+ {
+ res = httpGetRequest( objectId )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ Json jsonRes = Json::parse( res );
+ return getObjectFromJson( jsonRes );
+}
+
+libcmis::ObjectPtr SharePointSession::getObjectFromJson( Json& jsonRes, string parentId )
+{
+ libcmis::ObjectPtr object;
+ if ( !jsonRes["d"].toString( ).empty( ) ) {
+ jsonRes = jsonRes["d"];
+ }
+ string kind = jsonRes["__metadata"]["type"].toString( );
+ // only SharePointObject available for now
+ if ( kind == "SP.Folder" )
+ {
+ object.reset( new SharePointFolder( this, jsonRes, parentId ) );
+ }
+ else if ( kind == "SP.File" || kind == "SP.FileVersion" )
+ {
+ object.reset( new SharePointDocument( this, jsonRes, parentId ) );
+ }
+ else
+ {
+ object.reset( new SharePointObject( this, jsonRes, parentId ) );
+ }
+ return object;
+}
+
+libcmis::ObjectPtr SharePointSession::getObjectByPath( string path )
+{
+ libcmis::ObjectPtr object;
+ path = libcmis::escape( path );
+ // we don't know the object type so we try with Folder first
+ try
+ {
+ string folderUrl = getBindingUrl( ) + "/getFolderByServerRelativeUrl";
+ folderUrl += "('" + path + "')";
+ object = getObject( folderUrl );
+ }
+ catch ( const libcmis::Exception &e )
+ {
+ // it's not a Folder, maybe it's a File
+ string fileUrl = getBindingUrl( ) + "/getFileByServerRelativeUrl";
+ fileUrl += "('" + path + "')";
+ object = getObject( fileUrl );
+ }
+ return object;
+}
+
+libcmis::ObjectTypePtr SharePointSession::getType( string id )
+{
+ libcmis::ObjectTypePtr type( new SharePointObjectType( id ) );
+ return type;
+}
+
+vector< libcmis::ObjectTypePtr > SharePointSession::getBaseTypes( )
+{
+ vector< libcmis::ObjectTypePtr > types;
+ return types;
+}
+
+Json SharePointSession::getJsonFromUrl( string url )
+{
+ string response;
+ try
+ {
+ response = httpGetRequest( url )->getStream()->str();
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+ return Json::parse( response );
+}
+
+/* Overwriting HttpSession::httpRunRequest to add the "accept:application/json" header */
+void SharePointSession::httpRunRequest( string url, vector< string > headers, bool redirect )
+{
+ // Redirect
+ curl_easy_setopt( m_curlHandle, CURLOPT_FOLLOWLOCATION, redirect);
+
+ // Activate the cookie engine
+ curl_easy_setopt( m_curlHandle, CURLOPT_COOKIEFILE, "" );
+
+ // Grab something from the web
+ curl_easy_setopt( m_curlHandle, CURLOPT_URL, url.c_str() );
+
+ // Set the headers
+ struct curl_slist *headers_slist = NULL;
+ for ( vector< string >::iterator it = headers.begin( ); it != headers.end( ); ++it )
+ headers_slist = curl_slist_append( headers_slist, it->c_str( ) );
+
+ headers_slist = curl_slist_append( headers_slist, "accept:application/json; odata=verbose" );
+ headers_slist = curl_slist_append( headers_slist, ( "x-requestdigest:" + m_digestCode ).c_str( ) );
+
+ if ( !getUsername().empty() && !getPassword().empty() )
+ {
+ curl_easy_setopt( m_curlHandle, CURLOPT_HTTPAUTH, m_authMethod );
+#if LIBCURL_VERSION_VALUE >= 0x071301
+ curl_easy_setopt( m_curlHandle, CURLOPT_USERNAME, getUsername().c_str() );
+ curl_easy_setopt( m_curlHandle, CURLOPT_PASSWORD, getPassword().c_str() );
+#else
+ string userpwd = getUsername() + ":" + getPassword();
+ curl_easy_setopt( m_curlHandle, CURLOPT_USERPWD, userpwd.c_str( ) );
+#endif
+ }
+
+ curl_easy_setopt( m_curlHandle, CURLOPT_HTTPHEADER, headers_slist );
+
+ // Set the proxy configuration if any
+ if ( !libcmis::SessionFactory::getProxy( ).empty() )
+ {
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, libcmis::SessionFactory::getProxy( ).c_str() );
+#if LIBCURL_VERSION_VALUE >= 0x071304
+ curl_easy_setopt( m_curlHandle, CURLOPT_NOPROXY, libcmis::SessionFactory::getNoProxy( ).c_str() );
+#endif
+ const string& proxyUser = libcmis::SessionFactory::getProxyUser( );
+ const string& proxyPass = libcmis::SessionFactory::getProxyPass( );
+ if ( !proxyUser.empty( ) && !proxyPass.empty( ) )
+ {
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
+#if LIBCURL_VERSION_VALUE >= 0X071301
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERNAME, proxyUser.c_str( ) );
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYPASSWORD, proxyPass.c_str( ) );
+#else
+ string userpwd = proxyUser + ":" + proxyPass;
+ curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, userpwd.c_str( ) );
+#endif
+ }
+ }
+
+ // Get some feedback when something wrong happens
+ char errBuff[CURL_ERROR_SIZE];
+ errBuff[0] = 0;
+ curl_easy_setopt( m_curlHandle, CURLOPT_ERRORBUFFER, errBuff );
+
+ // We want to get the response even if there is an Http error
+ if ( !m_noHttpErrors )
+ curl_easy_setopt( m_curlHandle, CURLOPT_FAILONERROR, 1 );
+
+ if ( m_verbose )
+ curl_easy_setopt( m_curlHandle, CURLOPT_VERBOSE, 1 );
+
+ // We want to get the certificate infos in error cases
+#if LIBCURL_VERSION_VALUE >= 0X071301
+ curl_easy_setopt( m_curlHandle, CURLOPT_CERTINFO, 1 );
+#endif
+
+ if ( m_noSSLCheck )
+ {
+#if LIBCURL_VERSION_VALUE >= 0x070801
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+#if LIBCURL_VERSION_VALUE >= 0x070402
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYPEER, 0);
+#endif
+ }
+
+ // Perform the query
+ CURLcode errCode = curl_easy_perform( m_curlHandle );
+
+ // Free the headers list
+ curl_slist_free_all( headers_slist );
+
+ // Process the response
+ bool isHttpError = errCode == CURLE_HTTP_RETURNED_ERROR;
+ if ( CURLE_OK != errCode && !( m_noHttpErrors && isHttpError ) )
+ {
+ long httpError = 0;
+ curl_easy_getinfo( m_curlHandle, CURLINFO_RESPONSE_CODE, &httpError );
+
+ bool errorFixed = false;
+#if LIBCURL_VERSION_VALUE >= 0X071301
+ // If we had a bad certificate, then try to get more details
+ if ( CURLE_SSL_CACERT == errCode )
+ {
+ vector< string > certificates;
+
+ // We somehow need to rerun the request to get the certificate
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYHOST, 0);
+ curl_easy_setopt(m_curlHandle, CURLOPT_SSL_VERIFYPEER, 0);
+ errCode = curl_easy_perform( m_curlHandle );
+
+ union {
+ struct curl_slist *to_info;
+ struct curl_certinfo *to_certinfo;
+ } ptr;
+
+ ptr.to_info = NULL;
+
+ CURLcode res = curl_easy_getinfo(m_curlHandle, CURLINFO_CERTINFO, &ptr.to_info);
+
+ if ( !res && ptr.to_info )
+ {
+ // We need the first certificate in the chain only
+ if ( ptr.to_certinfo->num_of_certs > 0 )
+ {
+ struct curl_slist *slist;
+
+ string certStart( "Cert:" );
+ for ( slist = ptr.to_certinfo->certinfo[0]; slist; slist = slist->next )
+ {
+ string data( slist->data );
+ size_t startPos = data.find( certStart );
+ if ( startPos == 0 )
+ {
+ startPos = certStart.length();
+ data = data.substr( startPos );
+ certificates.push_back( data );
+ }
+ }
+ }
+ }
+
+ if ( !certificates.empty() )
+ {
+ libcmis::CertValidationHandlerPtr validationHandler =
+ libcmis::SessionFactory::getCertificateValidationHandler( );
+ bool ignoreCert = validationHandler && validationHandler->validateCertificate( certificates );
+ if ( ignoreCert )
+ {
+ m_noSSLCheck = true;
+
+ isHttpError = errCode == CURLE_HTTP_RETURNED_ERROR;
+ errorFixed = ( CURLE_OK == errCode || ( m_noHttpErrors && isHttpError ) );
+ if ( !errorFixed )
+ curl_easy_getinfo( m_curlHandle, CURLINFO_RESPONSE_CODE, &httpError );
+ }
+ else
+ {
+ throw CurlException( "Invalid SSL certificate" );
+ }
+ }
+ }
+#endif
+
+ if ( !errorFixed )
+ throw CurlException( string( errBuff ), errCode, url, httpError );
+ }
+}
+
+libcmis::HttpResponsePtr SharePointSession::httpPutRequest( std::string url,
+ std::istream& is,
+ std::vector< std::string > headers )
+{
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ response = HttpSession::httpPutRequest( url, is, headers );
+ }
+ catch ( const CurlException& e )
+ {
+ fetchDigestCodeCurl( );
+ response = HttpSession::httpPutRequest( url, is, headers );
+ }
+ return response;
+}
+
+libcmis::HttpResponsePtr SharePointSession::httpPostRequest( const std::string& url,
+ std::istream& is,
+ const std::string& contentType,
+ bool redirect )
+{
+ libcmis::HttpResponsePtr response;
+ try
+ {
+ response = HttpSession::httpPostRequest( url, is, contentType, redirect );
+ }
+ catch ( const CurlException& e )
+ {
+ fetchDigestCodeCurl( );
+ response = HttpSession::httpPostRequest( url, is, contentType, redirect );
+ }
+ return response;
+}
+
+void SharePointSession::httpDeleteRequest( std::string url )
+{
+ try
+ {
+ HttpSession::httpDeleteRequest( url );
+ }
+ catch ( const CurlException& e )
+ {
+ fetchDigestCodeCurl( );
+ HttpSession::httpDeleteRequest( url );
+ }
+}
+
+void SharePointSession::fetchDigestCode( )
+try
+{
+ fetchDigestCodeCurl( );
+}
+catch ( const CurlException& e )
+{
+ throw e.getCmisException( );
+}
+
+void SharePointSession::fetchDigestCodeCurl( )
+{
+ istringstream is( "empty" );
+ libcmis::HttpResponsePtr response;
+ // url = http://host/_api/contextinfo, first we remove the '/web' part
+ string url = m_bindingUrl.substr( 0, m_bindingUrl.size( ) - 4 ) + "/contextinfo";
+ response = HttpSession::httpPostRequest( url, is, "" );
+ string res = response->getStream( )->str( );
+ Json jsonRes = Json::parse( res );
+ m_digestCode = jsonRes["d"]["GetContextWebInformation"]["FormDigestValue"].toString( );
+}
diff --git a/src/libcmis/sharepoint-session.hxx b/src/libcmis/sharepoint-session.hxx
new file mode 100644
index 0000000..2d47cb9
--- /dev/null
+++ b/src/libcmis/sharepoint-session.hxx
@@ -0,0 +1,91 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SHAREPOINT_SESSION_HXX_
+#define _SHAREPOINT_SESSION_HXX_
+
+#include <libcmis/repository.hxx>
+
+#include "base-session.hxx"
+#include "json-utils.hxx"
+
+class SharePointSession : public BaseSession
+{
+ public:
+ SharePointSession( std::string baseUrl,
+ std::string username,
+ std::string password,
+ bool verbose = false );
+
+ SharePointSession( std::string baseUrl,
+ const HttpSession& httpSession,
+ libcmis::HttpResponsePtr response );
+
+ ~SharePointSession ( );
+
+ virtual libcmis::RepositoryPtr getRepository( );
+
+ virtual bool setRepository( std::string );
+
+ virtual libcmis::ObjectPtr getObject( std::string id );
+
+ virtual libcmis::ObjectPtr getObjectByPath( std::string path );
+
+ virtual libcmis::ObjectTypePtr getType( std::string id );
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
+ libcmis::ObjectPtr getObjectFromJson( Json& jsonRes,
+ std::string parentId = std::string( ) );
+
+ Json getJsonFromUrl( std::string url );
+
+ void fetchDigestCode( );
+
+ void httpRunRequest( std::string url,
+ std::vector< std::string > headers,
+ bool redirect );
+
+ libcmis::HttpResponsePtr httpPutRequest( std::string url,
+ std::istream& is,
+ std::vector< std::string > headers );
+ libcmis::HttpResponsePtr httpPostRequest( const std::string& url,
+ std::istream& is,
+ const std::string& contentType,
+ bool redirect = true );
+ void httpDeleteRequest( std::string url );
+
+
+ private:
+ SharePointSession( );
+ SharePointSession( const SharePointSession& copy ) = delete;
+ SharePointSession& operator=( const SharePointSession& copy ) = delete;
+ void fetchDigestCodeCurl( );
+ std::string m_digestCode;
+};
+
+#endif /* _SHAREPONT_SESSION_HXX_ */
diff --git a/src/libcmis/sharepoint-utils.cxx b/src/libcmis/sharepoint-utils.cxx
new file mode 100644
index 0000000..35a9f87
--- /dev/null
+++ b/src/libcmis/sharepoint-utils.cxx
@@ -0,0 +1,133 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "sharepoint-utils.hxx"
+
+#include <boost/shared_ptr.hpp>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "json-utils.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+string SharePointUtils::toCmisKey( const string& key )
+{
+ string convertedKey;
+ if ( key == "__metadata")
+ convertedKey = "cmis:objectId";
+ else if ( key == "CheckInComment" )
+ convertedKey = "cmis:checkinComment";
+ else if ( key == "TimeCreated" )
+ convertedKey = "cmis:creationDate";
+ else if ( key == "TimeLastModified" ||
+ key == "Created" )
+ convertedKey = "cmis:lastModificationDate";
+ else if ( key == "Name" )
+ convertedKey = "cmis:name";
+ else if ( key == "CheckOutType" )
+ convertedKey = "cmis:isVersionSeriesCheckedOut";
+ else if ( key == "UIVersionLabel" ||
+ key == "VersionLabel" )
+ convertedKey = "cmis:versionLabel";
+ else if ( key == "Length" ||
+ key == "Size" )
+ convertedKey = "cmis:contentStreamLength";
+ else convertedKey = key;
+ return convertedKey;
+}
+
+libcmis::PropertyType::Type SharePointUtils::getPropertyType( const string& key )
+{
+ libcmis::PropertyType::Type propertyType;
+ if ( key == "cmis:creationDate" ||
+ key == "cmis:lastModificationDate" )
+ {
+ propertyType = libcmis::PropertyType::DateTime;
+ }
+ else if ( key == "cmis:contentStreamLength" )
+ {
+ propertyType = libcmis::PropertyType::Integer;
+ }
+ else if ( key == "cmis:isVersionSeriesCheckedOut" )
+ {
+ propertyType = libcmis::PropertyType::Bool;
+ }
+ else
+ {
+ propertyType = libcmis::PropertyType::String;
+ }
+ return propertyType;
+}
+
+vector< string > SharePointUtils::parseSharePointProperty( string key, Json json )
+{
+ vector< string > values;
+ if ( key == "__metadata" )
+ {
+ string id = json["uri"].toString( );
+ values.push_back( id );
+ }
+ if ( key == "Author" ||
+ key == "CheckedOutByUser" ||
+ key == "CreatedBy" ||
+ key == "Files" ||
+ key == "Folders" ||
+ key == "ListItemAllFields" ||
+ key == "LockedByUser" ||
+ key == "ModifiedBy" ||
+ key == "ParentFolder" ||
+ key == "Properties" ||
+ key == "Versions" )
+ {
+ string propertyUri = json["__deferred"]["uri"].toString( );
+ values.push_back( propertyUri );
+ }
+ if ( key == "CheckOutType" )
+ {
+ // Online = 0, Offline = 1, None = 2
+ if ( json.toString( ) == "2" )
+ {
+ values.push_back( "false" );
+ }
+ else
+ {
+ values.push_back( "true" );
+ }
+ }
+ else values.push_back( json.toString( ) );
+ return values;
+}
+
+bool SharePointUtils::isSharePoint( string response )
+{
+ const boost::shared_ptr< xmlDoc > doc( xmlReadMemory( response.c_str( ), response.size( ), "noname.xml", NULL, 0 ), xmlFreeDoc );
+ const boost::shared_ptr< xmlXPathContext > xpath( xmlXPathNewContext( doc.get() ), xmlXPathFreeContext );
+ return "SP.Web" == libcmis::getXPathValue( xpath.get(), "//@term" );
+}
diff --git a/src/libcmis/sharepoint-utils.hxx b/src/libcmis/sharepoint-utils.hxx
new file mode 100644
index 0000000..80a5e51
--- /dev/null
+++ b/src/libcmis/sharepoint-utils.hxx
@@ -0,0 +1,54 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2014 Mihai Varga <mihai.mv13@gmail.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _SHAREPOINT_UTILS_HXX_
+#define _SHAREPOINT_UTILS_HXX_
+
+#include <string>
+
+#include <libcmis/property.hxx>
+
+#include "json-utils.hxx"
+
+class SharePointUtils
+{
+ public :
+
+ // Convert a SharePoint Property key to a CMIS key
+ static std::string toCmisKey( const std::string& key);
+
+ // Returns the property type (String/Bool/Integer etc )
+ static libcmis::PropertyType::Type getPropertyType( const std::string& key );
+
+ // Parse a SharePoint property value to CMIS values
+ static std::vector< std::string > parseSharePointProperty( std::string key, Json jsonValue );
+
+ // Checks if a response came from a SharePoint service
+ static bool isSharePoint( std::string response );
+};
+
+#endif
diff --git a/src/libcmis/ws-document.cxx b/src/libcmis/ws-document.cxx
new file mode 100644
index 0000000..ba2f2bc
--- /dev/null
+++ b/src/libcmis/ws-document.cxx
@@ -0,0 +1,135 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-document.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+WSDocument::WSDocument( const WSObject& object ) :
+ libcmis::Object( object ),
+ libcmis::Document( const_cast< WSObject& >( object ).getSession( ) ),
+ WSObject( object )
+{
+}
+
+WSDocument::~WSDocument( )
+{
+}
+
+vector< libcmis::FolderPtr > WSDocument::getParents( )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getNavigationService( ).getObjectParents( repoId, getId( ) );
+}
+
+boost::shared_ptr< istream > WSDocument::getContentStream( std::string /* streamId */ )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getObjectService( ).getContentStream( repoId, getId( ) );
+}
+
+void WSDocument::setContentStream( boost::shared_ptr< ostream > os, string contentType,
+ string fileName, bool overwrite )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ getSession( )->getObjectService( ).setContentStream( repoId, getId( ),
+ overwrite, getChangeToken( ), os, contentType, fileName );
+
+ refresh( );
+}
+
+libcmis::DocumentPtr WSDocument::checkOut( )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getVersioningService( ).checkOut( repoId, getId( ) );
+}
+
+void WSDocument::cancelCheckout( )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ getSession( )->getVersioningService( ).cancelCheckOut( repoId, getId( ) );
+}
+
+libcmis::DocumentPtr WSDocument::checkIn( bool isMajor, string comment,
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > stream,
+ string contentType, string fileName )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ libcmis::DocumentPtr newVersion;
+
+ // Try the normal request first, but if we have a server error, we may want to resend it
+ // without the stream as SharePoint wants no stream in the request, but gets the one from
+ // the PWC see the following discussion:
+ // http://social.technet.microsoft.com/Forums/eu/sharepoint2010programming/thread/b30e4d82-5b7e-4ceb-b9ad-c6f0d4c59d11
+ bool tryNoStream = false;
+ try
+ {
+ newVersion = getSession( )->getVersioningService( ).checkIn( repoId, getId( ),
+ isMajor, properties, stream, contentType, fileName, comment );
+ }
+ catch ( const libcmis::Exception& e )
+ {
+ string spError( "Object reference not set to an instance of an object" );
+ if ( string( e.what( ) ).find( spError ) != string::npos )
+ tryNoStream = true;
+ else
+ throw;
+ }
+
+ if ( tryNoStream )
+ {
+ // Set the content stream first
+ setContentStream( stream, contentType, fileName );
+
+ // Then check-in
+ boost::shared_ptr< ostream > nostream;
+ newVersion = getSession( )->getVersioningService( ).checkIn( repoId, getId( ),
+ isMajor, properties, nostream, string( ), string( ), comment );
+ }
+
+ if ( newVersion->getId( ) == getId( ) )
+ refresh( );
+
+ return newVersion;
+}
+
+vector< libcmis::DocumentPtr > WSDocument::getAllVersions( )
+{
+ vector< libcmis::DocumentPtr > versions;
+ string repoId = getSession( )->getRepositoryId( );
+ string versionSeries;
+ PropertyPtrMap::const_iterator it = getProperties( ).find( string( "cmis:versionSeriesId" ) );
+ if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) )
+ {
+ versionSeries = it->second->getStrings( ).front( );
+ versions = getSession( )->getVersioningService( ).getAllVersions( repoId, versionSeries );
+ }
+ return versions;
+}
diff --git a/src/libcmis/ws-document.hxx b/src/libcmis/ws-document.hxx
new file mode 100644
index 0000000..c569496
--- /dev/null
+++ b/src/libcmis/ws-document.hxx
@@ -0,0 +1,60 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_DOCUMENT_HXX_
+#define _WS_DOCUMENT_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "ws-object.hxx"
+
+class WSDocument : public libcmis::Document, public WSObject
+{
+ public:
+ WSDocument( const WSObject& object );
+ virtual ~WSDocument( );
+
+ virtual std::vector< libcmis::FolderPtr > getParents( );
+
+ virtual boost::shared_ptr< std::istream > getContentStream( std::string streamId = std::string( ) );
+
+ virtual void setContentStream( boost::shared_ptr< std::ostream > os, std::string contentType,
+ std::string fileName, bool overwrite = true );
+
+ virtual libcmis::DocumentPtr checkOut( );
+ virtual void cancelCheckout( );
+
+ virtual libcmis::DocumentPtr checkIn( bool isMajor, std::string comment,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType, std::string fileName );
+
+ virtual std::vector< libcmis::DocumentPtr > getAllVersions( );
+};
+
+#endif
diff --git a/src/libcmis/ws-folder.cxx b/src/libcmis/ws-folder.cxx
new file mode 100644
index 0000000..4e82ac2
--- /dev/null
+++ b/src/libcmis/ws-folder.cxx
@@ -0,0 +1,68 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-folder.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+WSFolder::WSFolder( const WSObject& object ) :
+ libcmis::Object( object ),
+ libcmis::Folder( const_cast< WSObject& >( object ).getSession( ) ),
+ WSObject( object )
+{
+}
+
+WSFolder::~WSFolder( )
+{
+}
+
+vector< libcmis::ObjectPtr > WSFolder::getChildren( )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getNavigationService( ).getChildren( repoId, getId( ) );
+}
+
+libcmis::FolderPtr WSFolder::createFolder( const PropertyPtrMap& properties )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getObjectService( ).createFolder( repoId, properties, getId( ) );
+}
+
+libcmis::DocumentPtr WSFolder::createDocument( const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > os, string contentType, string fileName )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getObjectService( ).createDocument( repoId, properties, getId( ), os, contentType, fileName );
+}
+
+vector< string > WSFolder::removeTree( bool allVersion, libcmis::UnfileObjects::Type unfile, bool continueOnError )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getObjectService( ).deleteTree( repoId, getId( ), allVersion, unfile, continueOnError );
+}
diff --git a/src/libcmis/ws-folder.hxx b/src/libcmis/ws-folder.hxx
new file mode 100644
index 0000000..2653967
--- /dev/null
+++ b/src/libcmis/ws-folder.hxx
@@ -0,0 +1,54 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_FOLDER_HXX_
+#define _WS_FOLDER_HXX_
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+
+#include "ws-object.hxx"
+#include "ws-session.hxx"
+
+class WSFolder : public libcmis::Folder, public WSObject
+{
+ public:
+ WSFolder( const WSObject& object );
+ virtual ~WSFolder( );
+
+ // virtual pure methods from Folder
+ virtual std::vector< libcmis::ObjectPtr > getChildren( );
+
+ virtual libcmis::FolderPtr createFolder( const std::map< std::string, libcmis::PropertyPtr >& properties );
+ virtual libcmis::DocumentPtr createDocument( const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > os, std::string contentType, std::string fileName );
+
+ virtual std::vector< std::string > removeTree( bool allVersion = true, libcmis::UnfileObjects::Type unfile = libcmis::UnfileObjects::Delete,
+ bool continueOnError = false );
+};
+
+#endif
diff --git a/src/libcmis/ws-navigationservice.cxx b/src/libcmis/ws-navigationservice.cxx
new file mode 100644
index 0000000..f3d18ec
--- /dev/null
+++ b/src/libcmis/ws-navigationservice.cxx
@@ -0,0 +1,101 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-navigationservice.hxx"
+
+#include "ws-requests.hxx"
+#include "ws-session.hxx"
+
+using namespace std;
+
+NavigationService::NavigationService( ) :
+ m_session( NULL ),
+ m_url( "" )
+{
+}
+
+NavigationService::NavigationService( WSSession* session ) :
+ m_session( session ),
+ m_url( session->getServiceUrl( "NavigationService" ) )
+{
+}
+
+NavigationService::NavigationService( const NavigationService& copy ) :
+ m_session( copy.m_session ),
+ m_url( copy.m_url )
+{
+}
+
+NavigationService::~NavigationService( )
+{
+}
+
+NavigationService& NavigationService::operator=( const NavigationService& copy )
+{
+ if ( this != &copy )
+ {
+ m_session = copy.m_session;
+ m_url = copy.m_url;
+ }
+
+ return *this;
+}
+
+vector< libcmis::FolderPtr > NavigationService::getObjectParents( std::string repoId, std::string objectId )
+{
+ vector< libcmis::FolderPtr > parents;
+
+ GetObjectParentsRequest request( repoId, objectId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetObjectParentsResponse* response = dynamic_cast< GetObjectParentsResponse* >( resp );
+ if ( response != NULL )
+ parents = response->getParents( );
+ }
+
+ return parents;
+}
+
+vector< libcmis::ObjectPtr > NavigationService::getChildren( string repoId, string folderId )
+{
+ vector< libcmis::ObjectPtr > children;
+
+ GetChildrenRequest request( repoId, folderId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetChildrenResponse* response = dynamic_cast< GetChildrenResponse* >( resp );
+ if ( response != NULL )
+ children = response->getChildren( );
+ }
+
+ return children;
+}
diff --git a/src/libcmis/ws-navigationservice.hxx b/src/libcmis/ws-navigationservice.hxx
new file mode 100644
index 0000000..c245bbc
--- /dev/null
+++ b/src/libcmis/ws-navigationservice.hxx
@@ -0,0 +1,60 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_NAVIGATIONSERVICE_HXX_
+#define _WS_NAVIGATIONSERVICE_HXX_
+
+#include <string>
+#include <vector>
+
+#include <libcmis/folder.hxx>
+
+class WSSession;
+
+class NavigationService
+{
+ private:
+ WSSession* m_session;
+ std::string m_url;
+
+ public:
+
+ NavigationService( WSSession* session );
+ NavigationService( const NavigationService& copy );
+ ~NavigationService( );
+
+ NavigationService& operator=( const NavigationService& copy );
+
+ std::vector< libcmis::FolderPtr > getObjectParents( std::string repoId, std::string objectId );
+ std::vector< libcmis::ObjectPtr > getChildren( std::string repoId, std::string folderId );
+
+ private:
+
+ NavigationService( );
+};
+
+#endif
diff --git a/src/libcmis/ws-object-type.cxx b/src/libcmis/ws-object-type.cxx
new file mode 100644
index 0000000..9275da9
--- /dev/null
+++ b/src/libcmis/ws-object-type.cxx
@@ -0,0 +1,90 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-object-type.hxx"
+
+using namespace std;
+
+WSObjectType::WSObjectType( WSSession* session, xmlNodePtr node ) :
+ libcmis::ObjectType( node ),
+ m_session( session )
+{
+}
+
+WSObjectType::WSObjectType( ) :
+ libcmis::ObjectType( ),
+ m_session( NULL )
+{
+}
+
+WSObjectType::WSObjectType( const WSObjectType& copy ) :
+ libcmis::ObjectType( copy ),
+ m_session( copy.m_session )
+{
+}
+
+WSObjectType::~WSObjectType( )
+{
+}
+
+WSObjectType& WSObjectType::operator=( const WSObjectType& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::ObjectType::operator=( copy );
+ m_session = copy.m_session;
+ }
+
+ return *this;
+}
+
+void WSObjectType::refresh( )
+{
+ libcmis::ObjectTypePtr type = m_session->getType( m_id );
+ WSObjectType* const other = dynamic_cast< WSObjectType* >( type.get( ) );
+ if ( other != NULL )
+ *this = *other;
+}
+
+libcmis::ObjectTypePtr WSObjectType::getParentType( )
+{
+ return m_session->getType( m_parentTypeId );
+}
+
+libcmis::ObjectTypePtr WSObjectType::getBaseType( )
+{
+ return m_session->getType( m_baseTypeId );
+}
+
+vector< libcmis::ObjectTypePtr > WSObjectType::getChildren( )
+{
+ vector< libcmis::ObjectTypePtr > children;
+ children = m_session->getRepositoryService( ).getTypeChildren(
+ m_session->getRepositoryId( ), m_id );
+ return children;
+}
diff --git a/src/libcmis/ws-object-type.hxx b/src/libcmis/ws-object-type.hxx
new file mode 100644
index 0000000..1fcf18d
--- /dev/null
+++ b/src/libcmis/ws-object-type.hxx
@@ -0,0 +1,57 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_OBJECT_TYPE_HXX_
+#define _WS_OBJECT_TYPE_HXX_
+
+#include <libcmis/object-type.hxx>
+
+#include "ws-session.hxx"
+
+class WSObjectType : public libcmis::ObjectType
+{
+ private:
+ WSSession* m_session;
+
+ public:
+ WSObjectType( WSSession* session, xmlNodePtr node );
+ WSObjectType( const WSObjectType& copy );
+ virtual ~WSObjectType( );
+
+ WSObjectType& operator=( const WSObjectType& copy );
+
+ virtual void refresh( );
+
+ virtual libcmis::ObjectTypePtr getParentType( );
+ virtual libcmis::ObjectTypePtr getBaseType( );
+ virtual std::vector< libcmis::ObjectTypePtr > getChildren( );
+
+ private:
+ WSObjectType( );
+};
+
+#endif
diff --git a/src/libcmis/ws-object.cxx b/src/libcmis/ws-object.cxx
new file mode 100644
index 0000000..65a238d
--- /dev/null
+++ b/src/libcmis/ws-object.cxx
@@ -0,0 +1,130 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-object.hxx"
+
+#include "ws-document.hxx"
+#include "ws-folder.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+WSObject::WSObject( WSSession* session ) :
+ libcmis::Object( session )
+{
+}
+
+
+WSObject::WSObject( WSSession* session, xmlNodePtr node ) :
+ libcmis::Object( session, node )
+{
+}
+
+WSObject::WSObject( const WSObject& copy ) :
+ libcmis::Object( copy )
+{
+}
+
+WSObject::~WSObject( )
+{
+}
+
+WSObject& WSObject::operator=( const WSObject& copy )
+{
+ if ( this != &copy )
+ {
+ libcmis::Object::operator=( copy );
+ }
+
+ return *this;
+}
+
+vector< libcmis::RenditionPtr > WSObject::getRenditions( string filter )
+{
+ // Check that the server supports that optional feature. There is no need to check it
+ // when getting the object as we may get them by shear luck
+ libcmis::RepositoryPtr repo = getSession( )->getRepository( );
+ bool isCapable = repo && repo->getCapability( libcmis::Repository::Renditions ) == "read";
+
+ if ( m_renditions.empty() && isCapable )
+ {
+ string repoId = getSession( )->getRepositoryId( );
+ m_renditions = getSession( )->getObjectService( ).getRenditions( repoId, this->getId( ), filter );
+ }
+ return m_renditions;
+}
+
+libcmis::ObjectPtr WSObject::updateProperties(
+ const PropertyPtrMap& properties )
+{
+ // No need to send HTTP request if there is nothing to update
+ if ( properties.empty( ) )
+ {
+ libcmis::ObjectPtr object;
+ if ( getBaseType( ) == "cmis:document" )
+ {
+ const WSDocument& thisDoc = dynamic_cast< const WSDocument& >( *this );
+ object.reset( new WSDocument( thisDoc ) );
+ }
+ else if ( getBaseType( ) == "cmis:folder" )
+ {
+ const WSFolder& thisFolder = dynamic_cast< const WSFolder& >( *this );
+ object.reset( new WSFolder( thisFolder ) );
+ }
+ return object;
+ }
+ string repoId = getSession( )->getRepositoryId( );
+ return getSession( )->getObjectService( ).updateProperties( repoId, this->getId( ), properties, this->getChangeToken( ) );
+}
+
+void WSObject::refresh( )
+{
+ libcmis::ObjectPtr object = m_session->getObject( getId( ) );
+ WSObject* const other = dynamic_cast< WSObject* >( object.get( ) );
+ if ( other != NULL )
+ *this = *other;
+}
+
+void WSObject::remove( bool allVersions )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ getSession( )->getObjectService( ).deleteObject( repoId, this->getId( ), allVersions );
+}
+
+void WSObject::move( libcmis::FolderPtr source, libcmis::FolderPtr destination )
+{
+ string repoId = getSession( )->getRepositoryId( );
+ getSession( )->getObjectService( ).move( repoId, getId( ), destination->getId( ), source->getId( ) );
+
+ refresh( );
+}
+
+WSSession* WSObject::getSession( )
+{
+ return dynamic_cast< WSSession* >( m_session );
+}
diff --git a/src/libcmis/ws-object.hxx b/src/libcmis/ws-object.hxx
new file mode 100644
index 0000000..f657371
--- /dev/null
+++ b/src/libcmis/ws-object.hxx
@@ -0,0 +1,61 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_OBJECT_HXX_
+#define _WS_OBJECT_HXX_
+
+#include <libcmis/folder.hxx>
+#include <libcmis/object.hxx>
+
+#include "ws-session.hxx"
+
+class WSObject : public virtual libcmis::Object
+{
+ protected:
+ WSObject( WSSession* session );
+
+ public:
+ WSObject( WSSession* session, xmlNodePtr node );
+ WSObject( const WSObject& copy );
+ virtual ~WSObject( );
+
+ WSObject& operator=( const WSObject& copy );
+
+ virtual std::vector< libcmis::RenditionPtr > getRenditions( std::string filter );
+ virtual libcmis::ObjectPtr updateProperties(
+ const std::map< std::string, libcmis::PropertyPtr >& properties );
+
+ virtual void refresh( );
+
+ virtual void remove( bool allVersions = true );
+
+ virtual void move( libcmis::FolderPtr source, libcmis::FolderPtr destination );
+
+ WSSession* getSession( );
+};
+
+#endif
diff --git a/src/libcmis/ws-objectservice.cxx b/src/libcmis/ws-objectservice.cxx
new file mode 100644
index 0000000..871349c
--- /dev/null
+++ b/src/libcmis/ws-objectservice.cxx
@@ -0,0 +1,242 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-objectservice.hxx"
+
+#include "ws-requests.hxx"
+#include "ws-session.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+ObjectService::ObjectService( ) :
+ m_session( NULL ),
+ m_url( "" )
+{
+}
+
+ObjectService::ObjectService( WSSession* session ) :
+ m_session( session ),
+ m_url( session->getServiceUrl( "ObjectService" ) )
+{
+}
+
+ObjectService::ObjectService( const ObjectService& copy ) :
+ m_session( copy.m_session ),
+ m_url( copy.m_url )
+{
+}
+
+ObjectService::~ObjectService( )
+{
+}
+
+ObjectService& ObjectService::operator=( const ObjectService& copy )
+{
+ if ( this != &copy )
+ {
+ m_session = copy.m_session;
+ m_url = copy.m_url;
+ }
+
+ return *this;
+}
+
+libcmis::ObjectPtr ObjectService::getObject( string repoId, string id )
+{
+ libcmis::ObjectPtr object;
+
+ GetObjectRequest request( repoId, id );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetObjectResponse* response = dynamic_cast< GetObjectResponse* >( resp );
+ if ( response != NULL )
+ object = response->getObject( );
+ }
+
+ return object;
+}
+
+libcmis::ObjectPtr ObjectService::getObjectByPath( string repoId, string path )
+{
+ libcmis::ObjectPtr object;
+
+ GetObjectByPathRequest request( repoId, path );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetObjectResponse* response = dynamic_cast< GetObjectResponse* >( resp );
+ if ( response != NULL )
+ object = response->getObject( );
+ }
+
+ return object;
+}
+
+vector< libcmis::RenditionPtr > ObjectService::getRenditions(
+ string repoId, string objectId, string filter )
+{
+ vector< libcmis::RenditionPtr > renditions;
+
+ GetRenditionsRequest request( repoId, objectId, filter );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetRenditionsResponse* response = dynamic_cast< GetRenditionsResponse* >( resp );
+ if ( response != NULL )
+ {
+ renditions = response->getRenditions( );
+ }
+ }
+
+ return renditions;
+}
+
+libcmis::ObjectPtr ObjectService::updateProperties(
+ string repoId, string objectId,
+ const PropertyPtrMap& properties,
+ string changeToken )
+{
+ libcmis::ObjectPtr object;
+
+ UpdatePropertiesRequest request( repoId, objectId, properties, changeToken );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ UpdatePropertiesResponse* response = dynamic_cast< UpdatePropertiesResponse* >( resp );
+ if ( response != NULL )
+ {
+ string id = response->getObjectId( );
+ object = getObject( repoId, id );
+ }
+ }
+
+ return object;
+}
+
+void ObjectService::deleteObject( string repoId, string id, bool allVersions )
+{
+ DeleteObjectRequest request( repoId, id, allVersions );
+ m_session->soapRequest( m_url, request );
+}
+
+vector< string > ObjectService::deleteTree( std::string repoId, std::string folderId, bool allVersions,
+ libcmis::UnfileObjects::Type unfile, bool continueOnFailure )
+{
+ vector< string > failedIds;
+
+ DeleteTreeRequest request( repoId, folderId, allVersions, unfile, continueOnFailure );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ DeleteTreeResponse* response = dynamic_cast< DeleteTreeResponse* >( resp );
+ if ( response != NULL )
+ failedIds = response->getFailedIds( );
+ }
+
+ return failedIds;
+}
+
+void ObjectService::move( string repoId, string objectId, string destId, string srcId )
+{
+ MoveObjectRequest request( repoId, objectId, destId, srcId );
+ m_session->soapRequest( m_url, request );
+}
+
+boost::shared_ptr< istream > ObjectService::getContentStream( string repoId, string objectId )
+{
+ boost::shared_ptr< istream > stream;
+
+ GetContentStreamRequest request( repoId, objectId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetContentStreamResponse* response = dynamic_cast< GetContentStreamResponse* >( resp );
+ if ( response != NULL )
+ stream = response->getStream( );
+ }
+
+ return stream;
+}
+
+void ObjectService::setContentStream( std::string repoId, std::string objectId, bool overwrite, std::string changeToken,
+ boost::shared_ptr< std::ostream > stream, std::string contentType, std::string fileName )
+{
+ SetContentStreamRequest request( repoId, objectId, overwrite, changeToken, stream, contentType, fileName );
+ m_session->soapRequest( m_url, request );
+}
+
+libcmis::FolderPtr ObjectService::createFolder( string repoId, const PropertyPtrMap& properties,
+ string folderId )
+{
+ libcmis::FolderPtr folder;
+
+ CreateFolderRequest request( repoId, properties, folderId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ CreateFolderResponse* response = dynamic_cast< CreateFolderResponse* >( resp );
+ if ( response != NULL )
+ {
+ string id = response->getObjectId( );
+ folder = m_session->getFolder( id );
+ }
+ }
+
+ return folder;
+}
+
+libcmis::DocumentPtr ObjectService::createDocument( string repoId, const PropertyPtrMap& properties,
+ string folderId, boost::shared_ptr< ostream > stream, string contentType, string fileName )
+{
+ libcmis::DocumentPtr document;
+
+ CreateDocumentRequest request( repoId, properties, folderId, stream, contentType, fileName );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ CreateFolderResponse* response = dynamic_cast< CreateFolderResponse* >( resp );
+ if ( response != NULL )
+ {
+ string id = response->getObjectId( );
+ libcmis::ObjectPtr object = m_session->getObject( id );
+ document = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ }
+ }
+
+ return document;
+}
diff --git a/src/libcmis/ws-objectservice.hxx b/src/libcmis/ws-objectservice.hxx
new file mode 100644
index 0000000..877deb7
--- /dev/null
+++ b/src/libcmis/ws-objectservice.hxx
@@ -0,0 +1,95 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_OBJECTSERVICE_HXX_
+#define _WS_OBJECTSERVICE_HXX_
+
+#include <istream>
+#include <string>
+#include <vector>
+
+#include <libcmis/document.hxx>
+#include <libcmis/folder.hxx>
+#include <libcmis/object.hxx>
+
+#include "base-session.hxx"
+#include "ws-soap.hxx"
+
+class WSSession;
+
+class ObjectService
+{
+ private:
+ WSSession* m_session;
+ std::string m_url;
+
+ public:
+
+ ObjectService( WSSession* session );
+ ObjectService( const ObjectService& copy );
+ ~ObjectService( );
+
+ ObjectService& operator=( const ObjectService& copy );
+
+ libcmis::ObjectPtr getObject( std::string repoId, std::string id );
+
+ libcmis::ObjectPtr getObjectByPath( std::string repoId, std::string path );
+
+ std::vector< libcmis::RenditionPtr > getRenditions(
+ std::string repoId, std::string objectId, std::string filter );
+
+ libcmis::ObjectPtr updateProperties(
+ std::string repoId,
+ std::string objectId,
+ const std::map< std::string, libcmis::PropertyPtr > & properties,
+ std::string changeToken );
+
+ void deleteObject( std::string repoId, std::string id, bool allVersions );
+
+ std::vector< std::string > deleteTree( std::string repoId, std::string folderId, bool allVersions,
+ libcmis::UnfileObjects::Type unfile, bool continueOnFailure );
+
+ void move( std::string repoId, std::string objectId, std::string destId, std::string srcId );
+
+ boost::shared_ptr< std::istream > getContentStream( std::string repoId, std::string objectId );
+
+ void setContentStream( std::string repoId, std::string objectId, bool overwrite, std::string changeToken,
+ boost::shared_ptr< std::ostream > stream, std::string contentType, std::string fileName );
+
+ libcmis::FolderPtr createFolder( std::string repoId, const std::map< std::string, libcmis::PropertyPtr >& properties,
+ std::string folderId );
+
+ libcmis::DocumentPtr createDocument( std::string repoId, const std::map< std::string, libcmis::PropertyPtr >& properties,
+ std::string folderId, boost::shared_ptr< std::ostream > stream, std::string contentType,
+ std::string fileName );
+
+ private:
+
+ ObjectService( );
+};
+
+#endif
diff --git a/src/libcmis/ws-relatedmultipart.cxx b/src/libcmis/ws-relatedmultipart.cxx
new file mode 100644
index 0000000..4def5dd
--- /dev/null
+++ b/src/libcmis/ws-relatedmultipart.cxx
@@ -0,0 +1,353 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-relatedmultipart.hxx"
+
+#include <algorithm>
+#include <sstream>
+#include <boost/algorithm/string.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <curl/curl.h>
+
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+using namespace boost::uuids;
+
+RelatedPart::RelatedPart( string& name, string& type, string& content ) :
+ m_name( name ),
+ m_contentType( type ),
+ m_content( content )
+{
+}
+
+// LCOV_EXCL_START
+string RelatedPart::toString( string cid )
+{
+ string buf;
+
+ buf += "Content-Id: <" + cid + ">\r\n";
+ buf += "Content-Type: " + getContentType( ) + "\r\n";
+ buf += "Content-Transfer-Encoding: binary\r\n\r\n";
+ buf += getContent( );
+
+ return buf;
+}
+// LCOV_EXCL_STOP
+
+RelatedMultipart::RelatedMultipart( ) :
+ m_startId( ),
+ m_startInfo( ),
+ m_parts( ),
+ m_boundary( )
+{
+ stringstream tmpStream("--------uuid:");
+ tmpStream << random_generator()();
+ m_boundary = tmpStream.str();
+}
+
+RelatedMultipart::RelatedMultipart( const string& body, const string& contentType ) :
+ m_startId( ),
+ m_startInfo( ),
+ m_parts( ),
+ m_boundary( )
+{
+ // Parse the content-type
+ size_t lastPos = 0;
+ size_t pos = contentType.find_first_of( ";\"" );
+ while ( pos != string::npos )
+ {
+ bool escaped = contentType[pos] == '"';
+ if ( escaped )
+ {
+ // Look for the closing quote and then look for the ; after it
+ pos = contentType.find( "\"", pos + 1 );
+ pos = contentType.find( ";", pos + 1 );
+ }
+
+ string param = contentType.substr( lastPos, pos - lastPos );
+ size_t eqPos = param.find( "=" );
+ if ( eqPos != string::npos )
+ {
+ string name = param.substr( 0, eqPos );
+ string value = param.substr( eqPos + 1 );
+ if ( value[0] == '"' && value[value.length() - 1] == '"' )
+ value = value.substr( 1, value.length( ) - 2 );
+
+ name = libcmis::trim( name );
+
+ if ( name == "start" )
+ {
+ m_startId = value;
+ // Remove the '<' '>' around the id if any
+ if ( m_startId[0] == '<' && m_startId[m_startId.size()-1] == '>' )
+ m_startId = m_startId.substr( 1, m_startId.size() - 2 );
+ }
+ else if ( name == "boundary" )
+ m_boundary = value;
+ else if ( name == "start-info" )
+ m_startInfo = value;
+ }
+
+ if ( pos != string::npos )
+ {
+ lastPos = pos + 1;
+ pos = contentType.find_first_of( ";\"", lastPos );
+ }
+ }
+
+ // Parse the multipart
+ string bodyFixed( body );
+ if ( boost::starts_with( bodyFixed, "--" + m_boundary + "\r\n" ) )
+ bodyFixed = "\r\n" + bodyFixed;
+
+ if ( bodyFixed[bodyFixed.length() - 1 ] != '\n' )
+ bodyFixed += '\n';
+
+ string lineEnd( "\n" );
+ string boundaryString( "--" + m_boundary );
+ string endBoundaryString( "--" + m_boundary + "--" );
+ pos = bodyFixed.find( lineEnd );
+ lastPos = 0;
+ bool inPart = false;
+ bool inHeaders = false;
+ string cid;
+ string name;
+ string type;
+ string partBody;
+
+ while ( pos != string::npos )
+ {
+ string line = bodyFixed.substr( lastPos, pos - lastPos );
+ if ( boost::starts_with( line, boundaryString ) )
+ {
+ // Found a part start
+ inPart = true;
+
+ if ( !cid.empty() && !type.empty( ) )
+ {
+ // Remove potential \r at the end of the body part
+ if ( partBody[partBody.length() - 1] == '\r' )
+ partBody = partBody.substr( 0, partBody.length() - 1 );
+
+ RelatedPartPtr relatedPart( new RelatedPart( name, type, partBody ) );
+ m_parts[cid] = relatedPart;
+
+ }
+ cid.clear( );
+ type.clear( );
+ name.clear( );
+ partBody.clear( );
+ inHeaders = true;
+ }
+ else if ( inPart )
+ {
+ if ( inHeaders )
+ {
+ // Remove potential \r at the end
+ if ( !line.empty() && line[line.length() - 1] == '\r' )
+ line = line.substr( 0, line.length() - 1 );
+
+ if ( line.empty( ) )
+ inHeaders = false;
+ else
+ {
+ size_t colonPos = line.find( ":" );
+ string headerName = line.substr( 0, colonPos );
+ string headerValue = line.substr( colonPos + 1 );
+ if ( boost::to_lower_copy( headerName ) == "content-id" )
+ {
+ cid = libcmis::trim( headerValue );
+ // Remove the '<' '>' around the id if any
+ if ( cid[0] == '<' && cid[cid.size()-1] == '>' )
+ cid = cid.substr( 1, cid.size() - 2 );
+ }
+ else if ( headerName == "Content-Type" )
+ type = libcmis::trim( headerValue );
+ // TODO Handle the Content-Transfer-Encoding
+ }
+ }
+ else
+ {
+ if ( !partBody.empty() )
+ partBody += lineEnd;
+ partBody += line;
+ }
+ }
+
+ // If we found the end of the multipart, no need to continue looping
+ if ( boost::starts_with( line, endBoundaryString ) )
+ break;
+
+ lastPos = pos + lineEnd.length();
+ pos = bodyFixed.find( lineEnd, lastPos );
+ }
+}
+
+vector< string > RelatedMultipart::getIds( )
+{
+ vector< string > ids;
+
+ for ( map< string, RelatedPartPtr >::iterator it = m_parts.begin( );
+ it != m_parts.end( ); ++it )
+ {
+ ids.push_back( it->first );
+ }
+
+ return ids;
+}
+
+RelatedPartPtr RelatedMultipart::getPart( string& cid )
+{
+ RelatedPartPtr part;
+ map< string, RelatedPartPtr >::iterator it = m_parts.find( cid );
+ if ( it != m_parts.end( ) )
+ part = it->second;
+
+ return part;
+}
+
+string RelatedMultipart::addPart( RelatedPartPtr part )
+{
+ string cid = createPartId( part->getName( ) );
+ m_parts[cid] = part;
+ return cid;
+}
+
+void RelatedMultipart::setStart( string& cid, string& startInfo )
+{
+ RelatedPartPtr start = getPart( cid );
+
+ if ( start.get( ) != NULL )
+ {
+ m_startId = cid;
+ m_startInfo = startInfo;
+ }
+}
+
+string RelatedMultipart::getContentType( )
+{
+ string type = "multipart/related;";
+
+ RelatedPartPtr start = getPart( getStartId( ) );
+ if ( start.get( ) != NULL )
+ {
+ type += "start=\"" + getStartId( ) + "\";";
+
+ string startType = start->getContentType( );
+ size_t pos = startType.find( ";" );
+ if ( pos != string::npos )
+ startType = startType.substr( 0, pos );
+
+ type += "type=\"" + startType + "\";";
+ }
+ type += "boundary=\"" + m_boundary + "\";";
+ type += "start-info=\"" + m_startInfo + "\"";
+
+ return type;
+}
+
+boost::shared_ptr< istringstream > RelatedMultipart::toStream( )
+{
+ string buf;
+
+ // Output the start part first
+ buf += "\r\n--" + m_boundary + "\r\n";
+ RelatedPartPtr part = getPart( getStartId( ) );
+ if ( part.get( ) != NULL )
+ {
+ buf += part->toString( getStartId( ) );
+ }
+
+ for ( map< string, RelatedPartPtr >::iterator it = m_parts.begin( );
+ it != m_parts.end( ); ++it )
+ {
+ if ( it->first != getStartId( ) )
+ {
+ buf += "\r\n--" + m_boundary + "\r\n";
+ buf += it->second->toString( it->first );
+ }
+ }
+
+ buf += "\r\n--" + m_boundary + "--\r\n";
+
+ boost::shared_ptr< istringstream > is( new istringstream( buf ) );
+ return is;
+}
+
+string RelatedMultipart::createPartId( const string& name )
+{
+ stringstream tmpStream(name);
+ tmpStream << "*";
+ tmpStream << random_generator()();
+ tmpStream << "@libcmis.sourceforge.net";
+
+ return tmpStream.str();
+}
+
+boost::shared_ptr< istream > getStreamFromNode( xmlNodePtr node, RelatedMultipart& multipart )
+{
+ boost::shared_ptr< stringstream > stream;
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "Include" ) ) )
+ {
+ // Get the content from the multipart
+ xmlChar* value = xmlGetProp( child, BAD_CAST( "href" ) );
+ string href( ( char* )value );
+ xmlFree( value );
+ // Get the Content ID from the href (cid:content-id)
+ string id = href;
+ if ( href.substr( 0, 4 ) == "cid:" )
+ {
+ id = href.substr( 4 );
+ // URL-decode the id
+ id = libcmis::unescape( id );
+ }
+ RelatedPartPtr part = multipart.getPart( id );
+ if ( part != NULL )
+ stream.reset( new stringstream( part->getContent( ) ) );
+ }
+ }
+
+ // If there was no xop:Include, then use the content as base64 data
+ if ( stream.get( ) == NULL )
+ {
+ xmlChar* content = xmlNodeGetContent( node );
+
+ stream.reset( new stringstream( ) );
+ libcmis::EncodedData decoder( stream.get( ) );
+ decoder.setEncoding( "base64" );
+ decoder.decode( ( void* )content, 1, xmlStrlen( content ) );
+ decoder.finish( );
+
+ xmlFree( content );
+ }
+ return stream;
+}
diff --git a/src/libcmis/ws-relatedmultipart.hxx b/src/libcmis/ws-relatedmultipart.hxx
new file mode 100644
index 0000000..cd17e73
--- /dev/null
+++ b/src/libcmis/ws-relatedmultipart.hxx
@@ -0,0 +1,138 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_RELATEDMULTIPART_HXX_
+#define _WS_RELATEDMULTIPART_HXX_
+
+#include <exception>
+#include <map>
+#include <string>
+#include <sstream>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+class RelatedPart
+{
+ private:
+ std::string m_name;
+ std::string m_contentType;
+ std::string m_content;
+
+ public:
+ RelatedPart( std::string& name, std::string& type, std::string& content );
+ ~RelatedPart( ) { };
+
+ std::string getName( ) { return m_name; }
+ std::string getContentType( ) { return m_contentType; }
+ std::string getContent( ) { return m_content; }
+
+ /** Create the string to place between the boundaries in the multipart.
+
+ \param cid the content Id to output
+ */
+ std::string toString( std::string cid );
+};
+typedef boost::shared_ptr< RelatedPart > RelatedPartPtr;
+
+/** Represents a multipart/related content as specified by RFC-2387.
+ */
+class RelatedMultipart
+{
+ private:
+
+ std::string m_startId;
+ std::string m_startInfo;
+ std::map< std::string, RelatedPartPtr > m_parts;
+ std::string m_boundary;
+
+ public:
+
+ /** Create a multipart/related from scratch (most probably
+ to output it later).
+ */
+ RelatedMultipart( );
+
+ /** Parse a multipart body to extract the entries from it.
+ */
+ RelatedMultipart( const std::string& body, const std::string& contentType );
+
+ /** Get the Content ids of all the parts;
+ */
+ std::vector< std::string > getIds( );
+
+ /** Get the entry corresponding to the given ID.
+ */
+ RelatedPartPtr getPart( std::string& cid );
+
+ /** Get the id of the multipart start entry.
+ */
+ std::string& getStartId( ) { return m_startId; }
+
+ std::string& getStartInfo( ) { return m_startInfo; }
+
+ /** Add an entry to the multipart and returns the content ID that
+ was created for it.
+ */
+ std::string addPart( RelatedPartPtr part );
+
+ /** Define the start of the multipart. That method needs to be
+ called before running toString(): the output order of the entries
+ is not guaranteed.
+
+ \param cid the Content-Id of the start entry
+ \param startInfo the type to use as start-info in the Content-Type
+ */
+ void setStart( std::string& cid, std::string& startInfo );
+
+ /** Compute the content type for the multipart object to set as the
+ Content-Type HTTP header.
+ */
+ std::string getContentType( );
+
+ /** Dump the multipart to an input stream: this can be provided as is as
+ an HTTP post request body.
+ */
+ boost::shared_ptr< std::istringstream > toStream( );
+
+ /** Provide an access to the boundary token for the unit tests.
+ */
+ std::string getBoundary( ) { return m_boundary; }
+
+ private:
+
+ /** Generate a content id, using an entry name and some random uuid.
+ */
+ std::string createPartId( const std::string& name );
+};
+
+/** Extract stream from xs:base64Binary node using either xop:Include or base64 encoded data.
+ */
+boost::shared_ptr< std::istream > getStreamFromNode( xmlNodePtr node, RelatedMultipart& multipart );
+
+#endif
diff --git a/src/libcmis/ws-repositoryservice.cxx b/src/libcmis/ws-repositoryservice.cxx
new file mode 100644
index 0000000..700078a
--- /dev/null
+++ b/src/libcmis/ws-repositoryservice.cxx
@@ -0,0 +1,136 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-repositoryservice.hxx"
+
+#include "ws-requests.hxx"
+#include "ws-session.hxx"
+
+using namespace std;
+
+RepositoryService::RepositoryService( ) :
+ m_session( NULL ),
+ m_url( "" )
+{
+}
+
+RepositoryService::RepositoryService( WSSession* session ) :
+ m_session( session ),
+ m_url( session->getServiceUrl( "RepositoryService" ) )
+{
+}
+
+RepositoryService::RepositoryService( const RepositoryService& copy ) :
+ m_session( copy.m_session ),
+ m_url( copy.m_url )
+{
+}
+
+RepositoryService::~RepositoryService( )
+{
+}
+
+RepositoryService& RepositoryService::operator=( const RepositoryService& copy )
+{
+ if ( this != &copy )
+ {
+ m_session = copy.m_session;
+ m_url = copy.m_url;
+ }
+
+ return *this;
+}
+
+map< string, string > RepositoryService::getRepositories( )
+{
+ map< string, string > repositories;
+
+ GetRepositoriesRequest request;
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+
+ if ( responses.size() == 1 )
+ {
+ GetRepositoriesResponse* response = dynamic_cast< GetRepositoriesResponse* >( responses.front( ).get( ) );
+ if ( response != NULL )
+ {
+ repositories = response->getRepositories();
+ }
+ }
+ return repositories;
+}
+
+libcmis::RepositoryPtr RepositoryService::getRepositoryInfo( string id )
+{
+ libcmis::RepositoryPtr repository;
+
+ GetRepositoryInfoRequest request( id );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetRepositoryInfoResponse* response = dynamic_cast< GetRepositoryInfoResponse* >( resp );
+ if ( response != NULL )
+ repository = response->getRepository( );
+ }
+
+ return repository;
+}
+
+libcmis::ObjectTypePtr RepositoryService::getTypeDefinition( string repoId, string typeId )
+{
+ libcmis::ObjectTypePtr type;
+
+ GetTypeDefinitionRequest request( repoId, typeId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetTypeDefinitionResponse* response = dynamic_cast< GetTypeDefinitionResponse* >( resp );
+ if ( response != NULL )
+ type = response->getType( );
+ }
+
+ return type;
+}
+
+vector< libcmis::ObjectTypePtr > RepositoryService::getTypeChildren( string repoId, string typeId )
+{
+ vector< libcmis::ObjectTypePtr > children;
+
+ GetTypeChildrenRequest request( repoId, typeId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetTypeChildrenResponse* response = dynamic_cast< GetTypeChildrenResponse* >( resp );
+ if ( response != NULL )
+ children = response->getChildren( );
+ }
+
+ return children;
+}
diff --git a/src/libcmis/ws-repositoryservice.hxx b/src/libcmis/ws-repositoryservice.hxx
new file mode 100644
index 0000000..4ef794f
--- /dev/null
+++ b/src/libcmis/ws-repositoryservice.hxx
@@ -0,0 +1,71 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_REPOSITORYSERVICE_HXX_
+#define _WS_REPOSITORYSERVICE_HXX_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <libcmis/repository.hxx>
+
+#include "base-session.hxx"
+#include "ws-soap.hxx"
+
+class WSSession;
+
+class RepositoryService
+{
+ private:
+ WSSession* m_session;
+ std::string m_url;
+
+ public:
+
+ RepositoryService( WSSession* session );
+ RepositoryService( const RepositoryService& copy );
+ ~RepositoryService( );
+
+ RepositoryService& operator=( const RepositoryService& copy );
+
+ std::map< std::string, std::string > getRepositories( );
+
+ /** Get the repository information based on its identifier.
+ */
+ libcmis::RepositoryPtr getRepositoryInfo( std::string id );
+
+ libcmis::ObjectTypePtr getTypeDefinition( std::string repoId, std::string typeId );
+
+ std::vector< libcmis::ObjectTypePtr > getTypeChildren( std::string repoId, std::string typeId );
+
+ private:
+
+ RepositoryService();
+};
+
+#endif
diff --git a/src/libcmis/ws-requests.cxx b/src/libcmis/ws-requests.cxx
new file mode 100644
index 0000000..e34d59e
--- /dev/null
+++ b/src/libcmis/ws-requests.cxx
@@ -0,0 +1,877 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-requests.hxx"
+
+#include <libcmis/xml-utils.hxx>
+
+#include "ws-document.hxx"
+#include "ws-folder.hxx"
+#include "ws-object.hxx"
+#include "ws-object-type.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+CmisSoapFaultDetail::CmisSoapFaultDetail( xmlNodePtr node ) :
+ SoapFaultDetail( ),
+ m_type( ),
+ m_code( 0 ),
+ m_message( )
+{
+ // Extract the type, code and message
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ string value( ( char * )content );
+ xmlFree( content );
+
+ if ( xmlStrEqual( child->name, BAD_CAST( "type" ) ) )
+ {
+ m_type = value;
+ }
+ else if ( xmlStrEqual( child->name, BAD_CAST( "code" ) ) )
+ {
+ try
+ {
+ m_code = libcmis::parseInteger( value );
+ }
+ catch ( const libcmis::Exception& )
+ {
+ // Simply leave the default error code if unparsable
+ }
+ }
+ else if ( xmlStrEqual( child->name, BAD_CAST( "message" ) ) )
+ {
+ m_message = value;
+ }
+ }
+}
+
+libcmis::Exception CmisSoapFaultDetail::toException( )
+{
+ libcmis::Exception e( m_message, m_type );
+ return e;
+}
+
+boost::shared_ptr< libcmis::Exception > getCmisException( const SoapFault& fault )
+{
+ boost::shared_ptr< libcmis::Exception > exception;
+
+ vector< SoapFaultDetailPtr > details = fault.getDetail( );
+ for ( vector< SoapFaultDetailPtr >::iterator it = details.begin( );
+ it != details.end( ) && exception.get( ) == NULL; ++ it )
+ {
+ boost::shared_ptr< CmisSoapFaultDetail > cmisDetail = boost::dynamic_pointer_cast< CmisSoapFaultDetail >( *it );
+ if ( cmisDetail.get( ) != NULL )
+ exception.reset( new libcmis::Exception( cmisDetail->toException( ) ) );
+ }
+
+ return exception;
+}
+
+void writeCmismStream( xmlTextWriterPtr writer, RelatedMultipart& multipart, boost::shared_ptr< ostream > os, string& contentType, string filename )
+{
+ // Get the stream as a string
+ istream is( os->rdbuf( ) );
+ is.seekg( 0, ios::end );
+ long size = is.tellg( );
+ is.seekg( 0, ios::beg );
+
+ char* buf = new char[ size ];
+ is.read( buf, size );
+ string content( buf, size );
+ delete[ ] buf;
+
+ xmlTextWriterWriteFormatElement( writer, BAD_CAST( "cmism:length" ), "%ld", static_cast<long int>(content.size( )) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:mimeType" ), BAD_CAST( contentType.c_str( ) ) );
+ if ( !filename.empty( ) )
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:filename" ), BAD_CAST( filename.c_str( ) ) );
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:stream" ) );
+
+ string name( "stream" );
+ RelatedPartPtr streamPart( new RelatedPart( name, contentType, content ) );
+ string partHref = "cid:";
+ partHref += multipart.addPart( streamPart );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "xop:Include" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:xop" ), BAD_CAST( "http://www.w3.org/2004/08/xop/include" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "href" ), BAD_CAST( partHref.c_str( ) ) );
+ xmlTextWriterEndElement( writer ); // xop:Include
+ xmlTextWriterEndElement( writer ); // cmism:stream
+}
+
+SoapFaultDetailPtr CmisSoapFaultDetail::create( xmlNodePtr node )
+{
+ return SoapFaultDetailPtr( new CmisSoapFaultDetail( node ) );
+}
+
+void GetRepositoriesRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getRepositories" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetRepositoriesResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ GetRepositoriesResponse* response = new GetRepositoriesResponse( );
+
+ // Look for the cmiss:repositories children
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "repositories" ) ) )
+ {
+ string id;
+ string name;
+
+ // Look for repositoryId and repositoryName
+ for ( xmlNodePtr repoChild = child->children; repoChild; repoChild = repoChild->next )
+ {
+ xmlChar* content = xmlNodeGetContent( repoChild );
+ string value( ( char* ) content );
+ xmlFree( content );
+
+ if ( xmlStrEqual( repoChild->name, BAD_CAST( "repositoryId" ) ) )
+ {
+ id = value;
+ }
+ else if ( xmlStrEqual( repoChild->name, BAD_CAST( "repositoryName" ) ) )
+ {
+ name = value;
+ }
+
+ }
+
+ if ( !id.empty( ) )
+ response->m_repositories[ id ] = name;
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetRepositoryInfoRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getRepositoryInfo" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_id.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetRepositoryInfoResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ GetRepositoryInfoResponse* response = new GetRepositoryInfoResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "repositoryInfo" ) ) )
+ {
+ libcmis::RepositoryPtr repository( new libcmis::Repository( child ) );
+ response->m_repository = repository;
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetTypeDefinitionRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getTypeDefinition" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:typeId" ), BAD_CAST( m_typeId.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetTypeDefinitionResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* session )
+{
+ GetTypeDefinitionResponse* response = new GetTypeDefinitionResponse( );
+ WSSession* wsSession = dynamic_cast< WSSession* >( session );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "type" ) ) )
+ {
+ libcmis::ObjectTypePtr type( new WSObjectType( wsSession, child ) );
+ response->m_type = type;
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetTypeChildrenRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getTypeChildren" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:typeId" ), BAD_CAST( m_typeId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:includePropertyDefinitions" ), BAD_CAST( "true" ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetTypeChildrenResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* session )
+{
+ GetTypeChildrenResponse* response = new GetTypeChildrenResponse( );
+ WSSession* wsSession = dynamic_cast< WSSession* >( session );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "types" ) ) )
+ {
+ for ( xmlNodePtr gdchild = child->children; gdchild; gdchild = gdchild->next )
+ {
+ if ( xmlStrEqual( gdchild->name, BAD_CAST( "types" ) ) )
+ {
+ libcmis::ObjectTypePtr type( new WSObjectType( wsSession, gdchild ) );
+ response->m_children.push_back( type );
+ }
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetObjectRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getObject" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_id.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:includeAllowableActions" ), BAD_CAST( "true" ) );
+
+ // Ask for renditions... some servers like Alfresco are providing them only this way
+ // and it saves time (another HTTP request) anyway.
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:renditionFilter" ), BAD_CAST( "*" ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetObjectResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* session )
+{
+ GetObjectResponse* response = new GetObjectResponse( );
+ WSSession* wsSession = dynamic_cast< WSSession* >( session );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "object" ) ) )
+ {
+ libcmis::ObjectPtr object;
+ WSObject tmp( wsSession, child );
+ if ( tmp.getBaseType( ) == "cmis:folder" )
+ {
+ object.reset( new WSFolder( tmp ) );
+ }
+ else if ( tmp.getBaseType( ) == "cmis:document" )
+ {
+ object.reset( new WSDocument( tmp ) );
+ }
+ else
+ {
+ // This should never happen... but who knows if the standard is 100% repected?
+ object.reset( new WSObject( wsSession, child ) );
+ }
+ response->m_object = object;
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetObjectByPathRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getObjectByPath" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:path" ), BAD_CAST( m_path.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:includeAllowableActions" ), BAD_CAST( "true" ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:renditionFilter" ), BAD_CAST( "*" ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+void UpdatePropertiesRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:updateProperties" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ if ( !m_changeToken.empty( ) )
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:changeToken" ), BAD_CAST( m_changeToken.c_str( ) ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:properties" ) );
+ for ( PropertyPtrMap::const_iterator it = m_properties.begin( );
+ it != m_properties.end( ); ++it )
+ {
+ libcmis::PropertyPtr property = it->second;
+ if( property->getPropertyType( )->isUpdatable( ) )
+ property->toXml( writer );
+ }
+ xmlTextWriterEndElement( writer ); // cmis:properties
+
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr UpdatePropertiesResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ UpdatePropertiesResponse* response = new UpdatePropertiesResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "objectId" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( content != NULL )
+ {
+ string value( ( char* ) content );
+ xmlFree( content );
+ response->m_id = value;
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void DeleteObjectRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:deleteObject" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ string allVersionsStr( "false" );
+ if ( m_allVersions )
+ allVersionsStr = "true";
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:allVersions" ), BAD_CAST( allVersionsStr.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+void DeleteTreeRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:deleteTree" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:folderId" ), BAD_CAST( m_folderId.c_str( ) ) );
+
+ string allVersionsStr( "false" );
+ if ( m_allVersions )
+ allVersionsStr = "true";
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:allVersions" ), BAD_CAST( allVersionsStr.c_str( ) ) );
+
+ string unfileStr( "" );
+ switch ( m_unfile )
+ {
+ case libcmis::UnfileObjects::Unfile:
+ unfileStr = "unfile";
+ break;
+ case libcmis::UnfileObjects::DeleteSingleFiled:
+ unfileStr = "deletesinglefiled";
+ break;
+ case libcmis::UnfileObjects::Delete:
+ unfileStr = "delete";
+ break;
+ default:
+ break;
+ }
+ if ( !unfileStr.empty( ) )
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:unfileObjects" ), BAD_CAST( unfileStr.c_str( ) ) );
+
+ string continueStr( "false" );
+ if ( m_continueOnFailure )
+ continueStr = "true";
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:continueOnFailure" ), BAD_CAST( continueStr.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr DeleteTreeResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ DeleteTreeResponse* response = new DeleteTreeResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "failedToDelete" ) ) )
+ {
+ for ( xmlNodePtr gdchild = child->children; gdchild; gdchild = gdchild->next )
+ {
+ if ( xmlStrEqual( gdchild->name, BAD_CAST( "objectIds" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( gdchild );
+ if ( content != NULL )
+ {
+ string value( ( char* ) content );
+ xmlFree( content );
+ response->m_failedIds.push_back( value );
+ }
+ }
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void MoveObjectRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:moveObject" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:targetFolderId" ), BAD_CAST( m_destId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:sourceFolderId" ), BAD_CAST( m_srcId.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+void GetContentStreamRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getContentStream" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetContentStreamResponse::create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* )
+{
+ GetContentStreamResponse* response = new GetContentStreamResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "contentStream" ) ) )
+ {
+ for ( xmlNodePtr gdchild = child->children; gdchild; gdchild = gdchild->next )
+ {
+ if ( xmlStrEqual( gdchild->name, BAD_CAST( "stream" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( gdchild );
+ if ( content != NULL )
+ {
+ // We can either have directly the base64 encoded data or
+ // an <xop:Include> pointing to another part of the multipart
+ response->m_stream = getStreamFromNode( gdchild, multipart );
+ }
+ xmlFree( content );
+ }
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetObjectParentsRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getObjectParents" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:includeAllowableActions" ), BAD_CAST( "true" ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:renditionFilter" ), BAD_CAST( "*" ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetObjectParentsResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* session )
+{
+ GetObjectParentsResponse* response = new GetObjectParentsResponse( );
+ WSSession* wsSession = dynamic_cast< WSSession* >( session );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "parents" ) ) )
+ {
+ for ( xmlNodePtr gdchild = child->children; gdchild; gdchild = gdchild->next )
+ {
+ if ( xmlStrEqual( gdchild->name, BAD_CAST( "object" ) ) )
+ {
+ libcmis::FolderPtr parent;
+ WSObject tmp( wsSession, gdchild );
+ if ( tmp.getBaseType( ) == "cmis:folder" )
+ {
+ parent.reset( new WSFolder( tmp ) );
+ response->m_parents.push_back( parent );
+ }
+ }
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetChildrenRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getChildren" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:folderId" ), BAD_CAST( m_folderId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:includeAllowableActions" ), BAD_CAST( "true" ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:renditionFilter" ), BAD_CAST( "*" ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetChildrenResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* session )
+{
+ GetChildrenResponse* response = new GetChildrenResponse( );
+ WSSession* wsSession = dynamic_cast< WSSession* >( session );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "objects" ) ) )
+ {
+ for ( xmlNodePtr gdchild = child->children; gdchild; gdchild = gdchild->next )
+ {
+ if ( xmlStrEqual( gdchild->name, BAD_CAST( "objects" ) ) )
+ {
+ for ( xmlNodePtr gdgdchild = gdchild->children; gdgdchild; gdgdchild = gdgdchild->next )
+ {
+ if ( xmlStrEqual( gdgdchild->name, BAD_CAST( "object" ) ) )
+ {
+ libcmis::ObjectPtr object;
+ WSObject tmp( wsSession, gdgdchild );
+ if ( tmp.getBaseType( ) == "cmis:folder" )
+ {
+ object.reset( new WSFolder( tmp ) );
+ }
+ else if ( tmp.getBaseType( ) == "cmis:document" )
+ {
+ object.reset( new WSDocument( tmp ) );
+ }
+ else
+ {
+ // This should never happen... but who knows if the standard is 100% repected?
+ object.reset( new WSObject( wsSession, gdgdchild ) );
+ }
+ response->m_children.push_back( object );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void CreateFolderRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:createFolder" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:properties" ) );
+ for ( PropertyPtrMap::const_iterator it = m_properties.begin( );
+ it != m_properties.end( ); ++it )
+ {
+ libcmis::PropertyPtr property = it->second;
+ property->toXml( writer );
+ }
+ xmlTextWriterEndElement( writer ); // cmis:properties
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:folderId" ), BAD_CAST( m_folderId.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr CreateFolderResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ CreateFolderResponse* response = new CreateFolderResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "objectId" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( content != NULL )
+ {
+ string value( ( char* ) content );
+ xmlFree( content );
+ response->m_id = value;
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void CreateDocumentRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:createDocument" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:properties" ) );
+ for ( PropertyPtrMap::const_iterator it = m_properties.begin( );
+ it != m_properties.end( ); ++it )
+ {
+ libcmis::PropertyPtr property = it->second;
+ property->toXml( writer );
+ }
+ xmlTextWriterEndElement( writer ); // cmis:properties
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:folderId" ), BAD_CAST( m_folderId.c_str( ) ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:contentStream" ) );
+ writeCmismStream( writer, m_multipart, m_stream, m_contentType, m_filename );
+ xmlTextWriterEndElement( writer ); // cmism:contentStream
+
+ xmlTextWriterEndElement( writer );
+}
+
+void SetContentStreamRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:setContentStream" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ string overwrite( "false" );
+ if ( m_overwrite )
+ overwrite = "true";
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:overwriteFlag" ), BAD_CAST( overwrite.c_str( ) ) );
+
+ if ( !m_changeToken.empty( ) )
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:changeToken" ), BAD_CAST( m_changeToken.c_str( ) ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:contentStream" ) );
+ writeCmismStream( writer, m_multipart, m_stream, m_contentType, m_filename );
+
+ xmlTextWriterEndElement( writer ); // cmism:contentStream
+
+ xmlTextWriterEndElement( writer );
+}
+
+void GetRenditionsRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getRenditions" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:renditionFilter" ), BAD_CAST( m_filter.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetRenditionsResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ GetRenditionsResponse* response = new GetRenditionsResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "renditions" ) ) )
+ {
+ libcmis::RenditionPtr rendition( new libcmis::Rendition( child ) );
+ response->m_renditions.push_back( rendition );
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void CheckOutRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:checkOut" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr CheckOutResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ CheckOutResponse* response = new CheckOutResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "objectId" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( content != NULL )
+ {
+ string value( ( char* ) content );
+ xmlFree( content );
+ response->m_objectId = value;
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void CancelCheckOutRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:cancelCheckOut" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+void CheckInRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:checkIn" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+
+ string major = "false";
+ if ( m_isMajor )
+ major = "true";
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:major" ), BAD_CAST( major.c_str( ) ) );
+
+ if ( m_properties.empty( ) )
+ {
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:properties" ) );
+ for ( PropertyPtrMap::const_iterator it = m_properties.begin( );
+ it != m_properties.end( ); ++it )
+ {
+ libcmis::PropertyPtr property = it->second;
+ property->toXml( writer );
+ }
+ xmlTextWriterEndElement( writer ); // cmis:properties
+ }
+
+ if ( m_stream.get( ) )
+ {
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:contentStream" ) );
+ writeCmismStream( writer, m_multipart, m_stream, m_contentType, m_fileName );
+ xmlTextWriterEndElement( writer ); // cmism:contentStream
+ }
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:checkinComment" ), BAD_CAST( m_comment.c_str( ) ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr CheckInResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* )
+{
+ CheckInResponse* response = new CheckInResponse( );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "objectId" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ if ( content != NULL )
+ {
+ string value( ( char* ) content );
+ xmlFree( content );
+ response->m_objectId = value;
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
+
+void GetAllVersionsRequest::toXml( xmlTextWriterPtr writer )
+{
+ xmlTextWriterStartElement( writer, BAD_CAST( "cmism:getAllVersions" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:repositoryId" ), BAD_CAST( m_repositoryId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:objectId" ), BAD_CAST( m_objectId.c_str( ) ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "cmism:includeAllowableActions" ), BAD_CAST( "true" ) );
+
+ xmlTextWriterEndElement( writer );
+}
+
+SoapResponsePtr GetAllVersionsResponse::create( xmlNodePtr node, RelatedMultipart&, SoapSession* session )
+{
+ GetAllVersionsResponse* response = new GetAllVersionsResponse( );
+ WSSession* wsSession = dynamic_cast< WSSession* >( session );
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "objects" ) ) )
+ {
+ WSObject tmp( wsSession, child );
+ if ( tmp.getBaseType( ) == "cmis:document" )
+ {
+ libcmis::DocumentPtr object( new WSDocument( tmp ) );
+ response->m_objects.push_back( object );
+ }
+ }
+ }
+
+ return SoapResponsePtr( response );
+}
diff --git a/src/libcmis/ws-requests.hxx b/src/libcmis/ws-requests.hxx
new file mode 100644
index 0000000..1782768
--- /dev/null
+++ b/src/libcmis/ws-requests.hxx
@@ -0,0 +1,786 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_REQUESTS_HXX_
+#define _WS_REQUESTS_HXX_
+
+#include <istream>
+#include <map>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include <libcmis/document.hxx>
+#include <libcmis/exception.hxx>
+#include <libcmis/folder.hxx>
+#include <libcmis/object.hxx>
+#include <libcmis/object-type.hxx>
+#include <libcmis/repository.hxx>
+
+#include "ws-soap.hxx"
+
+class CmisSoapFaultDetail : public SoapFaultDetail
+{
+ private:
+ std::string m_type;
+ long m_code;
+ std::string m_message;
+
+ CmisSoapFaultDetail( xmlNodePtr node );
+
+ public:
+ ~CmisSoapFaultDetail( ) noexcept { };
+
+ std::string getType( ) { return m_type; }
+ int getCode( ) { return m_code; }
+ std::string getMessage( ) { return m_message; }
+
+ libcmis::Exception toException( );
+
+ static SoapFaultDetailPtr create( xmlNodePtr node );
+};
+
+boost::shared_ptr< libcmis::Exception > getCmisException( const SoapFault& fault );
+
+void writeCmismStream( xmlTextWriterPtr writer, RelatedMultipart& multipart,
+ boost::shared_ptr< std::ostream >, std::string& contentType, std::string filename );
+
+/** getRepositories request.
+ */
+class GetRepositoriesRequest : public SoapRequest
+{
+ public:
+ GetRepositoriesRequest( ) { };
+ ~GetRepositoriesRequest( ) { };
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetRepositoriesResponse : public SoapResponse
+{
+ private:
+ std::map< std::string, std::string > m_repositories;
+
+ GetRepositoriesResponse( ) : SoapResponse( ), m_repositories( ) { };
+
+ public:
+
+ /** Parse cmism:getRepositoriesResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::map< std::string, std::string > getRepositories( ) { return m_repositories; }
+};
+
+class GetRepositoryInfoRequest : public SoapRequest
+{
+ private:
+ std::string m_id;
+
+ public:
+ GetRepositoryInfoRequest( std::string id ) : m_id( id ) { };
+ ~GetRepositoryInfoRequest( ) { };
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetRepositoryInfoResponse : public SoapResponse
+{
+ private:
+ libcmis::RepositoryPtr m_repository;
+
+ GetRepositoryInfoResponse( ) : SoapResponse( ), m_repository( ) { };
+
+ public:
+
+ /** Parse cmism:getRepositoriesResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ libcmis::RepositoryPtr getRepository( ) { return m_repository; }
+};
+
+class GetTypeDefinitionRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_typeId;
+
+ public:
+ GetTypeDefinitionRequest( std::string repoId, std::string typeId ) :
+ m_repositoryId( repoId ),
+ m_typeId( typeId )
+ {
+ }
+
+ ~GetTypeDefinitionRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetTypeDefinitionResponse : public SoapResponse
+{
+ private:
+ libcmis::ObjectTypePtr m_type;
+
+ GetTypeDefinitionResponse( ) : SoapResponse( ), m_type( ) { }
+
+ public:
+
+ /** Parse cmism:getTypeDefinitionResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ libcmis::ObjectTypePtr getType( ) { return m_type; }
+};
+
+class GetTypeChildrenRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_typeId;
+
+ public:
+ GetTypeChildrenRequest( std::string repoId, std::string typeId ) :
+ m_repositoryId( repoId ),
+ m_typeId( typeId )
+ {
+ }
+
+ ~GetTypeChildrenRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetTypeChildrenResponse : public SoapResponse
+{
+ private:
+ std::vector< libcmis::ObjectTypePtr > m_children;
+
+ GetTypeChildrenResponse( ) : SoapResponse( ), m_children( ) { }
+
+ public:
+
+ /** Parse cmism:getTypeChildrenResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::vector< libcmis::ObjectTypePtr > getChildren( ) { return m_children; }
+};
+
+class GetObjectRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_id;
+
+ public:
+ GetObjectRequest( std::string repoId, std::string id ) :
+ m_repositoryId( repoId ),
+ m_id( id )
+ {
+ }
+
+ ~GetObjectRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetObjectResponse : public SoapResponse
+{
+ private:
+ libcmis::ObjectPtr m_object;
+
+ GetObjectResponse( ) : SoapResponse( ), m_object( ) { }
+
+ public:
+
+ /** Parse cmism:getObjectResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ libcmis::ObjectPtr getObject( ) { return m_object; }
+};
+
+class GetObjectByPathRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_path;
+
+ public:
+ GetObjectByPathRequest( std::string repoId, std::string path ) :
+ m_repositoryId( repoId ),
+ m_path( path )
+ {
+ }
+
+ ~GetObjectByPathRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class UpdatePropertiesRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+ const std::map< std::string, libcmis::PropertyPtr >& m_properties;
+ std::string m_changeToken;
+
+ public:
+ UpdatePropertiesRequest( std::string repoId, std::string objectId,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ std::string changeToken ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId ),
+ m_properties( properties ),
+ m_changeToken( changeToken )
+ {
+ }
+
+ ~UpdatePropertiesRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class UpdatePropertiesResponse : public SoapResponse
+{
+ private:
+ std::string m_id;
+
+ UpdatePropertiesResponse( ) : SoapResponse( ), m_id( ) { }
+
+ public:
+
+ /** Parse cmism:updatePropertiesResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::string getObjectId( ) { return m_id; }
+};
+
+class DeleteObjectRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+ bool m_allVersions;
+
+ public:
+ DeleteObjectRequest( std::string repoId, std::string objectId, bool allVersions ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId ),
+ m_allVersions( allVersions )
+ {
+ }
+
+ ~DeleteObjectRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class DeleteTreeRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_folderId;
+ bool m_allVersions;
+ libcmis::UnfileObjects::Type m_unfile;
+ bool m_continueOnFailure;
+
+ public:
+ DeleteTreeRequest( std::string repoId,
+ std::string folderId,
+ bool allVersions,
+ libcmis::UnfileObjects::Type unfile,
+ bool continueOnFailure ) :
+ m_repositoryId( repoId ),
+ m_folderId( folderId ),
+ m_allVersions( allVersions ),
+ m_unfile( unfile ),
+ m_continueOnFailure( continueOnFailure )
+ {
+ }
+
+ ~DeleteTreeRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class DeleteTreeResponse : public SoapResponse
+{
+ private:
+ std::vector< std::string > m_failedIds;
+
+ DeleteTreeResponse( ) : SoapResponse( ), m_failedIds( ) { }
+
+ public:
+
+ /** Parse cmism:deleteTreeResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::vector< std::string > getFailedIds( ) { return m_failedIds; }
+};
+
+class MoveObjectRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+ std::string m_destId;
+ std::string m_srcId;
+
+ public:
+ MoveObjectRequest( std::string repoId, std::string objectId, std::string destId, std::string srcId ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId ),
+ m_destId( destId ),
+ m_srcId( srcId )
+ {
+ }
+
+ ~MoveObjectRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetContentStreamRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+
+ public:
+ GetContentStreamRequest( std::string repoId, std::string objectId ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId )
+ {
+ }
+
+ ~GetContentStreamRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetContentStreamResponse : public SoapResponse
+{
+ private:
+ boost::shared_ptr< std::istream > m_stream;
+
+ GetContentStreamResponse( ) : SoapResponse( ), m_stream( ) { }
+
+ public:
+
+ /** Parse cmism:getContentStreamResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ boost::shared_ptr< std::istream> getStream( ) { return m_stream; }
+};
+
+class GetObjectParentsRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+
+ public:
+ GetObjectParentsRequest( std::string repoId,
+ std::string objectId ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId )
+ {
+ }
+
+ ~GetObjectParentsRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetObjectParentsResponse : public SoapResponse
+{
+ private:
+ std::vector< libcmis::FolderPtr > m_parents;
+
+ GetObjectParentsResponse( ) : SoapResponse( ), m_parents( ) { }
+
+ public:
+
+ /** Parse cmism:getObjectParentsResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::vector< libcmis::FolderPtr > getParents( ) { return m_parents; }
+};
+
+class GetChildrenRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_folderId;
+
+ public:
+ GetChildrenRequest( std::string repoId,
+ std::string folderId ) :
+ m_repositoryId( repoId ),
+ m_folderId( folderId )
+ {
+ }
+
+ ~GetChildrenRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetChildrenResponse : public SoapResponse
+{
+ private:
+ std::vector< libcmis::ObjectPtr > m_children;
+
+ GetChildrenResponse( ) : SoapResponse( ), m_children( ) { }
+
+ public:
+
+ /** Parse cmism:getChildrenResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::vector< libcmis::ObjectPtr > getChildren( ) { return m_children; }
+};
+
+class CreateFolderRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ const std::map< std::string, libcmis::PropertyPtr >& m_properties;
+ std::string m_folderId;
+
+ public:
+ CreateFolderRequest( std::string repoId,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ std::string folderId ) :
+ m_repositoryId( repoId ),
+ m_properties( properties ),
+ m_folderId( folderId )
+ {
+ }
+
+ ~CreateFolderRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class CreateFolderResponse : public SoapResponse
+{
+ private:
+ std::string m_id;
+
+ CreateFolderResponse( ) : SoapResponse( ), m_id( ) { }
+
+ public:
+
+ /** Parse cmism:createFolderResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::string getObjectId( ) { return m_id; }
+};
+
+class CreateDocumentRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ const std::map< std::string, libcmis::PropertyPtr >& m_properties;
+ std::string m_folderId;
+ boost::shared_ptr< std::ostream > m_stream;
+ std::string m_contentType;
+ std::string m_filename;
+
+ public:
+ CreateDocumentRequest( std::string repoId,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ std::string folderId, boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string filename ) :
+ m_repositoryId( repoId ),
+ m_properties( properties ),
+ m_folderId( folderId ),
+ m_stream( stream ),
+ m_contentType( contentType ),
+ m_filename( filename )
+ {
+ }
+
+ ~CreateDocumentRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class SetContentStreamRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+ bool m_overwrite;
+ std::string m_changeToken;
+ boost::shared_ptr< std::ostream > m_stream;
+ std::string m_contentType;
+ std::string m_filename;
+
+ public:
+ SetContentStreamRequest( std::string repoId,
+ std::string objectId,
+ bool overwrite,
+ std::string changeToken,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType,
+ std::string filename ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId ),
+ m_overwrite( overwrite ),
+ m_changeToken( changeToken ),
+ m_stream( stream ),
+ m_contentType( contentType ),
+ m_filename( filename )
+ {
+ }
+
+ ~SetContentStreamRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetRenditionsRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+ std::string m_filter;
+
+ public:
+ GetRenditionsRequest( std::string repoId, std::string objectId, std::string filter ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId ),
+ m_filter( filter )
+ {
+ }
+
+ ~GetRenditionsRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetRenditionsResponse : public SoapResponse
+{
+ private:
+ std::vector< libcmis::RenditionPtr > m_renditions;
+
+ GetRenditionsResponse( ) : SoapResponse( ), m_renditions( ) { }
+
+ public:
+
+ /** Parse cmism:getRenditionsResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::vector< libcmis::RenditionPtr > getRenditions( ) { return m_renditions; }
+};
+
+class CheckOutRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+
+ public:
+ CheckOutRequest( std::string repoId,
+ std::string objectId ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId )
+ {
+ }
+
+ ~CheckOutRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class CheckOutResponse : public SoapResponse
+{
+ private:
+ std::string m_objectId;
+
+ CheckOutResponse( ) : SoapResponse( ), m_objectId( ) { }
+
+ public:
+
+ /** Parse cmism:checkOutResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::string getObjectId( ) { return m_objectId; }
+};
+
+class CancelCheckOutRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+
+ public:
+ CancelCheckOutRequest( std::string repoId,
+ std::string objectId ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId )
+ {
+ }
+
+ ~CancelCheckOutRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class CheckInRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+ bool m_isMajor;
+ const std::map< std::string, libcmis::PropertyPtr >& m_properties;
+ boost::shared_ptr< std::ostream > m_stream;
+ std::string m_contentType;
+ std::string m_fileName;
+ std::string m_comment;
+
+ public:
+ CheckInRequest( std::string repoId,
+ std::string objectId, bool isMajor,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > stream,
+ std::string contentType, std::string fileName, std::string comment ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId ),
+ m_isMajor( isMajor ),
+ m_properties( properties ),
+ m_stream( stream ),
+ m_contentType( contentType ),
+ m_fileName( fileName ),
+ m_comment( comment )
+ {
+ }
+
+ ~CheckInRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class CheckInResponse : public SoapResponse
+{
+ private:
+ std::string m_objectId;
+
+ CheckInResponse( ) : SoapResponse( ), m_objectId( ) { }
+
+ public:
+
+ /** Parse cmism:checkInResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::string getObjectId( ) { return m_objectId; }
+};
+
+class GetAllVersionsRequest : public SoapRequest
+{
+ private:
+ std::string m_repositoryId;
+ std::string m_objectId;
+
+ public:
+ GetAllVersionsRequest( std::string repoId, std::string objectId ) :
+ m_repositoryId( repoId ),
+ m_objectId( objectId )
+ {
+ }
+
+ ~GetAllVersionsRequest( ) { }
+
+ void toXml( xmlTextWriterPtr writer );
+};
+
+class GetAllVersionsResponse : public SoapResponse
+{
+ private:
+ std::vector< libcmis::DocumentPtr > m_objects;
+
+ GetAllVersionsResponse( ) : SoapResponse( ), m_objects( ) { }
+
+ public:
+
+ /** Parse cmism:getAllVersionsResponse. This function
+ assumes that the node is the expected one: this is
+ normally ensured by the SoapResponseFactory.
+ */
+ static SoapResponsePtr create( xmlNodePtr node, RelatedMultipart& multipart, SoapSession* session );
+
+ std::vector< libcmis::DocumentPtr > getObjects( ) { return m_objects; }
+};
+
+#endif
diff --git a/src/libcmis/ws-session.cxx b/src/libcmis/ws-session.cxx
new file mode 100644
index 0000000..3b1b291
--- /dev/null
+++ b/src/libcmis/ws-session.cxx
@@ -0,0 +1,417 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-session.hxx"
+
+#include <sstream>
+
+#include <boost/date_time.hpp>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#include <libcmis/xml-utils.hxx>
+
+#include "ws-requests.hxx"
+
+using namespace std;
+
+WSSession::WSSession( string bindingUrl, string repositoryId, string username,
+ string password, bool noSslCheck, libcmis::OAuth2DataPtr oauth2,
+ bool verbose ) :
+ BaseSession( bindingUrl, repositoryId, username, password, noSslCheck, oauth2, verbose ),
+ m_servicesUrls( ),
+ m_navigationService( NULL ),
+ m_objectService( NULL ),
+ m_repositoryService( NULL ),
+ m_versioningService( NULL ),
+ m_responseFactory( )
+{
+ // We don't want to have the HTTP exceptions as the errors are coming
+ // back as SoapFault elements.
+ setNoHttpErrors( true );
+ initialize( );
+}
+
+WSSession::WSSession( string bindingUrl, string repositoryId,
+ const HttpSession& httpSession,
+ libcmis::HttpResponsePtr response ) :
+ BaseSession( bindingUrl, repositoryId, httpSession ),
+ m_servicesUrls( ),
+ m_navigationService( NULL ),
+ m_objectService( NULL ),
+ m_repositoryService( NULL ),
+ m_versioningService( NULL ),
+ m_responseFactory( )
+{
+ // We don't want to have the HTTP exceptions as the errors are coming
+ // back as SoapFault elements.
+ setNoHttpErrors( true );
+ initialize( response );
+}
+
+WSSession::WSSession( ) :
+ BaseSession( ),
+ m_servicesUrls( ),
+ m_navigationService( NULL ),
+ m_objectService( NULL ),
+ m_repositoryService( NULL ),
+ m_versioningService( NULL ),
+ m_responseFactory( )
+{
+ setNoHttpErrors( true );
+}
+
+WSSession::~WSSession( )
+{
+ delete m_navigationService;
+ delete m_objectService;
+ delete m_repositoryService;
+ delete m_versioningService;
+}
+
+string WSSession::getWsdl( string url, libcmis::HttpResponsePtr response )
+{
+ string buf;
+ if ( response )
+ buf = response->getStream( )->str( );
+ else
+ buf = httpGetRequest( url )->getStream( )->str( );
+
+ // Do we have a wsdl file?
+ bool isWsdl = false;
+
+ xmlDocPtr doc = xmlReadMemory( buf.c_str(), buf.size(), m_bindingUrl.c_str(), NULL, 0 );
+ if ( NULL != doc )
+ {
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc );
+ libcmis::registerCmisWSNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ string definitionsXPath( "/wsdl:definitions" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( definitionsXPath.c_str() ), xpathCtx );
+
+ isWsdl = ( xpathObj != NULL ) && ( xpathObj->nodesetval != NULL ) && ( xpathObj->nodesetval->nodeNr > 0 );
+ xmlXPathFreeObject( xpathObj );
+ }
+ xmlXPathFreeContext( xpathCtx );
+ }
+ xmlFreeDoc( doc );
+
+ // If we don't have a wsdl file we may have received an HTML explanation for it,
+ // try to add ?wsdl to the URL (last chance to get something)
+ if ( !isWsdl )
+ {
+ if ( url.find( "?" ) == string::npos )
+ url += "?";
+ else
+ url += "&";
+ url += "wsdl";
+
+ buf = httpGetRequest( url )->getStream( )->str( );
+ }
+
+ return buf;
+}
+
+vector< SoapResponsePtr > WSSession::soapRequest( string& url, SoapRequest& request )
+{
+ vector< SoapResponsePtr > responses;
+
+ try
+ {
+ // Place the request in an envelope
+ RelatedMultipart& multipart = request.getMultipart( getUsername( ), getPassword( ) );
+ libcmis::HttpResponsePtr response = httpPostRequest( url, *multipart.toStream( ).get( ), multipart.getContentType( ) );
+
+ string responseType;
+ map< string, string >::iterator it = response->getHeaders( ).find( "Content-Type" );
+ if ( it != response->getHeaders( ).end( ) )
+ {
+ responseType = it->second;
+ if ( string::npos != responseType.find( "multipart/related" ) )
+ {
+ RelatedMultipart answer( response->getStream( )->str( ), responseType );
+
+ responses = getResponseFactory( ).parseResponse( answer );
+ }
+ else if ( string::npos != responseType.find( "text/xml" ) )
+ {
+ // Parse the envelope
+ string xml = response->getStream( )->str( );
+ responses = getResponseFactory( ).parseResponse( xml );
+ }
+ }
+ }
+ catch ( const SoapFault& fault )
+ {
+ boost::shared_ptr< libcmis::Exception > cmisException = getCmisException( fault );
+ if ( cmisException )
+ {
+ throw *cmisException;
+ }
+ throw libcmis::Exception( fault.what( ), "runtime" );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ return responses;
+}
+
+void WSSession::parseWsdl( string buf )
+{
+ // parse the content
+ const boost::shared_ptr< xmlDoc > doc( xmlReadMemory( buf.c_str(), buf.size(), m_bindingUrl.c_str(), NULL, 0 ), xmlFreeDoc );
+
+ if ( bool( doc ) )
+ {
+ // Check that we have a WSDL document
+ xmlNodePtr root = xmlDocGetRootElement( doc.get() );
+ if ( !xmlStrEqual( root->name, BAD_CAST( "definitions" ) ) )
+ throw libcmis::Exception( "Not a WSDL document" );
+
+ // Get all the services soap URLs
+ m_servicesUrls.clear( );
+
+ xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc.get() );
+ libcmis::registerCmisWSNamespaces( xpathCtx );
+
+ if ( NULL != xpathCtx )
+ {
+ string serviceXPath( "//wsdl:service" );
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( serviceXPath.c_str() ), xpathCtx );
+
+ if ( xpathObj != NULL )
+ {
+ int nbServices = 0;
+ if ( xpathObj->nodesetval )
+ nbServices = xpathObj->nodesetval->nodeNr;
+
+ for ( int i = 0; i < nbServices; i++ )
+ {
+ // What service do we have here?
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+ string name = libcmis::getXmlNodeAttributeValue( node, "name" );
+
+ // Gimme you soap:address location attribute
+ string locationXPath = serviceXPath + "[@name='" + name + "']/wsdl:port/soap:address/attribute::location";
+ string location = libcmis::getXPathValue( xpathCtx, locationXPath );
+
+ m_servicesUrls[name] = location;
+ }
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+ xmlXPathFreeContext( xpathCtx );
+ }
+ else
+ throw libcmis::Exception( "Failed to parse service document" );
+}
+
+void WSSession::initializeResponseFactory( )
+{
+ map< string, string > ns;
+ ns[ "wsssecurity" ] = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
+ ns[ NS_SOAP_ENV_PREFIX ] = NS_SOAP_ENV_URL;
+ ns[ "cmism" ] = NS_CMISM_URL;
+ ns[ "cmisw" ] = NS_CMISW_URL;
+ ns[ "cmis" ] = NS_CMIS_URL;
+ m_responseFactory.setNamespaces( ns );
+ m_responseFactory.setMapping( getResponseMapping() );
+ m_responseFactory.setDetailMapping( getDetailMapping( ) );
+ m_responseFactory.setSession( this );
+}
+
+void WSSession::initializeRepositories( map< string, string > repositories )
+{
+ for ( map< string, string >::iterator it = repositories.begin( );
+ it != repositories.end( ); ++it )
+ {
+ string repoId = it->first;
+ m_repositories.push_back( getRepositoryService( ).getRepositoryInfo( repoId ) );
+ }
+}
+
+void WSSession::initialize( libcmis::HttpResponsePtr response )
+{
+ if ( m_repositories.empty() )
+ {
+ // Get the wsdl file
+ string buf;
+ try
+ {
+ buf = getWsdl( m_bindingUrl, response );
+ }
+ catch ( const CurlException& e )
+ {
+ throw e.getCmisException( );
+ }
+
+ parseWsdl( buf );
+ initializeResponseFactory( );
+ map< string, string > repositories = getRepositoryService( ).getRepositories( );
+ initializeRepositories( repositories );
+ }
+}
+
+map< string, SoapResponseCreator > WSSession::getResponseMapping( )
+{
+ map< string, SoapResponseCreator > mapping;
+
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getRepositoriesResponse" ] = &GetRepositoriesResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getRepositoryInfoResponse" ] = &GetRepositoryInfoResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getTypeDefinitionResponse" ] = &GetTypeDefinitionResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getTypeChildrenResponse" ] = &GetTypeChildrenResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getObjectResponse" ] = &GetObjectResponse::create;
+ // No need to create a GetObjectByPathResponse as it would do the same than GetObjectResponse
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getObjectByPathResponse" ] = &GetObjectResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}updatePropertiesResponse" ] = &UpdatePropertiesResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}deleteTreeResponse" ] = &DeleteTreeResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getContentStreamResponse" ] = &GetContentStreamResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getObjectParentsResponse" ] = &GetObjectParentsResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getChildrenResponse" ] = &GetChildrenResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}createFolderResponse" ] = &CreateFolderResponse::create;
+ // Use the same response object than folders as it contains the same elements
+ mapping[ "{" + string( NS_CMISM_URL ) + "}createDocumentResponse" ] = &CreateFolderResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}checkOutResponse" ] = &CheckOutResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}checkInResponse" ] = &CheckInResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getAllVersionsResponse" ] = &GetAllVersionsResponse::create;
+ mapping[ "{" + string( NS_CMISM_URL ) + "}getRenditionsResponse" ] = &GetRenditionsResponse::create;
+
+ return mapping;
+}
+
+map< string, SoapFaultDetailCreator > WSSession::getDetailMapping( )
+{
+ map< string, SoapFaultDetailCreator > mapping;
+
+ mapping[ "{" + string( NS_CMISM_URL ) + "}cmisFault" ] = &CmisSoapFaultDetail::create;
+
+ return mapping;
+}
+
+string WSSession::getServiceUrl( string name )
+{
+ string url;
+
+ map< string, string >::iterator it = m_servicesUrls.find( name );
+ if ( it != m_servicesUrls.end( ) )
+ url = it->second;
+
+ return url;
+}
+
+RepositoryService& WSSession::getRepositoryService( )
+{
+ if ( m_repositoryService == NULL )
+ m_repositoryService = new RepositoryService( this );
+ return *m_repositoryService;
+}
+
+ObjectService& WSSession::getObjectService( )
+{
+ if ( m_objectService == NULL )
+ m_objectService = new ObjectService( this );
+ return *m_objectService;
+}
+
+NavigationService& WSSession::getNavigationService( )
+{
+ if ( m_navigationService == NULL )
+ m_navigationService = new NavigationService( this );
+ return *m_navigationService;
+}
+
+VersioningService& WSSession::getVersioningService( )
+{
+ if ( m_versioningService == NULL )
+ m_versioningService = new VersioningService( this );
+ return *m_versioningService;
+}
+
+libcmis::RepositoryPtr WSSession::getRepository( )
+{
+ // Check if we already have the repository
+ libcmis::RepositoryPtr repo;
+ vector< libcmis::RepositoryPtr >::iterator it = m_repositories.begin();
+ while ( !repo && it != m_repositories.end() )
+ {
+ if ( ( *it )->getId() == m_repositoryId )
+ repo = *it;
+ ++it;
+ }
+
+ // We found nothing cached, so try to get it from the server
+ if ( !repo )
+ {
+ repo = getRepositoryService( ).getRepositoryInfo( m_repositoryId );
+ if ( repo )
+ m_repositories.push_back( repo );
+ }
+
+ return repo;
+}
+
+bool WSSession::setRepository( string repositoryId )
+{
+ bool success = false;
+ try
+ {
+ libcmis::RepositoryPtr repo = getRepositoryService( ).getRepositoryInfo( repositoryId );
+ if (repo && repo->getId( ) == repositoryId )
+ m_repositoryId = repositoryId;
+ success = true;
+ }
+ catch ( const libcmis::Exception& )
+ {
+ }
+ return success;
+}
+
+libcmis::ObjectPtr WSSession::getObject( string id )
+{
+ return getObjectService( ).getObject( getRepositoryId( ), id );
+}
+
+libcmis::ObjectPtr WSSession::getObjectByPath( string path )
+{
+ return getObjectService( ).getObjectByPath( getRepositoryId( ), path );
+}
+
+libcmis::ObjectTypePtr WSSession::getType( string id )
+{
+ return getRepositoryService( ).getTypeDefinition( m_repositoryId, id );
+}
+
+vector< libcmis::ObjectTypePtr > WSSession::getBaseTypes( )
+{
+ return getRepositoryService().getTypeChildren( m_repositoryId, "" );
+}
diff --git a/src/libcmis/ws-session.hxx b/src/libcmis/ws-session.hxx
new file mode 100644
index 0000000..a7e6710
--- /dev/null
+++ b/src/libcmis/ws-session.hxx
@@ -0,0 +1,124 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_SESSION_HXX_
+#define _WS_SESSION_HXX_
+
+#include <map>
+#include <string>
+
+#include "base-session.hxx"
+#include "ws-navigationservice.hxx"
+#include "ws-objectservice.hxx"
+#include "ws-repositoryservice.hxx"
+#include "ws-soap.hxx"
+#include "ws-versioningservice.hxx"
+
+class WSSession : public BaseSession, public SoapSession
+{
+ private:
+ std::map< std::string, std::string > m_servicesUrls;
+ NavigationService* m_navigationService;
+ ObjectService* m_objectService;
+ RepositoryService* m_repositoryService;
+ VersioningService* m_versioningService;
+
+ SoapResponseFactory m_responseFactory;
+
+ public:
+ WSSession( std::string bindingUrl, std::string repositoryId,
+ std::string username, std::string password,
+ bool noSslCheck = false,
+ libcmis::OAuth2DataPtr oauth2 = libcmis::OAuth2DataPtr(),
+ bool verbose = false );
+
+ /** This constructor uses the response of an HTTP request made
+ before to spare some HTTP request. This constructor has mostly
+ been designed for the SessionFactory use.
+ */
+ WSSession( std::string bindingUrl, std::string repositoryId,
+ const HttpSession& HttpSession,
+ libcmis::HttpResponsePtr response );
+ ~WSSession( );
+
+ // Utility methods
+
+ /** Get an instance of the SoapResponseFactory, setup with all the
+ CMIS namespaces and function pointers.
+ */
+ SoapResponseFactory& getResponseFactory( ) { return m_responseFactory; }
+
+ /** Try hard to get a WSDL file at the given URL (tries to add ?wsdl if needed)
+ */
+ std::string getWsdl( std::string url, libcmis::HttpResponsePtr response );
+
+ std::vector< SoapResponsePtr > soapRequest( std::string& url, SoapRequest& request );
+
+ /** Get the service location URL given its name.
+ */
+ std::string getServiceUrl( std::string name );
+
+ RepositoryService& getRepositoryService( );
+
+ ObjectService& getObjectService( );
+
+ NavigationService& getNavigationService( );
+
+ VersioningService& getVersioningService( );
+
+
+ // Override session methods
+
+ virtual libcmis::RepositoryPtr getRepository( );
+
+ virtual bool setRepository( std::string repositoryId );
+
+ virtual libcmis::ObjectPtr getObject( std::string id );
+
+ virtual libcmis::ObjectPtr getObjectByPath( std::string path );
+
+ virtual libcmis::ObjectTypePtr getType( std::string id );
+
+ virtual std::vector< libcmis::ObjectTypePtr > getBaseTypes( );
+
+ private:
+
+ // Default constructor shouldn't be called
+ WSSession( );
+ WSSession( const WSSession& copy ) = delete;
+ WSSession& operator=( const WSSession& copy ) = delete;
+
+ void parseWsdl( std::string buf );
+ void initializeResponseFactory( );
+ void initializeRepositories( std::map< std::string, std::string > repositories );
+ void initialize( libcmis::HttpResponsePtr response = libcmis::HttpResponsePtr() );
+
+ std::map< std::string, SoapResponseCreator > getResponseMapping( );
+ std::map< std::string, SoapFaultDetailCreator > getDetailMapping( );
+};
+
+#endif
diff --git a/src/libcmis/ws-soap.cxx b/src/libcmis/ws-soap.cxx
new file mode 100644
index 0000000..20e9c68
--- /dev/null
+++ b/src/libcmis/ws-soap.cxx
@@ -0,0 +1,335 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-soap.hxx"
+
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xmlstring.h>
+
+#include <libcmis/xml-utils.hxx>
+
+using namespace std;
+using namespace boost::uuids;
+
+SoapFault::SoapFault( xmlNodePtr node, SoapResponseFactory* factory ) :
+ exception( ),
+ m_faultcode( ),
+ m_faultstring( ),
+ m_detail( ),
+ m_message( )
+{
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ if ( xmlStrEqual( child->name, BAD_CAST( "faultcode" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ xmlChar* prefix = NULL;
+ xmlChar* localName = xmlSplitQName2( content, &prefix );
+ if (localName == NULL)
+ localName = xmlStrdup( content );
+ m_faultcode = string( ( char* )localName );
+ xmlFree( content );
+ xmlFree( prefix );
+ xmlFree( localName );
+ }
+ else if ( xmlStrEqual( child->name, BAD_CAST( "faultstring" ) ) )
+ {
+ xmlChar* content = xmlNodeGetContent( child );
+ m_faultstring = string( ( char* )content );
+ xmlFree( content );
+ }
+ else if ( xmlStrEqual( child->name, BAD_CAST( "detail" ) ) )
+ {
+ m_detail = factory->parseFaultDetail( child );
+ }
+ }
+
+ m_message = getFaultcode() + ": " + getFaultstring();
+ for ( vector< SoapFaultDetailPtr >::const_iterator it = m_detail.begin( ); it != m_detail.end( ); ++it )
+ {
+ m_message += "\n" + ( *it )->toString( );
+ }
+
+}
+
+// LCOV_EXCL_START
+const char* SoapFault::what( ) const noexcept
+{
+ return m_message.c_str( );
+}
+// LCOV_EXCL_STOP
+
+
+SoapResponseFactory::SoapResponseFactory( ) :
+ m_mapping( ),
+ m_namespaces( ),
+ m_detailMapping( ),
+ m_session( NULL )
+{
+}
+
+SoapResponseFactory::SoapResponseFactory( const SoapResponseFactory& copy ) :
+ m_mapping( copy.m_mapping ),
+ m_namespaces( copy.m_namespaces ),
+ m_detailMapping( copy.m_detailMapping ),
+ m_session( copy.m_session )
+{
+}
+
+SoapResponseFactory& SoapResponseFactory::operator=( const SoapResponseFactory& copy )
+{
+ if ( this != &copy )
+ {
+ m_mapping = copy.m_mapping;
+ m_namespaces = copy.m_namespaces;
+ m_detailMapping = copy.m_detailMapping;
+ m_session = copy.m_session;
+ }
+
+ return *this;
+}
+
+vector< SoapResponsePtr > SoapResponseFactory::parseResponse( string& xml )
+{
+ // Create a fake multipart
+ RelatedMultipart multipart;
+ string name = "root";
+ string type = "text/xml";
+ string info;
+ RelatedPartPtr part( new RelatedPart( name, type, xml ) );
+ string cid = multipart.addPart( part );
+ multipart.setStart( cid, info );
+
+ // Then parse it normally
+ return parseResponse( multipart );
+}
+
+vector< SoapResponsePtr > SoapResponseFactory::parseResponse( RelatedMultipart& multipart )
+{
+ string xml;
+ RelatedPartPtr part = multipart.getPart( multipart.getStartId( ) );
+ if ( part.get() != NULL )
+ xml = part->getContent( );
+
+ vector< SoapResponsePtr > responses;
+
+ const boost::shared_ptr< xmlDoc > doc( xmlReadMemory( xml.c_str(), xml.size(), "", NULL, 0 ), xmlFreeDoc );
+
+ if ( bool( doc ) )
+ {
+ const boost::shared_ptr< xmlXPathContext > xpathCtx( xmlXPathNewContext( doc.get() ), xmlXPathFreeContext );
+ libcmis::registerSoapNamespaces( xpathCtx.get() );
+
+ for ( map< string, string >::iterator it = m_namespaces.begin( );
+ it != m_namespaces.end( ); ++it )
+ {
+ xmlXPathRegisterNs( xpathCtx.get(), BAD_CAST( it->first.c_str() ), BAD_CAST( it->second.c_str( ) ) );
+ }
+
+ if ( bool( xpathCtx ) )
+ {
+ string bodyXPath( "//soap-env:Body/*" );
+ const boost::shared_ptr< xmlXPathObject > xpathObj( xmlXPathEvalExpression( BAD_CAST( bodyXPath.c_str() ), xpathCtx.get() ), xmlXPathFreeObject );
+
+ if ( bool( xpathObj ) )
+ {
+ int nbChildren = 0;
+ if ( xpathObj->nodesetval )
+ nbChildren = xpathObj->nodesetval->nodeNr;
+
+ for ( int i = 0; i < nbChildren; i++ )
+ {
+ xmlNodePtr node = xpathObj->nodesetval->nodeTab[i];
+
+ // Is it a fault?
+ if ( xmlStrEqual( BAD_CAST( NS_SOAP_ENV_URL ), node->ns->href ) &&
+ xmlStrEqual( BAD_CAST( "Fault" ), node->name ) )
+ {
+ throw SoapFault( node, this );
+ }
+ SoapResponsePtr response = createResponse( node, multipart );
+ if ( NULL != response.get( ) )
+ responses.push_back( response );
+ }
+ }
+ }
+ }
+
+ return responses;
+}
+
+SoapResponsePtr SoapResponseFactory::createResponse( xmlNodePtr node, RelatedMultipart& multipart )
+{
+ SoapResponsePtr response;
+
+ string ns( ( const char* ) node->ns->href );
+ string name( ( const char* ) node->name );
+ string id = "{" + ns + "}" + name;
+ map< string, SoapResponseCreator >::iterator it = m_mapping.find( id );
+
+ if ( it != m_mapping.end( ) )
+ {
+ SoapResponseCreator creator = it->second;
+ response = creator( node, multipart, m_session );
+ }
+
+ return response;
+}
+
+vector< SoapFaultDetailPtr > SoapResponseFactory::parseFaultDetail( xmlNodePtr node )
+{
+ vector< SoapFaultDetailPtr > detail;
+
+ for ( xmlNodePtr child = node->children; child; child = child->next )
+ {
+ string ns;
+ if ( child->ns != NULL )
+ ns = string( ( const char* ) child->ns->href );
+ string name( ( const char* ) child->name );
+ string id = "{" + ns + "}" + name;
+ map< string, SoapFaultDetailCreator >::iterator it = m_detailMapping.find( id );
+
+ if ( it != m_detailMapping.end( ) )
+ {
+ SoapFaultDetailCreator creator = it->second;
+ detail.push_back( creator( child ) );
+ }
+ }
+
+ return detail;
+}
+
+RelatedMultipart& SoapRequest::getMultipart( string& username, string& password )
+{
+ // Generate the envelope and add it to the multipart
+ string envelope = createEnvelope( username, password );
+ string name( "root" );
+ string type( "application/xop+xml;charset=UTF-8;type=\"text/xml\"" );
+ RelatedPartPtr envelopePart( new RelatedPart( name, type, envelope ) );
+ string rootId = m_multipart.addPart( envelopePart );
+
+ // Set the envelope as the start part of the multipart
+ string startInfo( "text/xml" );
+ m_multipart.setStart( rootId, startInfo );
+
+ return m_multipart;
+}
+
+string SoapRequest::createEnvelope( string& username, string& password )
+{
+ xmlBufferPtr buf = xmlBufferCreate( );
+ xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 );
+
+ xmlTextWriterStartDocument( writer, NULL, NULL, NULL );
+
+ /* Sample envelope:
+ <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
+ <S:Header>
+ <Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
+ <Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
+ <Created>2012-06-14T09:20:29Z</Created>
+ <Expires>2012-06-15T09:20:29Z</Expires>
+ </Timestamp>
+ <UsernameToken>
+ <Username>admin</Username>
+ <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">admin</Password>
+ <Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2012-06-14T09:20:29Z</Created>
+ </UsernameToken>
+ </Security>
+ </S:Header>
+ <S:Body>
+ <ns2:getRepositories xmlns="http://docs.oasis-open.org/ns/cmis/core/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/messaging/200908/"/>
+ </S:Body>
+ </S:Envelope>
+ */
+ xmlChar* wsseUrl = BAD_CAST( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" );
+ xmlChar* wsuUrl = BAD_CAST( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" );
+
+ // Use an unsecure password transmission (PasswordText) because some clients can't support the PasswordDigest.
+ xmlChar* passTypeStr = BAD_CAST( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText" );
+
+ // Created must be a UTC time with no more than 3 digits fractional seconds.
+ boost::posix_time::ptime created( boost::posix_time::second_clock::universal_time( ) );
+ boost::posix_time::ptime expires( created );
+ expires = expires + boost::gregorian::days( 1 );
+ string createdStr = libcmis::writeDateTime( created );
+ string expiresStr = libcmis::writeDateTime( expires );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "S:Envelope" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:S" ), BAD_CAST( NS_SOAP_ENV_URL ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:wsu" ), wsuUrl );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "xmlns:wsse" ), wsseUrl );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "S:Header" ) );
+
+ // Write out the Basic Security Profile 1.0 compliant headers
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsse:Security" ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsse:Timestamp" ) );
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsse:Created" ) );
+ xmlTextWriterWriteRaw( writer, BAD_CAST( createdStr.c_str( ) ) );
+ xmlTextWriterEndElement( writer ); // End of Created
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsse:Expires" ) );
+ xmlTextWriterWriteRaw( writer, BAD_CAST( expiresStr.c_str( ) ) );
+ xmlTextWriterEndElement( writer ); // End of Expires
+ xmlTextWriterEndElement( writer ); // End of Timestamp
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsse:UsernameToken" ) );
+ xmlTextWriterWriteElement( writer, BAD_CAST( "wsse:Username" ), BAD_CAST( username.c_str( ) ) );
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsse:Password" ) );
+ xmlTextWriterWriteAttribute( writer, BAD_CAST( "Type" ), passTypeStr );
+ xmlTextWriterWriteRaw( writer, BAD_CAST( password.c_str( ) ) );
+ xmlTextWriterEndElement( writer ); // End of Password
+ xmlTextWriterStartElement( writer, BAD_CAST( "wsu:Created" ) );
+ xmlTextWriterWriteRaw( writer, BAD_CAST( createdStr.c_str( ) ) );
+ xmlTextWriterEndElement( writer ); // End of Created
+ xmlTextWriterEndElement( writer ); // End of UsernameToken
+
+ xmlTextWriterEndElement( writer ); // End of Security
+
+ xmlTextWriterEndElement( writer ); // End of S:Header
+
+ xmlTextWriterStartElement( writer, BAD_CAST( "S:Body" ) );
+ toXml( writer );
+ xmlTextWriterEndElement( writer ); // End of S:Body
+
+ xmlTextWriterEndElement( writer ); // End of S:Envelope
+ xmlTextWriterEndDocument( writer );
+
+ string str( ( const char * )xmlBufferContent( buf ) );
+
+ xmlFreeTextWriter( writer );
+ xmlBufferFree( buf );
+
+ return str;
+}
diff --git a/src/libcmis/ws-soap.hxx b/src/libcmis/ws-soap.hxx
new file mode 100644
index 0000000..62b8b36
--- /dev/null
+++ b/src/libcmis/ws-soap.hxx
@@ -0,0 +1,178 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_SOAP_HXX_
+#define _WS_SOAP_HXX_
+
+#include <exception>
+#include <map>
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+#include <libxml/tree.h>
+
+#include <libcmis/xmlserializable.hxx>
+
+#include "ws-relatedmultipart.hxx"
+
+/** Interface for soap sessions to communicate to response objects.
+
+ \attention
+ It currently doesn't provide anything, but it may later
+ provide all useful methods for SOAP requests low level handling.
+ */
+class SoapSession
+{
+ public:
+ SoapSession( ) { }
+ virtual ~SoapSession( ) { }
+};
+
+/** Base class for all SOAP response objects.
+
+ The factory will need to create the response objects using a static
+ creator method in each class.
+ */
+class SoapResponse
+{
+ public:
+ virtual ~SoapResponse( ) { };
+};
+typedef boost::shared_ptr< SoapResponse > SoapResponsePtr;
+typedef SoapResponsePtr ( *SoapResponseCreator ) ( xmlNodePtr, RelatedMultipart&, SoapSession* session );
+
+/** Base clas for SoapFault details parsed data.
+ */
+class SoapFaultDetail
+{
+ public:
+ virtual ~SoapFaultDetail() {};
+
+ virtual const std::string toString( ) const { return std::string( ); }
+};
+typedef boost::shared_ptr< SoapFaultDetail > SoapFaultDetailPtr;
+typedef SoapFaultDetailPtr ( *SoapFaultDetailCreator ) ( xmlNodePtr );
+
+class SoapResponseFactory;
+/** Class representing a SOAP Fault element, to be used as an exception.
+ */
+class SoapFault : public std::exception
+{
+ private:
+ std::string m_faultcode;
+ std::string m_faultstring;
+ std::vector< SoapFaultDetailPtr > m_detail;
+ std::string m_message;
+
+ public:
+ SoapFault( xmlNodePtr faultNode, SoapResponseFactory* factory );
+ virtual ~SoapFault( ) noexcept { };
+
+ const std::string& getFaultcode ( ) const { return m_faultcode; }
+ const std::string& getFaultstring ( ) const { return m_faultstring; }
+ std::vector< SoapFaultDetailPtr > getDetail( ) const { return m_detail; }
+
+ virtual const char* what() const noexcept;
+};
+
+
+/** Class parsing the SOAP response message and extracting the SoapResponse objects.
+ */
+class SoapResponseFactory
+{
+ private:
+ std::map< std::string, SoapResponseCreator > m_mapping;
+ std::map< std::string, std::string > m_namespaces;
+ std::map< std::string, SoapFaultDetailCreator > m_detailMapping;
+ SoapSession* m_session;
+
+ public:
+
+ SoapResponseFactory( );
+ SoapResponseFactory( const SoapResponseFactory& copy );
+
+ SoapResponseFactory& operator=( const SoapResponseFactory& copy );
+
+ void setMapping( std::map< std::string, SoapResponseCreator > mapping ) { m_mapping = mapping; }
+
+ /** Set the additional namespaces to parse the responses. There is no need to
+ add the soap / wsdl namespaces... they are automatically added.
+ */
+ void setNamespaces( std::map< std::string, std::string > namespaces ) { m_namespaces = namespaces; }
+
+ void setDetailMapping( std::map< std::string, SoapFaultDetailCreator > mapping ) { m_detailMapping = mapping; }
+
+ void setSession( SoapSession* session ) { m_session = session; }
+
+ /** Get the Soap envelope from the multipart and extract the response objects from it. This
+ method will also read the possible related parts to construct the response.
+ */
+ std::vector< SoapResponsePtr > parseResponse( RelatedMultipart& multipart );
+
+ /** Get the Soap envelope from an XML-only file and extract the response objects from it.
+ */
+ std::vector< SoapResponsePtr > parseResponse( std::string& xml );
+
+ /** Create a SoapResponse object depending on the node we have. This shouldn't be used
+ directly: only from parseResponse or unit tests.
+ */
+ SoapResponsePtr createResponse( xmlNodePtr node, RelatedMultipart& multipart );
+
+ std::vector< SoapFaultDetailPtr > parseFaultDetail( xmlNodePtr detailNode );
+};
+
+
+/** Base class for all SOAP request objects.
+
+ The implementer's toXml() method needs to take care of two things:
+ \li generate the XML to put in the Soap envelope body
+ \li add the potential attachement to the multipart.
+
+ There is no need to add the envelope to the multipart: it will
+ automatically be added as the start part of it by getMultipart().
+ This also means that adding parts to the multipart will have to
+ be done directly on the m_multipart protected member.
+
+ The RelatedMultipart object is the final result to be used.
+ */
+class SoapRequest : public libcmis::XmlSerializable
+{
+ protected:
+ RelatedMultipart m_multipart;
+
+ public:
+ SoapRequest( ) : m_multipart( ) { };
+ virtual ~SoapRequest( ) { };
+
+ RelatedMultipart& getMultipart( std::string& username, std::string& password );
+
+ protected:
+
+ std::string createEnvelope( std::string& username, std::string& password );
+};
+
+#endif
diff --git a/src/libcmis/ws-versioningservice.cxx b/src/libcmis/ws-versioningservice.cxx
new file mode 100644
index 0000000..579ec11
--- /dev/null
+++ b/src/libcmis/ws-versioningservice.cxx
@@ -0,0 +1,138 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include "ws-versioningservice.hxx"
+
+#include "ws-requests.hxx"
+#include "ws-session.hxx"
+
+using namespace std;
+using libcmis::PropertyPtrMap;
+
+VersioningService::VersioningService( ) :
+ m_session( NULL ),
+ m_url( "" )
+{
+}
+
+VersioningService::VersioningService( WSSession* session ) :
+ m_session( session ),
+ m_url( session->getServiceUrl( "VersioningService" ) )
+{
+}
+
+VersioningService::VersioningService( const VersioningService& copy ) :
+ m_session( copy.m_session ),
+ m_url( copy.m_url )
+{
+}
+
+VersioningService::~VersioningService( )
+{
+}
+
+VersioningService& VersioningService::operator=( const VersioningService& copy )
+{
+ if ( this != &copy )
+ {
+ m_session = copy.m_session;
+ m_url = copy.m_url;
+ }
+
+ return *this;
+}
+
+libcmis::DocumentPtr VersioningService::checkOut( string repoId, string documentId )
+{
+ libcmis::DocumentPtr pwc;
+
+ CheckOutRequest request( repoId, documentId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ CheckOutResponse* response = dynamic_cast< CheckOutResponse* >( resp );
+ if ( response != NULL )
+ {
+ string pwcId = response->getObjectId( );
+ libcmis::ObjectPtr object = m_session->getObject( pwcId );
+ pwc = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ }
+ }
+
+ return pwc;
+}
+
+void VersioningService::cancelCheckOut( string repoId, string documentId )
+{
+ CancelCheckOutRequest request( repoId, documentId );
+ m_session->soapRequest( m_url, request );
+}
+
+libcmis::DocumentPtr VersioningService::checkIn( string repoId, string objectId, bool isMajor,
+ const PropertyPtrMap& properties,
+ boost::shared_ptr< ostream > stream, string contentType, string fileName,
+ string comment )
+{
+ libcmis::DocumentPtr newVersion;
+
+ CheckInRequest request( repoId, objectId, isMajor, properties, stream, contentType, fileName, comment );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ CheckInResponse* response = dynamic_cast< CheckInResponse* >( resp );
+ if ( response != NULL )
+ {
+ string newId = response->getObjectId( );
+ libcmis::ObjectPtr object = m_session->getObject( newId );
+ newVersion = boost::dynamic_pointer_cast< libcmis::Document >( object );
+ }
+ }
+
+ return newVersion;
+}
+
+vector< libcmis::DocumentPtr > VersioningService::getAllVersions( string repoId, string objectId )
+{
+ vector< libcmis::DocumentPtr > versions;
+
+ GetAllVersionsRequest request( repoId, objectId );
+ vector< SoapResponsePtr > responses = m_session->soapRequest( m_url, request );
+ if ( responses.size( ) == 1 )
+ {
+ SoapResponse* resp = responses.front( ).get( );
+ GetAllVersionsResponse* response = dynamic_cast< GetAllVersionsResponse* >( resp );
+ if ( response != NULL )
+ {
+ versions = response->getObjects( );
+ }
+ }
+
+ return versions;
+}
diff --git a/src/libcmis/ws-versioningservice.hxx b/src/libcmis/ws-versioningservice.hxx
new file mode 100644
index 0000000..5156ebb
--- /dev/null
+++ b/src/libcmis/ws-versioningservice.hxx
@@ -0,0 +1,67 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+#ifndef _WS_VERSIONINGSERVICE_HXX_
+#define _WS_VERSIONINGSERVICE_HXX_
+
+#include <string>
+
+#include <libcmis/document.hxx>
+
+class WSSession;
+
+class VersioningService
+{
+ private:
+ WSSession* m_session;
+ std::string m_url;
+
+ public:
+
+ VersioningService( WSSession* session );
+ VersioningService( const VersioningService& copy );
+ ~VersioningService( );
+
+ VersioningService& operator=( const VersioningService& copy );
+
+ libcmis::DocumentPtr checkOut( std::string repoId, std::string documentId );
+
+ void cancelCheckOut( std::string repoId, std::string documentId );
+
+ libcmis::DocumentPtr checkIn( std::string repoId, std::string objectId, bool isMajor,
+ const std::map< std::string, libcmis::PropertyPtr >& properties,
+ boost::shared_ptr< std::ostream > stream, std::string contentType,
+ std::string fileName, std::string comment );
+
+ std::vector< libcmis::DocumentPtr > getAllVersions( std::string repoId, std::string objectId );
+
+ private:
+
+ VersioningService( );
+};
+
+#endif
diff --git a/src/libcmis/xml-utils.cxx b/src/libcmis/xml-utils.cxx
new file mode 100644
index 0000000..3fa2df7
--- /dev/null
+++ b/src/libcmis/xml-utils.cxx
@@ -0,0 +1,573 @@
+/* libcmis
+ * Version: MPL 1.1 / GPLv2+ / LGPLv2+
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License or as specified alternatively below. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * Major Contributor(s):
+ * Copyright (C) 2011 SUSE <cbosdonnat@suse.com>
+ *
+ *
+ * All Rights Reserved.
+ *
+ * For minor contributions see the git repository.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
+ * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
+ * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
+ * instead of those above.
+ */
+
+#include <libcmis/xml-utils.hxx>
+
+#include <errno.h>
+#include <memory>
+#include <sstream>
+#include <stdlib.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/version.hpp>
+
+#if BOOST_VERSION >= 106800
+#include <boost/uuid/detail/sha1.hpp>
+#else
+#include <boost/uuid/sha1.hpp>
+#endif
+#include <curl/curl.h>
+
+#if LIBCURL_VERSION_VALUE < 0x070F04
+#define curl_easy_escape( dummy, str, len ) curl_escape( str, len )
+#define curl_easy_unescape( dummy, str, len, dummy2 ) curl_unescape( str, len )
+#endif
+
+using namespace std;
+
+namespace
+{
+ static const char chars64[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ bool lcl_getBufValue( char encoded, int* value )
+ {
+ bool found = false;
+ const char *i = chars64;
+ while ( !found && *i )
+ {
+ if ( *i == encoded )
+ {
+ found = true;
+ *value = ( i - chars64 );
+ }
+ ++i;
+ }
+ return found;
+ }
+}
+
+namespace libcmis
+{
+ EncodedData::EncodedData( FILE* stream ) :
+ m_writer( NULL ),
+ m_stream( stream ),
+ m_outStream( NULL ),
+ m_encoding( ),
+ m_decode( false ),
+ m_pendingValue( 0 ),
+ m_pendingRank( 0 ),
+ m_missingBytes( 0 )
+ {
+ }
+
+ EncodedData::EncodedData( ostream* stream ) :
+ m_writer( NULL ),
+ m_stream( NULL ),
+ m_outStream( stream ),
+ m_encoding( ),
+ m_decode( false ),
+ m_pendingValue( 0 ),
+ m_pendingRank( 0 ),
+ m_missingBytes( 0 )
+ {
+ }
+
+ EncodedData::EncodedData( xmlTextWriterPtr writer ) :
+ m_writer( writer ),
+ m_stream( NULL ),
+ m_outStream( NULL ),
+ m_encoding( ),
+ m_decode( false ),
+ m_pendingValue( 0 ),
+ m_pendingRank( 0 ),
+ m_missingBytes( 0 )
+ {
+ }
+
+ EncodedData::EncodedData( const EncodedData& copy ) :
+ m_writer( copy.m_writer ),
+ m_stream( copy.m_stream ),
+ m_outStream( copy.m_outStream ),
+ m_encoding( copy.m_encoding ),
+ m_decode( copy.m_decode ),
+ m_pendingValue( copy.m_pendingValue ),
+ m_pendingRank( copy.m_pendingRank ),
+ m_missingBytes( copy.m_missingBytes )
+ {
+ }
+
+ EncodedData& EncodedData::operator=( const EncodedData& copy )
+ {
+ if ( this != &copy )
+ {
+ m_writer = copy.m_writer;
+ m_stream = copy.m_stream;
+ m_outStream = copy.m_outStream;
+ m_encoding = copy.m_encoding;
+ m_decode = copy.m_decode;
+ m_pendingValue = copy.m_pendingValue;
+ m_pendingRank = copy.m_pendingRank;
+ m_missingBytes = copy.m_missingBytes;
+ }
+ return *this;
+ }
+
+ void EncodedData::write( void* buf, size_t size, size_t nmemb )
+ {
+ if ( m_writer )
+ xmlTextWriterWriteRawLen( m_writer, ( xmlChar* )buf, size * nmemb );
+ else if ( m_stream )
+ fwrite( buf, size, nmemb, m_stream );
+ else if ( m_outStream )
+ m_outStream->write( ( const char* )buf, size * nmemb );
+ }
+
+ void EncodedData::decode( void* buf, size_t size, size_t nmemb )
+ {
+ m_decode = true;
+ if ( 0 == m_encoding.compare( "base64" ) )
+ {
+ decodeBase64( ( const char* )buf, size * nmemb );
+ }
+ else
+ write( buf, size, nmemb );
+ }
+
+ void EncodedData::encode( void* buf, size_t size, size_t nmemb )
+ {
+ m_decode = false;
+ if ( 0 == m_encoding.compare( "base64" ) )
+ {
+ encodeBase64( ( const char* )buf, size * nmemb );
+ }
+ else
+ write( buf, size, nmemb );
+ }
+
+ void EncodedData::finish( )
+ {
+ // Flushes the last bytes in base64 encoding / decoding if any
+ if ( 0 == m_encoding.compare( "base64" ) )
+ {
+ if ( m_decode && ( m_pendingValue != 0 || m_pendingRank != 0 || m_missingBytes != 0 ) )
+ {
+ int missingBytes = m_missingBytes;
+ if ( 0 == m_missingBytes )
+ missingBytes = 4 - m_pendingRank;
+
+ char decoded[3];
+ decoded[0] = ( m_pendingValue & 0xFF0000 ) >> 16;
+ decoded[1] = ( m_pendingValue & 0xFF00 ) >> 8;
+ decoded[2] = ( m_pendingValue & 0xFF );
+
+ write( decoded, 1, 3 - missingBytes );
+
+ m_pendingRank = 0;
+ m_pendingValue = 0;
+ m_missingBytes = 0;
+ }
+ else if ( !m_decode && ( m_pendingValue != 0 || m_pendingRank != 0 ) )
+ {
+ // Missing bytes should be zeroed: no need to do it
+ char encoded[4];
+ encoded[0] = chars64[ ( m_pendingValue & 0xFC0000 ) >> 18 ];
+ encoded[1] = chars64[ ( m_pendingValue & 0x03F000 ) >> 12 ];
+ encoded[2] = chars64[ ( m_pendingValue & 0x000FC0 ) >> 6 ];
+ encoded[3] = chars64[ ( m_pendingValue & 0x00003F ) ];
+
+ // Output the padding
+ int nEquals = 3 - m_pendingRank;
+ for ( int i = 0; i < nEquals; ++i )
+ encoded[ 3 - i ] = '=';
+
+ write( encoded, 1, 4 );
+
+ m_pendingRank = 0;
+ m_pendingValue = 0;
+ }
+ }
+ }
+
+ void EncodedData::decodeBase64( const char* buf, size_t len )
+ {
+ unsigned long blockValue = m_pendingValue;
+ int byteRank = m_pendingRank;
+ int missingBytes = m_missingBytes;
+
+ size_t i = 0;
+ while ( i < len )
+ {
+ int value = 0;
+ if ( lcl_getBufValue( buf[i], &value ) )
+ {
+ blockValue += value << ( ( 3 - byteRank ) * 6 );
+ ++byteRank;
+ }
+ else if ( buf[i] == '=' )
+ {
+ ++missingBytes;
+ ++byteRank;
+ }
+
+ // Reached the end of a block, decode it
+ if ( byteRank >= 4 )
+ {
+ char decoded[3];
+ decoded[0] = ( blockValue & 0xFF0000 ) >> 16;
+ decoded[1] = ( blockValue & 0xFF00 ) >> 8;
+ decoded[2] = ( blockValue & 0xFF );
+
+ write( decoded, 1, 3 - missingBytes );
+
+ byteRank = 0;
+ blockValue = 0;
+ missingBytes = 0;
+ }
+ ++i;
+ }
+
+ // Store the values if the last block is incomplete: they may come later
+ m_pendingValue = blockValue;
+ m_pendingRank = byteRank;
+ m_missingBytes = missingBytes;
+ }
+
+ void EncodedData::encodeBase64( const char* buf, size_t len )
+ {
+ unsigned long blockValue = m_pendingValue;
+ int byteRank = m_pendingRank;
+
+ size_t i = 0;
+ while ( i < len )
+ {
+ // Cast the char to an unsigned char or we'll shift negative values
+ blockValue += static_cast< unsigned char >( buf[i] ) << ( 2 - byteRank ) * 8;
+ ++byteRank;
+
+ // Reached the end of a block, encode it
+ if ( byteRank >= 3 )
+ {
+ char encoded[4];
+ encoded[0] = chars64[ ( blockValue & 0xFC0000 ) >> 18 ];
+ encoded[1] = chars64[ ( blockValue & 0x03F000 ) >> 12 ];
+ encoded[2] = chars64[ ( blockValue & 0x000FC0 ) >> 6 ];
+ encoded[3] = chars64[ ( blockValue & 0x00003F ) ];
+
+ write( encoded, 1, 4 );
+
+ byteRank = 0;
+ blockValue = 0;
+ }
+ ++i;
+ }
+
+ // Store the values if the last block is incomplete: they may come later
+ m_pendingValue = blockValue;
+ m_pendingRank = byteRank;
+ }
+
+ HttpResponse::HttpResponse( ) :
+ m_headers( ),
+ m_stream( ),
+ m_data( )
+ {
+ m_stream.reset( new stringstream( ) );
+ m_data.reset( new EncodedData( m_stream.get( ) ) );
+ }
+
+ void registerNamespaces( xmlXPathContextPtr xpathCtx )
+ {
+ if ( xpathCtx != NULL )
+ {
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "app" ), BAD_CAST( NS_APP_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "atom" ), BAD_CAST( NS_ATOM_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmisra" ), BAD_CAST( NS_CMISRA_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmism" ), BAD_CAST( NS_CMISM_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "xsi" ), BAD_CAST( "http://www.w3.org/2001/XMLSchema-instance" ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "type" ), BAD_CAST( "cmis:cmisTypeDocumentDefinitionType" ) );
+ }
+ }
+
+ void registerCmisWSNamespaces( xmlXPathContextPtr xpathCtx )
+ {
+ if ( xpathCtx != NULL )
+ {
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmisw" ), BAD_CAST( NS_CMISW_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmis" ), BAD_CAST( NS_CMIS_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmisra" ), BAD_CAST( NS_CMISRA_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "cmism" ), BAD_CAST( NS_CMISM_URL ) );
+
+ registerSoapNamespaces( xpathCtx );
+ }
+ }
+
+ void registerSoapNamespaces( xmlXPathContextPtr xpathCtx )
+ {
+ if ( xpathCtx != NULL )
+ {
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "soap" ), BAD_CAST( NS_SOAP_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "soap-env" ), BAD_CAST( NS_SOAP_ENV_URL ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "wsdl" ), BAD_CAST ( "http://schemas.xmlsoap.org/wsdl/" ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "ns" ), BAD_CAST ( "http://schemas.xmlsoap.org/soap/encoding/" ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "jaxws" ), BAD_CAST( "http://java.sun.com/xml/ns/jaxws" ) );
+ xmlXPathRegisterNs( xpathCtx, BAD_CAST( "xsd" ), BAD_CAST ( "http://www.w3.org/2001/XMLSchema" ) );
+ }
+ }
+
+ string getXPathValue( xmlXPathContextPtr xpathCtx, string req )
+ {
+ string value;
+ if ( xpathCtx != NULL )
+ {
+ xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST( req.c_str() ), xpathCtx );
+ if ( xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 )
+ {
+ xmlChar* pContent = xmlNodeGetContent( xpathObj->nodesetval->nodeTab[0] );
+ value = string( ( char* )pContent );
+ xmlFree( pContent );
+ }
+ xmlXPathFreeObject( xpathObj );
+ }
+
+ return value;
+ }
+
+ xmlDocPtr wrapInDoc( xmlNodePtr entryNd )
+ {
+ xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
+ if ( entryNd != NULL )
+ {
+ xmlNodePtr entryCopy = xmlCopyNode( entryNd, 1 );
+ xmlDocSetRootElement( doc, entryCopy );
+ }
+ return doc;
+ }
+
+ string getXmlNodeAttributeValue( xmlNodePtr node,
+ const char* attributeName,
+ const char* defaultValue )
+ {
+ xmlChar* xmlStr = xmlGetProp( node, BAD_CAST( attributeName ) );
+ if ( xmlStr == NULL )
+ {
+ if ( !defaultValue )
+ throw Exception( "Missing attribute" );
+ else
+ return string( defaultValue );
+ }
+ string value( ( char * ) xmlStr );
+ xmlFree( xmlStr );
+ return value;
+ }
+
+ boost::posix_time::ptime parseDateTime( string dateTimeStr )
+ {
+ boost::posix_time::ptime t( boost::date_time::not_a_date_time );
+ // Get the time zone offset
+ boost::posix_time::time_duration tzOffset( boost::posix_time::duration_from_string( "+00:00" ) );
+
+ if ( dateTimeStr.empty( ) )
+ return t; // obviously not a time
+
+ size_t teePos = dateTimeStr.find( 'T' );
+ if ( teePos == string::npos || teePos == dateTimeStr.size() - 1 )
+ return t; // obviously not a time
+
+ string noTzStr = dateTimeStr.substr( 0, teePos + 1 );
+ string timeStr = dateTimeStr.substr( teePos + 1 );
+
+ // Get the TZ if any
+ if ( timeStr[ timeStr.size() - 1] == 'Z' )
+ {
+ noTzStr += timeStr.substr( 0, timeStr.size() - 1 );
+ }
+ else
+ {
+ size_t tzPos = timeStr.find( '+' );
+ if ( tzPos == string::npos )
+ tzPos = timeStr.find( '-' );
+
+ if ( tzPos != string::npos )
+ {
+ noTzStr += timeStr.substr( 0, tzPos );
+
+ // Check the validity of the TZ value
+ string tzStr = timeStr.substr( tzPos );
+ try
+ {
+ tzOffset = boost::posix_time::time_duration( boost::posix_time::duration_from_string( tzStr.c_str() ) );
+ }
+ catch ( const std::exception& )
+ {
+ // Error converting, not a datetime
+ return t;
+ }
+
+ }
+ else
+ noTzStr += timeStr;
+ }
+
+ // Remove all the '-' and ':'
+ size_t pos = noTzStr.find_first_of( ":-" );
+ while ( pos != string::npos )
+ {
+ noTzStr.erase( pos, 1 );
+ pos = noTzStr.find_first_of( ":-" );
+ }
+ try
+ {
+ t = boost::posix_time::from_iso_string( noTzStr.c_str( ) );
+ t = t + tzOffset;
+ }
+ catch ( const std::exception& )
+ {
+ // Ignore boost parsing errors: will result in not_a_date_time
+ }
+
+ return t;
+ }
+
+ string writeDateTime( boost::posix_time::ptime time )
+ {
+ string str;
+ if ( !time.is_special( ) )
+ {
+ str = boost::posix_time::to_iso_extended_string( time );
+ str += "Z";
+ }
+ return str;
+ }
+
+ bool parseBool( string boolStr )
+ {
+ bool value = false;
+ if ( boolStr == "true" || boolStr == "1" )
+ value = true;
+ else if ( boolStr == "false" || boolStr == "0" )
+ value = false;
+ else
+ throw Exception( string( "Invalid xsd:boolean input: " ) + boolStr );
+ return value;
+ }
+
+ long parseInteger( string intStr )
+ {
+ char* end;
+ errno = 0;
+ long value = strtol( intStr.c_str(), &end, 0 );
+
+ if ( ( ERANGE == errno && ( LONG_MAX == value || LONG_MIN == value ) ) ||
+ ( errno != 0 && value == 0 ) )
+ {
+ throw Exception( string( "xsd:integer input can't fit to long: " ) + intStr );
+ }
+ else if ( !string( end ).empty( ) )
+ {
+ throw Exception( string( "Invalid xsd:integer input: " ) + intStr );
+ }
+
+ return value;
+ }
+
+ double parseDouble( string doubleStr )
+ {
+ char* end;
+ errno = 0;
+ double value = strtod( doubleStr.c_str(), &end );
+
+ if ( ( ERANGE == errno ) || ( errno != 0 && value == 0 ) )
+ {
+ throw Exception( string( "xsd:decimal input can't fit to double: " ) + doubleStr );
+ }
+ else if ( !string( end ).empty( ) )
+ {
+ throw Exception( string( "Invalid xsd:decimal input: " ) + doubleStr );
+ }
+
+ return value;
+ }
+
+ string trim( const string& str )
+ {
+ return boost::trim_copy_if( str, boost::is_any_of( " \t\r\n" ) );
+ }
+
+ std::string base64encode( const std::string& str )
+ {
+ stringstream stream;
+ EncodedData data( &stream );
+ data.setEncoding( "base64" );
+ data.encode( ( void * )str.c_str( ), size_t( 1 ), str.size() );
+ data.finish( );
+ return stream.str();
+ }
+
+ std::string sha1( const std::string& str )
+ {
+ boost::uuids::detail::sha1 sha1;
+ sha1.process_bytes( str.c_str(), str.size() );
+
+ unsigned int digest[5];
+ sha1.get_digest( digest );
+
+ stringstream out;
+ // Setup writing mode. Every number must produce eight
+ // hexadecimal digits, including possible leading 0s, or we get
+ // less than 40 digits as result.
+ out << hex << setfill('0') << right;
+ for ( int i = 0; i < 5; ++i )
+ out << setw(8) << digest[i];
+ return out.str();
+ }
+
+ int stringstream_write_callback( void * context, const char * s, int len )
+ {
+ stringstream * ss=static_cast< stringstream * >( context );
+ if ( ss )
+ {
+ ss->write( s, len );
+ return len;
+ }
+ return 0;
+ }
+
+ string escape( string str )
+ {
+ std::unique_ptr< char, void(*)( void* ) > escaped{ curl_easy_escape( NULL, str.c_str(), str.length() ), curl_free };
+ return escaped.get();
+ }
+
+ string unescape( string str )
+ {
+ std::unique_ptr< char, void(*)( void* ) > unescaped{ curl_easy_unescape( NULL, str.c_str(), str.length(), NULL ), curl_free };
+ return unescaped.get();
+ }
+}