libidav/resource.c

changeset 609
dc3d70848c7c
parent 605
bbc66c72661a
child 713
a1c36a6410f6
--- a/libidav/resource.c	Fri Jul 12 16:59:08 2019 +0200
+++ b/libidav/resource.c	Sun Jul 28 13:07:53 2019 +0200
@@ -120,11 +120,13 @@
 }
 
 void resource_free_properties(DavSession *sn, UcxMap *properties) {
+    if(!properties) return;
+    
     UcxMapIterator i = ucx_map_iterator(properties);
-    DavXmlNode *node;
-    UCX_MAP_FOREACH(key, node, i) {
+    DavProperty *property;
+    UCX_MAP_FOREACH(key, property, i) {
         // TODO: free everything
-        dav_session_free(sn, node);
+        dav_session_free(sn, property);
     }
     ucx_map_free(properties);
 }
@@ -140,6 +142,7 @@
     
     DavResourceData *data = res->data;
     resource_free_properties(sn, data->properties);
+    resource_free_properties(sn, data->crypto_properties);
     
     UCX_FOREACH(elm, data->set) {
         DavProperty *p = elm->data;
@@ -221,10 +224,13 @@
         return NULL;
     }
     data->properties = ucx_map_new_a(sn->mp->allocator, 32);
+    data->crypto_properties = NULL;
     data->set = NULL;
     data->remove = NULL;
+    data->crypto_set = NULL;
+    data->crypto_remove = NULL;
+    data->read = NULL;
     data->content = NULL;
-    data->read = NULL;
     data->seek = NULL;
     data->length = 0;
     return data;
@@ -239,15 +245,29 @@
     return resource->href;
 }
 
+void resource_add_prop(DavResource *res, const char *ns, const char *name, DavXmlNode *val) {
+    DavSession *sn = res->session;
+    
+    DavNamespace *namespace = dav_session_malloc(sn, sizeof(DavNamespace));
+    namespace->prefix = NULL;
+    namespace->name = dav_session_strdup(sn, ns);
+    
+    DavProperty *prop = dav_session_malloc(sn, sizeof(DavProperty));
+    prop->name = dav_session_strdup(sn, name);
+    prop->ns = namespace;
+    prop->value = val;
+    
+    sstr_t key = dav_property_key(ns, name);
+    ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, prop);
+    free(key.ptr);
+}
+
 void resource_add_property(DavResource *res, const char *ns, const char *name, xmlNode *val) {
     if(!val) {
         return;
     }
     
-    sstr_t key = dav_property_key(ns, name);
-    DavXmlNode *v = dav_convert_xml(res->session, val);
-    ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v);
-    free(key.ptr);
+    resource_add_prop(res, ns, name, dav_convert_xml(res->session, val));
 }
 
 void resource_add_string_property(DavResource *res, char *ns, char *name, char *val) {
@@ -255,23 +275,45 @@
         return;
     }
     
-    sstr_t key = dav_property_key(ns, name);
-    DavXmlNode *v = dav_text_node(res->session, val);
-    ucx_map_sstr_put(((DavResourceData*)res->data)->properties, key, v);
-    free(key.ptr);
+    resource_add_prop(res, ns, name, dav_text_node(res->session, val));
+}
+
+void resource_set_crypto_properties(DavResource *res, UcxMap *cprops) {
+    DavResourceData *data = res->data;
+    resource_free_properties(res->session, data->crypto_properties);
+    data->crypto_properties = cprops;
 }
 
 DavXmlNode* resource_get_property(DavResource *res, const char *ns, const char *name) {
     sstr_t keystr = dav_property_key(ns, name);
     UcxKey key = ucx_key(keystr.ptr, keystr.length);
-    DavXmlNode *property = resource_get_property_k(res, key);
+    DavXmlNode *ret = resource_get_property_k(res, key);
     free(keystr.ptr);
-    return property;
+    
+    return ret;
+}
+
+DavXmlNode* resource_get_encrypted_property(DavResource *res, const char *ns, const char *name) {
+    sstr_t keystr = dav_property_key(ns, name);
+    UcxKey key = ucx_key(keystr.ptr, keystr.length);
+    DavXmlNode *ret = resource_get_encrypted_property_k(res, key);
+    free(keystr.ptr);
+    
+    return ret;
 }
 
 DavXmlNode* resource_get_property_k(DavResource *res, UcxKey key) {
     DavResourceData *data = (DavResourceData*)res->data;
-    return ucx_map_get(data->properties, key);
+    DavProperty *property = ucx_map_get(data->properties, key);
+    
+    return property ? property->value : NULL;
+}
+
+DavXmlNode* resource_get_encrypted_property_k(DavResource *res, UcxKey key) {
+    DavResourceData *data = (DavResourceData*)res->data;
+    DavProperty *property = ucx_map_get(data->crypto_properties, key);
+    
+    return property ? property->value : NULL;
 }
 
 sstr_t dav_property_key(const char *ns, const char *name) {
@@ -445,17 +487,37 @@
     return dav_get_property_ns(res, pns, pname);
 }
 
-DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name) {
+static DavXmlNode* get_property_ns(DavResource *res, DavBool encrypted, const char *ns, const char *name) {
     if(!ns || !name) {
         return NULL;
     }
-    DavXmlNode *property = resource_get_property(res, ns, name);
+    
     DavResourceData *data = res->data;
+    
+    DavXmlNode *property = NULL;
+    UcxList *remove_list = NULL;
+    UcxList *set_list = NULL;
+    
+    if(encrypted) {
+        // check if crypto_properties because it will only be created
+        // if the resource has encrypted properties
+        if(!data->crypto_properties) {
+            return NULL;
+        }
+        property = resource_get_encrypted_property(res, ns, name);
+        remove_list = data->crypto_remove;
+        set_list = data->crypto_set;
+    } else {
+        property = resource_get_property(res, ns, name);
+        remove_list = data->remove;
+        set_list = data->set;
+    }
+    
     // resource_get_property only returns persistent properties
     // check the remove and set list
     if(property) {
         // if the property is in the remove list, we return NULL
-        UCX_FOREACH(elm, data->remove) {
+        UCX_FOREACH(elm, remove_list) {
             DavProperty *p = elm->data;
             if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) {
                 return NULL;
@@ -464,16 +526,31 @@
     }
     // the set list contains property updates
     // we return an updated property if possible
-    UCX_FOREACH(elm, data->set) {
+    UCX_FOREACH(elm, set_list) {
         DavProperty *p = elm->data;
         if(!strcmp(p->name, name) && !strcmp(p->ns->name, ns)) {
             return p->value; // TODO: fix
         }
     }
     // no property update
+    
     return property;
 }
 
+DavXmlNode* dav_get_property_ns(DavResource *res, const char *ns, const char *name) {
+    DavXmlNode *property_value = get_property_ns(res, FALSE, ns, name);
+    
+    if(!property_value && DAV_DECRYPT_PROPERTIES(res->session)) {
+        property_value = get_property_ns(res, TRUE, ns, name);
+    }
+    
+    return property_value;
+}
+
+DavXmlNode* dav_get_encrypted_property_ns(DavResource *res, const char *ns, const char *name) {
+    return get_property_ns(res, TRUE, ns, name);
+}
+
 static DavProperty* createprop(DavSession *sn, const char *ns, const char *name) {
     DavProperty *property = dav_session_malloc(sn, sizeof(DavProperty));
     property->name = dav_session_strdup(sn, name);
@@ -496,13 +573,18 @@
 }
 
 void dav_set_string_property_ns(DavResource *res, char *ns, char *name, char *value) {
+    DavSession *sn = res->session;
     UcxAllocator *a = res->session->mp->allocator;
     DavResourceData *data = res->data;
     
     DavProperty *property = createprop(res->session, ns, name);
     property->value = dav_text_node(res->session, value);
     
-    data->set = ucx_list_append_a(a, data->set, property);
+    if(DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
+        data->crypto_set = ucx_list_append_a(a, data->crypto_set, property);
+    } else {
+        data->set = ucx_list_append_a(a, data->set, property);
+    }
 }
 
 void dav_set_property(DavResource *res, char *name, DavXmlNode *value) {
@@ -513,13 +595,18 @@
 }
 
 void dav_set_property_ns(DavResource *res, char *ns, char *name, DavXmlNode *value) {
-    UcxAllocator *a = res->session->mp->allocator;
+    DavSession *sn = res->session;
+    UcxAllocator *a = sn->mp->allocator; 
     DavResourceData *data = res->data;
     
-    DavProperty *property = createprop(res->session, ns, name);
+    DavProperty *property = createprop(sn, ns, name);
     property->value = value; // TODO: copy node?
     
-    data->set = ucx_list_append_a(a, data->set, property);
+    if(DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
+        data->crypto_set = ucx_list_append_a(a, data->crypto_set, property);
+    } else {
+        data->set = ucx_list_append_a(a, data->set, property);
+    }
 }
 
 void dav_remove_property(DavResource *res, char *name) {
@@ -530,12 +617,17 @@
 }
 
 void dav_remove_property_ns(DavResource *res, char *ns, char *name) {
+    DavSession *sn = res->session;
     DavResourceData *data = res->data;
     UcxAllocator *a = res->session->mp->allocator;
     
     DavProperty *property = createprop(res->session, ns, name);
     
-    data->remove = ucx_list_append_a(a, data->remove, property);
+    if(DAV_ENCRYPT_PROPERTIES(sn) && dav_namespace_is_encrypted(sn->context, ns)) {
+        data->crypto_remove = ucx_list_append_a(a, data->crypto_remove, property);
+    } else {
+        data->remove = ucx_list_append_a(a, data->remove, property);
+    }
 }
 
 void dav_set_encrypted_property_ns(DavResource *res, char *ns, char *name, DavXmlNode *value) {
@@ -590,18 +682,14 @@
     
     
     UcxMapIterator i = ucx_map_iterator(data->properties);
-    void *value;
+    DavProperty *value;
     int j = 0;
     UCX_MAP_FOREACH(key, value, i) {
         DavPropName *name = &names[j];
-        // the map key is namespace + '\0' + name
-        name->ns = (char*)key.data;
-        for(int k=0;j<key.len;k++) {
-            if(((char*)key.data)[k] == '\0') {
-                name->name = (char*)key.data + k + 1;
-                break;
-            }
-        }
+        
+        name->ns = value->ns->name;
+        name->name = value->name;
+        
         j++;
     }
     
@@ -833,6 +921,67 @@
         }
     }
     
+    // generate crypto-prop content
+    if(DAV_ENCRYPT_PROPERTIES(sn) && sn->key && (data->crypto_set || data->crypto_remove)) {
+        DavResource *crypto_res = dav_resource_new_href(sn, res->href);
+        int ret = 1;
+        
+        if(crypto_res) {
+            UcxBuffer *rqbuf = create_cryptoprop_propfind_request();
+            ret = dav_propfind(res->session, res, rqbuf);
+            ucx_buffer_free(rqbuf);
+        }
+        
+        if(!ret) {
+            DavXmlNode *crypto_prop_node = dav_get_property_ns(crypto_res, DAV_NS, "crypto-prop");
+            UcxMap *crypto_props = parse_crypto_prop(sn, sn->key, crypto_prop_node);
+            if(!crypto_props) {
+                // resource hasn't encrypted properties yet
+                crypto_props = ucx_map_new(32); // create new map
+            }
+            
+            // remove all properties
+            UCX_FOREACH(elm, data->crypto_remove) {
+                if(crypto_props->count == 0) {
+                    break; // map already empty, can't remove any more
+                }
+                
+                DavProperty *property = elm->data;
+                sstr_t key = dav_property_key(property->ns->name, property->name);
+                DavProperty *existing_prop = ucx_map_sstr_remove(crypto_props, key);
+                if(existing_prop) {
+                    // TODO: free existing_prop
+                }                
+                free(key.ptr);
+            }
+            
+            // set properties
+            UCX_FOREACH(elm, data->crypto_set) {
+                DavProperty *property = elm->data;
+                sstr_t key = dav_property_key(property->ns->name, property->name);
+                DavProperty *existing_prop = ucx_map_sstr_remove(crypto_props, key);
+                ucx_map_sstr_put(crypto_props, key, property);
+                if(existing_prop) {
+                    // TODO: free existing_prop
+                }  
+                free(key.ptr);
+            }
+            
+            DavXmlNode *crypto_prop_value = create_crypto_prop(sn, crypto_props);
+            if(crypto_prop_value) {
+                DavProperty *new_crypto_prop = createprop(sn, DAV_NS, "crypto-prop");
+                new_crypto_prop->value = crypto_prop_value;
+                data->set = ucx_list_prepend_a(sn->mp->allocator, data->set, new_crypto_prop);
+            }
+            
+            dav_resource_free(crypto_res);
+        }
+        
+        if(ret) {
+            return 1;
+        }
+    }
+    
     // store properties
     int r = 0;
     sn->error = DAV_OK;
@@ -858,7 +1007,7 @@
         ucx_buffer_free(request);
         ucx_buffer_free(response);
     }
-    
+     
     return r;
 }
 
@@ -1352,13 +1501,17 @@
     return ret;
 }
 
-UcxMap* parse_crypto_prop(DavSession *sn, DavXmlNode *node) {
+UcxMap* parse_crypto_prop(DavSession *sn, DavKey *key, DavXmlNode *node) {
     if(!node || node->type != DAV_XML_TEXT || node->contentlength == 0) {
         return NULL;
     }
     
+    return parse_crypto_prop_str(sn, key, node->content);
+}
+
+UcxMap* parse_crypto_prop_str(DavSession *sn, DavKey *key, const char *content) {
     size_t len = 0;
-    char *dec_str = aes_decrypt(node->content, &len, sn->key);
+    char *dec_str = aes_decrypt(content, &len, key);
     
     xmlDoc *doc = xmlReadMemory(dec_str, len, NULL, NULL, 0);
     free(dec_str);

mercurial