2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2018 Olaf Wintermann. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
32 #include <libxml/tree.h>
38 #include "ucx/buffer.h"
39 #include "ucx/utils.h"
40 #include "davqlparser.h"
41 #include "davqlexec.h"
44 DavContext* dav_context_new(void) {
46 DavContext *context = calloc(1, sizeof(DavContext));
50 context->sessions = NULL;
51 context->http_proxy = calloc(1, sizeof(DavProxy));
52 if(!context->http_proxy) {
53 dav_context_destroy(context);
56 context->https_proxy = calloc(1, sizeof(DavProxy));
57 if(!context->https_proxy) {
58 dav_context_destroy(context);
61 context->namespaces = ucx_map_new(16);
62 if(!context->namespaces) {
63 dav_context_destroy(context);
66 context->namespaceinfo = ucx_map_new(16);
67 if(!context->namespaceinfo) {
68 dav_context_destroy(context);
70 context->keys = ucx_map_new(16);
72 dav_context_destroy(context);
77 if(dav_add_namespace(context, "D", "DAV:")) {
78 dav_context_destroy(context);
84 if(dav_add_namespace(context, "idav", DAV_NS)) {
85 dav_context_destroy(context);
89 // add idavprops namespace
90 if(dav_add_namespace(context, "idavprops", DAV_PROPS_NS)) {
91 dav_context_destroy(context);
98 void dav_context_destroy(DavContext *ctx) {
99 // destroy all sessions assoziated with this context
100 UcxList *elm = ctx->sessions;
102 DavSession *sn = elm->data;
104 dav_session_destroy(sn);
106 if(ctx->http_proxy) {
107 free(ctx->http_proxy);
109 if(ctx->https_proxy) {
110 free(ctx->https_proxy);
113 if(ctx->namespaces) {
114 UcxMapIterator i = ucx_map_iterator(ctx->namespaces);
117 UCX_MAP_FOREACH(k, ns, i) {
127 ucx_map_free(ctx->namespaces);
129 if(ctx->namespaceinfo) {
133 UcxMapIterator i = ucx_map_iterator(ctx->keys);
136 UCX_MAP_FOREACH(k, key, i) {
146 ucx_map_free(ctx->keys);
152 void dav_context_add_key(DavContext *context, DavKey *key) {
153 ucx_map_cstr_put(context->keys, key->name, key);
156 DavKey* dav_context_get_key(DavContext *context, char *name) {
158 return ucx_map_cstr_get(context->keys, name);
163 int dav_add_namespace(DavContext *context, const char *prefix, const char *name) {
164 DavNamespace *namespace = malloc(sizeof(DavNamespace));
169 char *p = strdup(prefix);
170 char *n = strdup(name);
174 namespace->prefix = p;
176 err = ucx_map_cstr_put(context->namespaces, prefix, namespace);
188 DavNamespace* dav_get_namespace(DavContext *context, const char *prefix) {
189 return ucx_map_cstr_get(context->namespaces, prefix);
192 DavNamespace* dav_get_namespace_s(DavContext *context, sstr_t prefix) {
193 return ucx_map_sstr_get(context->namespaces, prefix);
196 int dav_enable_namespace_encryption(DavContext *context, const char *ns, DavBool encrypt) {
197 DavNSInfo *info = ucx_map_cstr_get(context->namespaceinfo, ns);
199 info = calloc(1, sizeof(DavNSInfo));
200 info->encrypt = encrypt;
201 ucx_map_cstr_put(context->namespaceinfo, ns, info);
203 info->encrypt = encrypt;
208 int dav_namespace_is_encrypted(DavContext *context, const char *ns) {
209 DavNSInfo *info = ucx_map_cstr_get(context->namespaceinfo, ns);
211 return info->encrypt;
216 void dav_get_property_namespace_str(
222 // TODO: rewrite using dav_get_property_ns
224 char *pname = strchr(prefixed_name, ':');
227 DavNamespace *ns = dav_get_namespace_s(
229 sstrn(prefixed_name, pname-prefixed_name));
238 pname = prefixed_name;
244 DavNamespace* dav_get_property_namespace(
249 char *pname = strchr(prefixed_name, ':');
251 DavNamespace *ns = dav_get_namespace_s(
253 sstrn(prefixed_name, pname-prefixed_name));
262 *name = prefixed_name;
263 return dav_get_namespace_s(ctx, S("D"));
267 // TODO: add sstr_t version of dav_get_property_ns
269 void dav_set_effective_href(DavSession *sn, DavResource *resource) {
271 curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &eff_url);
273 char *href = util_url_path(eff_url);
274 if(strcmp(href, resource->href)) {
275 dav_session_free(sn, resource->href);
276 resource->href = dav_session_strdup(sn, href);
281 DavResource* dav_get(DavSession *sn, char *path, char *properties) {
282 CURL *handle = sn->handle;
283 DavResource *resource = dav_resource_new(sn, path);
284 util_set_url(sn, dav_resource_get_href(resource));
286 UcxList *proplist = NULL;
288 proplist = parse_properties_string(sn->context, sstr(properties));
290 UcxBuffer *rqbuf = create_propfind_request(sn, proplist, "propfind", 0);
291 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
293 //fwrite(rqbuf->space, 1, rqbuf->size, stdout);
296 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf);
298 curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
299 if(ret == CURLE_OK && status == 207) {
300 dav_set_effective_href(sn, resource);
302 //printf("response\n%s\n", rpbuf->space);
303 // TODO: use PropfindParser
304 resource = parse_propfind_response(sn, resource, rpbuf);
305 resource->exists = 1;
308 dav_session_set_error(sn, ret, status);
309 dav_resource_free(resource);
313 ucx_buffer_free(rqbuf);
314 ucx_buffer_free(rpbuf);
316 DavProperty *p = proplist->data;
319 UcxList *next = proplist->next;
328 int dav_propfind(DavSession *sn, DavResource *root, UcxBuffer *rqbuf) {
329 // clean resource properties
330 DavResourceData *data = root->data;
331 ucx_map_clear(data->properties); // TODO: free existing content
333 CURL *handle = sn->handle;
334 util_set_url(sn, dav_resource_get_href(root));
336 UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
337 DavResource *resource = root;
338 CURLcode ret = do_propfind_request(sn, rqbuf, rpbuf);
341 curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status);
342 if(ret == CURLE_OK && status == 207) {
343 //printf("response\n%s\n", rpbuf->space);
344 dav_set_effective_href(sn, resource);
345 // TODO: use PropfindParser
346 resource = parse_propfind_response(sn, resource, rpbuf);
350 dav_session_set_error(sn, ret, status);
353 ucx_buffer_free(rpbuf);
357 UcxList* parse_properties_string(DavContext *context, sstr_t str) {
358 UcxList *proplist = NULL;
360 sstr_t *props = sstrsplit(str, S(","), &nprops);
361 for(int i=0;i<nprops;i++) {
363 sstr_t nsname = sstrchr(s, ':');
364 if(nsname.length > 0) {
365 sstr_t nspre = sstrsubsl(s, 0, nsname.ptr - s.ptr);
369 DavProperty *dp = malloc(sizeof(DavProperty));
370 sstr_t pre = sstrtrim(nspre);
371 dp->ns = dav_get_namespace_s(context, pre);
372 dp->name = sstrdup(nsname).ptr;
373 if(dp->ns && dp->name) {
374 proplist = ucx_list_append(proplist, dp);
386 DavResource* dav_query(DavSession *sn, char *query, ...) {
387 DavQLStatement *stmt = dav_parse_statement(sstr(query));
389 sn->error = DAV_ERROR;
392 if(stmt->errorcode != 0) {
393 sn->error = DAV_QL_ERROR;
394 dav_free_statement(stmt);
400 DavResult result = dav_statement_execv(sn, stmt, ap);
403 dav_free_statement(stmt);
404 return result.result;