1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <stdbool.h>
33 #include <libxml/tree.h>
34
35 #include "utils.h"
36 #include "session.h"
37 #include "methods.h"
38 #include "crypto.h"
39 #include <cx/buffer.h>
40 #include <cx/utils.h>
41 #include <cx/hash_map.h>
42 #include <cx/printf.h>
43 #include <cx/mempool.h>
44 #include <cx/array_list.h>
45
46 #include "resource.h"
47 #include "xml.h"
48 #include "davqlexec.h"
49
50 #define xstreq(a,b) xmlStrEqual(
BAD_CAST a,
BAD_CAST b)
51
52 DavResource* dav_resource_new(DavSession *sn,
const char *path) {
53
54
55 char *parent = util_parent_path(path);
56 const char *name = util_resource_name(path);
57 char *href = dav_session_create_plain_href(sn, path);
58
59 DavResource *res = dav_resource_new_full(sn, parent, name, href);
60 free(parent);
61 return res;
62 }
63
64 DavResource* dav_resource_new_child(DavSession *sn, DavResource *parent,
const char *name) {
65 char *path = util_concat_path(parent->path, name);
66 char *href = dav_session_create_plain_href(sn, path);
67 DavResource *res = dav_resource_new_full(sn, parent->path, name, href);
68 free(path);
69 return res;
70 }
71
72
73 DavResource* dav_resource_new_href(DavSession *sn,
const char *href) {
74 DavResource *res = cxCalloc(sn->mp->allocator,
1,
sizeof(DavResource));
75 res->session = sn;
76
77
78 resource_set_info(res, href);
79
80
81 res->data = resource_data_new(sn);
82
83 return res;
84 }
85
86 DavResource* dav_resource_new_full(DavSession *sn,
const char *parent_path,
const char *name,
char *href) {
87 cxstring n = cx_str(name);
88
89 if(n.length >
0 && href) {
90 for(
int i=
0;i<n.length-
1;i++) {
91 char c = n.ptr[i];
92 if(c ==
'/' || c ==
'\\') {
93 n = cx_str(util_resource_name(href));
94 break;
95 }
96 }
97 }
98
99 if(n.length >
0 && n.ptr[n.length-
1] ==
'/') {
100 n.length--;
101 }
102
103 DavResource *res = cxCalloc(sn->mp->allocator,
1,
sizeof(DavResource));
104 res->session = sn;
105
106
107 res->name = cx_strdup_a(sn->mp->allocator, n).ptr;
108
109 char *path = util_concat_path(parent_path, name);
110 res->path = dav_session_strdup(sn, path);
111
112 res->href = href;
113
114
115 res->data = resource_data_new(sn);
116
117
118 if(href) {
119 dav_session_cache_path(sn, cx_str(path), cx_str(href));
120 }
121 free(path);
122
123 return res;
124 }
125
126 void resource_free_properties(DavSession *sn, CxMap *properties) {
127 if(!properties)
return;
128
129 CxIterator i = cxMapIteratorValues(properties);
130 cx_foreach(DavProperty*, proper
, i) {
131
132 dav_session_free(sn, property);
133 }
134 cxMapDestroy(properties);
135 }
136
137 void dav_resource_free(DavResource *res) {
138 DavSession *sn = res->session;
139
140 dav_session_free(sn, res->name);
141 dav_session_free(sn, res->path);
142 if(res->href) {
143 dav_session_free(sn, res->href);
144 }
145
146 DavResourceData *data = res->data;
147 resource_free_properties(sn, data->properties);
148 resource_free_properties(sn, data->crypto_properties);
149
150 if(data->set) {
151 CxIterator i = cxListIterator(data->set);
152 cx_foreach(DavProperty *, p, i) {
153 dav_session_free(sn, p->ns->name);
154 if(p->ns->prefix) {
155 dav_session_free(sn, p->ns->prefix);
156 }
157 dav_session_free(sn, p->ns);
158
159 dav_session_free(sn, p->name);
160 dav_free_xml_node_sn(sn, p->value);
161 dav_session_free(sn, p);
162 }
163 }
164
165 if(data->remove) {
166 CxIterator i = cxListIterator(data->remove);
167 cx_foreach(DavProperty *, p, i) {
168 dav_session_free(sn, p->ns->name);
169 if(p->ns->prefix) {
170 dav_session_free(sn, p->ns->prefix);
171 }
172 dav_session_free(sn, p->ns);
173
174 dav_session_free(sn, p->name);
175 dav_session_free(sn, p);
176 }
177 }
178
179 if(data->crypto_set) {
180 CxIterator i = cxListIterator(data->crypto_set);
181 cx_foreach(DavProperty *, p, i) {
182 dav_session_free(sn, p->ns->name);
183 if(p->ns->prefix) {
184 dav_session_free(sn, p->ns->prefix);
185 }
186 dav_session_free(sn, p->ns);
187
188 dav_session_free(sn, p->name);
189 dav_free_xml_node_sn(sn, p->value);
190 dav_session_free(sn, p);
191 }
192 }
193
194 if(data->crypto_remove) {
195 CxIterator i = cxListIterator(data->crypto_remove);
196 cx_foreach(DavProperty *, p, i) {
197 dav_session_free(sn, p->ns->name);
198 if(p->ns->prefix) {
199 dav_session_free(sn, p->ns->prefix);
200 }
201 dav_session_free(sn, p->ns);
202
203 dav_session_free(sn, p->name);
204 dav_session_free(sn, p);
205 }
206 }
207
208 if(!data->read && data->content) {
209 dav_session_free(sn, data->content);
210 }
211 dav_session_free(sn, data);
212
213 dav_session_free(sn, res);
214 }
215
216 void dav_resource_free_all(DavResource *res) {
217 DavResource *child = res->children;
218 dav_resource_free(res);
219 while(child) {
220 DavResource *next = child->next;
221 dav_resource_free_all(child);
222 child = next;
223 }
224 }
225
226 void resource_set_href(DavResource *res, cxstring href) {
227 res->href = cx_strdup_a(res->session->mp->allocator, href).ptr;
228 }
229
230 void resource_set_info(DavResource *res,
const char *href_str) {
231 char *url_str =
NULL;
232 curl_easy_getinfo(res->session->handle,
CURLINFO_EFFECTIVE_URL, &url_str);
233 cxstring name = cx_str(util_resource_name(href_str));
234 cxstring href = cx_str(href_str);
235
236 cxstring base_href = cx_str(util_url_path(res->session->base_url));
237 cxstring path = cx_strsubs(href, base_href.length -
1);
238
239 const CxAllocator *a = res->session->mp->allocator;
240 CURL *handle = res->session->handle;
241
242 int nlen =
0;
243 char *uname = curl_easy_unescape(handle, name.ptr, name.length , &nlen);
244 int plen =
0;
245 char *upath = curl_easy_unescape(handle, path.ptr, path.length, &plen);
246
247 res->name = cx_strdup_a(a, cx_strn(uname, nlen)).ptr;
248 res->href = cx_strdup_a(a, href).ptr;
249 res->path = cx_strdup_a(a, cx_strn(upath, plen)).ptr;
250
251 curl_free(uname);
252 curl_free(upath);
253 }
254
255 DavResourceData* resource_data_new(DavSession *sn) {
256 DavResourceData *data = cxMalloc(
257 sn->mp->allocator,
258 sizeof(DavResourceData));
259 if(!data) {
260 return NULL;
261 }
262 data->properties = cxHashMapCreate(sn->mp->allocator,
CX_STORE_POINTERS,
32);
263 data->crypto_properties =
NULL;
264 data->set =
NULL;
265 data->remove =
NULL;
266 data->crypto_set =
NULL;
267 data->crypto_remove =
NULL;
268 data->read =
NULL;
269 data->content =
NULL;
270 data->seek =
NULL;
271 data->length =
0;
272 return data;
273 }
274
275 char* dav_resource_get_href(DavResource *resource) {
276 if(!resource->href) {
277 resource->href = dav_session_get_href(
278 resource->session,
279 resource->path);
280 }
281 return resource->href;
282 }
283
284 void resource_add_prop(DavResource *res,
const char *ns,
const char *name, DavXmlNode *val) {
285 DavSession *sn = res->session;
286
287 DavNamespace *namespace = dav_session_malloc(sn,
sizeof(DavNamespace));
288 namespace->prefix =
NULL;
289 namespace->name = dav_session_strdup(sn, ns);
290
291 DavProperty *prop = dav_session_malloc(sn,
sizeof(DavProperty));
292 prop->name = dav_session_strdup(sn, name);
293 prop->ns = namespace;
294 prop->value = val;
295
296 cxmutstr keystr = dav_property_key(ns, name);
297 CxHashKey key = cx_hash_key(keystr.ptr, keystr.length);
298 cxMapPut(((DavResourceData*)res->data)->properties, key, prop);
299 free(keystr.ptr);
300 }
301
302 void resource_add_property(DavResource *res,
const char *ns,
const char *name, xmlNode *val) {
303 if(!val) {
304 return;
305 }
306
307 resource_add_prop(res, ns, name, dav_convert_xml(res->session, val));
308 }
309
310 void resource_add_string_property(DavResource *res,
char *ns,
char *name,
char *val) {
311 if(!val) {
312 return;
313 }
314
315 resource_add_prop(res, ns, name, dav_text_node(res->session, val));
316 }
317
318 void resource_set_crypto_properties(DavResource *res, CxMap *cprops) {
319 DavResourceData *data = res->data;
320 resource_free_properties(res->session, data->crypto_properties);
321 data->crypto_properties = cprops;
322 }
323
324 DavXmlNode* resource_get_property(DavResource *res,
const char *ns,
const char *name) {
325 cxmutstr keystr = dav_property_key(ns, name);
326 CxHashKey key = cx_hash_key(keystr.ptr, keystr.length);
327 DavXmlNode *ret = resource_get_property_k(res, key);
328 free(keystr.ptr);
329
330 return ret;
331 }
332
333 DavXmlNode* resource_get_encrypted_property(DavResource *res,
const char *ns,
const char *name) {
334 cxmutstr keystr = dav_property_key(ns, name);
335 CxHashKey key = cx_hash_key(keystr.ptr, keystr.length);
336 DavXmlNode *ret = resource_get_encrypted_property_k(res, key);
337 free(keystr.ptr);
338
339 return ret;
340 }
341
342 DavXmlNode* resource_get_property_k(DavResource *res, CxHashKey key) {
343 DavResourceData *data = (DavResourceData*)res->data;
344 DavProperty *property = cxMapGet(data->properties, key);
345
346 return property ? property->value :
NULL;
347 }
348
349 DavXmlNode* resource_get_encrypted_property_k(DavResource *res, CxHashKey key) {
350 DavResourceData *data = (DavResourceData*)res->data;
351 DavProperty *property = cxMapGet(data->crypto_properties, key);
352
353 return property ? property->value :
NULL;
354 }
355
356 cxmutstr dav_property_key(
const char *ns,
const char *name) {
357 return dav_property_key_a(cxDefaultAllocator, ns, name);
358 }
359
360 cxmutstr dav_property_key_a(
const CxAllocator *a,
const char *ns,
const char *name) {
361 cxstring ns_str = cx_str(ns);
362 cxstring name_str = cx_str(name);
363
364 return cx_strcat_a(a,
4, ns_str,
CX_STR(
"\0"), name_str,
CX_STR(
"\0"));
365 }
366
367
368
369
370 void resource_add_child(DavResource *parent, DavResource *child) {
371 child->next =
NULL;
372 if(parent->children) {
373 DavResource *last = parent->children;
374 while(last->next) {
375 last = last->next;
376 }
377 last->next = child;
378 child->prev = last;
379 }
else {
380 child->prev =
NULL;
381 parent->children = child;
382 }
383 child->parent = parent;
384 }
385
386 static int resource_cmp(DavResource *res1, DavResource *res2, DavOrderCriterion *cr) {
387 if(!(res1 && res2)) {
388 return 0;
389 }
390
391 int ret;
392 if(cr->type ==
0) {
393 switch(cr->column.resprop) {
394 case DAVQL_RES_NAME: {
395 ret = strcmp(res1->name, res2->name);
396 break;
397 }
398 case DAVQL_RES_PATH: {
399 ret = strcmp(res1->path, res2->path);
400 break;
401 }
402 case DAVQL_RES_HREF: {
403 ret = strcmp(res1->href, res2->href);
404 break;
405 }
406 case DAVQL_RES_CONTENTLENGTH: {
407 int c = res1->contentlength == res2->contentlength;
408 ret = c ?
0 : (res1->contentlength < res2->contentlength?-
1:
1);
409 break;
410 }
411 case DAVQL_RES_CONTENTTYPE: {
412 ret = strcmp(res1->contenttype, res2->contenttype);
413 break;
414 }
415 case DAVQL_RES_CREATIONDATE: {
416 int c = res1->creationdate == res2->creationdate;
417 ret = c ?
0 : (res1->creationdate < res2->creationdate?-
1:
1);
418 break;
419 }
420 case DAVQL_RES_LASTMODIFIED: {
421 int c = res1->lastmodified == res2->lastmodified;
422 ret = c ?
0 : (res1->lastmodified < res2->lastmodified?-
1:
1);
423 break;
424 }
425 case DAVQL_RES_ISCOLLECTION: {
426 int c = res1->iscollection == res2->iscollection;
427
ret = c ?
0 : (res1->iscollection < res2->iscollection?-
1:
1);
428 break;
429 }
430 default: ret =
0;
431 }
432 }
else if(cr->type ==
1) {
433 DavXmlNode *xvalue1 = resource_get_property_k(res1, cr->column.property);
434 DavXmlNode *xvalue2 = resource_get_property_k(res2, cr->column.property);
435 char *value1 = dav_xml_getstring(xvalue1);
436 char *value2 = dav_xml_getstring(xvalue2);
437 if(!value1) {
438 ret = value2 ? -
1 :
0;
439 }
else if(!value2) {
440 ret = value1 ?
1 :
0;
441 }
else {
442 ret = strcmp(value1, value2);
443 }
444 }
else {
445 return 0;
446 }
447
448 return cr->descending ? -ret : ret;
449 }
450
451 void resource_add_ordered_child(DavResource *parent, DavResource *child, CxList *ordercr) {
452 if(!ordercr) {
453 resource_add_child(parent, child);
454 return;
455 }
456
457 child->parent = parent;
458
459 if(!parent->children) {
460 child->next =
NULL;
461 child->prev =
NULL;
462 parent->children = child;
463 }
else {
464 DavResource *resource = parent->children;
465 while(resource) {
466 int r =
0;
467 CxIterator i = cxListIterator(ordercr);
468 cx_foreach(DavOrderCriterion*, cr, i) {
469 r = resource_cmp(child, resource, cr);
470 if(r !=
0) {
471 break;
472 }
473 }
474
475 if(r <
0) {
476
477 child->prev = resource->prev;
478 child->next = resource;
479 if(resource->prev) {
480 resource->prev->next = child;
481 }
else {
482 parent->children = child;
483 }
484 resource->prev = child;
485 break;
486 }
if(!resource->next) {
487
488 child->prev = resource;
489 child->next =
NULL;
490 resource->next = child;
491 break;
492 }
else {
493 resource = resource->next;
494 }
495 }
496 }
497 }
498
499 char* dav_get_string_property(DavResource *res,
char *name) {
500 char *pns;
501 char *pname;
502 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
503 if(!pns || !pname) {
504 return NULL;
505 }
506 return dav_get_string_property_ns(res, pns, pname);
507 }
508
509 char* dav_get_string_property_ns(DavResource *res,
char *ns,
char *name) {
510 DavXmlNode *prop = dav_get_property_ns(res, ns, name);
511 if(!prop) {
512 return NULL;
513 }
514 return dav_xml_getstring(prop);
515 }
516
517 DavXmlNode* dav_get_property(DavResource *res,
char *name) {
518 char *pns;
519 char *pname;
520 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
521 if(!pns || !pname) {
522 return NULL;
523 }
524 return dav_get_property_ns(res, pns, pname);
525 }
526
527 static DavXmlNode* get_property_ns(DavResource *res, DavBool encrypted,
const char *ns,
const char *name) {
528 if(!ns || !name) {
529 return NULL;
530 }
531
532 DavResourceData *data = res->data;
533
534 DavXmlNode *property =
NULL;
535 CxList *remove_list =
NULL;
536 CxList *set_list =
NULL;
537
538 if(encrypted) {
539
540
541 if(!data->crypto_properties) {
542 return NULL;
543 }
544 property = resource_get_encrypted_property(res, ns, name);
545 remove_list = data->crypto_remove;
546 set_list = data->crypto_set;
547 }
else {
548 property = resource_get_property(res, ns, name);
549 remove_list = data->remove;
550 set_list = data->set;
551 }
552
553
554
555 if(property && remove_list) {
556
557 CxIterator i = cxListIterator(remove_list);
558 cx_foreach(DavProperty*, p, i) {
559 if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) {
560 return NULL;
561 }
562 }
563 }
564
565
566
567 if(set_list) {
568 CxIterator i = cxListIterator(set_list);
569 cx_fore
h(DavProperty*, p, i) {
570 if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) {
571 return p->value;
572 }
573 }
574 }
575
576
577
578 return property;
579 }
580
581 DavXmlNode* dav_get_property_ns(DavResource *res,
const char *ns,
const char *name) {
582 DavXmlNode *property_value = get_property_ns(res,
FALSE, ns, name);
583
584 if(!property_value &&
DAV_DECRYPT_PROPERTIES(res->session)) {
585 property_value = get_property_ns(res,
TRUE, ns, name);
586 }
587
588 return property_value;
589 }
590
591 DavXmlNode* dav_get_encrypted_property_ns(DavResource *res,
const char *ns,
const char *name) {
592 return get_property_ns(res,
TRUE, ns, name);
593 }
594
595 static DavProperty* createprop(DavSession *sn,
const char *ns,
const char *name) {
596 DavProperty *property = dav_session_malloc(sn,
sizeof(DavProperty));
597 property->name = dav_session_strdup(sn, name);
598 property->value =
NULL;
599
600 DavNamespace *namespace = dav_session_malloc(sn,
sizeof(DavNamespace));
601 namespace->prefix =
NULL;
602 namespace->name = dav_session_strdup(sn, ns);
603
604 property->ns = namespace;
605
606 return property;
607 }
608
609 void dav_set_string_property(DavResource *res,
char *name,
char *value) {
610 char *pns;
611 char *pname;
612 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
613 dav_set_string_property_ns(res, pns, pname, value);
614 }
615
616 static int add2propertylist(
const CxAllocator *a, CxList **list, DavProperty *property) {
617 if(!*list) {
618 CxList *newlist = cxLinkedListCreate(a,
NULL,
CX_STORE_POINTERS);
619 if(!newlist) {
620 return 1;
621 }
622 *list = newlist;
623 }
624 cxListAdd(*list, property);
625 return 0;
626 }
627
628 void dav_set_string_property_ns(DavResource *res,
char *ns,
char *name,
char *value) {
629 DavSession *sn = res->session;
630 const CxAllocator *a = res->session->mp->allocator;
631 DavResourceData *data = res->data;
632
633 DavProperty *property = createprop(res->session, ns, name);
634 property->value = dav_text_node(res->session, value);
635
636 if(
DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
637 add2propertylist(a, &data->crypto_set, property);
638 }
else {
639 add2propertylist(a, &data->set, property);
640 }
641 }
642
643 void dav_set_property(DavResource *res,
char *name, DavXmlNode *value) {
644 char *pns;
645 char *pname;
646 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
647 dav_set_property_ns(res, pns, pname, value);
648 }
649
650 void dav_set_property_ns(DavResource *res,
char *ns,
char *name, DavXmlNode *value) {
651 DavSession *sn = res->session;
652 const CxAllocator *a = sn->mp->allocator;
653 DavResourceData *data = res->data;
654
655 DavProperty *property = createprop(sn, ns, name);
656
657
658 property->value = value;
659
660 if(
DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
661 add2propertylist(a, &data->crypto_set, property);
662 }
else {
663 add2propertylist(a, &data->set, property);
664 }
665 }
666
667 void dav_remove_property(DavResource *res,
char *name) {
668 char *pns;
669 char *pname;
670 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
671 dav_remove_property_ns(res, pns, pname);
672 }
673
674 void dav_remove_property_ns(DavResource *res,
char *ns,
char *name) {
675 DavSession *sn = res->session;
676 DavResourceData *data = res->data;
677 const CxAllocator *a = res->session->mp->allocator;
678
679 DavProperty *property = createprop(res->session, ns, name);
680
681 if(
DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
682 add2propertylist(a, &data->crypto_remove, property);
683 }
else {
684 add2propertylist(a, &data->remove, property);
685 }
686 }
687
688 void dav_set_encrypted_property_ns(DavResource *res,
char *ns,
char *name, DavXmlNode *value) {
689 const CxAllocator *a = res->session->mp->allocator;
690 DavResourceData *data = res->data;
691
692 DavProperty *property = createprop(res->session, ns, name);
693 property->value = value;
694
695 add2propertylist(a, &data->crypto_set, property);
696 }
697
698 void dav_set_encrypted_string_property_ns(DavResource *res,
char *ns,
char *name,
char *value) {
699 const CxAllocator *a = res->session->mp->allocator;
700 DavResourceData *data = res->data;
701
702 DavProperty *property = createprop(res->session, ns, name);
703 property->value = dav_text_node(res->session, value);
704
705 add2propertylist(a, &data->crypto_set, property);
706 }
707
708 void dav_remove_encrypted_property_ns(DavResource *res,
char *ns,
char
an> *name) {
709 DavResourceData *data = res->data;
710 const CxAllocator *a = res->session->mp->allocator;
711
712 DavProperty *property = createprop(res->session, ns, name);
713
714 add2propertylist(a, &data->crypto_remove, property);
715 }
716
717 static int compare_propname(const void *a, const void *b) {
718 const DavPropName *p1 = a;
719 const DavPropName *p2 = b;
720
721 int result = strcmp(p1->ns, p2->ns);
722 if(result) {
723 return result;
724 } else {
725 return strcmp(p1->name, p2->name);
726 }
727 }
728
729 DavPropName* dav_get_property_names(DavResource *res, size_t *count) {
730 DavResourceData *data = res->data;
731
732 *count = cxMapSize(data->properties);
733 DavPropName *names = dav_session_calloc(
734 res->session,
735 *count,
736 sizeof(DavPropName));
737
738
739 CxIterator i = cxMapIteratorValues(data->properties);
740 cx_foreach(DavProperty*, value, i) {
741 DavPropName *name = &names[i.index];
742 name->ns = value->ns->name;
743 name->name = value->name;
744 }
745
746 qsort(names, *count, sizeof(DavPropName), compare_propname);
747
748 return names;
749 }
750
751
752 void dav_set_content(DavResource *res, void *stream, dav_read_func read_func, dav_seek_func seek_func) {
753 DavResourceData *data = res->data;
754 data->content = stream;
755 data->read = read_func;
756 data->seek = seek_func;
757 data->length = 0;
758 }
759
760 void dav_set_content_data(DavResource *res, char *content, size_t length) {
761 DavSession *sn = res->session;
762 DavResourceData *data = res->data;
763 data->content = dav_session_malloc(sn, length);
764 memcpy(data->content, content, length);
765 data->read = NULL;
766 data->seek = NULL;
767 data->length = length;
768 }
769
770 void dav_set_content_length(DavResource *res, size_t length) {
771 DavResourceData *data = res->data;
772 data->length = length;
773 }
774
775
776 int dav_load(DavResource *res) {
777 CxBuffer *rqbuf = create_allprop_propfind_request();
778 int ret = dav_propfind(res->session, res, rqbuf);
779 cxBufferFree(rqbuf);
780 return ret;
781 }
782
783 int dav_load_prop(DavResource *res, DavPropName *properties, size_t numprop) {
784 CxMempool *mp = cxMempoolCreate(64, NULL);
785 const CxAllocator *a = mp->allocator;
786
787 CxList *proplist = cxArrayListCreate(a, NULL, sizeof(DavProperty), numprop);
788 for(size_t i=0;i<numprop;i++) {
789 DavProperty p;
790 p.name = properties[i].name;
791 p.ns = cxMalloc(a, sizeof(DavNamespace));
792 p.ns->name = properties[i].ns;
793 if(!strcmp(properties[i].ns, "DAV:")) {
794 p.ns->prefix = "D";
795 } else {
796 p.ns->prefix = cx_asprintf_a(a, "x%d", (int)i).ptr;
797 }
798 p.value = NULL;
799 cxListAdd(proplist, &p);
800 }
801
802 CxBuffer *rqbuf = create_propfind_request(res->session, proplist, "propfind", 0);
803 int ret = dav_propfind(res->session, res, rqbuf);
804 cxBufferFree(rqbuf);
805 cxMempoolDestroy(mp);
806 return ret;
807 }
808
809
810 static void init_hash_stream(HashStream *hstr, void *stream, dav_read_func readfn, dav_seek_func seekfn) {
811 hstr->sha = NULL;
812 hstr->stream = stream;
813 hstr->read = readfn;
814 hstr->seek = seekfn;
815 hstr->error = 0;
816 }
817
818 static size_t dav_read_h(void *buf, size_t size, size_t nelm, void *stream) {
819 HashStream *s = stream;
820 if(!s->sha) {
821 s->sha = dav_hash_init();
822 }
823
824 size_t r = s->read(buf, size, nelm, s->stream);
825 dav_hash_update(s->sha, buf, r);
826 return r;
827 }
828
829 static int dav_seek_h(void *stream, long offset, int whence) {
830 HashStream *s = stream;
831 if(offset == 0 && whence == SEEK_SET) {
832 unsigned char buf[DAV_SHA256_DIGEST_LENGTH];
833 dav_hash_final(s->sha, buf);
834 s->sha = NULL;
835 } else {
836 s->error = 1;
837 }
838 return s->seek(s->stream, offset, whence);
839 }
840
841
842 int dav_store(DavResource *res) {
843 DavSession *sn = res->session;
844 DavResourceData *data = res->data;
845
846 util_set_url(sn, dav_resource_get_href(res));
847
848 DavLock *lock = dav_get_lock(sn, res->path);
849 char *locktoken = lock ? lock->token : NULL;
850
851
852 if(data->content) {
853 curl_easy_setopt(sn->handle, CURLOPT_XFERINFOFUNCTION, dav_session_put_progress);
854 curl_easy_setopt(sn->handle, CURLOPT_XFERINFODATA, res);
855 curl_easy_setopt(sn->handle, CURLOPT_NOPROGRESS, 0L);
856
857 int encryption = DAV_ENCRYPT_CONTENT(sn) && sn->key;
858 CURLcode ret;
859 if(encryption) {
860 AESEncrypter *enc = NULL;
861 CxBuffer *buf = NULL;
862 if(data->read) {
863 enc = aes_encrypter_new(
864 sn->key,
865 data->content,
866 data->read,
867 data->seek);
868 } else {
869 buf = cxBufferCreate(data->content, data->length, cxDefaultAllocator, 0);
870 buf->size = data->length;
871 enc = aes_encrypter_new(
872 sn->key,
873 buf,
874 (dav_read_func)cxBufferRead,
875 (dav_seek_func)cxBufferSeek);
876 }
877
878
879 ret = do_put_request(
880 sn,
881 locktoken,
882 TRUE,
883 enc,
884 (dav_read_func)aes_read,
885 (dav_seek_func)aes_encrypter_reset,
886 0);
887
888
889 dav_get_hash(&enc->sha256, (unsigned char*)data->hash);
890 char *enc_hash = aes_encrypt(data->hash, DAV_SHA256_DIGEST_LENGTH, sn->key);
891
892 aes_encrypter_close(enc);
893 if(buf) {
894 cxBufferFree(buf);
895 }
896
897
898
899 if(resource_add_crypto_info(sn, res->href, res->name, enc_hash)) {
900 free(enc_hash);
901 curl_easy_setopt(sn->handle, CURLOPT_XFERINFOFUNCTION, NULL);
902 curl_easy_setopt(sn->handle, CURLOPT_NOPROGRESS, 1L);
903 return 1;
904 }
905 resource_add_string_property(res, DAV_NS, "crypto-hash", enc_hash);
906 free(enc_hash);
907 } else if((sn->flags & DAV_SESSION_STORE_HASH) == DAV_SESSION_STORE_HASH) {
908 HashStream hstr;
909 CxBuffer *iobuf = NULL;
910 if(!data->read) {
911 iobuf = cxBufferCreate(data->content, data->length, cxDefaultAllocator, 0);
912 iobuf->size = data->length;
913 init_hash_stream(
914 &hstr,
915 iobuf,
916 (dav_read_func)cxBufferRead,
917 (dav_seek_func)cxBufferSeek);
918 } else {
919 init_hash_stream(
920 &hstr,
921 data->content,
922 data->read,
923 data->seek);
924 }
925
926 ret = do_put_request(
927 sn,
928 locktoken,
929 TRUE,
930 &hstr,
931 dav_read_h,
932 (dav_seek_func)dav_seek_h,
933 data->length);
934
935 if(hstr.sha) {
936 dav_hash_final(hstr.sha, (unsigned char*)data->hash);
937 char *hash = util_hexstr((unsigned char*)data->hash, 32);
938 dav_set_string_property_ns(res, DAV_NS, "content-hash", hash);
939 free(hash);
940 }
941 } else {
942 ret = do_put_request(
943 sn,
944 locktoken,
945 TRUE,
946 data->content,
947 data->read,
948 data->seek,
949 data->length);
950 }
951
952 curl_easy_setopt(sn->handle, CURLOPT_XFERINFOFUNCTION, NULL);
953 curl_easy_setopt(sn->handle, CURLOPT_NOPROGRESS, 1L);
954
955 long status = 0;
956 curl_easy_getinfo(sn->handle, CURLINFO_RESPONSE_CODE, &status);
957 if(ret == CURLE_OK && (status >= 200 && status < 300)) {
958 res->session->error = 0;
959
960 if(!data->read) {
961 cxFree(sn->mp->allocator, data->content);
962 }
963 data->content = NULL;
964 data->read = NULL;
965 data->length = 0;
966 } else {
967 dav_session_set_error(sn, ret, status);
968 return 1;
969 }
970 }
971
972
973 if(DAV_ENCRYPT_PROPERTIES(sn) && sn->key && (data->crypto_set || data->crypto_remove)) {
974 DavResource *crypto_res = dav_resource_new_href(sn, res->href);
975 int ret = 1;
976
977 if(crypto_res) {
978 CxBuffer *rqbuf = create_cryptoprop_propfind_request();
979 ret = dav_propfind(res->session, res, rqbuf);
980 cxBufferFree(rqbuf);
981 }
982
983 if(!ret) {
984 DavXmlNode *crypto_prop_node = dav_get_property_ns(crypto_res, DAV_NS, "crypto-prop");
985 CxMap *crypto_props = parse_crypto_prop(sn, sn->key, crypto_prop_node);
986 if(!crypto_props) {
987
988 crypto_props = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 32);
989 }
990
991
992 if(data->crypto_remove) {
993 CxIterator i = cxListIterator(data->crypto_remove);
994 cx_foreach(DavProperty *, property, i) {
995 if(cxMapSize(crypto_props) ==
0) {
996 break;
997 }
998
999 cxmutstr key = dav_property_key(property->ns->name, property->name);
1000 DavProperty *existing_prop = cxMapGet(crypto_props, cx_hash_key(key.ptr, key.length));
1001 if(existing_prop) {
1002
1003 }
1004 free(key.ptr);
1005 }
1006 }
1007
1008
1009 if(data->crypto_set) {
1010 CxIterator i = cxListIterator(data->crypto_set);
1011 cx_foreach(DavProperty *, property, i) {
1012 cxmutstr keystr = dav_property_key(property->ns->name, property->name);
1013 CxHashKey key = cx_hash_key(keystr.ptr, keystr.length);
1014 DavProperty *existing_prop = cxMapRemoveAndGet(crypto_props, key);
1015 cxMapPut(crypto_props, key, property);
1016 if(existing_prop) {
1017
1018 }
1019 free(keystr.ptr);
1020 }
1021 }
1022
1023 DavXmlNode *crypto_prop_value = create_crypto_prop(sn, crypto_props);
1024 if(crypto_prop_value) {
1025 DavProperty *new_crypto_prop = createprop(sn,
DAV_NS,
"crypto-prop");
1026 new_crypto_prop->value = crypto_prop_value;
1027 add2propertylist(sn->mp->allocator, &data->set, new_crypto_prop);
1028 }
1029
1030 dav_resource_free(crypto_res);
1031 }
1032
1033 if(ret) {
1034 return 1;
1035 }
1036 }
1037
1038
1039 int r =
0;
1040 sn->error =
DAV_OK;
1041 if(data->set || data->remove) {
1042 CxBuffer *request = create_proppatch_request(data);
1043 CxBuffer *response = cxBufferCreate(
NULL,
1024, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1044
1045
1046 CURLcode ret = do_proppatch_request(sn, locktoken, request, response);
1047 long status =
0;
1048 curl_easy_getinfo (sn->handle,
CURLINFO_RESPONSE_CODE, &status);
1049 if(ret ==
CURLE_OK && status ==
207) {
1050
1051
1052
1053 data->set =
NULL;
1054 data->remove =
NULL;
1055 }
else {
1056 dav_session_set_error(sn, ret, status);
1057 r = -
1;
1058 }
1059
1060 cxBufferFree(request);
1061 cxBufferFree(response);
1062 }
1063
1064 return r;
1065 }
1066
1067 #if LIBCURL_VERSION_MAJOR >=
7 &&
LIBCURL_VERSION_MINOR >=
32
1068 static void set_progressfunc(DavResource *res) {
1069 CURL *handle = res->session->handle;
1070 curl_easy_setopt(handle,
CURLOPT_XFERINFOFUNCTION, dav_session_get_progress);
1071 curl_easy_setopt(handle,
CURLOPT_XFERINFODATA, res);
1072 curl_easy_setopt(handle,
CURLOPT_NOPROGRESS,
0L);
1073 }
1074
1075 static void unset_progressfunc(DavResource *res) {
1076 CURL *handle = res->session->handle;
1077 curl_easy_setopt(handle,
CURLOPT_XFERINFOFUNCTION,
NULL);
1078 curl_easy_setopt(handle,
CURLOPT_XFERINFODATA,
NULL);
1079 curl_easy_setopt(handle,
CURLOPT_NOPROGRESS,
1L);
1080 }
1081 #else
1082 static void set_progressfunc(DavResource *res) {
1083
1084 }
1085 static void unset_progressfunc(DavResource *res) {
1086
1087 }
1088 #endif
1089
1090 int dav_get_content(DavResource *res,
void *stream, dav_write_func write_fnc) {
1091 DavSession *sn = res->session;
1092 CURL *handle = sn->handle;
1093 util_set_url(res->session, dav_resource_get_href(res));
1094
1095
1096 AESDecrypter *dec =
NULL;
1097 DavKey *key =
NULL;
1098 if(
DAV_DECRYPT_CONTENT(sn)) {
1099 char *keyname = dav_get_string_property_ns(res,
DAV_NS,
"crypto-key");
1100 if(keyname) {
1101 key = dav_context_get_key(sn->context, keyname);
1102 if(key) {
1103 dec = aes_decrypter_new(key, stream, write_fnc);
1104 stream = dec;
1105 write_fnc = (dav_write_func)aes_write;
1106 }
1107 }
1108 }
1109
1110 curl_easy_setopt(handle,
CURLOPT_HTTPHEADER,
NULL);
1111 curl_easy_setopt(handle,
CURLOPT_CUSTOMREQUEST,
NULL);
1112 curl_easy_setopt(handle,
CURLOPT_PUT,
0L);
1113 curl_easy_setopt(handle,
CURLOPT_UPLOAD,
0L);
1114
1115 curl_easy_setopt(handle,
CURLOPT_WRITEFUNCTION, write_fnc);
1116 curl_easy_setopt(handle,
CURLOPT_WRITEDATA, stream);
1117
1118 if(sn->get_progress) {
1119 set_progressfunc(res);
1120 }
1121
1122 long status =
pan class="c2html-macroconst">0;
1123 CURLcode ret = dav_session_curl_perform(sn, &status);
1124
1125 if(sn->get_progress) {
1126 unset_progressfunc(res);
1127 }
1128
1129 char *hash =
NULL;
1130 if(dec) {
1131 aes_decrypter_shutdown(dec);
1132
1133
1134 unsigned char sha[
DAV_SHA256_DIGEST_LENGTH];
1135 dav_get_hash(&dec->sha256, sha);
1136 hash = util_hexstr(sha,
DAV_SHA256_DIGEST_LENGTH);
1137
1138 aes_decrypter_close(dec);
1139 }
1140
1141 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1142 int verify_failed =
0;
1143 if(
DAV_DECRYPT_CONTENT(sn) && key) {
1144
1145 char *res_hash = dav_get_string_property_ns(res,
DAV_NS,
"crypto-hash");
1146
1147 if(res_hash) {
1148 size_t len =
0;
1149 char *dec_hash = aes_decrypt(res_hash, &len, key);
1150 char *hex_hash = util_hexstr((
unsigned char*)dec_hash, len);
1151 if(strcmp(hash, hex_hash)) {
1152 verify_failed =
1;
1153 }
1154 free(dec_hash);
1155 free(hex_hash);
1156 }
1157 }
1158 if(hash) {
1159 free(hash);
1160 }
1161
1162 if(verify_failed) {
1163 res->session->error =
DAV_CONTENT_VERIFICATION_ERROR;
1164 return 1;
1165 }
1166
1167 res->session->error =
DAV_OK;
1168 return 0;
1169 }
else {
1170 if(hash) {
1171 free(hash);
1172 }
1173 dav_session_set_error(res->session, ret, status);
1174 return 1;
1175 }
1176 }
1177
1178 DavResource* dav_create_child(DavResource *parent,
char *name) {
1179 DavResource *res = dav_resource_new_child(parent->session, parent, name);
1180 if(dav_create(res)) {
1181 dav_resource_free(res);
1182 return NULL;
1183 }
else {
1184 return res;
1185 }
1186 }
1187
1188 int dav_delete(DavResource *res) {
1189 CURL *handle = res->session->handle;
1190 util_set_url(res->session, dav_resource_get_href(res));
1191
1192 DavLock *lock = dav_get_lock(res->session, res->path);
1193 char *locktoken = lock ? lock->token :
NULL;
1194
1195 CxBuffer *response = cxBufferCreate(
NULL,
4096, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1196 CURLcode ret = do_delete_request(res->session, locktoken, response);
1197 long status =
0;
1198 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1199 int r =
0;
1200 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1201 res->session->error =
DAV_OK;
1202 res->exists =
0;
1203
1204
1205
1206 }
else {
1207 dav_session_set_error(res->session, ret, status);
1208 r =
1;
1209 }
1210
1211 cxBufferFree(response);
1212 return r;
1213 }
1214
1215 static int create_ancestors(DavSession *sn,
char *href,
char *path) {
1216 CURL *handle = sn->handle;
1217 CURLcode code;
1218
1219 DavLock *lock = dav_get_lock(sn, path);
1220 char *locktoken = lock ? lock->token :
NULL;
1221
1222 long status =
0;
1223 int ret =
0;
1224
1225 if(strlen(path) <=
1) {
1226 return 0;
1227 }
1228
1229 char *p = util_parent_path(path);
1230 char *h = util_parent_path(href);
1231
1232 for(
int i=
0;i<
2;i++) {
1233 util_set_url(sn, h);
1234 code = do_mkcol_request(sn, locktoken);
1235 curl_easy_getinfo(handle,
CURLINFO_RESPONSE_CODE, &status);
1236 if(status ==
201) {
1237
1238 char *name = (
char*)util_resource_name(p);
1239 int len = strlen(name);
1240 if(name[len -
1] ==
'/') {
1241 name[len -
1] =
'\0';
1242 }
1243 if(resource_add_crypto_info(sn, h, name,
NULL)) {
1244 sn->error =
DAV_ERROR;
1245 dav_session_set_errstr(sn,
"Cannot set crypto properties for ancestor");
1246 }
1247 break;
1248 }
else if(status ==
405) {
1249
1250 break;
1251 }
else if(status ==
409) {
1252
1253 if(create_ancestors(sn, h, p)) {
1254 ret =
1;
1255 break;
1256 }
1257 }
else {
1258 dav_session_set_error(sn, code, status);
1259 ret =
1;
1260 break;
1261 }
1262 }
1263
1264 free(p);
1265 free(h);
1266 return ret;
1267 }
1268
1269 static int create_resource(DavResource *res,
int *status) {
1270 DavSession *sn = res->session;
1271 CURL *handle = sn->handle;
1272 util_set_url(sn, dav_resource_get_href(res));
1273
1274 DavLock *lock = dav_get_lock(res->session, res->path);
1275 char *locktoken = lock ? lock->token :
NULL;
1276
1277 CURLcode code;
1278 if(res->iscollection) {
1279 code = do_mkcol_request(sn, locktoken);
1280 }
else {
1281 code = do_put_request(sn, locktoken,
TRUE,
"",
NULL,
NULL,
0);
1282 }
1283 long s =
0;
1284 curl_easy_getinfo(handle,
CURLINFO_RESPONSE_CODE, &s);
1285 *status = s;
1286 if(code ==
CURLE_OK && (s >=
200 && s <
300)) {
1287 sn->error =
DAV_OK;
1288
1289 if(!resource_add_crypto_info(sn, res->href, res->name,
NULL)) {
1290
1291 CxBuffer *rqbuf = create_propfind_request(sn,
NULL,
"propfind",
0);
1292 int ret = dav_propfind(sn, res, rqbuf);
1293 cxBufferFree(rqbuf);
1294 return ret;
1295 }
else {
1296 return 1;
1297 }
1298 }
else {
1299 dav_session_set_error(sn, code, s);
1300 return 1;
1301 }
1302 }
1303
1304 int dav_create(DavResource *res) {
1305 int status;
1306 if(!create_resource(res, &status)) {
1307
1308 res->exists =
1;
1309 return 0;
1310 }
1311
1312 if(status ==
403 || status ==
409 || status ==
404) {
1313
1314 if(create_ancestors(res->session, res->href, res->path)) {
1315 return 1;
1316 }
1317 }
1318
1319 return create_resource(res, &status);
1320 }
1321
1322 int dav_exists(DavResource *res) {
1323 if(!dav_load_prop(res,
NULL,
0)) {
1324 res->exists =
1;
1325 return 1;
1326 }
else {
1327 if(res->session->error ==
DAV_NOT_FOUND) {
1328 res->exists =
0;
1329 }
1330 return 0;
1331 }
1332 }
1333
1334 static int dav_cp_mv_url(DavResource *res,
char *desturl, _Bool copy, _Bool override) {
1335 DavSession *sn = res->session;
1336 CURL *handle = sn->handle;
1337 util_set_url(sn, dav_resource_get_href(res));
1338
1339 DavLock *lock = dav_get_lock(sn, res->path);
1340 char *locktoken = lock ? lock->token :
NULL;
1341
1342 CURLcode ret = do_copy_move_request(sn, desturl, locktoken, copy, override);
1343
1344 long status =
0;
1345 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1346 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1347 return 0;
1348 }
else {
1349 dav_session_set_error(sn, ret, status);
1350 return 1;
1351 }
1352 }
1353
1354 static int dav_cp_mv(DavResource *res,
char *newpath, _Bool copy, _Bool override) {
1355 char *dest = dav_session_get_href(res->session, newpath);
1356 char *desturl = util_get_url(res->session, dest);
1357 dav_session_free(res->session, dest);
1358
1359 int ret = dav_cp_mv_url(res, desturl, copy, override);
1360 free(desturl);
1361 return ret;
1362 }
1363
1364 int dav_copy(DavResource *res,
char *newpath) {
1365 return dav_cp_mv(res, newpath, true, false);
1366 }
1367
1368 int dav_move(DavResource *res,
char *newpath) {
1369 return dav_cp_mv(res, newpath, false, false);
1370 }
1371
1372 int dav_copy_o(DavResource *res,
char *newpath, DavBool override) {
1373 return dav_cp_mv(res, newpath, true, override);
1374 }
1375
1376 int dav_move_o(DavResource *res,
char *newpath, DavBool override) {
1377 return dav_cp_mv(res, newpath, false, override);
1378 }
1379
1380 int dav_copyto(DavResource *res,
char *url, DavBool override) {
1381 return dav_cp_mv_url(res, url, true, override);
1382 }
1383
1384 int dav_moveto(DavResource *res,
char *url, DavBool override) {
1385 return dav_cp_mv_url(res, url, false, override);
1386 }
1387
1388 int dav_lock(DavResource *res) {
1389 return dav_lock_t(res,
0);
1390 }
1391
1392 int dav_lock_t(DavResource *res,
time_t timeout) {
1393 DavSession *sn = res->session;
1394 CURL *handle = sn->handle;
1395 util_set_url(sn, dav_resource_get_href(res));
1396
1397 CxBuffer *request = create_lock_request();
1398 CxBuffer *response = cxBufferCreate(
NULL,
512, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1399 CURLcode ret = do_lock_request(sn, request, response, timeout);
1400
1401
1402
1403
1404
1405 cxBufferFree(request);
1406
1407 long status =
0;
1408 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1409 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1410 LockDiscovery lock;
1411 int parse_error = parse_lock_response(sn, response, &lock);
1412 cxBufferFree(response);
1413 if(parse_error) {
1414 sn->error =
DAV_ERROR;
1415 return -
1;
1416 }
1417
1418 DavLock *l = dav_create_lock(sn, lock.locktoken, lock.timeout);
1419 free(lock.locktoken);
1420 free(lock.timeout);
1421
1422 int r =
0;
1423 if(res->iscollection) {
1424 r = dav_add_collection_lock(sn, res->path, l);
1425 }
else {
1426 r = dav_add_resource_lock(sn, res->path, l);
1427 }
1428
1429 if(r ==
0) {
1430 return 0;
1431 }
else {
1432 (
void)dav_unlock(res);
1433 sn->error =
DAV_ERROR;
1434 dav_destroy_lock(sn, l);
1435 return -
1;
1436 }
1437 }
else {
1438 dav_session_set_error(sn, ret, status);
1439 cxBufferFree(response);
1440 return -
1;
1441 }
1442 }
1443
1444 int dav_unlock(DavResource *res) {
1445 DavSession *sn = res->session;
1446 CURL *handle = sn->handle;
1447 util_set_url(sn, dav_resource_get_href(res));
1448
1449 DavLock *lock = dav_get_lock(res->session, res->path);
1450 if(!lock) {
1451 sn->error =
DAV_ERROR;
1452 return -
1;
1453 }
1454
1455 CURLcode ret = do_unlock_request(sn, lock->token);
1456 long status =
0;
1457 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1458 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1459 dav_remove_lock(sn, res->path, lock);
1460 }
else {
1461 dav_session_set_error(sn, ret, status);
1462 return 1;
1463 }
1464
1465 return 0;
1466 }
1467
1468
1469 int resource_add_crypto_info(DavSession *sn,
const char *href,
const char *name,
const char *hash) {
1470 if(!
DAV_IS_ENCRYPTED(sn)) {
1471 return 0;
1472 }
1473
1474 CxBuffer *request = create_crypto_proppatch_request(sn, sn->key, name, hash);
1475 CxBuffer *response = cxBufferCreate(
NULL,
1024, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1476
1477 util_set_url(sn, href);
1478
1479 CURLcode ret = do_proppatch_request(sn,
NULL, request, response);
1480 cxBufferFree(request);
1481 long status =
0;
1482 curl_easy_getinfo (sn->handle,
CURLINFO_RESPONSE_CODE, &status);
1483 if(ret ==
CURLE_OK && status ==
207) {
1484
1485 sn->error =
DAV_OK;
1486 cxBufferFree(response);
1487 return 0;
1488 }
else {
1489 dav_session_set_error(sn, ret, status);
1490 cxBufferFree(response);
1491 return 1;
1492 }
1493 }
1494
1495
1496
1497 DavXmlNode* create_crypto_prop(DavSession *sn, CxMap *properties) {
1498 if(!sn->key) {
1499 return NULL;
1500 }
1501
1502 CxBuffer *content = cxBufferCreate(
NULL,
2048, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1503
1504
1505 CxMap *nsmap = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
8);
1506 cxDefineDestructor(nsmap, free);
1507 cxMapPut(nsmap, cx_hash_key_str(
"DAV:"), strdup(
"D"));
1508
1509 cxBufferPutString(content,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1510 cxBufferPutString(content,
"<D:prop xmlns:D=\"DAV:\">\n");
1511
1512 CxIterator i = cxMapIteratorValues(properties);
1513 cx_foreach(DavProperty*, prop, i) {
1514 DavXmlNode pnode;
1515 pnode.type =
DAV_XML_ELEMENT;
1516 pnode.namespace = prop->ns->name;
1517 pnode.name = prop->name;
1518 pnode.prev =
NULL;
1519
/a> pnode.next = NULL;
1520 pnode.children = prop->value;
1521 pnode.parent =
NULL;
1522 pnode.attributes =
NULL;
1523 pnode.content =
NULL;
1524 pnode.contentlength =
0;
1525
1526 dav_print_node(content, (cx_write_func)cxBufferWrite, nsmap, &pnode);
1527 cxBufferPut(content,
'\n');
1528 }
1529
1530 cxBufferPutString(content,
"</D:prop>");
1531
1532 cxMapDestroy(nsmap);
1533
1534
1535 char *crypto_prop_content = aes_encrypt(content->space, content->size, sn->key);
1536 cxBufferDestroy(content);
1537
1538 DavXmlNode *ret =
NULL;
1539 if(crypto_prop_content) {
1540 ret = dav_text_node(sn, crypto_prop_content);
1541 free(crypto_prop_content);
1542 }
1543 return ret;
1544 }
1545
1546 CxMap* parse_crypto_prop(DavSession *sn, DavKey *key, DavXmlNode *node) {
1547 if(!node || node->type !=
DAV_XML_TEXT || node->contentlength ==
0) {
1548 return NULL;
1549 }
1550
1551 return parse_crypto_prop_str(sn, key, node->content);
1552 }
1553
1554 CxMap* parse_crypto_prop_str(DavSession *sn, DavKey *key,
const char *content) {
1555 size_t len =
0;
1556 char *dec_str = aes_decrypt(content, &len, key);
1557
1558 xmlDoc *doc = xmlReadMemory(dec_str, len,
NULL,
NULL,
0);
1559 free(dec_str);
1560 if(!doc) {
1561 return NULL;
1562 }
1563
1564 int err =
0;
1565 xmlNode *xml_root = xmlDocGetRootElement(doc);
1566 if(xml_root) {
1567 if(
1568 !xml_root->ns ||
1569 !xstreq(xml_root->name,
"prop") ||
1570 !xstreq(xml_root->ns->href,
"DAV:"))
1571 {
1572 err =
1;
1573 }
1574 }
else {
1575 err =
1;
1576 }
1577
1578 if(err) {
1579 xmlFreeDoc(doc);
1580 return NULL;
1581 }
1582
1583
1584 CxMap *map = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
32);
1585 xmlNode *n = xml_root->children;
1586 while(n) {
1587 if(n->type ==
XML_ELEMENT_NODE && n->ns && n->ns->href) {
1588 DavProperty *property = dav_session_malloc(sn,
sizeof(DavProperty));
1589 property->name = dav_session_strdup(sn, (
const char*)n->name);
1590 property->ns = dav_session_malloc(sn,
sizeof(DavNamespace));
1591 property->ns->name = dav_session_strdup(sn, (
const char*)n->ns->href);
1592 property->ns->prefix = n->ns->prefix ?
1593 dav_session_strdup(sn, (
const char*)n->ns->prefix) :
NULL;
1594 property->value = n->children ? dav_convert_xml(sn, n->children) :
NULL;
1595
1596 cxmutstr propkey = dav_property_key(property->ns->name, property->name);
1597 cxMapPut(map, cx_hash_key_cxstr(propkey), property);
1598 cx_strfree(&propkey);
1599 }
1600 n = n->next;
1601 }
1602
1603 xmlFreeDoc(doc);
1604 if(cxMapSize(map) ==
0) {
1605 cxMapDestroy(map);
1606 return NULL;
1607 }
1608 return map;
1609 }
1610
1611
1612
1613
1614 static size_t in_write(
const char *ptr,
size_t size,
size_t nitems,
void *in_stream) {
1615 DavInputStream *in = in_stream;
1616 size_t len = size * nitems;
1617
1618 if(in->alloc < len) {
1619 char *newb = realloc(in->buffer, len);
1620 if(!newb) {
1621 if(in->buffer) free(in->buffer);
1622 in->eof =
1;
1623 return 0;
1624 }
1625
1626 in->buffer = newb;
1627 in->alloc = len;
1628 }
1629
1630 memcpy(in->buffer, ptr, len);
1631
1632 in->size = len;
1633 in->pos =
0;
1634
1635 return nitems;
1636 }
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878