Sat, 08 Nov 2014 20:27:10 +0100
changed sync behavior
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <libxml/tree.h> #include "utils.h" #include "webdav.h" #include "session.h" #include "methods.h" #include "davql.h" #include "ucx/buffer.h" #include "ucx/utils.h" DavContext* dav_context_new() { DavContext *context = malloc(sizeof(DavContext)); if(!context) { return NULL; } context->sessions = NULL; context->http_proxy = calloc(1, sizeof(DavProxy)); context->https_proxy = calloc(1, sizeof(DavProxy)); context->namespaces = ucx_map_new(16); if(!context->namespaces) { free(context); return NULL; } context->keys = ucx_map_new(16); DavNamespace *davns = malloc(sizeof(DavNamespace)); if(!davns) { ucx_map_free(context->namespaces); free(context); return NULL; } davns->prefix = "D"; davns->name = "DAV:"; if(ucx_map_cstr_put(context->namespaces, "D", davns)) { free(davns); ucx_map_free(context->namespaces); free(context); return NULL; } DavNamespace *idavns = malloc(sizeof(DavNamespace)); if(!idavns) { free(davns); ucx_map_free(context->namespaces); free(context); return NULL; } idavns->prefix = "idav"; idavns->name = DAV_NS; if(ucx_map_cstr_put(context->namespaces, "idav", idavns)) { free(davns); free(idavns); ucx_map_free(context->namespaces); free(context); return NULL; } return context; } void dav_context_destroy(DavContext *ctx) { // destroy all sessions assoziated with this context UCX_FOREACH(elm, ctx->sessions) { dav_session_destroy(elm->data); } free(ctx->http_proxy); free(ctx->https_proxy); UcxMapIterator i = ucx_map_iterator(ctx->namespaces); UcxKey k; DavNamespace *ns; // TODO: free map elements ucx_map_free(ctx->namespaces); free(ctx); } void dav_context_add_key(DavContext *context, DavKey *key) { ucx_map_cstr_put(context->keys, key->name, key); } DavKey* dav_context_get_key(DavContext *context, char *name) { if(name) { return ucx_map_cstr_get(context->keys, name); } else { return NULL; } } int dav_add_namespace(DavContext *context, char *prefix, char *name) { DavNamespace *namespace = malloc(sizeof(DavNamespace)); if(!namespace) { return 1; } namespace->prefix = strdup(prefix); namespace->name = strdup(name); return ucx_map_cstr_put(context->namespaces, prefix, namespace); } DavNamespace* dav_get_namespace(DavContext *context, char *prefix) { return ucx_map_cstr_get(context->namespaces, prefix); } DavNamespace* dav_get_namespace_s(DavContext *context, sstr_t prefix) { return ucx_map_sstr_get(context->namespaces, prefix); } void dav_get_property_namespace( DavContext *ctx, char *prefixed_name, char **ns, char **name) { char *pname = strchr(prefixed_name, ':'); char *pns = "DAV:"; if(pname) { DavNamespace *ns = dav_get_namespace_s( ctx, sstrn(prefixed_name, pname-prefixed_name)); pns = ns->name; pname++; } else { pname = prefixed_name; } *ns = pns; *name = pname; } DavResource* dav_get(DavSession *sn, char *path, char *properties) { CURL *handle = sn->handle; DavResource *resource = dav_resource_new(sn, path); util_set_url(sn, dav_resource_get_href(resource)); UcxList *proplist = NULL; if(properties) { proplist = parse_properties_string(sn->context, sstr(properties)); } UcxBuffer *rqbuf = create_propfind_request(sn, proplist); UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); //fwrite(rqbuf->space, 1, rqbuf->size, stdout); //printf("\n"); CURLcode ret = do_propfind_request(handle, rqbuf, rpbuf); int status = 0; curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); if(ret == CURLE_OK && status == 207) { //printf("response\n%s\n", rpbuf->space); resource = parse_propfind_response(sn, resource, rpbuf, NULL, 0); sn->error = DAV_OK; } else { dav_session_set_error(sn, ret, status); dav_resource_free(resource); } ucx_buffer_free(rqbuf); ucx_buffer_free(rpbuf); return resource; } int dav_propfind(DavSession *sn, DavResource *root, UcxBuffer *rqbuf, DavQOp *cond, size_t len) { // clean resource properties DavResourceData *data = root->data; if(data->properties->count > 0) { UcxKey key; void *value; UcxMapIterator i = ucx_map_iterator(data->properties); UCX_MAP_FOREACH(key, value, i) { ucx_map_remove(data->properties, key); } } CURL *handle = sn->handle; util_set_url(sn, dav_resource_get_href(root)); UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); DavResource *resource = root; CURLcode ret = do_propfind_request(handle, rqbuf, rpbuf); int status = 0; int error = 0; curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); if(ret == CURLE_OK && status == 207) { //printf("response\n%s\n", rpbuf->space); resource = parse_propfind_response(sn, resource, rpbuf, cond, len); sn->error = DAV_OK; } else { dav_session_set_error(sn, ret, status); error = 1; } ucx_buffer_free(rpbuf); return error; } UcxList* propfind_stack_push(UcxList *stack, DavResource *children) { while(children) { if(children->iscollection) { stack = ucx_list_prepend(stack, children); } children = children->next; } return stack; } DavResource* dav_query_get(DavSession *sn, DavGetQuery *query) { char *path; int depth = query->depth; /* if(parse_path_query(query->from, &path, &depth)) { sn->error = DAV_ERROR; return NULL; } */ path = sstrdup(query->from).ptr; sstr_t ps = query->properties; UcxBuffer *rqbuf; if(!sstrcmp(ps, S("*"))) { rqbuf = create_allprop_propfind_request(); } else if(!sstrcmp(ps, S("-"))) { rqbuf = create_propfind_request(sn, NULL); } else { UcxList *proplist = parse_properties_string(sn->context, ps); rqbuf = create_propfind_request(sn, proplist); } //fwrite(rqbuf->space, 1, rqbuf->size, stdout); //printf("\n"); DavResource *resource = dav_resource_new(sn, path); free(path); if(dav_propfind(sn, resource, rqbuf, query->condition, query->condlen)) { dav_resource_free(resource); resource = NULL; } int error = 0; if(resource && depth == -1) { UcxList *stack = NULL; // stack with DavResource* elements stack = propfind_stack_push(stack, resource->children); while(stack) { DavResource *sr = stack->data; // get first element from the stack stack = ucx_list_remove(stack, stack); // remove first element // do propfind request for sr if(dav_propfind(sn, sr, rqbuf, query->condition, query->condlen)) { error = 1; printf("subrequest failed\n"); break; } stack = propfind_stack_push(stack, sr->children); // add children } } ucx_buffer_free(rqbuf); return resource; } UcxList* parse_properties_string(DavContext *context, sstr_t str) { UcxList *proplist = NULL; size_t nprops = 0; sstr_t *props = sstrsplit(str, S(","), &nprops); for(int i=0;i<nprops;i++) { sstr_t s = props[i]; sstr_t nsname = sstrchr(s, ':'); if(nsname.length > 0) { sstr_t nspre = sstrsubsl(s, 0, nsname.ptr - s.ptr); nsname.ptr++; nsname.length--; DavProperty *dp = malloc(sizeof(DavProperty)); sstr_t pre = sstrtrim(nspre); dp->ns = dav_get_namespace_s(context, pre); dp->name = sstrdup(nsname).ptr; if(dp->ns && dp->name) { proplist = ucx_list_append(proplist, dp); } else { free(dp->name); free(dp); } } free(s.ptr); } free(props); return proplist; } DavResource* dav_query(DavSession *sn, char *query, ...) { va_list ap; va_start(ap, query); DavQuery q = dav_ql_parse(query, ap); va_end(ap); DavResource *res = NULL; switch(q.command) { case DAV_QUERY_GET: { res = dav_query_get(sn, q.command_data); free_get_query(q.command_data); break; } case DAV_QUERY_ERROR: { // TODO break; } } return res; }