Mon, 26 Aug 2013 14:44:21 +0200
removed debug code
dav/davql.c | file | annotate | diff | comparison | revisions | |
dav/davql.h | file | annotate | diff | comparison | revisions | |
dav/main.c | file | annotate | diff | comparison | revisions | |
dav/methods.c | file | annotate | diff | comparison | revisions | |
dav/methods.h | file | annotate | diff | comparison | revisions | |
dav/utils.c | file | annotate | diff | comparison | revisions | |
dav/utils.h | file | annotate | diff | comparison | revisions | |
dav/webdav.c | file | annotate | diff | comparison | revisions | |
dav/webdav.h | file | annotate | diff | comparison | revisions |
--- a/dav/davql.c Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,694 +0,0 @@ -/* - * 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 "davql.h" -#include "methods.h" -#include "utils.h" - -DavQuery dav_ql_parse(char *query, va_list ap) { - DavQuery davquery; - davquery.command = DAV_QUERY_ERROR; - davquery.command_data = NULL; - sstr_t q = sstr(query); - q = sstrtrim(q); - - // get query command - sstr_t cmd; - cmd.ptr = NULL; - int i; - for(i=0;i<q.length;i++) { - if(q.ptr[i] == ' ') { - cmd = sstrsubsl(q, 0, i); - break; - } - } - if(!cmd.ptr) { - fprintf(stderr, "DQL syntax error\n"); - return davquery; - } - - cmd = sstrtrim(cmd); - q = sstrtrim(sstrsubs(q, i)); - if(!sstrcmp(cmd, S("get"))) { - davquery.command = DAV_QUERY_GET; - davquery.command_data = dav_ql_parse_get(q, ap); - } - - return davquery; -} - -DavGetQuery* dav_ql_parse_get(sstr_t q, va_list ap) { - sstr_t property_query = q; - q = util_getsubstr_until_token(q, S("from"), &property_query); - - sstr_t from_query = q; - sstr_t cond = util_getsubstr_until_token(q, S("where"), &from_query); - - // insert variable values - UcxBuffer *fbuf = ucx_buffer_new(NULL, 128, UCX_BUFFER_AUTOEXTEND); - int var = 0; - for(int i=0;i<from_query.length;i++) { - char c = from_query.ptr[i]; - if(c == '%') { - if(var) { - ucx_buffer_putc(fbuf, '%'); // previous '%' - } else { - var = 1; - } - } else if(var) { - switch(c) { - case 's': { - char *arg = va_arg(ap, char*); - ucx_buffer_puts(fbuf, arg); - break; - } - default: { - ucx_buffer_putc(fbuf, '%'); - ucx_buffer_putc(fbuf, c); - } - } - var = 0; - } else { - ucx_buffer_putc(fbuf, c); - } - } - - // condition - DavQOp *condition = NULL; - size_t oplen = 0; - if(cond.ptr) { - //printf("cond: {%.*s}\n", cond.length, cond.ptr); - UcxList *ops = NULL; - if(dav_parse_condition(&ops, cond, ap)) { - // TODO: error - printf("parse error\n"); - return NULL; - } - oplen = ucx_list_size(ops); - condition = calloc(sizeof(DavQOp), oplen); - int l = 0; - UCX_FOREACH(elm, ops) { - condition[l] = *(DavQOp*)elm->data; - free(elm->data); - l++; - } - ucx_list_free(ops); - } - - DavGetQuery *getquery = malloc(sizeof(DavGetQuery)); - getquery->properties = sstrdup(property_query); - getquery->from = sstrn(fbuf->space, fbuf->pos); - if(condition) { - getquery->condition = condition; - getquery->condlen = oplen; - } else { - getquery->condition = NULL; - getquery->condlen = 0; - } - return getquery; -} - -void free_get_query(DavGetQuery *q) { - free(q->from.ptr); - free(q->properties.ptr); - free(q); -} - -int parse_path_query(sstr_t query, char **path, int *depth) { - if(query.length == 1) { - if(query.ptr[0] == '/') { - *path = sstrdup(query).ptr; - *depth = 1; - return 0; - } else { - *path = NULL; - return 1; - } - } - - if(query.ptr[query.length-1] == '*') { - *depth = -1; - *path = sstrdup(sstrsubsl(query, 0, query.length-1)).ptr; - } else { - *path = sstrdup(query).ptr; - *depth = 1; - } - - return 0; -} - -int dav_parse_condition(UcxList **ops, sstr_t cond, va_list ap) { - sstr_t token; - DavQOp *op1 = NULL; // level 1 operator - DavQOp *op2 = NULL; // level 2 operator - DavQOp *op3 = NULL; // level 3 operator - while((token = condition_parser_next_token(&cond)).length > 0) { - //printf("token: {%.*s}[%d]\n", token.length, token.ptr, token.length); - int64_t type = 0; - int tkop = condition_operator_type(token, &type); - DavQOp *operation = malloc(sizeof(DavQOp)); - if(tkop > 0) { - // operator token - operation->type = DAVQOP_OPERATOR; - operation->val = NULL; - operation->intval = type; - switch(tkop) { - case 1: { - // operators: + - / * not - // add operation after next non operator token - op1 = operation; - break; - } - case 2: { - // operators: < > == != <= >= - if(op2) { - *ops = ucx_list_append(*ops, op2); - } - op2 = operation; - break; - } - case 3: { - // operators: and or xor - if(op2) { - *ops = ucx_list_append(*ops, op2); - op2 = NULL; - } - if(op3) { - *ops = ucx_list_append(*ops, op3); - } - op3 = operation; - break; - } - } - } else { - if(token.ptr[0] == '"' || token.ptr[0] == '\'') { - operation->type = DAVQOP_STRING; - operation->val = token.ptr+1; - operation->intval = token.length-2; - } else if(!sstrcmp(token, S("true")) || - !sstrcmp(token, S("false"))) - { - operation->type = DAVQOP_INTEGER; - operation->val = NULL; - operation->intval = util_getboolean(token.ptr); - } else if(token.length == 2 && token.ptr[0] == '%') { - switch(token.ptr[1]) { - case 's': { - char *arg = va_arg(ap, char*); - operation->type = DAVQOP_STRING; - operation->val = arg; - operation->intval = strlen(arg); - break; - } - case 'd': { - operation->type = DAVQOP_INTEGER; - operation->val = NULL; - operation->intval = va_arg(ap, int); - break; - } - case 't': { - operation->type = DAVQOP_INTEGER; - operation->val = NULL; - operation->intval = va_arg(ap, time_t); - break; - } - default: { - operation->type = DAVQOP_STRING; - operation->val = token.ptr; - operation->intval = token.length; - } - } - } else { - sstr_t d = sstrdup(token); - char *end; - int64_t val = strtoll(d.ptr, &end, 0); - int intval = strlen(end) == 0 ? 1 : 0; - free(d.ptr); - if(intval) { - operation->type = DAVQOP_INTEGER; - operation->val = NULL; - operation->intval = val; - } else { - if(!sstrcmp(token, S("contentlength"))) { - operation->type = DAVQOP_RESPROP; - } else if(!sstrcmp(token, S("lastmodified"))) { - operation->type = DAVQOP_RESPROP; - } else if(!sstrcmp(token, S("creationdate"))) { - operation->type = DAVQOP_RESPROP; - } else if(!sstrcmp(token, S("name"))) { - operation->type = DAVQOP_RESPROP; - } else if(!sstrcmp(token, S("path"))) { - operation->type = DAVQOP_RESPROP; - } else if(!sstrcmp(token, S("iscollection"))) { - operation->type = DAVQOP_RESPROP; - } else { - operation->type = DAVQOP_PROPERTY; - } - operation->val = token.ptr; - operation->intval = token.length; - } - } - - // add operation - *ops = ucx_list_append(*ops, operation); - if(op1) { - // add level 1 operator - *ops = ucx_list_append(*ops, op1); - op1 = NULL; - } - } - } - if(op1) { - *ops = ucx_list_append(*ops, op1); - } - if(op2) { - *ops = ucx_list_append(*ops, op2); - } - if(op3) { - *ops = ucx_list_append(*ops, op3); - } - return 0; -} - -sstr_t condition_parser_next_token(sstr_t *str) { - sstr_t s = *str; - sstr_t t; - t.ptr = NULL; - t.length = 0; - // remove leading space - int i; - for(i=0;i<s.length;i++) { - if(s.ptr[i] > 32) { - break; - } - } - s.length -= i; - s.ptr += i; - - if(s.length == 0) { - *str = s; - return t; - } - - // check for single char operators - switch(s.ptr[0]) { - case '<': - case '>': - case '+': - case '-': - case '*': - case '/': { - t.ptr = s.ptr; - t.length = 1; - str->ptr = s.ptr + 1; - str->length = s.length - 1; - return t; - } - } - - if(s.length > 1) { - // check for double char operators - int16_t op = *(int16_t*)s.ptr; - if(op == '==' || op == '!=' || op == '>=' || op == '=<') { - t.ptr = s.ptr; - t.length = 2; - str->ptr = s.ptr + 2; - str->length = s.length - 2; - return t; - } - } else { - t.ptr = s.ptr; - t.length = 1; - str->ptr = s.ptr + 1; - str->length = s.length - 1; - return t; - } - - // TODO: brackets - - // check for string literal - if(s.ptr[0] == '\'' || s.ptr[0] == '"') { - for(i=1;i<s.length;i++) { - if(s.ptr[0] == s.ptr[i]) { - i++; - break; - } - } - t.ptr = s.ptr; - t.length = i; - str->ptr = s.ptr + i; - str->length = s.length - i; - return t; - } - - for(i=0;i<s.length;i++) { - char c = s.ptr[i]; - if((c < 33) || (c > 41 && c < 48) || (c > 59 && c < 63)) { - break; - } - } - t.ptr = s.ptr; - t.length = i; - str->ptr = s.ptr + i; - str->length = s.length - i; - return t; -} - -int condition_operator_type(sstr_t token, int64_t *type) { - // returns the operator level and sets the type - - if(token.ptr[0] == '"' || token.ptr[0] == '\'' || token.ptr[0] == '(') { - return 0; - } - - if(token.length == 1) { - switch(token.ptr[0]) { - case '+': *type = 1; return 1; - case '-': *type = 2; return 1; - case '*': *type = 3; return 1; - case '/': *type = 4; return 1; - case '<': *type = 5; return 2; - case '>': *type = 6; return 2; - } - } - if(!sstrcmp(token, S("not"))) { - *type = 0; - return 1; - } - - if(!sstrcmp(token, S("=="))) { - *type = 7; - return 2; - } - if(!sstrcmp(token, S("!="))) { - *type = 8; - return 2; - } - if(!sstrcmp(token, S("<="))) { - *type = 9; - return 2; - } - if(!sstrcmp(token, S(">="))) { - *type = 10; - return 2; - } - - if(!sstrcmp(token, S("and"))) { - *type = 11; - return 3; - } - if(!sstrcmp(token, S("or"))) { - *type = 12; - return 3; - } - if(!sstrcmp(token, S("xor"))) { - *type = 13; - return 3; - } - - return 0; -} - -int condition_eval(DavResource *res, DavQOp *cond, size_t len) { - DavQOp stack[128]; - int stackpos = 0; - for(int i=0;i<len;i++) { - DavQOp op = cond[i]; - switch(op.type) { - case DAVQOP_OPERATOR: { - if(op.intval == 0) { - // not operator - if(stackpos < 1) { - // error - printf("no data on stack\n"); - return 0; - } - int pos = stackpos-1; - if(stack[pos].type == DAVQOP_INTEGER) { - //printf("not %" PRId64 "\n", stack[pos].intval); - stack[pos].intval = !stack[pos].intval; - } else { - // error - printf("wrong value for 'not' operator\n"); - return 0; - } - } else { - DavQOp val1 = stack[stackpos-2]; - DavQOp val2 = stack[stackpos-1]; - DavQOp result; - if(val1.type == DAVQOP_INTEGER) { - if(val2.type == DAVQOP_INTEGER) { - result = compare_intint( - op.intval, - val1.intval, - val2.intval); - } else { - result = compare_intstr(op.intval, val1, val2); - } - } else { - if(val2.type == DAVQOP_INTEGER) { - result = compare_strint(op.intval, val1, val2); - } else { - result = compare_strstr(op.intval, val1, val2); - } - } - stack[stackpos-2] = result; - stackpos--; - } - break; - } - case DAVQOP_STRING: - case DAVQOP_INTEGER: - case DAVQOP_TIME: { - if(op.type == DAVQOP_STRING) { - //printf("put on stack: '%s'\n", op.val); - } else { - //printf("put on stack[%d]: %" PRId64 "\n", stackpos, op.intval); - } - stack[stackpos++] = op; - break; - } - case DAVQOP_PROPERTY: { - sstr_t pname = sstrn(op.val, op.intval); - pname = sstrdup(pname); - char *property_value = dav_get_property(res, pname.ptr); - free(pname.ptr); - DavQOp value; - value.type = DAVQOP_STRING; - if(property_value) { - //printf("put on stack: \"%s\"\n", property_value); - value.val = property_value; - value.intval = strlen(property_value); - } else { - //printf("put on stack: null string\n"); - value.val = NULL; - value.intval = 0; - } - stack[stackpos++] = value; - break; - } - case DAVQOP_RESPROP: { - sstr_t name = sstrn(op.val, op.intval); - DavQOp value; - value.type = DAVQOP_INTEGER; - value.val = NULL; - if(!sstrcmp(name, S("contentlength"))) { - //printf("put contentlength\n"); - value.intval = res->contentlength; - } else if(!sstrcmp(name, S("lastmodified"))) { - //printf("put getlastmodified\n"); - value.intval = res->lastmodified; - } else if(!sstrcmp(name, S("creationdate"))) { - value.intval = res->creationdate; - } else if(!sstrcmp(name, S("name"))) { - value.type = DAVQOP_STRING; - value.val = res->name; - value.intval = strlen(res->name); - } else if(!sstrcmp(name, S("path"))) { - value.type = DAVQOP_STRING; - value.val = res->path; - value.intval = strlen(res->path); - } else if(!sstrcmp(name, S("iscollection"))) { - value.type = DAVQOP_INTEGER; - value.val = NULL; - value.intval = res->iscollection; - } - stack[stackpos++] = value; - break; - } - } - } - if(stackpos != 1) { - return 0; - } - DavQOp result = stack[0]; - //printf("result: %" PRId64 "\n", result.intval); - return (int)result.intval; -} - -DavQOp compare_intint(int op, int64_t v1, int64_t v2) { - DavQOp res; - res.type = DAVQOP_INTEGER; - res.val = NULL; - res.intval = 0; - switch(op) { - case 5: { - // < - //printf("compare: %" PRId64 " < %" PRId64 "\n", v1, v2); - res.intval = v1 < v2; - break; - } - case 6: { - // > - //printf("compare: %" PRId64 " > %" PRId64 "\n", v1, v2); - res.intval = v1 > v2; - break; - } - case 7: { - // == - //printf("compare: %" PRId64 " == %" PRId64 "\n", v1, v2); - res.intval = v1 == v2; - break; - } - case 8: { - // != - //printf("compare: %" PRId64 " != %" PRId64 "\n", v1, v2); - res.intval = v1 != v2; - break; - } - case 9: { - // <= - //printf("compare: %" PRId64 " <= %" PRId64 "\n", v1, v2); - res.intval = v1 <= v2; - break; - } - case 10: { - // >= - //printf("compare: %" PRId64 " >= %" PRId64 "\n", v1, v2); - res.intval = v1 >= v2; - break; - } - case 11: { - // and - //printf("compare: %" PRId64 " and %" PRId64 "\n", v1, v2); - res.intval = v1 && v2; - break; - } - case 12: { - // or - //printf("compare: %" PRId64 " or %" PRId64 "\n", v1, v2); - res.intval = v1 || v2; - break; - } - case 13: { - // xor - //printf("compare: %" PRId64 " xor %" PRId64 "\n", v1, v2); - res.intval = v1 ^ v2; - break; - } - } - return res; -} - -DavQOp compare_strint(int op, DavQOp v1, DavQOp v2) { - // TODO -} - -DavQOp compare_intstr(int op, DavQOp v1, DavQOp v2) { - // TODO -} - -DavQOp compare_strstr(int op, DavQOp v1, DavQOp v2) { - DavQOp res; - res.type = DAVQOP_INTEGER; - res.val = NULL; - res.intval = 0; - sstr_t s1 = sstrn(v1.val, v1.intval); - sstr_t s2 = sstrn(v2.val, v2.intval); - switch(op) { - case 5: { - // < - //printf("str compare: %.*s < %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = s1.length < s2.length; - break; - } - case 6: { - // > - //printf("str compare: %.*s > %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = s1.length > s2.length; - break; - } - case 7: { - // == - //printf("str compare: %.*s == %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = sstrcmp(s1, s2) == 0; - break; - } - case 8: { - // != - //printf("str compare: %.*s != %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = sstrcmp(s1, s2) != 0; - break; - } - case 9: { - // <= - //printf("str compare: %.*s <= %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = s1.length <= s2.length; - break; - } - case 10: { - // >= - //printf("str compare: %.*s >= %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = s1.length >= s2.length; - break; - } - case 11: { - // and - //printf("str compare: %.*s and %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = s1.ptr && s2.ptr; - break; - } - case 12: { - // or - //printf("str compare: %.*s or %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = s1.ptr || s2.ptr; - break; - } - case 13: { - // xor - //printf("str compare: %.*s xor %.*s\n", s1.length, s1.ptr, s2.length, s2.ptr); - res.intval = (intptr_t)s1.ptr ^ (intptr_t)s2.ptr; - break; - } - } - return res; -}
--- a/dav/davql.h Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * 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 "webdav.h" - -#ifndef DAVQL_H -#define DAVQL_H - -#include <ucx/string.h> -#include <ucx/list.h> -#include <inttypes.h> -#include <stdarg.h> - -#ifdef __cplusplus -extern "C" { -#endif - -enum DavQueryType { - DAV_QUERY_ERROR = 0, - DAV_QUERY_GET -}; -typedef enum DavQueryType DavQueryType; - -#define DAVQOP_OPERATOR 0 -#define DAVQOP_STRING 1 -#define DAVQOP_INTEGER 2 -#define DAVQOP_TIME 3 -#define DAVQOP_PROPERTY 4 -#define DAVQOP_RESPROP 5 - -typedef struct { - int type; - void *val; - int64_t intval; -} DavQOp; - -typedef struct { - DavQueryType command; - void *command_data; -} DavQuery; - -typedef struct { - sstr_t properties; - sstr_t from; - DavQOp *condition; - size_t condlen; -} DavGetQuery; - -DavQuery dav_ql_parse(char *query, va_list ap); -DavGetQuery* dav_ql_parse_get(sstr_t q, va_list ap); -void free_get_query(DavGetQuery *q); - -int parse_path_query(sstr_t query, char **path, int *depth); - -int dav_parse_condition(UcxList **ops, sstr_t cond, va_list ap); -sstr_t condition_parser_next_token(sstr_t *str); -int condition_operator_type(sstr_t token, int64_t *type); - -int condition_eval(DavResource *res, DavQOp *cond, size_t len); -DavQOp compare_intint(int op, int64_t v1, int64_t v2); -DavQOp compare_strint(int op, DavQOp v1, DavQOp v2); -DavQOp compare_intstr(int op, DavQOp v1, DavQOp v2); -DavQOp compare_strstr(int op, DavQOp v1, DavQOp v2); - -#ifdef __cplusplus -} -#endif - -#endif /* DAVQL_H */ -
--- a/dav/main.c Mon Aug 26 14:42:09 2013 +0200 +++ b/dav/main.c Mon Aug 26 14:44:21 2013 +0200 @@ -50,28 +50,20 @@ } int main(int argc, char **argv) { - - char *xargv[4]; - xargv[0] = "dav"; - xargv[1] = "put"; - xargv[2] = "sunfire"; - xargv[3] = "config.xml"; - int xargc = 4; - xmlGenericErrorFunc fnc = xmlerrorfnc; initGenericErrorDefaultFunc(&fnc); load_config(); ctx = dav_context_new(); dav_add_namespace(ctx, "U", "http://www.uap-core.de/"); - if(xargc < 2) { + if(argc < 2) { fprintf(stderr, "Missing command\n"); print_usage(argv[0]); return -1; } - char *cmd = xargv[1]; - CmdArgs *args = cmd_parse_args(xargc - 2, xargv + 2); + char *cmd = argv[1]; + CmdArgs *args = cmd_parse_args(argc - 2, argv + 2); if(!args) { print_usage(argv[0]); return -1;
--- a/dav/methods.c Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,518 +0,0 @@ -/* - * 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 "utils.h" -#include "methods.h" -#include "davql.h" - -#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) - -/* ----------------------------- PROPFIND ----------------------------- */ - -CURLcode do_propfind_request( - CURL *handle, - UcxBuffer *request, - UcxBuffer *response) -{ - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPFIND"); - - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Content-Type: text/xml"); - headers = curl_slist_append(headers, "Depth: 1"); - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); - - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); - curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read); - curl_easy_setopt(handle, CURLOPT_READDATA, request); - curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - - ucx_buffer_seek(request, 0, SEEK_SET); - return curl_easy_perform(handle); -} - -UcxBuffer* create_allprop_propfind_request() { - UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); - sstr_t s; - - s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - s = S("<D:propfind xmlns:D=\"DAV:\">\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - s = S("<D:allprop/></D:propfind>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - return buf; -} - -UcxBuffer* create_propfind_request(UcxList *properties) { - UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); - sstr_t s; - - UcxMap *namespaces = ucx_map_new(8); - UCX_FOREACH(elm, properties) { - DavProperty *p = elm->data; - if(strcmp(p->ns->name, "DAV:")) { - ucx_map_cstr_put(namespaces, p->ns->prefix, p->ns); - } - } - - s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - // write root element and namespaces - s = S("<D:propfind xmlns:D=\"DAV:\""); - ucx_buffer_write(s.ptr, 1, s.length, buf); - UcxMapIterator mapi = ucx_map_iterator(namespaces); - UcxKey key; - DavNamespace *ns; - UCX_MAP_FOREACH(key, ns, mapi) { - s = S(" xmlns:"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(ns->prefix); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S("=\""); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(ns->name); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S("\""); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - s = S(">\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - // default properties - s = S("<D:prop>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - s = S("<D:creationdate />\n<D:getlastmodified />\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - s = S("<D:getcontentlength />\n<D:getcontenttype />\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - s = S("<D:resourcetype />\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - // extra properties - UCX_FOREACH(elm, properties) { - DavProperty *prop = elm->data; - s = S("<"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prop->ns->prefix); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prop->name); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(" />\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - - // end - s = S("</D:prop>\n</D:propfind>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - return buf; -} - -DavResource* parse_propfind_response(DavSession *sn, DavResource *root, UcxBuffer *response, DavQOp *cond, size_t len) { - char *url = NULL; - curl_easy_getinfo(sn->handle, CURLINFO_EFFECTIVE_URL, &url); - if(!root) { - root = resource_new_href(sn, util_url_path(url)); - } - - xmlDoc *doc = xmlReadMemory(response->space, response->size, url, NULL, 0); - if(!doc) { - // TODO: free stuff - sn->error = DAV_ERROR; - return NULL; - } - - xmlNode *xml_root = xmlDocGetRootElement(doc); - xmlNode *node = xml_root->children; - while(node) { - if(node->type == XML_ELEMENT_NODE) { - if(xstreq(node->name, "response")) { - parse_response_tag(root, node, cond, len); - } - } - - node = node->next; - } - - return root; -} - -int parse_response_tag(DavResource *resource, xmlNode *node, DavQOp *cond, size_t clen) { - DavResource *res = resource; - node = node->children; - while(node) { - if(node->type == XML_ELEMENT_NODE) { - if(xstreq(node->name, "href")) { - xmlNode *href_content = node->children; - if(href_content->type != XML_TEXT_NODE) { - // error - resource->session->error = DAV_ERROR; - return 1; - } - if(xstreq(resource->href, href_content->content)) { - res = resource; - } else { - res = resource_new_href(resource->session, (char*)href_content->content); - res->parent = resource; - } - } else if(xstreq(node->name, "propstat")) { - xmlNode *n = node->children; - xmlNode *prop_node = NULL; - int ok = 0; - // get the status code - while(n) { - if(n->type == XML_ELEMENT_NODE) { - if(xstreq(n->name, "prop")) { - prop_node = n; - } else if(xstreq(n->name, "status")) { - xmlNode *status_node = n->children; - if(status_node->type != XML_TEXT_NODE) { - resource->session->error = DAV_ERROR; - return 1; - } - sstr_t status_str = sstr((char*)status_node->content); - if(status_str.length < 13) { - resource->session->error = DAV_ERROR; - return 1; - } - status_str = sstrsubsl(status_str, 9, 3); - if(!sstrcmp(status_str, S("200"))) { - ok = 1; - } - } - } - n = n->next; - } - // if status is ok, get all properties - if(ok) { - n = prop_node->children; - while(n) { - if(n->type == XML_ELEMENT_NODE) { - if(xstreq(n->name, "resourcetype")) { - xmlNode *rsnode = n->children; - if(rsnode && rsnode->type == XML_ELEMENT_NODE) { - // TODO: this is a ugly lazy hack - resource_add_property(res, "DAV:", (char*)n->name, "collection"); - res->iscollection = 1; - } - } else { - xmlNode *content = n->children; - if(content) { - resource_add_property( - res, - (char*)n->ns->href, - (char*)n->name, - (char*)content->content); - } - } - } - n = n->next; - } - } - } - } - - node = node->next; - } - - set_davprops(res); - if(res != resource) { - if(clen > 0) { - if(!condition_eval(res, cond, clen)) { - // skip resource - return 0; - } - } - resource_add_child(resource, res); - } - - return 0; -} - -void set_davprops(DavResource *res) { - char *cl = dav_get_property_ns(res, "DAV:", "getcontentlength"); - char *ct = dav_get_property_ns(res, "DAV:", "getcontenttype"); - char *cd = dav_get_property_ns(res, "DAV:", "creationdate"); - char *lm = dav_get_property_ns(res, "DAV:", "getlastmodified"); - - res->contenttype = ct; - if(cl) { - char *end = NULL; - res->contentlength = strtoull(cl, &end, 0); - } - res->creationdate = util_parse_creationdate(cd); - res->lastmodified = util_parse_lastmodified(lm); -} - - -/* ----------------------------- PROPPATCH ----------------------------- */ - -CURLcode do_proppatch_request( - CURL *handle, - UcxBuffer *request, - UcxBuffer *response) -{ - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPPATCH"); - - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Content-Type: text/xml"); - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); - - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); - curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read); - curl_easy_setopt(handle, CURLOPT_READDATA, request); - curl_easy_setopt(handle, CURLOPT_INFILESIZE, request->size); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - - ucx_buffer_seek(request, 0, SEEK_SET); - return curl_easy_perform(handle); -} - -UcxBuffer* create_proppatch_request(DavNodeData *data) { - UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); - sstr_t s; - - UcxMap *namespaces = ucx_map_new(8); - char prefix[8]; - int pfxnum = 0; - UCX_FOREACH(elm, data->set) { - DavProperty *p = elm->data; - if(strcmp(p->ns->name, "DAV:")) { - snprintf(prefix, 8, "x%d\0", pfxnum++); - ucx_map_cstr_put(namespaces, p->ns->name, prefix); - } - } - UCX_FOREACH(elm, data->remove) { - DavProperty *p = elm->data; - if(strcmp(p->ns->name, "DAV:")) { - snprintf(prefix, 8, "x%d\0", pfxnum++); - ucx_map_cstr_put(namespaces, p->ns->name, prefix); - } - } - - s = S("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - // write root element and namespaces - s = S("<D:propertyupdate xmlns:D=\"DAV:\""); - ucx_buffer_write(s.ptr, 1, s.length, buf); - UcxMapIterator mapi = ucx_map_iterator(namespaces); - UcxKey key; - char *pfxval; - UCX_MAP_FOREACH(key, pfxval, mapi) { - s = S(" xmlns:"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(pfxval); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S("=\""); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstrn(key.data, key.len); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S("\""); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - s = S(">\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - if(data->set) { - s = S("<D:set>\n<D:prop>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - UCX_FOREACH(elm, data->set) { - DavProperty *property = elm->data; - char *prefix = ucx_map_cstr_get(namespaces, property->ns->name); - - s = S("<"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prefix); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->name); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(">"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->value); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S("</"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prefix); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->name); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(">\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - s = S("</D:prop>\n</D:set>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - if(data->remove) { - s = S("<D:set>\n<D:prop>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - UCX_FOREACH(elm, data->set) { - DavProperty *property = elm->data; - char *prefix = ucx_map_cstr_get(namespaces, property->ns->name); - - s = S("<"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prefix); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->name); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(">"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->value); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S("</"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(prefix); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(":"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = sstr(property->name); - ucx_buffer_write(s.ptr, 1, s.length, buf); - s = S(">\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - s = S("</D:prop>\n</D:set>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - } - - s = S("</D:propertyupdate>\n"); - ucx_buffer_write(s.ptr, 1, s.length, buf); - - return buf; -} - -/* ----------------------------- PUT ----------------------------- */ - -static size_t dummy_write(void *buf, size_t s, size_t n, void *data) { - return s*n; -} - -CURLcode do_put_request(CURL *handle, void *data, dav_read_func read_func, size_t length) { - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, NULL); - curl_easy_setopt(handle, CURLOPT_PUT, 1L); - curl_easy_setopt(handle, CURLOPT_UPLOAD, 1L); - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - UcxBuffer *buf = NULL; - if(!read_func) { - buf = ucx_buffer_new(data, length, 0); - buf->size = length; - data = buf; - read_func = (dav_read_func)ucx_buffer_read; - curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); - } else if(length == 0) { - struct curl_slist *headers = NULL; - headers = curl_slist_append(headers, "Transfer-Encoding: chunked"); - curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)1); - curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); - } else { - curl_easy_setopt(handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)length); - } - - curl_easy_setopt(handle, CURLOPT_READFUNCTION, read_func); - curl_easy_setopt(handle, CURLOPT_READDATA, data); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); - - CURLcode ret = curl_easy_perform(handle); - if(buf) { - ucx_buffer_free(buf); - } - return ret; -} - -CURLcode do_delete_request(CURL *handle, UcxBuffer *response) { - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "DELETE"); - curl_easy_setopt(handle, CURLOPT_PUT, 0L); - curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, response); - - CURLcode ret = curl_easy_perform(handle); - return ret; -} - -CURLcode do_mkcol_request(CURL *handle) { - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "MKCOL"); - curl_easy_setopt(handle, CURLOPT_PUT, 0L); - curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); - - CURLcode ret = curl_easy_perform(handle); - return ret; -} - - -CURLcode do_head_request(CURL *handle) { - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "HEAD"); - curl_easy_setopt(handle, CURLOPT_PUT, 0L); - curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(handle, CURLOPT_NOBODY, 1L); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, dummy_write); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, NULL); - - CURLcode ret = curl_easy_perform(handle); - curl_easy_setopt(handle, CURLOPT_NOBODY, 0L); - return ret; -}
--- a/dav/methods.h Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/* - * 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. - */ - -#ifndef METHODS_H -#define METHODS_H - -#include "webdav.h" - -#ifdef __cplusplus -extern "C" { -#endif - -CURLcode do_propfind_request( - CURL *handle, - UcxBuffer *request, - UcxBuffer *response); - -CURLcode do_proppatch_request( - CURL *handle, - UcxBuffer *request, - UcxBuffer *response); - -CURLcode do_put_request( - CURL *handle, - void *data, - dav_read_func read_func, - size_t length); - -UcxBuffer* create_allprop_propfind_request(); -UcxBuffer* create_propfind_request(UcxList *properties); -DavResource* parse_propfind_response(DavSession *sn, DavResource *root, UcxBuffer *response, DavQOp *cond, size_t len); -int parse_response_tag(DavResource *resource, xmlNode *node, DavQOp *cond, size_t len); -void set_davprops(DavResource *res); - -UcxBuffer* create_proppatch_request(DavNodeData *data); - -CURLcode do_delete_request(CURL *handle, UcxBuffer *response); - -CURLcode do_mkcol_request(CURL *handle); - -CURLcode do_head_request(CURL *handle); - -#ifdef __cplusplus -} -#endif - -#endif /* METHODS_H */ -
--- a/dav/utils.c Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,248 +0,0 @@ -/* - * 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 <time.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ucx/string.h> -#include <libxml/tree.h> -#include <curl/curl.h> - -#include <openssl/sha.h> -#include <openssl/hmac.h> -#include <openssl/evp.h> -#include <openssl/bio.h> -#include <openssl/buffer.h> - -#include "utils.h" - - -time_t util_parse_creationdate(char *str) { - // example: 2012-11-29T21:35:35Z - if(!str) { - return 0; - } - // TODO - return 0; -} - -time_t util_parse_lastmodified(char *str) { - // example: Thu, 29 Nov 2012 21:35:35 GMT - if(!str) { - return 0; - } else { - return curl_getdate(str, NULL); - } -} - -int util_getboolean(char *v) { - if(v[0] == 'T' || v[0] == 't') { - return 1; - } - return 0; -} - -char* util_url_path(char *url) { - char *path = NULL; - size_t len = strlen(url); - int slashcount = 0; - int slmax; - if(len > 7 && !strncasecmp(url, "http://", 7)) { - slmax = 3; - } else if(len > 8 && !strncasecmp(url, "https://", 8)) { - slmax = 3; - } else { - slmax = 1; - } - char c; - for(int i=0;i<len;i++) { - c = url[i]; - if(c == '/') { - slashcount++; - if(slashcount == slmax) { - path = url + i; - break; - } - } - } - return path; -} - -char* util_resource_name(char *url) { - int si = 0; - int osi = 0; - int i = 0; - int p = 0; - char c; - while((c = url[i]) != 0) { - if(c == '/') { - osi = si; - si = i; - p = 1; - } - i++; - } - - char *name = url + si + p; - if(name[0] == 0) { - name = url + osi + p; - if(name[0] == 0) { - return url; - } - } - - return name; -} - -int util_mkdir(char *path, mode_t mode) { -#ifdef _WIN32 - return mkdir(path); -#else - return mkdir(path, mode); -#endif -} - -char* util_concat_path(char *url_base, char *p) { - sstr_t base = sstr(url_base); - sstr_t path; - if(p) { - path = sstr(p); - } else { - path = sstrn("", 0); - } - - int add_separator = 0; - if(base.ptr[base.length-1] == '/') { - if(path.ptr[0] == '/') { - base.length--; - } - } else { - if(path.length == 0 || path.ptr[0] != '/') { - add_separator = 1; - } - } - - sstr_t url; - url.length = base.length + path.length + add_separator; - url.ptr = malloc(url.length + 1); - url.ptr[url.length] = '\0'; - - if(add_separator) { - url = sstrncat(url, 3, base, sstr("/"), path); - } else { - url = sstrncat(url, 2, base, path); - } - - return url.ptr; -} - -char* util_parent_path(char *path) { - char *name = util_resource_name(path); - size_t namelen = strlen(name); - size_t pathlen = strlen(path); - size_t parentlen = pathlen - namelen; - char *parent = malloc(parentlen + 1); - memcpy(parent, path, parentlen); - parent[parentlen] = '\0'; - return parent; -} - - -char* util_xml_get_text(xmlNode *elm) { - xmlNode *node = elm->children; - while(node) { - if(node->type == XML_TEXT_NODE) { - return (char*)node->content; - } - node = node->next; - } - return NULL; -} - - - -char* util_base64decode(char* in) { - size_t len = strlen(in); - char *out = calloc(1, len); - - BIO* b = BIO_new_mem_buf(in, len); - BIO *d = BIO_new(BIO_f_base64()); - BIO_set_flags(d, BIO_FLAGS_BASE64_NO_NL); - b = BIO_push(d, b); - - BIO_read(b, out, len); - BIO_free_all(b); - - return out; -} - -/* - * gets a substring from 0 to the appearance of the token - * tokens are separated by space - * sets sub to the substring and returns the remaining string - */ -sstr_t util_getsubstr_until_token(sstr_t str, sstr_t token, sstr_t *sub) { - int i; - int token_start = -1; - int token_end = -1; - for(i=0;i<=str.length;i++) { - int c; - if(i == str.length) { - c = ' '; - } else { - c = str.ptr[i]; - } - if(c < 33) { - if(token_start != -1) { - token_end = i; - size_t len = token_end - token_start; - sstr_t tk = sstrsubsl(str, token_start, len); - //printf("token: {%.*s}\n", token.length, token.ptr); - if(!sstrcmp(tk, token)) { - *sub = sstrtrim(sstrsubsl(str, 0, token_start)); - break; - } - token_start = -1; - token_end = -1; - } - } else { - if(token_start == -1) { - token_start = i; - } - } - } - - if(i < str.length) { - return sstrtrim(sstrsubs(str, i)); - } else { - str.ptr = NULL; - str.length = 0; - return str; - } -}
--- a/dav/utils.h Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,75 +0,0 @@ -/* - * 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. - */ - -#ifndef UTILS_H -#define UTILS_H - -#include <sys/types.h> -#include <libxml/tree.h> -#include <ucx/string.h> -#include <sys/stat.h> -#ifdef _WIN32 -#include <io.h> -#define S_IRWXG 070 -#define S_IRGRP 040 -#define S_IWGRP 020 -#define S_IXGRP 010 -#define S_IRWXO 07 -#define S_IROTH 04 -#define S_IWOTH 02 -#define S_IXOTH 01 -#endif /* _WIN32 */ - -#ifdef __cplusplus -extern "C" { -#endif - -time_t util_parse_creationdate(char *str); -time_t util_parse_lastmodified(char *str); - -int util_mkdir(char *path, mode_t mode); - -char* util_url_path(char *url); -char* util_resource_name(char *url); -char* util_concat_path(char *url_base, char *path); -char* util_parent_path(char *path); - -int util_getboolean(char *v); - -char* util_xml_get_text(xmlNode *elm); - -char* util_base64decode(char* in); - -sstr_t util_getsubstr_until_token(sstr_t str, sstr_t token, sstr_t *sub); - -#ifdef __cplusplus -} -#endif - -#endif /* UTILS_H */ -
--- a/dav/webdav.c Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,831 +0,0 @@ -/* - * 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 "methods.h" -#include "davql.h" -#include "ucx/buffer.h" -#include "ucx/utils.h" - -#define xstreq(a,b) xmlStrEqual(BAD_CAST a, BAD_CAST b) - -DavContext* dav_context_new() { - DavContext *context = malloc(sizeof(DavContext)); - if(!context) { - return NULL; - } - context->sessions = NULL; - context->namespaces = ucx_map_new(16); - context->http_proxy = NULL; - context->https_proxy = NULL; - context->no_proxy = NULL; - if(!context->namespaces) { - free(context); - return NULL; - } - 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; - } - - 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); - } - - UcxMapIterator i = ucx_map_iterator(ctx->namespaces); - UcxKey k; - DavNamespace *ns; - // TODO: free map elements - ucx_map_free(ctx->namespaces); - free(ctx); -} - -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); -} - -DavSession* dav_session_new(DavContext *context, char *base_url) { - if(!base_url) { - return NULL; - } - sstr_t url = sstr(base_url); - if(url.length == 0) { - return NULL; - } - DavSession *sn = malloc(sizeof(DavSession)); - sn->errorstr = NULL; - sn->error = DAV_OK; - if(url.ptr[url.length - 1] == '/') { - sn->base_url = strdup(base_url); - } else { - char *url_str = malloc(url.length + 2); - memcpy(url_str, base_url, url.length); - url_str[url.length] = '/'; - url_str[url.length + 1] = '\0'; - sn->base_url = url_str; - } - sn->context = context; - sn->handle = curl_easy_init(); - //curl_easy_setopt(sn->handle, CURLOPT_VERBOSE, 1L); - //curl_easy_setopt(sn->handle, CURLOPT_STDERR, stderr); - - // set proxy - if(sstrprefix(url, S("https"))) { - if(context->https_proxy) { - //printf("use https_proxy: %s\n", context->https_proxy); - curl_easy_setopt(sn->handle, CURLOPT_PROXY, context->https_proxy); - } - } else { - if(context->http_proxy) { - //printf("use http_proxy: %s\n", context->http_proxy); - curl_easy_setopt(sn->handle, CURLOPT_PROXY, context->http_proxy); - } - } - if(context->no_proxy) { - //printf("use no_proxy: %s\n", context->no_proxy); - curl_easy_setopt(sn->handle, CURLOPT_NOPROXY, context->no_proxy); - } - // set url - curl_easy_setopt(sn->handle, CURLOPT_URL, base_url); - - sn->mp = ucx_mempool_new(1024); - sn->allocator = ucx_mempool_allocator(sn->mp); - - context->sessions = ucx_list_append(context->sessions, sn); - - return sn; -} - -DavSession* dav_session_new_auth(DavContext *context, char *base_url, char *user, char *password) { - DavSession *sn = dav_session_new(context, base_url); - if(!sn) { - return NULL; - } - dav_session_set_auth(sn, user, password); - return sn; -} - -void dav_session_set_auth(DavSession *sn, char *user, char *password) { - if(user && password) { - size_t ulen = strlen(user); - size_t plen = strlen(password); - size_t upwdlen = ulen + plen + 2; - char *upwdbuf = malloc(upwdlen); - snprintf(upwdbuf, upwdlen, "%s:%s\0", user, password); - curl_easy_setopt(sn->handle, CURLOPT_USERPWD, upwdbuf); - free(upwdbuf); - } -} - -void session_set_error(DavSession *sn, CURLcode c, int status) { - if(status > 0) { - switch(status) { - default: sn->error = DAV_ERROR; break; - case 401: sn->error = DAV_UNAUTHORIZED; break; - case 403: sn->error = DAV_FORBIDDEN; break; - case 404: sn->error = DAV_NOT_FOUND; break; - case 405: sn->error = DAV_METHOD_NOT_ALLOWED; break; - case 409: sn->error = DAV_CONFLICT; break; - } - } else { - sn->error = DAV_ERROR; - } - if(c != CURLE_OK) { - sn->errorstr = curl_easy_strerror(c); - } else { - sn->errorstr = NULL; - } -} - -void dav_session_destroy(DavSession *sn) { - // remove session from context - UcxList *sessions = sn->context->sessions; - ssize_t i = ucx_list_find(sessions, sn, ucx_ptrcmp, NULL); - if(i > 0) { - UcxList *elm = ucx_list_get(sessions, i); - if(elm) { - sn->context->sessions = ucx_list_remove(sessions, elm); - } - } - - ucx_mempool_destroy(sn->mp); - curl_easy_cleanup(sn->handle); - free(sn->base_url); - free(sn); -} - -DavResource* dav_get(DavSession *sn, char *path, char *properties) { - char *url = util_concat_path(sn->base_url, path); - - CURL *handle = sn->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - UcxList *proplist = NULL; - if(properties) { - proplist = parse_properties_string(sn->context, sstr(properties)); - } - UcxBuffer *rqbuf = create_propfind_request(proplist); - UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - - //fwrite(rqbuf->space, 1, rqbuf->size, stdout); - //printf("\n"); - - DavResource *resource = NULL; - 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, NULL, rpbuf, NULL, 0); - sn->error = DAV_OK; - } else { - session_set_error(sn, ret, status); - } - return resource; -} - -DavResource* dav_propfind(DavSession *sn, DavResource *root, UcxBuffer *rqbuf, char *path, DavQOp *cond, size_t len) { - char *url = util_concat_path(sn->base_url, path); - CURL *handle = sn->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - DavResource *resource = root; - 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, cond, len); - sn->error = DAV_OK; - } else { - session_set_error(sn, ret, status); - resource = NULL; - } - ucx_buffer_free(rpbuf); - return resource; -} - -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_get2(DavSession *sn, DavGetQuery *query) { - char *path; - int depth = 0; - if(parse_path_query(query->from, &path, &depth)) { - sn->error = DAV_ERROR; - return NULL; - } - - 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(NULL); - } else { - UcxList *proplist = parse_properties_string(sn->context, ps); - rqbuf = create_propfind_request(proplist); - } - - //fwrite(rqbuf->space, 1, rqbuf->size, stdout); - //printf("\n"); - - DavResource *resource = dav_propfind(sn, NULL, rqbuf, path, query->condition, query->condlen); - free(path); - 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 - sr = dav_propfind(sn, sr, rqbuf, sr->path, query->condition, query->condlen); - if(!sr) { - error = 1; - printf("subrequest failed\n"); - break; - } - stack = propfind_stack_push(stack, sr->children); // add children - } - } - return resource; -} - -UcxList* parse_properties_string(DavContext *context, sstr_t str) { - UcxList *proplist = NULL; - size_t nprops; - 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 = sstrdup(sstrtrim(nspre)); - dp->ns = dav_get_namespace(context, pre.ptr); - free(pre.ptr); - 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_get2(sn, q.command_data); - free_get_query(q.command_data); - break; - } - } - return res; -} - - - -DavResource* dav_resource_new(DavSession *sn, char *path) { - char *url = util_concat_path(sn->base_url, path); - char *href = util_url_path(url); - DavResource *res = resource_new_href(sn, href); - free(url); - return res; -} - -DavResource* resource_new_href(DavSession *sn, char *href) { - UcxMempool *mp = sn->mp; - UcxAllocator *a = sn->allocator; - - DavResource *res = ucx_mempool_calloc(mp, 1, sizeof(DavResource)); - res->session = sn; - - // set name, path and href - resource_set_info(res, href); - - // initialize node data - res->data = node_data_new(sn); - - return res; -} - -void resource_add_property(DavResource *res, char *ns, char *name, char *value) { - if(!value) { - return; - } - UcxMempool *mp = res->session->mp; - UcxAllocator *a = res->session->allocator; - - UcxKey key = dav_property_key(ns, name); - sstr_t v = sstrdup_a(a, sstr(value)); - ucx_map_put(res->data->properties, key, v.ptr); - free(key.data); -} - -char* resource_get_property(DavResource *res, char *ns, char *name) { - UcxKey key = dav_property_key(ns, name); - return ucx_map_get(res->data->properties, key); -} - -UcxKey dav_property_key(char *ns, char *name) { - sstr_t ns_str = sstr(ns); - sstr_t name_str = sstr(name); - - sstr_t key; - key.length = ns_str.length + name_str.length + 1; - key.ptr = malloc(key.length + 1); - key = sstrncat(key, 3, ns_str, S(" "), name_str); - - return ucx_key(key.ptr, key.length); -} - -void resource_add_child(DavResource *parent, DavResource *child) { - child->next = NULL; - if(parent->children) { - DavResource *last = parent->children; - while(last->next) { - last = last->next; - } - last->next = child; - child->prev = last; - } else { - child->prev = NULL; - parent->children = child; - } - child->parent = parent; -} - -void resource_set_info(DavResource *res, char *href_str) { - char *url_str = NULL; - curl_easy_getinfo(res->session->handle, CURLINFO_EFFECTIVE_URL, &url_str); - sstr_t name = sstr(util_resource_name(href_str)); - sstr_t href = sstr(href_str); - - sstr_t base_href = sstr(util_url_path(res->session->base_url)); - sstr_t path = sstrsubs(href, base_href.length - 1); - - UcxAllocator *a = res->session->allocator; - res->name = sstrdup_a(a, name).ptr; - res->href = sstrdup_a(a, href).ptr; - res->path = sstrdup_a(a, path).ptr; -} - -DavNodeData* node_data_new(DavSession *sn) { - DavNodeData *data = ucx_mempool_malloc(sn->mp, sizeof(DavNodeData)); - if(!data) { - return NULL; - } - data->properties = ucx_map_new_a(sn->allocator, 32); - data->set = NULL; - data->remove = NULL; - data->content = NULL; - data->read = NULL; - data->length = 0; - return data; -} - -int dav_load(DavResource *res) { - DavSession *sn = res->session; - // clean map - UcxKey key; - void *value; - UcxMapIterator i = ucx_map_iterator(res->data->properties); - UCX_MAP_FOREACH(key, value, i) { - ucx_map_remove(res->data->properties, key); - } - - char *url = util_concat_path(sn->base_url, res->path); - - CURL *handle = sn->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - UcxBuffer *rqbuf = create_allprop_propfind_request(); - UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - - //fwrite(rpbuf->space, 1, rpbuf->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) { - //printf("response\n%s\n", rpbuf->space); - // TODO: use parse_propfind_response() - xmlDoc *doc = xmlReadMemory(rpbuf->space, rpbuf->size, url, NULL, 0); - if(!doc) { - return 1; - } - - xmlNode *xml_root = xmlDocGetRootElement(doc); - xmlNode *node = xml_root->children; - while(node) { - if(node->type == XML_ELEMENT_NODE) { - if(xstreq(node->name, "response")) { - parse_response_tag(res, node, NULL, 0); - } - } - node = node->next; - } - - set_davprops(res); - } else { - session_set_error(sn, ret, status); - } - return 0; -} - -int dav_store(DavResource *res) { - DavSession *sn = res->session; - - char *url = util_concat_path(sn->base_url, res->path); - CURL *handle = res->session->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - DavNodeData *data = res->data; - - // store content - if(data->content) { - CURLcode ret = do_put_request(handle, data->content, data->read, data->length); - int status = 0; - curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && (status >= 200 && status < 300)) { - res->session->error = 0; - // cleanup node data - if(!data->read) { - ucx_mempool_free(sn->mp, data->content); - } - data->content = NULL; - data->read = NULL; - data->length = 0; - } else { - session_set_error(sn, ret, status); - return 1; - } - } - - // store properties - if(data->set || data->remove) { - UcxBuffer *request = create_proppatch_request(data); - UcxBuffer *response = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); - - CURLcode ret = do_proppatch_request(handle, request, response); - int status = 0; - curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && status == 207) { - //printf("%s\n", response->space); - // TODO: parse response - // TODO: cleanup node data correctly - data->set = NULL; - data->remove = NULL; - } else { - session_set_error(sn, ret, status); - return 1; - } - } - sn->error = DAV_OK; - return 0; -} - -void 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; -} - -char* dav_get_property(DavResource *res, char *name) { - char *pns; - char *pname; - get_property_namespace(res->session->context, name, &pns, &pname); - return dav_get_property_ns(res, pns, pname); -} - -char* dav_get_property_ns(DavResource *res, char *ns, char *name) { - char *property = resource_get_property(res, ns, name); - // resource_get_property only returns persistent properties - // check the remove and set list - if(property) { - // if the property is in the remove list, we return NULL - UCX_FOREACH(elm, res->data->remove) { - DavProperty *p = elm->data; - if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) { - return NULL; - } - } - } - // the set list contains property updates - // we return an updated property if possible - UCX_FOREACH(elm, res->data->set) { - DavProperty *p = elm->data; - if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) { - return p->value; - } - } - // no property update - return property; -} - -void dav_set_property(DavResource *res, char *name, char *value) { - char *pns; - char *pname; - get_property_namespace(res->session->context, name, &pns, &pname); - dav_set_property_ns(res, pns, pname, value); -} - -void dav_set_property_ns(DavResource *res, char *ns, char *name, char *value) { - UcxAllocator *a = res->session->allocator; - - DavProperty *property = a->malloc(a->pool, sizeof(DavProperty)); - property->name = sstrdup_a(a, sstr(name)).ptr; - property->value = sstrdup_a(a, sstr(value)).ptr; - DavNamespace *namespace = a->malloc(a->pool, sizeof(DavNamespace)); - namespace->prefix = NULL; - namespace->name = sstrdup_a(a, sstr(ns)).ptr; - property->ns = namespace; - - res->data->set = ucx_list_append_a(a, res->data->set, property); -} - -void dav_remove_property(DavResource *res, char *name) { - char *pns; - char *pname; - get_property_namespace(res->session->context, name, &pns, &pname); - dav_remove_property_ns(res, pns, pname); -} - -void dav_remove_property_ns(DavResource *res, char *ns, char *name) { - UcxAllocator *a = res->session->allocator; - - DavProperty *property = a->malloc(a->pool, sizeof(DavProperty)); - property->name = sstrdup_a(a, sstr(name)).ptr; - property->value = NULL; - DavNamespace *namespace = a->malloc(a->pool, sizeof(DavNamespace)); - namespace->prefix = NULL; - namespace->name = sstrdup_a(a, sstr(ns)).ptr; - property->ns = namespace; - - res->data->remove = ucx_list_append_a(a, res->data->remove, property); -} - - -void dav_set_content(DavResource *res, void *stream, dav_read_func read_func) { - DavNodeData *data = res->data; - data->content = stream; - data->read = read_func; - data->length = 0; -} - -void dav_set_content_data(DavResource *res, char *content, size_t length) { - DavSession *sn = res->session; - DavNodeData *data = res->data; - data->content = content; - data->read = NULL; - data->length = length; -} - -int dav_get_content(DavResource *res, void *stream, dav_write_func write_func) { - char *url = util_concat_path(res->session->base_url, res->path); - CURL *handle = res->session->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0); - curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, NULL); - curl_easy_setopt(handle, CURLOPT_PUT, 0L); - curl_easy_setopt(handle, CURLOPT_UPLOAD, 0L); - - curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_func); - curl_easy_setopt(handle, CURLOPT_WRITEDATA, stream); - - CURLcode ret = curl_easy_perform(handle); - int status = 0; - curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && (status >= 200 && status < 300)) { - res->session->error = DAV_OK; - return 0; - } else { - session_set_error(res->session, ret, status); - return 1; - } -} - -int dav_delete(DavResource *res) { - char *url = util_concat_path(res->session->base_url, res->path); - CURL *handle = res->session->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - UcxBuffer *response = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - CURLcode ret = do_delete_request(handle, response); - int status = 0; - curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && (status >= 200 && status < 300)) { - res->session->error = DAV_OK; - - // TODO: parse response - // TODO: free res - - return 0; - } else { - session_set_error(res->session, ret, status); - return 1; - } -} - -int dav_create(DavResource *res) { - char *url = util_concat_path(res->session->base_url, res->path); - char *parent = util_parent_path(res->path); - - DavSession *sn = res->session; - DavResource *parent_res = dav_get(sn, parent, NULL); - if(!parent_res && sn->error == DAV_NOT_FOUND) { - parent_res = dav_resource_new(sn, parent); - parent_res->iscollection = 1; - int r = dav_create(parent_res); - if(r) { - free(parent); - return r; - } - } else if(parent_res && !parent_res->iscollection) { - sn->error = DAV_FORBIDDEN; - return 1; - } else if(sn->error != DAV_OK) { - return 1; - } - - CURL *handle = res->session->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - free(parent); - - // create new collection or do an empty put request - CURLcode ret; - if(res->iscollection) { - ret = do_mkcol_request(handle); - } else { - ret = do_put_request(handle, "", NULL, 0); - } - int status = 0; - curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && (status >= 200 && status < 300)) { - res->session->error = DAV_OK; - } else { - session_set_error(res->session, ret, status); - return 1; - } - - // do an minimal propfind request - UcxBuffer *rqbuf = create_propfind_request(NULL); - UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); - - //fwrite(rpbuf->space, 1, rpbuf->size, stdout); - //printf("\n"); - - ret = do_propfind_request(handle, rqbuf, rpbuf); - status = 0; - curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && (status >= 200 && status < 300)) { - //printf("response\n%s\n", rpbuf->space); - // TODO: use parse_propfind_response() - xmlDoc *doc = xmlReadMemory(rpbuf->space, rpbuf->size, url, NULL, 0); - if(!doc) { - return 1; - } - - xmlNode *xml_root = xmlDocGetRootElement(doc); - xmlNode *node = xml_root->children; - while(node) { - if(node->type == XML_ELEMENT_NODE) { - if(xstreq(node->name, "response")) { - parse_response_tag(res, node, NULL, 0); - } - } - node = node->next; - } - - set_davprops(res); - return 0; - } else { - session_set_error(sn, ret, status); - return 1; - } -} - -int dav_exists(DavResource *res) { - DavSession *sn = res->session; - char *url = util_concat_path(sn->base_url, res->path); - CURL *handle = sn->handle; - curl_easy_setopt(handle, CURLOPT_URL, url); - free(url); - - CURLcode ret = do_head_request(handle); - int status = 0; - curl_easy_getinfo (handle, CURLINFO_RESPONSE_CODE, &status); - if(ret == CURLE_OK && (status >= 200 && status < 300)) { - return 1; - } else { - session_set_error(sn, ret, status); - return 0; - } -}
--- a/dav/webdav.h Mon Aug 26 14:42:09 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBDAV_H -#define WEBDAV_H - -#include <inttypes.h> -#include <ucx/map.h> -#include <ucx/mempool.h> -#include <ucx/list.h> -#include <ucx/buffer.h> -#include <curl/curl.h> -#include <libxml/tree.h> - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct DavContext DavContext; -typedef struct DavSession DavSession; -typedef struct DavResource DavResource; -typedef struct DavRequest DavRequest; -typedef struct DavNamespace DavNamespace; -typedef struct DavNodeData DavNodeData; -typedef struct DavProperty DavProperty; - -#include "davql.h" - -typedef size_t(*dav_read_func)(void*, size_t, size_t, void*); -typedef size_t(*dav_write_func)(const void*, size_t, size_t, void*); - -enum DavError { - DAV_OK = 0, - DAV_ERROR, - DAV_NOT_FOUND, - DAV_UNAUTHORIZED, - DAV_FORBIDDEN, - DAV_METHOD_NOT_ALLOWED, - DAV_CONFLICT -}; - -typedef enum DavError DavError; - -struct DavNamespace { - char *prefix; - char *name; -}; - -struct DavResource { - DavSession *session; - DavResource *prev; - DavResource *next; - DavResource *parent; - DavResource *children; - char *name; - char *path; - char *href; - uint64_t contentlength; - char *contenttype; - time_t creationdate; - time_t lastmodified; - DavNodeData *data; - int iscollection; -}; - -struct DavSession { - DavContext *context; - CURL *handle; - char *base_url; - UcxMempool *mp; - UcxAllocator *allocator; - DavError error; - const char *errorstr; -}; - -struct DavContext { - UcxMap *namespaces; - UcxList *sessions; - char *http_proxy; - char *https_proxy; - char *no_proxy; -}; - -struct dav_content_data { - char *data; - size_t length; -}; - -struct dav_content_stream { - void *stream; - read_func read; -}; - -struct DavNodeData { - UcxMap *properties; - UcxList *set; - UcxList *remove; - - /* - * char* or stream - */ - void *content; - /* - * if NULL, content is a char* - */ - read_func read; - /* - * content length - */ - size_t length; -}; - -struct DavProperty { - DavNamespace *ns; - char *name; - char *value; -}; - -DavContext* dav_context_new(); -void dav_context_destroy(DavContext *ctx); -int dav_add_namespace(DavContext *context, char *prefix, char *ns); -DavNamespace* dav_get_namespace(DavContext *context, char *prefix); - -DavSession* dav_session_new(DavContext *context, char *base_url); -DavSession* dav_session_new_auth(DavContext *context, char *base_url, char *user, char *password); -void dav_session_set_auth(DavSession *sn, char *user, char *password); - -void session_set_error(DavSession *sn, CURLcode c, int status); - -void dav_session_destroy(DavSession *sn); - -DavResource* dav_get(DavSession *sn, char *path, char *properties); -DavResource* dav_get2(DavSession *sn, DavGetQuery *query); - -UcxList* parse_properties_string(DavContext *context, sstr_t str); - -DavResource* dav_query(DavSession *sn, char *query, ...); - -DavResource* dav_resource_new(DavSession *sn, char *path); -DavResource* resource_new_href(DavSession *sn, char *href); - -void resource_add_property(DavResource *res, char *ns, char *name, char *value); -void resource_add_child(DavResource *parent, DavResource *child); -UcxKey dav_property_key(char *ns, char *name); -void resource_set_info(DavResource *res, char *href); -DavNodeData* node_data_new(DavSession *sn); - -int dav_load(DavResource *res); -int dav_store(DavResource *res); - -void get_property_namespace( - DavContext *ctx, - char *prefixed_name, - char **ns, - char **name); - -char* dav_get_property(DavResource *res, char *name); -char* dav_get_property_ns(DavResource *res, char *ns, char *name); -void dav_set_property(DavResource *res, char *name, char *value); -void dav_set_property_ns(DavResource *res, char *ns, char *name, char *value); -void dav_remove_property(DavResource *res, char *name); -void dav_remove_property_ns(DavResource *res, char *ns, char *name); - - - -void dav_set_content(DavResource *res, void *stream, dav_read_func read_func); -void dav_set_content_data(DavResource *res, char *content, size_t length); - -int dav_get_content(DavResource *res, void *stream, dav_write_func write_func); - -int dav_delete(DavResource *res); -int dav_create(DavResource *res); - -int dav_exists(DavResource *res); - -#ifdef __cplusplus -} -#endif - -#endif /* WEBDAV_H */ -