87 p.xmlns,\n\ |
87 p.xmlns,\n\ |
88 p.pname,\n\ |
88 p.pname,\n\ |
89 p.pvalue\n\ |
89 p.pvalue\n\ |
90 from Resource r\n\ |
90 from Resource r\n\ |
91 left join Property p on r.resource_id = p.resource_id\n\ |
91 left join Property p on r.resource_id = p.resource_id\n\ |
92 inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\ |
92 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\ |
93 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ |
93 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ |
94 where r.resource_id = $1;"; |
94 where r.resource_id = $1;"; |
95 |
95 |
96 // propfind with depth = 1 |
96 // propfind with depth = 1 |
97 // params: $1: resource_id |
97 // params: $1: resource_id |
98 static const char *sql_propfind_allprop_depth1 = "\ |
98 static const char *sql_propfind_allprop_depth1 = "\ |
99 select\n\ |
99 select\n\ |
100 NULL ass ppath,\n\ |
100 case when r.resource_id = $1 then $2\n\ |
|
101 else $2 || '/' || r.nodename\n\ |
|
102 end as ppath,\n\ |
101 r.resource_id,\n\ |
103 r.resource_id,\n\ |
102 r.parent_id,\n\ |
104 r.parent_id,\n\ |
103 r.nodename,\n\ |
105 r.nodename,\n\ |
104 r.iscollection,\n\ |
106 r.iscollection,\n\ |
105 r.lastmodified,\n\ |
107 r.lastmodified,\n\ |
129 p.xmlns,\n\ |
133 p.xmlns,\n\ |
130 p.pname,\n\ |
134 p.pname,\n\ |
131 p.pvalue\n\ |
135 p.pvalue\n\ |
132 from Resource r\n\ |
136 from Resource r\n\ |
133 left join Property p on r.resource_id = p.resource_id\n\ |
137 left join Property p on r.resource_id = p.resource_id\n\ |
134 inner join (select unnest($2::text[]) as xmlns, unnest($3::text[]) as pname) n\n\ |
138 inner join (select unnest($3::text[]) as xmlns, unnest($4::text[]) as pname) n\n\ |
135 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ |
139 on ( p.xmlns = n.xmlns and p.pname = n.pname ) or p.property_id is null\n\ |
136 where r.resource_id = $1 or r.parent_id = $1\n\ |
140 where r.resource_id = $1 or r.parent_id = $1\n\ |
137 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;"; |
141 order by order by case when resource_id = $1 then 0 else 1 end, nodename, resource_id;"; |
138 |
142 |
139 // recursive propfind |
143 // recursive propfind |
293 |
302 |
294 // get all resources and properties |
303 // get all resources and properties |
295 char resource_id_str[32]; |
304 char resource_id_str[32]; |
296 snprintf(resource_id_str, 32, "%" PRId64, resource_id); |
305 snprintf(resource_id_str, 32, "%" PRId64, resource_id); |
297 |
306 |
298 const char* params[1] = { resource_id_str }; |
307 size_t href_len = strlen(href); |
|
308 char *href_param = pool_malloc(rq->sn->pool, href_len + 1); |
|
309 memcpy(href_param, href, href_len); |
|
310 if(href_param[href_len-1] == '/') { |
|
311 href_len--; |
|
312 } |
|
313 href_param[href_len] = '\0'; |
|
314 |
|
315 |
|
316 const char* params[2] = { resource_id_str, href_param }; |
299 PGresult *result = PQexecParams( |
317 PGresult *result = PQexecParams( |
300 pgdav->connection, |
318 pgdav->connection, |
301 sql_propfind_allprop_recursive, |
319 sql_propfind_allprop_recursive, |
302 1, // number of parameters |
320 2, // number of parameters |
303 NULL, |
321 NULL, |
304 params, // parameter value |
322 params, // parameter value |
305 NULL, |
323 NULL, |
306 NULL, |
324 NULL, |
307 0); // 0: result in text format |
325 0); // 0: result in text format |
308 int nrows = PQntuples(result); |
326 int nrows = PQntuples(result); |
|
327 pool_free(rq->sn->pool, href_param); |
309 if(nrows < 1) { |
328 if(nrows < 1) { |
310 PQclear(result); |
329 PQclear(result); |
311 return 1; |
330 return 1; |
312 } |
331 } |
313 |
332 |
351 // 9: property name |
370 // 9: property name |
352 // 10: property value |
371 // 10: property value |
353 |
372 |
354 char *path = PQgetvalue(result, r, 0); |
373 char *path = PQgetvalue(result, r, 0); |
355 char *res_id = PQgetvalue(result, r, 1); |
374 char *res_id = PQgetvalue(result, r, 1); |
|
375 char *iscollection_str = PQgetvalue(result, r, 4); |
|
376 WSBool iscollection = iscollection_str && iscollection_str[0] == 't'; |
356 int64_t resource_id; |
377 int64_t resource_id; |
357 if(!util_strtoint(res_id, &resource_id)) { |
378 if(!util_strtoint(res_id, &resource_id)) { |
358 log_ereport(LOG_FAILURE, "pg_dav_propfind_do: cannot convert resource_id '%s' to int", res_id); |
379 log_ereport(LOG_FAILURE, "pg_dav_propfind_do: cannot convert resource_id '%s' to int", res_id); |
359 return 1; |
380 return 1; |
360 } |
381 } |
361 |
382 |
362 char *nodename = PQgetvalue(result, r, 3); |
383 char *nodename = PQgetvalue(result, r, 3); |
363 if(resource_id != current_resource_id) { |
384 if(resource_id != current_resource_id) { |
|
385 // create a href string for the new resource |
|
386 // if the resource is a collection, it should have a trailing '/' |
|
387 size_t pathlen = strlen(path); |
|
388 if(pathlen == 0) { |
|
389 log_ereport(LOG_FAILURE, "pg_dav_propfind_do: query returned invalid path"); |
|
390 return 1; |
|
391 } |
|
392 char *newres_href = pool_malloc(pool, pathlen+2); |
|
393 memcpy(newres_href, path, pathlen); |
|
394 if(iscollection && path[pathlen-1] != '/') { |
|
395 newres_href[pathlen++] = '/'; |
|
396 } |
|
397 newres_href[pathlen] = '\0'; |
|
398 |
364 // new resource |
399 // new resource |
365 resource = response->addresource(response, nodename); |
400 resource = response->addresource(response, newres_href); |
366 vfsprops_set = FALSE; |
401 vfsprops_set = FALSE; |
367 current_resource_id = resource_id; |
402 current_resource_id = resource_id; |
368 } |
403 } |
369 |
404 |
370 // standard webdav properties |
405 // standard webdav properties |
371 if(!vfsprops_set) { |
406 if(!vfsprops_set) { |
372 if(vfsprops.getresourcetype) { |
407 if(vfsprops.getresourcetype) { |
373 char *iscollection = PQgetvalue(result, r, 4); |
408 if(iscollection) { |
374 if(iscollection && iscollection[0] == 't') { |
|
375 resource->addproperty(resource, webdav_resourcetype_collection(), 200); |
409 resource->addproperty(resource, webdav_resourcetype_collection(), 200); |
376 } else { |
410 } else { |
377 resource->addproperty(resource, webdav_resourcetype_empty(), 200); |
411 resource->addproperty(resource, webdav_resourcetype_empty(), 200); |
378 } |
412 } |
379 } |
413 } |
404 property->lang = NULL; |
438 property->lang = NULL; |
405 property->name = pool_strdup(pool, pname); |
439 property->name = pool_strdup(pool, pname); |
406 |
440 |
407 xmlNs *namespace = pool_malloc(pool, sizeof(xmlNs)); |
441 xmlNs *namespace = pool_malloc(pool, sizeof(xmlNs)); |
408 memset(namespace, 0, sizeof(struct _xmlNs)); |
442 memset(namespace, 0, sizeof(struct _xmlNs)); |
409 namespace->href = pool_strdup(pool, xmlns); |
443 namespace->href = (xmlChar*)pool_strdup(pool, xmlns); |
410 namespace->prefix = "zx1"; |
444 namespace->prefix = (xmlChar*)"zx1"; // TODO |
411 property->namespace = namespace; |
445 property->namespace = namespace; |
412 |
446 |
413 property->vtype = WS_VALUE_TEXT; |
447 property->vtype = WS_VALUE_TEXT; |
414 property->value.text.str = pool_strdup(pool, pvalue); |
448 property->value.text.str = pool_strdup(pool, pvalue); |
415 property->value.text.length = strlen(pvalue); |
449 property->value.text.length = strlen(pvalue); |