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*, property, 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_foreach(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 int 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 if(!pns) {
614 res->session->errorstr =
"Property namespace not found";
615 return 1;
616 }
617 dav_set_string_property_ns(res, pns, pname, value);
618 return 0;
619 }
620
621 static int add2propertylist(
const CxAllocator *a, CxList **list, DavProperty *property) {
622 if(!*list) {
623 CxList *newlist = cxLinkedListCreate(a,
NULL,
CX_STORE_POINTERS);
624 if(!newlist) {
625 return 1;
626 }
627 *list = newlist;
628 }
629 cxListAdd(*list, property);
630 return 0;
631 }
632
633 void dav_set_string_property_ns(DavResource *res,
char *ns,
char *name,
char *value) {
634 DavSession *sn = res->session;
635 const CxAllocator *a = res->session->mp->allocator;
636 DavResourceData *data = res->data;
637
638 DavProperty *property = createprop(res->session, ns, name);
639 property->value = dav_text_node(res->session, value);
640
641 if(
DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
642 add2propertylist(a, &data->crypto_set, property);
643 }
else {
644 add2propertylist(a, &data->set, property);
645 }
646 }
647
648 void dav_set_property(DavResource *res,
char *name, DavXmlNode *value) {
649 char *pns;
650 char *pname;
651 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
652 dav_set_property_ns(res, pns, pname, value);
653 }
654
655 void dav_set_property_ns(DavResource *res,
char *ns,
char *name, DavXmlNode *value) {
656 DavSession *sn = res->session;
657 const CxAllocator *a = sn->mp->allocator;
658 DavResourceData *data = res->data;
659
660 DavProperty *property = createprop(sn, ns, name);
661
662
663 property->value = value;
664
665 if(
DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
666 add2propertylist(a, &data->crypto_set, property);
667 }
else {
668 add2propertylist(a, &data->set, property);
669 }
670 }
671
672 void dav_remove_property(DavResource *res,
char *name) {
673 char *pns;
674 char *pname;
675 dav_get_property_namespace_str(res->session->context, name, &pns, &pname);
676 dav_remove_property_ns(res, pns, pname);
677 }
678
679 void dav_remove_property_ns(DavResource *res,
char *ns,
char *name) {
680 DavSession *sn = res->session;
681 DavResourceData *data = res->data;
682 const CxAllocator *a = res->session->mp->allocator;
683
684 DavProperty *property = createprop(res->session, ns, name);
685
686 if(
DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
687 add2propertylist(a, &data->crypto_remove, property);
688 }
else {
689 add2propertylist(a, &data->remove, property);
690 }
691 }
692
693 void dav_set_encrypted_property_ns(DavResource *res,
char *ns,
char *name, DavXmlNode *value) {
694 const CxAllocator *a = res->session->mp->allocator;
695 DavResourceData *data = res->data;
696
697 DavProperty *property = createprop(res->session, ns, name);
698 property->value = value;
699
700 add2propertylist(a, &data->crypto_set, property);
701 }
702
703 void dav_set_encrypted_string_property_ns(DavResource *res,
char *ns,
char *name,
char *value) {
704 const CxAllocator *a = res->session->mp->allocator;
705 DavResourceData *data = res->data;
706
707 DavProperty *property = createprop(res->session, ns, name);
708 property->value = dav_text_node(res->session, value);
709
710 add2propertylist(a, &data->crypto_set, property);
711 }
712
713 void dav_remove_encrypted_property_ns(DavResource *res,
char *ns,
char *name) {
714 DavResourceData *data = res->data;
715 const CxAllocator *a = res->session->mp->allocator;
716
717 DavProperty *property = createprop(res->session, ns, name);
718
719 add2propertylist(a, &data->crypto_remove, property);
720 }
721
722 static int compare_propname(
const void *a,
const void *b) {
723 const DavPropName *p1 = a;
724 const DavPropName *p2 = b;
725
726 int result = strcmp(p1->ns, p2->ns);
727 if(result) {
728 return result;
729 }
else {
730 return strcmp(p1->name, p2->name);
731 }
732 }
733
734 DavPropName* dav_get_property_names(DavResource *res,
size_t *count) {
735 DavResourceData *data = res->data;
736
737 *count = cxMapSize(data->properties);
738 DavPropName *names = dav_session_calloc(
739 res->session,
740 *count,
741 sizeof(DavPropName));
742
743
744 CxIterator i = cxMapIteratorValues(data->properties);
745 cx_foreach(DavProperty*, value, i) {
746 DavPropName *name = &names[i.index];
747 name->ns = value->ns->name;
748 name->name = value->name;
749 }
750
751 qsort(names, *count,
sizeof(DavPropName), compare_propname);
752
753 return names;
754 }
755
756
757 void dav_set_content(DavResource *res,
void *stream, dav_read_func read_func, dav_seek_func seek_func) {
758 DavResourceData *data = res->data;
759 data->content = stream;
760 data->read = read_func;
761 data->seek = seek_func;
762 data->length =
0;
763 }
764
765 void dav_set_content_data(DavResource *res,
char *content,
size_t length) {
766 DavSession *sn = res->session;
767 DavResourceData *data = res->data;
768 data->content = dav_session_malloc(sn, length);
769 memcpy(data->content, content, length);
770 data->read =
NULL;
771 data->seek =
NULL;
772 data->length = length;
773 }
774
775 void dav_set_content_length(DavResource *res,
size_t length) {
776 DavResourceData *data = res->data;
777 data->length = length;
778 }
779
780
781 int dav_load(DavResource *res) {
782 CxBuffer *rqbuf = create_allprop_propfind_request();
783 int ret = dav_propfind(res->session, res, rqbuf);
784 cxBufferFree(rqbuf);
785 return ret;
786 }
787
788 int dav_load_prop(DavResource *res, DavPropName *properties,
size_t numprop) {
789 CxMempool *mp = cxMempoolCreate(
64,
NULL);
790 const CxAllocator *a = mp->allocator;
791
792 CxList *proplist = cxArrayListCreate(a,
NULL,
sizeof(DavProperty), numprop);
793 for(
size_t i=
0;i<numprop;i++) {
794 DavProperty p;
795 p.name = properties[i].name;
796 p.ns = cxMalloc(a,
sizeof(DavNamespace));
797 p.ns->name = properties[i].ns;
798 if(!strcmp(properties[i].ns,
"DAV:")) {
799 p.ns->prefix =
"D";
800 }
else {
801 p.ns->prefix = cx_asprintf_a(a,
"x%d", (
int)i).ptr;
802 }
803 p.value =
NULL;
804 cxListAdd(proplist, &p);
805 }
806
807 CxBuffer *rqbuf = create_propfind_request(res->session, proplist,
"propfind",
0);
808 int ret = dav_propfind(res->session, res, rqbuf);
809 cxBufferFree(rqbuf);
810 cxMempoolDestroy(mp);
811 return ret;
812 }
813
814
815 static void init_hash_stream(HashStream *hstr,
void *stream, dav_read_func readfn, dav_seek_func seekfn) {
816 hstr->sha =
NULL;
817 hstr->stream = stream;
818 hstr->read = readfn;
819 hstr->seek = seekfn;
820 hstr->error =
0;
821 }
822
823 static size_t dav_read_h(
void *buf,
size_t size,
size_t nelm,
void *stream) {
824 HashStream *s = stream;
825 if(!s->sha) {
826 s->sha = dav_hash_init();
827 }
828
829 size_t r = s->read(buf, size, nelm, s->stream);
830 dav_hash_update(s->sha, buf, r);
831 return r;
832 }
833
834 static int dav_seek_h(
void *stream,
long offset,
int whence) {
835 HashStream *s = stream;
836 if(offset ==
0 && whence ==
SEEK_SET) {
837 unsigned char buf[
DAV_SHA256_DIGEST_LENGTH];
838 dav_hash_final(s->sha, buf);
839 s->sha =
NULL;
840 }
else {
841 s->error =
1;
842 }
843 return s->seek(s->stream, offset, whence);
844 }
845
846
847 int dav_store(DavResource *res) {
848 DavSession *sn = res->session;
849 DavResourceData *data = res->data;
850
851 util_set_url(sn, dav_resource_get_href(res));
852
853 DavLock *lock = dav_get_lock(sn, res->path);
854 char *locktoken = lock ? lock->token :
NULL;
855
856
857 if(data->content) {
858 curl_easy_setopt(sn->handle,
CURLOPT_XFERINFOFUNCTION, dav_session_put_progress);
859 curl_easy_setopt(sn->handle,
CURLOPT_XFERINFODATA, res);
860 curl_easy_setopt(sn->handle,
CURLOPT_NOPROGRESS,
0L);
861
862 int encryption =
DAV_ENCRYPT_CONTENT(sn) && sn->key;
863 CURLcode ret;
864 if(encryption) {
865 AESEncrypter *enc =
NULL;
866 CxBuffer *buf =
NULL;
867 if(data->read) {
868 enc = aes_encrypter_new(
869 sn->key,
870 data->content,
871 data->read,
872 data->seek);
873 }
else {
874 buf = cxBufferCreate(data->content, data->length, cxDefaultAllocator,
0);
875 buf->size = data->length;
876 enc = aes_encrypter_new(
877 sn->key,
878 buf,
879 (dav_read_func)cxBufferRead,
880 (dav_seek_func)cxBufferSeek);
881 }
882
883
884 ret = do_put_request(
885 sn,
886 locktoken,
887 TRUE,
888 enc,
889 (dav_read_func)aes_read,
890 (dav_seek_func)aes_encrypter_reset,
891 0);
892
893
894 dav_get_hash(&enc->sha256, (
unsigned char*)data->hash);
895 char *enc_hash = aes_encrypt(data->hash,
DAV_SHA256_DIGEST_LENGTH, sn->key);
896
897 aes_encrypter_close(enc);
898 if(buf) {
899 cxBufferFree(buf);
900 }
901
902
903
904 if(resource_add_crypto_info(sn, res->href, res->name, enc_hash)) {
905 free(enc_hash);
906 curl_easy_setopt(sn->handle,
CURLOPT_XFERINFOFUNCTION,
NULL);
907 curl_easy_setopt(sn->handle,
CURLOPT_NOPROGRESS,
1L);
908 return 1;
909 }
910 resource_add_string_property(res,
DAV_NS,
"crypto-hash", enc_hash);
911 free(enc_hash);
912 }
else if((sn->flags &
DAV_SESSION_STORE_HASH) ==
DAV_SESSION_STORE_HASH) {
913 HashStream hstr;
914 CxBuffer *iobuf =
NULL;
915 if(!data->read) {
916 iobuf = cxBufferCreate(data->content, data->length, cxDefaultAllocator,
0);
917 iobuf->size = data->length;
918 init_hash_stream(
919 &hstr,
920 iobuf,
921 (dav_read_func)cxBufferRead,
922 (dav_seek_func)cxBufferSeek);
923 }
else {
924 init_hash_stream(
925 &hstr,
926 data->content,
927 data->read,
928 data->seek);
929 }
930
931 ret = do_put_request(
932 sn,
933 locktoken,
934 TRUE,
935 &hstr,
936 dav_read_h,
937 (dav_seek_func)dav_seek_h,
938 data->length);
939
940 if(hstr.sha) {
941 dav_hash_final(hstr.sha, (
unsigned char*)data->hash);
942 char *hash = util_hexstr((
unsigned char*)data->hash,
32);
943 dav_set_string_property_ns(res,
DAV_NS,
"content-hash", hash);
944 free(hash);
945 }
946 }
else {
947 ret = do_put_request(
948 sn,
949 locktoken,
950 TRUE,
951 data->content,
952 data->read,
953 data->seek,
954 data->length);
955 }
956
957 curl_easy_setopt(sn->handle,
CURLOPT_XFERINFOFUNCTION,
NULL);
958 curl_easy_setopt(sn->handle,
CURLOPT_NOPROGRESS,
1L);
959
960 long status =
0;
961 curl_easy_getinfo(sn->handle,
CURLINFO_RESPONSE_CODE, &status);
962 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
963 res->session->error =
0;
964
965 if(!data->read) {
966 cxFree(sn->mp->allocator, data->content);
967 }
968 data->content =
NULL;
969 data->read =
NULL;
970 data->length =
0;
971 }
else {
972 dav_session_set_error(sn, ret, status);
973 return 1;
974 }
975 }
976
977
978 if(
DAV_ENCRYPT_PROPERTIES(sn) && sn->key && (data->crypto_set || data->crypto_remove)) {
979 DavResource *crypto_res = dav_resource_new_href(sn, res->href);
980 int ret =
1;
981
982 if(crypto_res) {
983 CxBuffer *rqbuf = create_cryptoprop_propfind_request();
984 ret = dav_propfind(res->session, res, rqbuf);
985 cxBufferFree(rqbuf);
986 }
987
988 if(!ret) {
989 DavXmlNode *crypto_prop_node = dav_get_property_ns(crypto_res,
DAV_NS,
"crypto-prop");
990 CxMap *crypto_props = parse_crypto_prop(sn, sn->key, crypto_prop_node);
991 if(!crypto_props) {
992
993 crypto_props = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
32);
994 }
995
996
997 if(data->crypto_remove) {
998 CxIterator i = cxListIterator(data->crypto_remove);
999 cx_foreach(DavProperty *, property, i) {
1000 if(cxMapSize(crypto_props) ==
0) {
1001 break;
1002 }
1003
1004 cxmutstr key = dav_property_key(property->ns->name, property->name);
1005 DavProperty *existing_prop = cxMapGet(crypto_props, cx_hash_key(key.ptr, key.length));
1006 if(existing_prop) {
1007
1008 }
1009 free(key.ptr);
1010 }
1011 }
1012
1013
1014 if(data->crypto_set) {
1015 CxIterator i = cxListIterator(data->crypto_set);
1016 cx_foreach(DavProperty *, property, i) {
1017 cxmutstr keystr = dav_property_key(property->ns->name, property->name);
1018 CxHashKey key = cx_hash_key(keystr.ptr, keystr.length);
1019 DavProperty *existing_prop = cxMapRemoveAndGet(crypto_props, key);
1020 cxMapPut(crypto_props, key, property);
1021 if(existing_prop) {
1022
1023 }
1024 free(keystr.ptr);
1025 }
1026 }
1027
1028 DavXmlNode *crypto_prop_value = create_crypto_prop(sn, crypto_props);
1029 if(crypto_prop_value) {
1030 DavProperty *new_crypto_prop = createprop(sn,
DAV_NS,
"crypto-prop");
1031 new_crypto_prop->value = crypto_prop_value;
1032 add2propertylist(sn->mp->allocator, &data->set, new_crypto_prop);
1033 }
1034
1035 dav_resource_free(crypto_res);
1036 }
1037
1038 if(ret) {
1039 return 1;
1040 }
1041 }
1042
1043
1044 int r =
0;
1045 sn->error =
DAV_OK;
1046 if(data->set || data->remove >
0) {
1047 CxBuffer *request = create_proppatch_request(data);
1048 CxBuffer *response = cxBufferCreate(
NULL,
1024, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1049
1050
1051 CURLcode ret = do_proppatch_request(sn, locktoken, request, response);
1052 long status =
0;
1053 curl_easy_getinfo (sn->handle,
CURLINFO_RESPONSE_CODE, &status);
1054 if(ret ==
CURLE_OK && status ==
207) {
1055
1056
1057
1058 data->set =
NULL;
1059 data->remove =
NULL;
1060 }
else {
1061 dav_session_set_error(sn, ret, status);
1062 r = -
1;
1063 }
1064
1065 cxBufferFree(request);
1066 cxBufferFree(response);
1067 }
1068
1069 return r;
1070 }
1071
1072 #if LIBCURL_VERSION_MAJOR >=
7 &&
LIBCURL_VERSION_MINOR >=
32
1073 static void set_progressfunc(DavResource *res) {
1074 CURL *handle = res->session->handle;
1075 curl_easy_setopt(handle,
CURLOPT_XFERINFOFUNCTION, dav_session_get_progress);
1076 curl_easy_setopt(handle,
CURLOPT_XFERINFODATA, res);
1077 curl_easy_setopt(handle,
CURLOPT_NOPROGRESS,
0L);
1078 }
1079
1080 static void unset_progressfunc(DavResource *res) {
1081 CURL *handle = res->session->handle;
1082 curl_easy_setopt(handle,
CURLOPT_XFERINFOFUNCTION,
NULL);
1083 curl_easy_setopt(handle,
CURLOPT_XFERINFODATA,
NULL);
1084 curl_easy_setopt(handle,
CURLOPT_NOPROGRESS,
1L);
1085 }
1086 #else
1087 static void set_progressfunc(DavResource *res) {
1088
1089 }
1090 static void unset_progressfunc(DavResource *res) {
1091
1092 }
1093 #endif
1094
1095 int dav_get_content(DavResource *res,
void *stream, dav_write_func write_fnc) {
1096 DavSession *sn = res->session;
1097 CURL *handle = sn->handle;
1098 util_set_url(res->session, dav_resource_get_href(res));
1099
1100
1101 AESDecrypter *dec =
NULL;
1102 DavKey *key =
NULL;
1103 if(
DAV_DECRYPT_CONTENT(sn)) {
1104 char *keyname = dav_get_string_property_ns(res,
DAV_NS,
"crypto-key");
1105 if(keyname) {
1106 key = dav_context_get_key(sn->context, keyname);
1107 if(key) {
1108 dec = aes_decrypter_new(key, stream, write_fnc);
1109 stream = dec;
1110 write_fnc = (dav_write_func)aes_write;
1111 }
1112 }
1113 }
1114
1115 curl_easy_setopt(handle,
CURLOPT_HTTPHEADER,
NULL);
1116 curl_easy_setopt(handle,
CURLOPT_CUSTOMREQUEST,
NULL);
1117 curl_easy_setopt(handle,
CURLOPT_PUT,
0L);
1118 curl_easy_setopt(handle,
CURLOPT_UPLOAD,
0L);
1119
1120 curl_easy_setopt(handle,
CURLOPT_WRITEFUNCTION, write_fnc);
1121 curl_easy_setopt(handle,
CURLOPT_WRITEDATA, stream);
1122
1123 if(sn->get_progress) {
1124 set_progressfunc(res);
1125 }
1126
1127 long status =
0;
1128 CURLcode ret = dav_session_curl_perform(sn, &status);
1129
1130 if(sn->get_progress) {
1131 unset_progressfunc(res);
1132 }
1133
1134 char *hash =
NULL;
1135 if(dec) {
1136 aes_decrypter_shutdown(dec);
1137
1138
1139 unsigned char sha[
DAV_SHA256_DIGEST_LENGTH];
1140 dav_get_hash(&dec->sha256, sha);
1141 hash = util_hexstr(sha,
DAV_SHA256_DIGEST_LENGTH);
1142
1143 aes_decrypter_close(dec);
1144 }
1145
1146 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1147 int verify_failed =
0;
1148 if(
DAV_DECRYPT_CONTENT(sn) && key) {
1149
1150 char *res_hash = dav_get_string_property_ns(res,
DAV_NS,
"crypto-hash");
1151
1152 if(res_hash) {
1153 size_t len =
0;
1154 char *dec_hash = aes_decrypt(res_hash, &len, key);
1155 char *hex_hash = util_hexstr((
unsigned char*)dec_hash, len);
1156 if(strcmp(hash, hex_hash)) {
1157 verify_failed =
1;
1158 }
1159 free(dec_hash);
1160 free(hex_hash);
1161 }
1162 }
1163 if(hash) {
1164 free(hash);
1165 }
1166
1167 if(verify_failed) {
1168 res->session->error =
DAV_CONTENT_VERIFICATION_ERROR;
1169 return 1;
1170 }
1171
1172 res->session->error =
DAV_OK;
1173 return 0;
1174 }
else {
1175 if(hash) {
1176 free(hash);
1177 }
1178 dav_session_set_error(res->session, ret, status);
1179 return 1;
1180 }
1181 }
1182
1183 DavResource* dav_create_child(DavResource *parent,
char *name) {
1184 DavResource *res = dav_resource_new_child(parent->session, parent, name);
1185 if(dav_create(res)) {
1186 dav_resource_free(res);
1187 return NULL;
1188 }
else {
1189 return res;
1190 }
1191 }
1192
1193 int dav_delete(DavResource *res) {
1194 CURL *handle = res->session->handle;
1195 util_set_url(res->session, dav_resource_get_href(res));
1196
1197 DavLock *lock = dav_get_lock(res->session, res->path);
1198 char *locktoken = lock ? lock->token :
NULL;
1199
1200 CxBuffer *response = cxBufferCreate(
NULL,
4096, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1201 CURLcode ret = do_delete_request(res->session, locktoken, response);
1202 long status =
0;
1203 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1204 int r =
0;
1205 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1206 res->session->error =
DAV_OK;
1207 res->exists =
0;
1208
1209
1210
1211 }
else {
1212 dav_session_set_error(res->session, ret, status);
1213 r =
1;
1214 }
1215
1216 cxBufferFree(response);
1217 return r;
1218 }
1219
1220 static int create_ancestors(DavSession *sn,
char *href,
char *path) {
1221 CURL *handle = sn->handle;
1222 CURLcode code;
1223
1224 DavLock *lock = dav_get_lock(sn, path);
1225 char *locktoken = lock ? lock->token :
NULL;
1226
1227 long status =
0;
1228 int ret =
0;
1229
1230 if(strlen(path) <=
1) {
1231 return 0;
1232 }
1233
1234 char *p = util_parent_path(path);
1235 char *h = util_parent_path(href);
1236
1237 for(
int i=
0;i<
2;i++) {
1238 util_set_url(sn, h);
1239 code = do_mkcol_request(sn, locktoken);
1240 curl_easy_getinfo(handle,
CURLINFO_RESPONSE_CODE, &status);
1241 if(status ==
201) {
1242
1243 char *name = (
char*)util_resource_name(p);
1244 int len = strlen(name);
1245 if(name[len -
1] ==
'/') {
1246 name[len -
1] =
'\0';
1247 }
1248 if(resource_add_crypto_info(sn, h, name,
NULL)) {
1249 sn->error =
DAV_ERROR;
1250 dav_session_set_errstr(sn,
"Cannot set crypto properties for ancestor");
1251 }
1252 break;
1253 }
else if(status ==
405) {
1254
1255 break;
1256 }
else if(status ==
409) {
1257
1258 if(create_ancestors(sn, h, p)) {
1259 ret =
1;
1260 break;
1261 }
1262 }
else {
1263 dav_session_set_error(sn, code, status);
1264 ret =
1;
1265 break;
1266 }
1267 }
1268
1269 free(p);
1270 free(h);
1271 return ret;
1272 }
1273
1274 static int create_resource(DavResource *res,
int *status) {
1275 DavSession *sn = res->session;
1276 CURL *handle = sn->handle;
1277 util_set_url(sn, dav_resource_get_href(res));
1278
1279 DavLock *lock = dav_get_lock(res->session, res->path);
1280 char *locktoken = lock ? lock->token :
NULL;
1281
1282 CURLcode code;
1283 if(res->iscollection) {
1284 code = do_mkcol_request(sn, locktoken);
1285 }
else {
1286 code = do_put_request(sn, locktoken,
TRUE,
"",
NULL,
NULL,
0);
1287 }
1288 long s =
0;
1289 curl_easy_getinfo(handle,
CURLINFO_RESPONSE_CODE, &s);
1290 *status = s;
1291 if(code ==
CURLE_OK && (s >=
200 && s <
300)) {
1292 sn->error =
DAV_OK;
1293
1294 if(!resource_add_crypto_info(sn, res->href, res->name,
NULL)) {
1295
1296 CxBuffer *rqbuf = create_propfind_request(sn,
NULL,
"propfind",
0);
1297 int ret = dav_propfind(sn, res, rqbuf);
1298 cxBufferFree(rqbuf);
1299 return ret;
1300 }
else {
1301 return 1;
1302 }
1303 }
else {
1304 dav_session_set_error(sn, code, s);
1305 return 1;
1306 }
1307 }
1308
1309 int dav_create(DavResource *res) {
1310 int status;
1311 if(!create_resource(res, &status)) {
1312
1313 res->exists =
1;
1314 return 0;
1315 }
1316
1317 if(status ==
403 || status ==
409 || status ==
404) {
1318
1319 if(create_ancestors(res->session, res->href, res->path)) {
1320 return 1;
1321 }
1322 }
1323
1324 return create_resource(res, &status);
1325 }
1326
1327 int dav_exists(DavResource *res) {
1328 if(!dav_load_prop(res,
NULL,
0)) {
1329 res->exists =
1;
1330 return 1;
1331 }
else {
1332 if(res->session->error ==
DAV_NOT_FOUND) {
1333 res->exists =
0;
1334 }
1335 return 0;
1336 }
1337 }
1338
1339 static int dav_cp_mv_url(DavResource *res,
char *desturl, _Bool copy, _Bool override) {
1340 DavSession *sn = res->session;
1341 CURL *handle = sn->handle;
1342 util_set_url(sn, dav_resource_get_href(res));
1343
1344 DavLock *lock = dav_get_lock(sn, res->path);
1345 char *locktoken = lock ? lock->token :
NULL;
1346
1347 CURLcode ret = do_copy_move_request(sn, desturl, locktoken, copy, override);
1348
1349 long status =
0;
1350 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1351 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1352 return 0;
1353 }
else {
1354 dav_session_set_error(sn, ret, status);
1355 return 1;
1356 }
1357 }
1358
1359 static int dav_cp_mv(DavResource *res,
char *newpath, _Bool copy, _Bool override) {
1360 char *dest = dav_session_get_href(res->session, newpath);
1361 char *desturl = util_get_url(res->session, dest);
1362 dav_session_free(res->session, dest);
1363
1364 int ret = dav_cp_mv_url(res, desturl, copy, override);
1365 free(desturl);
1366 return ret;
1367 }
1368
1369 int dav_copy(DavResource *res,
char *newpath) {
1370 return dav_cp_mv(res, newpath, true, false);
1371 }
1372
1373 int dav_move(DavResource *res,
char *newpath) {
1374 return dav_cp_mv(res, newpath, false, false);
1375 }
1376
1377 int dav_copy_o(DavResource *res,
char *newpath, DavBool override) {
1378 return dav_cp_mv(res, newpath, true, override);
1379 }
1380
1381 int dav_move_o(DavResource *res,
char *newpath, DavBool override) {
1382 return dav_cp_mv(res, newpath, false, override);
1383 }
1384
1385 int dav_copyto(DavResource *res,
char *url, DavBool override) {
1386 return dav_cp_mv_url(res, url, true, override);
1387 }
1388
1389 int dav_moveto(DavResource *res,
char *url, DavBool override) {
1390 return dav_cp_mv_url(res, url, false, override);
1391 }
1392
1393 int dav_lock(DavResource *res) {
1394 return dav_lock_t(res,
0);
1395 }
1396
1397 int dav_lock_t(DavResource *res,
time_t timeout) {
1398 DavSession *sn = res->session;
1399 CURL *handle = sn->handle;
1400 util_set_url(sn, dav_resource_get_href(res));
1401
1402 CxBuffer *request = create_lock_request();
1403 CxBuffer *response = cxBufferCreate(
NULL,
512, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1404 CURLcode ret = do_lock_request(sn, request, response, timeout);
1405
1406
1407
1408
1409
1410 cxBufferFree(request);
1411
1412 long status =
0;
1413 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1414 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1415 LockDiscovery lock;
1416 int parse_error = parse_lock_response(sn, response, &lock);
1417 cxBufferFree(response);
1418 if(parse_error) {
1419 sn->error =
DAV_ERROR;
1420 return -
1;
1421 }
1422
1423 DavLock *l = dav_create_lock(sn, lock.locktoken, lock.timeout);
1424 free(lock.locktoken);
1425 free(lock.timeout);
1426
1427 int r =
0;
1428 if(res->iscollection) {
1429 r = dav_add_collection_lock(sn, res->path, l);
1430 }
else {
1431 r = dav_add_resource_lock(sn, res->path, l);
1432 }
1433
1434 if(r ==
0) {
1435 return 0;
1436 }
else {
1437 (
void)dav_unlock(res);
1438 sn->error =
DAV_ERROR;
1439 dav_destroy_lock(sn, l);
1440 return -
1;
1441 }
1442 }
else {
1443 dav_session_set_error(sn, ret, status);
1444 cxBufferFree(response);
1445 return -
1;
1446 }
1447 }
1448
1449 int dav_unlock(DavResource *res) {
1450 DavSession *sn = res->session;
1451 CURL *handle = sn->handle;
1452 util_set_url(sn, dav_resource_get_href(res));
1453
1454 DavLock *lock = dav_get_lock(res->session, res->path);
1455 if(!lock) {
1456 sn->error =
DAV_ERROR;
1457 return -
1;
1458 }
1459
1460 CURLcode ret = do_unlock_request(sn, lock->token);
1461 long status =
0;
1462 curl_easy_getinfo (handle,
CURLINFO_RESPONSE_CODE, &status);
1463 if(ret ==
CURLE_OK && (status >=
200 && status <
300)) {
1464 dav_remove_lock(sn, res->path, lock);
1465 }
else {
1466 dav_session_set_error(sn, ret, status);
1467 return 1;
1468 }
1469
1470 return 0;
1471 }
1472
1473
1474 int resource_add_crypto_info(DavSession *sn,
const char *href,
const char *name,
const char *hash) {
1475 if(!
DAV_IS_ENCRYPTED(sn)) {
1476 return 0;
1477 }
1478
1479 CxBuffer *request = create_crypto_proppatch_request(sn, sn->key, name, hash);
1480 CxBuffer *response = cxBufferCreate(
NULL,
1024, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1481
1482 util_set_url(sn, href);
1483
1484 CURLcode ret = do_proppatch_request(sn,
NULL, request, response);
1485 cxBufferFree(request);
1486 long status =
0;
1487 curl_easy_getinfo (sn->handle,
CURLINFO_RESPONSE_CODE, &status);
1488 if(ret ==
CURLE_OK && status ==
207) {
1489
1490 sn->error =
DAV_OK;
1491 cxBufferFree(response);
1492 return 0;
1493 }
else {
1494 dav_session_set_error(sn, ret, status);
1495 cxBufferFree(response);
1496 return 1;
1497 }
1498 }
1499
1500
1501
1502 DavXmlNode* create_crypto_prop(DavSession *sn, CxMap *properties) {
1503 if(!sn->key) {
1504 return NULL;
1505 }
1506
1507 CxBuffer *content = cxBufferCreate(
NULL,
2048, cxDefaultAllocator,
CX_BUFFER_FREE_CONTENTS|
CX_BUFFER_AUTO_EXTEND);
1508
1509
1510 CxMap *nsmap = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
8);
1511 cxDefineDestructor(nsmap, free);
1512 cxMapPut(nsmap, cx_hash_key_str(
"DAV:"), strdup(
"D"));
1513
1514 cxBufferPutString(content,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1515 cxBufferPutString(content,
"<D:prop xmlns:D=\"DAV:\">\n");
1516
1517 CxIterator i = cxMapIteratorValues(properties);
1518 cx_foreach(DavProperty*, prop, i) {
1519 DavXmlNode pnode;
1520 pnode.type =
DAV_XML_ELEMENT;
1521 pnode.namespace = prop->ns->name;
1522 pnode.name = prop->name;
1523 pnode.prev =
NULL;
1524 pnode.next =
NULL;
1525 pnode.children = prop->value;
1526 pnode.parent =
NULL;
1527 pnode.attributes =
NULL;
1528 pnode.content =
NULL;
1529 pnode.contentlength =
0;
1530
1531 dav_print_node(content, (cx_write_func)cxBufferWrite, nsmap, &pnode);
1532 cxBufferPut(content,
'\n');
1533 }
1534
1535 cxBufferPutString(content,
"</D:prop>");
1536
1537 cxMapDestroy(nsmap);
1538
1539
1540 char *crypto_prop_content = aes_encrypt(content->space, content->size, sn->key);
1541 cxBufferDestroy(content);
1542
1543 DavXmlNode *ret =
NULL;
1544 if(crypto_prop_content) {
1545 ret = dav_text_node(sn, crypto_prop_content);
1546 free(crypto_prop_content);
1547 }
1548 return ret;
1549 }
1550
1551 CxMap* parse_crypto_prop(DavSession *sn, DavKey *key, DavXmlNode *node) {
1552 if(!node || node->type !=
DAV_XML_TEXT || node->contentlength ==
0) {
1553 return NULL;
1554 }
1555
1556 return parse_crypto_prop_str(sn, key, node->content);
1557 }
1558
1559 CxMap* parse_crypto_prop_str(DavSession *sn, DavKey *key,
const char *content) {
1560 size_t len =
0;
1561 char *dec_str = aes_decrypt(content, &len, key);
1562
1563 xmlDoc *doc = xmlReadMemory(dec_str, len,
NULL,
NULL,
0);
1564 free(dec_str);
1565 if(!doc) {
1566 return NULL;
1567 }
1568
1569 int err =
0;
1570 xmlNode *xml_root = xmlDocGetRootElement(doc);
1571 if(xml_root) {
1572 if(
1573 !xml_root->ns ||
1574 !xstreq(xml_root->name,
"prop") ||
1575 !xstreq(xml_root->ns->href,
"DAV:"))
1576 {
1577 err =
1;
1578 }
1579 }
else {
1580 err =
1;
1581 }
1582
1583 if(err) {
1584 xmlFreeDoc(doc);
1585 return NULL;
1586 }
1587
1588
1589 CxMap *map = cxHashMapCreate(cxDefaultAllocator,
CX_STORE_POINTERS,
32);
1590 xmlNode *n = xml_root->children;
1591 while(n) {
1592 if(n->type ==
XML_ELEMENT_NODE && n->ns && n->ns->href) {
1593 DavProperty *property = dav_session_malloc(sn,
sizeof(DavProperty));
1594 property->name = dav_session_strdup(sn, (
const char*)n->name);
1595 property->ns = dav_session_malloc(sn,
sizeof(DavNamespace));
1596 property->ns->name = dav_session_strdup(sn, (
const char*)n->ns->href);
1597 property->ns->prefix = n->ns->prefix ?
1598 dav_session_strdup(sn, (
const char*)n->ns->prefix) :
NULL;
1599 property->value = n->children ? dav_convert_xml(sn, n->children) :
NULL;
1600
1601 cxmutstr propkey = dav_property_key(property->ns->name, property->name);
1602 cxMapPut(map, cx_hash_key_cxstr(propkey), property);
1603 cx_strfree(&propkey);
1604 }
1605 n = n->next;
1606 }
1607
1608 xmlFreeDoc(doc);
1609 if(cxMapSize(map) ==
0) {
1610 cxMapDestroy(map);
1611 return NULL;
1612 }
1613 return map;
1614 }
1615
1616
1617
1618
1619 static size_t in_write(
const char *ptr,
size_t size,
size_t nitems,
void *in_stream) {
1620 DavInputStream *in = in_stream;
1621 size_t len = size * nitems;
1622
1623 if(in->alloc < len) {
1624 char *newb = realloc(in->buffer, len);
1625 if(!newb) {
1626 if(in->buffer) free(in->buffer);
1627 in->eof =
1;
1628 return 0;
1629 }
1630
1631 in->buffer = newb;
1632 in->alloc = len;
1633 }
1634
1635 memcpy(in->buffer, ptr, len);
1636
1637 in->size = len;
1638 in->pos =
0;
1639
1640 return nitems;
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
1879
1880
1881
1882
1883