Files
2026-08-07 17:38:18 +09:00

921 lines
26 KiB
C

/****************************************************************************
mod_dav_pgsql (DASL) for apache 2.X
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Author : sean kim (sean@solutionbox.co.kr)
$Id: search.c,v 1.2 2006/09/20 09:22:59 sean Exp $
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
****************************************************************************/
/*
** DASL SEARCH method
*/
#include <httpd.h>
#include <http_config.h>
#include <http_protocol.h>
#include <http_log.h>
#include <http_core.h> /* for ap_construct_url */
#include <apr_strings.h>
#include <apr_hash.h>
#include "dav_repos.h"
#include "dbms.h"
#include "util.h"
/**
* Used to hold the mappings from dead properties to the temporary
* table aliases they should be associated with.
*/
struct dead_prop_list
{
char *prop;
struct dead_prop_list *next;
};
typedef struct
{
char *query;
char *where_cond;
char *orderby;
char *limit;
char *err_msg;
}
search_ctx;
typedef struct dead_prop_list dead_prop_list;
int build_query(request_rec * r, apr_xml_doc * doc, search_ctx * sctx,
dav_repos_resource * search_result);
int build_xml_response(dav_repos_resource * query_results,
dav_response ** res);
int parse_select(request_rec * r, search_ctx * sctx,
apr_xml_elem * select_elem, dead_prop_list ** sel_list);
int parse_from(request_rec * r, dav_repos_resource * search_result,
search_ctx * sctx,
apr_xml_elem * from_elem, dead_prop_list * sel_list,
dead_prop_list * where_list);
int parse_where(request_rec * r, search_ctx * sctx, apr_xml_elem * where_elem,
dead_prop_list ** where_list);
int parse_orderby(request_rec * r, search_ctx * sctx,
apr_xml_elem * orderby_elem);
int parse_limit(request_rec * r, search_ctx * sctx,
apr_xml_elem * limit_elem);
int is_dead_prop(const char *prop);
static dav_error *dav_repos_set_option_head(request_rec * r)
{
TRACE();
/*DASL: <DAV:basicsearch>
* DASL: <http://foo.bar.com/syntax1>
* DASL: <http://akuma.com/syntax2>
*/
/*
apr_table_addn(r->headers_out, "DASL", "<http://dav.cse.ucsc.edu/syntax1>");
apr_table_addn(r->headers_out, "DASL", "<http://foo.bar.com/syntax2>");
*/
apr_table_addn(r->headers_out, "DASL", "<DAV:basicsearch>");
return NULL;
}
/**
* Handles the DASL SEARCH method
* @param r The method request record
* @return The HTTP response code
*/
static dav_error *dav_repos_search_resource(request_rec * r,
dav_response ** res)
{
int result;
apr_xml_doc *doc = NULL;
apr_xml_doc *response_body = NULL;
dav_repos_resource *search_result = NULL;
search_ctx *sctx = apr_pcalloc(r->pool, sizeof(*sctx));
/* FIXME :
*/
sctx->err_msg = "unknown: Plesae specify your error!";
TRACE();
if ((result = ap_xml_parse_input(r, &doc)) != 0) {
return solbox_dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
"ap_xml_parse_input error");
}
/*initialize search result structure */
search_result = (dav_repos_resource *) apr_pcalloc(r->pool,
sizeof(*search_result));
search_result->p = r->pool;
/* We need XML doc */
if (doc == NULL || doc->root == NULL) {
return solbox_dav_new_error(r->pool, HTTP_BAD_REQUEST, 0, "doc is NULL");
}
/* Build query */
if ((result = build_query(r, doc, sctx,
search_result)) != HTTP_OK) {
return solbox_dav_new_error(r->pool, result, 0, sctx->err_msg);
}
/* Seek DBMS */
if ((dbms_search(sctx->query, search_result)) != 0) {
return solbox_dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0,
"DBMS_SEARCH error");
}
/** FIXME : It might be too slow
*/
/* Get properties in a form of property link for every resource */
dbms_fill_dead_property(search_result);
/* Make result */
response_body = (apr_xml_doc *) apr_pcalloc(r->pool,
sizeof(*response_body));
if ((result =
build_xml_response(search_result, res) != HTTP_OK)) {
return solbox_dav_new_error(r->pool, HTTP_BAD_REQUEST, 0,
"An error occurred while building XML response!");
}
return NULL;
}
/**
* Builds the SQL query from the XML body of the request
* @param r The method request record
* @param doc The XML doc being parsed
* @param query The SQL query being built
* @param search_result The result record(s) returned from the DB query
* @param db_handle Pointer to the DB
* @return The HTTP response code
*/
int build_query(request_rec * r, apr_xml_doc * doc, search_ctx * sctx,
dav_repos_resource * search_result)
{
int result = -23;
apr_xml_elem *cur_elem = NULL;
apr_xml_elem *from_elem = NULL;
apr_xml_elem *select_elem = NULL;
apr_xml_elem *where_elem = NULL;
apr_xml_elem *order_elem = NULL;
apr_xml_elem *limit_elem = NULL;
dead_prop_list *sel_list = NULL;
dead_prop_list *where_list = NULL;
TRACE();
/* basicsearch */
cur_elem = dav_find_child(doc->root, "basicsearch");
if (cur_elem == NULL) {
sctx->err_msg =
apr_pstrdup(r->pool,
"Requested search grammar not supported."
" We support only <basicsearch>");
return HTTP_BAD_REQUEST;
}
/* initialize the query */
sctx->query = apr_pstrdup(r->pool, "SELECT distinct ");
/* Find elements */
select_elem = dav_find_child(cur_elem, "select");
from_elem = dav_find_child(cur_elem, "from");
where_elem = dav_find_child(cur_elem, "where");
order_elem = dav_find_child(cur_elem, "orderby");
limit_elem = dav_find_child(cur_elem, "limit");
/* process the select portion */
if (select_elem == NULL) {
sctx->err_msg =
apr_pstrdup(r->pool, "We don't have <select> element");
return HTTP_BAD_REQUEST;
}
/* Parse select element */
if ((result = parse_select(r, sctx, select_elem, &sel_list)) != HTTP_OK) {
return result;
}
/* process the from portion */
if (from_elem == NULL) {
sctx->err_msg = apr_pstrdup(r->pool, "We don't have <from> element");
return HTTP_BAD_REQUEST;
}
/* process the from portion */
if (where_elem == NULL || where_elem->first_child == NULL) {
sctx->err_msg =
apr_pstrdup(r->pool, "We don't have <where> element or child");
return HTTP_BAD_REQUEST;
}
if ((result = parse_where(r, sctx, where_elem->first_child,
&where_list)) != HTTP_OK) {
return result;
}
/* FIXME : What is this?? */
sctx->where_cond = apr_pstrcat(r->pool, " AND ", sctx->where_cond, NULL);
if (order_elem
&& (result = parse_orderby(r, sctx, order_elem)) != HTTP_OK) {
return result;
}
if (limit_elem && limit_elem->first_child) {
const char *limit_cdata =
dav_xml_get_cdata(limit_elem->first_child, r->pool, 1);
sctx->limit = apr_pstrcat(r->pool, " LIMIT ", limit_cdata, NULL);
}
if ((result = parse_from(r, search_result, sctx, from_elem,
sel_list, where_list)) != HTTP_OK) {
return result;
}
/* Combine all queries */
sctx->query = apr_pstrcat(r->pool, sctx->query, sctx->where_cond,
sctx->orderby, sctx->limit, NULL);
DBG0(sctx->query);
return HTTP_OK;
}
/**
* Processes the SELECT portion of the XML query
* @param r The method request record
* @param query The SQL query being constructed
* @param cur_elem The current XML element of WHERE clause being processed
* @param assoc The association list of dead props and their tables
* @return The HTTP response code
*/
int parse_select(request_rec * r, search_ctx * sctx, apr_xml_elem * cur_elem,
dead_prop_list ** dead_props)
{
dead_prop_list *tmp = NULL;
TRACE();
if (cur_elem->first_child) {
cur_elem = cur_elem->first_child;
}
else {
sctx->err_msg = apr_pstrdup(r->pool, "PARSE_SELECT 1");
}
if (cur_elem->name == NULL) {
sctx->err_msg = apr_pstrdup(r->pool, "No select element name");
}
if (apr_strnatcmp(cur_elem->name, "allprop") == 0) {
sctx->query = apr_pstrcat(r->pool, sctx->query,
"dasl_resource.serialno, ",
"dasl_resource.URI, ",
"dasl_resource.creationdate, ",
"dasl_resource.displayname, ",
"dasl_resource.getcontentlanguage, ",
"dasl_resource.getcontenttype, ",
"dasl_resource.getcontentlength, ",
"dasl_resource.getetag, ",
"dasl_resource.getlastmodified, ",
"dasl_resource.lockdiscovery, ",
"dasl_resource.resourcetype, ",
"dasl_resource.source, ",
"dasl_resource.supportedlock ", NULL);
return HTTP_OK;
}
if (apr_strnatcmp(cur_elem->name, "prop") == 0) {
sctx->query = apr_pstrcat(r->pool, sctx->query,
"dasl_resource.serialno, dasl_resource.URI",
NULL);
/* No prop information */
if (!cur_elem->first_child || cur_elem->first_child->first_child) {
sctx->err_msg = apr_pstrdup(r->pool, "No prop information");
return HTTP_BAD_REQUEST;
}
/* gather up the properties to search for */
for (cur_elem = cur_elem->first_child->first_child;
cur_elem; cur_elem = cur_elem->next) {
if ((is_dead_prop(cur_elem->name) == 23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = (char *) apr_pstrdup(r->pool, cur_elem->name);
*dead_props = tmp;
}
else {
sctx->query = apr_pstrcat(r->pool, sctx->query,
", dasl_resource.", cur_elem->name,
NULL);
}
}
return HTTP_OK;
}
/* Unkonw element name */
sctx->err_msg = apr_psprintf(r->pool, "Unkonw element name(%s) in select."
"Use <allprop> or <prop>", cur_elem->name);
return HTTP_BAD_REQUEST;
}
/**
* Processes the ORDER BY portion of the XML query
* @param r The method request record
* @param query The SQL query being constructed
* @param cur_elem The current XML element of WHERE clause being processed
* @return The HTTP response code
*/
int parse_from(request_rec * r, dav_repos_resource * search_result,
search_ctx * sctx,
apr_xml_elem * from_elem, dead_prop_list * sel_list,
dead_prop_list * where_list)
{
int result = -1;
apr_xml_elem *cur_elem = NULL;
const char *href = NULL;
const char *depth = NULL;
dead_prop_list *tmp = NULL;
TRACE();
if (sel_list) {
/* PK */
sctx->query = apr_pstrcat(r->pool, sctx->query, ", t.name, t.value",
" FROM dasl_resource left join dasl_property t USING (serialno) ",
NULL);
}
else {
sctx->query =
apr_pstrcat(r->pool, sctx->query, " FROM dasl_resource", NULL);
}
if ((tmp = where_list)) {
while (tmp) {
/* PK */
sctx->query =
apr_pstrcat(r->pool, sctx->query, " left join dasl_property ",
tmp->prop, "_t", " USING (serialno) ", NULL);
tmp = tmp->next;
}
}
sctx->query = apr_pstrcat(r->pool, sctx->query, " ", NULL);
/* ignore the SCOPE elem */
if (from_elem->first_child && from_elem->first_child->first_child) {
cur_elem = from_elem->first_child->first_child;
}
else {
sctx->err_msg = apr_pstrdup(r->pool, "SCOPE");
return HTTP_BAD_REQUEST;
}
/* Read Href CDATA */
href = dav_xml_get_cdata(cur_elem, r->pool, 1);
if (href == NULL || strlen(href) == 0) {
sctx->err_msg = apr_pstrdup(r->pool, "NO Href");
return HTTP_BAD_REQUEST;
}
/* If it is full URL, we need only path */
if (ap_is_url(href)) {
apr_uri_t uptr;
if (apr_uri_parse(r->pool, href, &uptr) != APR_SUCCESS ||
uptr.path == NULL) {
sctx->err_msg = apr_pstrdup(r->pool, "Malformed HREF");
return HTTP_BAD_REQUEST;
}
search_result->m_uri = apr_pstrdup(r->pool, uptr.path);
}
else if (*href == '/') { /* absolute href */
search_result->m_uri = apr_pstrdup(r->pool, href);
}
else {
sctx->err_msg =
apr_pstrdup(r->pool, "HREF must be full URL or absolute URI");
return HTTP_BAD_REQUEST;
}
/*PK*/
sctx->query = apr_pstrcat(r->pool, sctx->query, "WHERE (1=1) ", NULL);
/* PK
if (where_list) {
sctx->query = apr_pstrcat(r->pool, sctx->query, "dasl_resource.serialno = ",
where_list->prop, "_t.serialno ", NULL);
for (tmp = where_list; tmp; tmp = tmp->next) {
sctx->query =
apr_pstrcat(r->pool, sctx->query, "AND dasl_resource.serialno = ",
tmp->prop, "_t.serialno ", NULL);
}
}
*/
if (sel_list) {
/* PK
if (where_list == NULL) {
sctx->query = apr_pstrcat(r->pool, sctx->query,
"dasl_resource.serialno = dasl_property.serialno ",
"AND dasl_resource.serialno = t.serialno ",
NULL);
}
else {
sctx->query = apr_pstrcat(r->pool, sctx->query,
"AND dasl_resource.serialno = t.serialno ",
NULL);
}
*/
tmp = sel_list;
sctx->query = apr_pstrcat(r->pool, sctx->query, "AND (t.name = ",
sel_list->prop, NULL);
for (tmp = sel_list; tmp; tmp = tmp->next) {
if ((tmp->prop)) {
sctx->query =
apr_pstrcat(r->pool, sctx->query, " OR t.name = ",
tmp->prop, NULL);
}
}
sctx->query = apr_pstrcat(r->pool, sctx->query, ")", NULL);
} /* end if(sel_list) */
/* skip over SCOPE element */
if (cur_elem->next) {
cur_elem = cur_elem->next;
}
else {
sctx->err_msg = apr_pstrdup(r->pool, "Closing SCOPE");
return HTTP_BAD_REQUEST;
}
/* get depth */
depth = dav_xml_get_cdata(cur_elem, r->pool, 1);
/* Delete last slash */
dav_repos_no_trail(search_result->m_uri);
if ((result = dbms_get_resourcetype(search_result)) != 0) {
if (result == 100) { /* resource not found */
sctx->err_msg = apr_pstrdup(r->pool, "Resource not found");
return HTTP_NOT_FOUND;
}
else { /* must be -1: internal server error */
sctx->err_msg = apr_pstrdup(r->pool, "BAB DB");
return HTTP_INTERNAL_SERVER_ERROR;
}
}
/** FIXME : */
/*
search_result->resourcetype = 1;
*/
/* add "AND" to continue where we left off */
/*if (sel_list || where_list) {
sctx->query = apr_pstrcat(r->pool, sctx->query, " AND", NULL);
}
*/
sctx->query = apr_pstrcat(r->pool, sctx->query, " AND", NULL);
/** FIXME : What about the full URL ?? */
if ((apr_strnatcmp(depth, "0") == 0) ||
(search_result->m_resource_type == 0)) {
sctx->query = apr_pstrcat(r->pool, sctx->query, " uri = '",
search_result->m_uri, "'", NULL);
}
else {
/* this will be the same whether depth is 1 or infinity */
sctx->query =
apr_pstrcat(r->pool, sctx->query, " uri like '",
search_result->m_uri, "%'", NULL);
if (apr_strnatcmp(depth, "1") == 0) {
search_result->m_depth = ap_count_dirs(search_result->m_uri);
depth = apr_psprintf(r->pool, "%d", search_result->m_depth + 1);
sctx->query = apr_pstrcat(r->pool, sctx->query,
" AND depth = '", depth, "'", NULL);
}
}
return HTTP_OK;
}
/**
* Uses a recursive, depth first, in-order approach to construct the
* WHERE clause of the SQL query. The resulting query is completely
* parenthesized in order to maintain operator precedence.
* @param r The method request record
* @param query The SQL query being constructed
* @param cur_elem The current XML element of WHERE clause being processed
* @return The HTTP response code
*/
int parse_where(request_rec * r, search_ctx * sctx, apr_xml_elem * cur_elem,
dead_prop_list ** dead_props)
{
char *op = NULL;
dead_prop_list *tmp = NULL;
TRACE();
op = apr_pstrdup(r->pool, cur_elem->name);
if (sctx->where_cond) {
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond, "(", NULL);
}
else {
sctx->where_cond = apr_pstrdup(r->pool, "(");
}
/* To do:
(1) Add error checking for correct number of arguments. Return HTTP_BAD_REQUEST if
incorrect...
(2) Handle case sensitive searches...
*/
if (apr_strnatcmp(op, "and") == 0) {
if (cur_elem->first_child && cur_elem->first_child->next) {
parse_where(r, sctx, cur_elem->first_child, dead_props);
sctx->where_cond =
apr_pstrcat(r->pool, sctx->where_cond, " AND ", NULL);
parse_where(r, sctx, cur_elem->first_child->next, dead_props);
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "or") == 0) {
if (cur_elem->first_child && cur_elem->first_child->next) {
parse_where(r, sctx, cur_elem->first_child, dead_props);
sctx->where_cond =
apr_pstrcat(r->pool, sctx->where_cond, " OR ", NULL);
parse_where(r, sctx, cur_elem->first_child->next, dead_props);
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "not") == 0) {
if (cur_elem->first_child) {
sctx->where_cond =
apr_pstrcat(r->pool, sctx->where_cond, "NOT ", NULL);
parse_where(r, sctx, cur_elem->first_child, dead_props);
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "eq") == 0) {
if (cur_elem->first_child &&
cur_elem->first_child->first_child &&
cur_elem->first_child->first_child->name &&
cur_elem->first_child->next &&
cur_elem->first_child->next->first_cdata.first->text) {
if ((is_dead_prop(cur_elem->first_child->first_child->name) ==
23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = apr_pstrdup(r->pool,
cur_elem->first_child->first_child->
name);
*dead_props = tmp;
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
tmp->prop, "_t.name = '",
tmp->prop, "' AND ", tmp->prop,
"_t.value = '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
else {
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
cur_elem->first_child->
first_child->name, " = '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "lt") == 0) {
if (cur_elem->first_child &&
cur_elem->first_child->first_child &&
cur_elem->first_child->first_child->name &&
cur_elem->first_child->next &&
cur_elem->first_child->next->first_cdata.first->text) {
if ((is_dead_prop(cur_elem->first_child->first_child->name) ==
23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = apr_pstrdup(r->pool,
cur_elem->first_child->first_child->
name);
*dead_props = tmp;
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
tmp->prop, "_t.name = '",
tmp->prop, "' AND ", tmp->prop,
"_t.value < '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
else {
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
cur_elem->first_child->
first_child->name, " < '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "gt") == 0) {
if (cur_elem->first_child &&
cur_elem->first_child->first_child &&
cur_elem->first_child->first_child->name &&
cur_elem->first_child->next &&
cur_elem->first_child->next->first_cdata.first->text) {
if ((is_dead_prop(cur_elem->first_child->first_child->name) ==
23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = apr_pstrdup(r->pool,
cur_elem->first_child->first_child->
name);
*dead_props = tmp;
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
tmp->prop, "_t.name = '",
tmp->prop, "' AND ", tmp->prop,
"_t.value > '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
else {
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
cur_elem->first_child->
first_child->name, " > '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "lte") == 0) {
if (cur_elem->first_child &&
cur_elem->first_child->first_child &&
cur_elem->first_child->first_child->name &&
cur_elem->first_child->next &&
cur_elem->first_child->next->first_cdata.first->text) {
if ((is_dead_prop((char *) cur_elem->first_child->
first_child->name) == 23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = apr_pstrdup(r->pool,
cur_elem->first_child->first_child->
name);
*dead_props = tmp;
}
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
cur_elem->first_child->
first_child->name, " <= '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "gte") == 0) {
if (cur_elem->first_child &&
cur_elem->first_child->first_child &&
cur_elem->first_child->first_child->name &&
cur_elem->first_child->next &&
cur_elem->first_child->next->first_cdata.first->text) {
if ((is_dead_prop(cur_elem->first_child->first_child->name) ==
23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = apr_pstrdup(r->pool,
cur_elem->first_child->first_child->
name);
*dead_props = tmp;
}
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
cur_elem->first_child->
first_child->name, " >= '",
cur_elem->first_child->next->
first_cdata.first->text, "' ",
NULL);
}
else {
return HTTP_BAD_REQUEST;
}
}
else if (apr_strnatcmp(op, "like") == 0) {
if (cur_elem->first_child &&
cur_elem->first_child->first_child &&
cur_elem->first_child->first_child->name &&
cur_elem->first_child->next &&
cur_elem->first_child->next->first_cdata.first->text) {
if ((is_dead_prop(cur_elem->first_child->first_child->name) ==
23)) {
tmp = (dead_prop_list *) apr_pcalloc(r->pool, sizeof(*tmp));
tmp->next = *dead_props;
tmp->prop = apr_pstrdup(r->pool,
cur_elem->first_child->first_child->
name);
*dead_props = tmp;
}
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond,
cur_elem->first_child->
first_child->name, " like '",
cur_elem->first_child->next->
first_cdata.first->text, "'",
NULL);
}
else {
return HTTP_BAD_REQUEST;
}
/* According to the spec, the isdefined operator is optional. We'll
need to implement contains, however...
} else if (apr_strnatcmp(op, "isdefined") == 0) {
} else if (apr_strnatcmp(op, "contains") == 0) {
*/
}
sctx->where_cond = apr_pstrcat(r->pool, sctx->where_cond, ")", NULL);
return HTTP_OK;
}
/**
* Processes the ORDER BY portion of the XML query
* @param r The method request record
* @param query The SQL query being constructed
* @param cur_elem The current XML element of WHERE clause being processed
* @return The HTTP response code
*/
int parse_orderby(request_rec * r, search_ctx * sctx,
apr_xml_elem * orderby_elem)
{
apr_xml_elem *cur_elem = NULL;
TRACE();
sctx->orderby = apr_pstrdup(r->pool, " ORDER BY ");
/* iterate through <D:order> elements */
for (cur_elem = orderby_elem->first_child;
cur_elem; cur_elem = cur_elem->next) {
if (!cur_elem->first_child || !cur_elem->first_child->first_child) {
return HTTP_BAD_REQUEST;
}
sctx->orderby = apr_pstrcat(r->pool, sctx->orderby,
cur_elem->first_child->first_child->
name, NULL);
if (cur_elem->first_child->next) {
if (!cur_elem->first_child->next->name) {
return HTTP_BAD_REQUEST;
}
if (apr_strnatcmp(cur_elem->first_child->next->name,
"descending") == 0) {
sctx->orderby =
apr_pstrcat(r->pool, sctx->orderby, " DESC ", NULL);
}
else {
sctx->orderby =
apr_pstrcat(r->pool, sctx->orderby, " ASC ", NULL);
}
}
else { /* order not specified, use default ordering... */
sctx->orderby =
apr_pstrcat(r->pool, sctx->orderby, " ASC ", NULL);
}
} /* end for */
return HTTP_OK;
}
/**
* Tests whether a property is live or dead.
* @param prop The property to test
* @return A positive result indicates the property is dead
*/
static const char *dead_prop_names[] = {
"creationdate",
"displayname",
"getcontentlanguage",
"getcontenttype",
"getcontentlength",
"getetag",
"getlastmodified",
"lockdiscovery",
"resourcetype",
"source",
"supportedlock",
"filename",
"uri",
"textcontent",
"istext",
NULL
};
int is_dead_prop(const char *prop)
{
int i;
for (i = 0; dead_prop_names[i]; i++) {
if (!apr_strnatcmp(prop, dead_prop_names[i])) {
return -23;
}
}
return 23;
}
/**
* Builds the XML body of the response from the SQL query results
* @param r The method request record
* @param search_results The result(s) of the SQL query
*/
int build_xml_response(dav_repos_resource * query_results,
dav_response ** res)
{
dav_repos_resource *tmp_resource;
dav_response *newres = NULL;
TRACE();
*res = NULL;
/*
** loop through the dbms_result
** and build results
*/
/* Build name space id hash
* It will build query_results->ns_id_hash
*/
dbms_build_ns_id_hash(query_results);
/* FIXME : First data is root, so We need to skip this
*/
for (tmp_resource = query_results->next; tmp_resource;
tmp_resource = tmp_resource->next) {
/* need to set pool */
tmp_resource->p = query_results->p;
/* Need to set ns_id */
tmp_resource->ns_id_hash = query_results->ns_id_hash;
/* Build live property hash */
dav_repos_build_lpr_hash(tmp_resource);
newres = dav_repos_mkresponse(tmp_resource);
newres->next = *res;
*res = newres;
}
return HTTP_OK;
}
/*
** search hook functions
*/
const dav_hooks_search dav_repos_hooks_search = {
dav_repos_set_option_head,
dav_repos_search_resource
};