diff -r 7072a2b4ae35 -r 649eb328674a libidav/methods.c --- a/libidav/methods.c Tue Jun 02 10:07:20 2015 +0200 +++ b/libidav/methods.c Tue Jun 02 20:57:23 2015 +0200 @@ -225,6 +225,156 @@ return buf; } +PropfindParser* create_propfind_parser(UcxBuffer *response, char *url) { + PropfindParser *parser = malloc(sizeof(PropfindParser)); + if(!parser) { + return NULL; + } + parser->document = xmlReadMemory(response->space, response->size, url, NULL, 0); + parser->current = NULL; + if(parser->document) { + xmlNode *xml_root = xmlDocGetRootElement(parser->document); + if(xml_root) { + xmlNode *node = xml_root->children; + while(node) { + // find first response tag + if(node->type == XML_ELEMENT_NODE) { + if(xstreq(node->name, "response")) { + parser->current = node; + break; + } + } + node = node->next; + } + return parser; + } else { + xmlFreeDoc(parser->document); + } + } + free(parser); + return NULL; +} + +int get_propfind_response(PropfindParser *parser, ResponseTag *result) { + if(parser->current == NULL) { + return 0; + } + + char *href = NULL; + int iscollection = 0; + UcxList *properties = NULL; // xmlNode list + char *crypto_name = NULL; // name set by crypto-name property + char *crypto_key = NULL; + + xmlNode *node = parser->current->children; + while(node) { + if(node->type == XML_ELEMENT_NODE) { + if(xstreq(node->name, "href")) { + xmlNode *href_node = node->children; + if(href_node->type != XML_TEXT_NODE) { + // error + return -1; + } + href = (char*)href_node->content; + } 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) { + // error + return -1; + } + sstr_t status_str = sstr((char*)status_node->content); + if(status_str.length < 13) { + // 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) { + properties = ucx_list_append(properties, n); + if(xstreq(n->name, "resourcetype")) { + xmlNode *rsnode = n->children; + if(rsnode && rsnode->type == XML_ELEMENT_NODE) { + // TODO: check content + iscollection = 1; + } + } else if(xstreq(n->ns->href, DAV_NS)) { + if(xstreq(n->name, "crypto-name")) { + crypto_name = util_xml_get_text(n); + } else if(xstreq(n->name, "crypto-key")) { + crypto_key = util_xml_get_text(n); + } + } + } + n = n->next; + } + } + } + } + node = node->next; + } + + result->href = href; + result->iscollection = iscollection; + result->properties = properties; + result->crypto_name = crypto_name; + result->crypto_key = crypto_key; + + // find next response tag + xmlNode *next = parser->current->next; + while(next) { + if(next->type == XML_ELEMENT_NODE) { + if(xstreq(next->name, "response")) { + break; + } + } + next = next->next; + } + parser->current = next; + + return 1; +} + +int hrefeq(DavSession *sn, char *href1, char *href2) { + sstr_t href_s = sstr(util_url_decode(sn, href1)); + sstr_t href_r = sstr(util_url_decode(sn, href2)); + int ret = 0; + if(!sstrcmp(href_s, href_r)) { + ret = 1; + } else if(href_s.length == href_r.length + 1) { + if(href_s.ptr[href_s.length-1] == '/') { + href_s.length--; + if(!sstrcmp(href_s, href_r)) { + ret = 1; + } + } + } + + free(href_s.ptr); + free(href_r.ptr); + + return ret; +} + + 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); @@ -256,6 +406,63 @@ return root; } +DavResource* response2resource(DavSession *sn, ResponseTag *response, char *parent_path) { + // create resource + char *name = NULL; + if(DAV_DECRYPT_NAME(sn) && response->crypto_name) { + if(!response->crypto_key) { + // TODO: error + fprintf(stderr, "encrypted resource without key\n"); + return NULL; + } + name = util_decrypt_str(sn, response->crypto_name, response->crypto_key); + if(!name) { + // TODO: error + fprintf(stderr, "decrypted name is null\n"); + return NULL; + } + } else { + sstr_t resname = sstr(util_resource_name(response->href)); + int nlen = 0; + char *uname = curl_easy_unescape( + sn->handle, + resname.ptr, + resname.length, + &nlen); + name = dav_session_strdup(sn, uname); + curl_free(uname); + } + + char *href = dav_session_strdup(sn, href); + DavResource *res = NULL; + if(parent_path) { + res = dav_resource_new_full(sn, parent_path, name, href); + } else { + res = dav_resource_new_href(sn, href); + } + dav_session_free(sn, name); + + add_properties(res, response); + return res; +} + +void add_properties(DavResource *res, ResponseTag *response) { + res->iscollection = response->iscollection; + + // add properties + UCX_FOREACH(elm, response->properties) { + xmlNode *prop = elm->data; + + // TODO: add xml data instead of a string + char *text = util_xml_get_text(prop); + if(text) { + resource_add_property(res, (char*)prop->ns->href, (char*)prop->name, text); + } + } + + set_davprops(res); +} + int parse_response_tag(DavResource *resource, xmlNode *node, DavQOp *cond, size_t clen) { DavSession *sn = resource->session;