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