doubango/trunk/tinyXCAP2/src/txc_node.c

339 lines
13 KiB
C

/*
* Copyright (C) 2009 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou@yahoo.fr>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/
/**@file txc_node.c
* @brief RFC 4825 subclause <a href="http://tools.ietf.org/html/rfc4825#section-6.4">6.4 (Namespace Bindings for the Selector
)</a> and subclause <a href="http://tools.ietf.org/html/rfc4825#section-6.3">6.3 (Node Selector)</a>
*
* @author Mamadou Diop <diopmamadou(at)yahoo.fr>
*
* @date Created: Sat Nov 8 16:54:58 2009 mdiop
*/
#include "txc_node.h"
#include "txc_document.h"
#include "txc_macros.h"
#include <stdarg.h>
#include "txc_document.h"
#include "txc_macros.h"
/**@defgroup txc_node_group XCAP node selector
*/
/**@page txc_node_page XCAP node selector Tutorial
*
* @sa txc_document_page
*
* @par ABNF<br>
* Node Selector as per rfc 4825 subclause 6.3<br>
* node-selector = element-selector ["/" terminal-selector]<br>
* terminal-selector = attribute-selector / namespace-selector /<br>
* extension-selector<br>
* element-selector = step *( "/" step)<br>
* step = by-name / by-pos / by-attr / by-pos-attr /<br>
* extension-selector<br>
* by-name = NameorAny<br>
* by-pos = NameorAny "[" position "]"<br>
* position = 1*DIGIT<br>
* attr-test = "@" att-name "=" att-value<br>
* by-attr = NameorAny "[" attr-test "]"<br>
* by-pos-attr = NameorAny "[" position "]" "[" attr-test "]"<br>
* NameorAny = QName / "*" ; QName from XML Namespaces<br>
* att-name = QName<br>
* att-value = AttValue ; from XML specification<br>
* attribute-selector = "@" att-name<br>
* namespace-selector = "namespace::*"<br>
* extension-selector = 1*( %x00-2e / %x30-ff ) ; anything but "/"<br>
*
* @par Settings<br>
* @a XCAP-ROOT = http://xcap.example.com:8080/services <br>
* @a XUI = sip:doubango@example.com <br>
*
* <H3>=== Find list with {name='Default' and auid='resource-list'} ===</H3>
* @code
#include "txc_api.h"
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_ATTR("list", "name", "Default"), //==> /resource-lists/list[@name="Default"]
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>===Find list with {position='2' and auid='resource-list'} ===</H3>
* @code
#include "txc_api.h"
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_POS("list", 2), //==> /resource-lists/list[2]
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>=== Find list with {position='4' and using wildcard} ===</H3>
* @code
#include "txc_api.h
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_POS("*", 4), //==> /resource-lists/*[4]
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>=== Find entry with {uri='sip:doubango@example.com' and from list->name='Ennemies' and auid='resource-list'} ===</H3>
* @code
#include "txc_api.h
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_ATTR("list", "name", "Ennemies"),//==> /resource-lists/list[@name="Ennemies"]
TXC_NODE_SELECT_BY_ATTR("entry", "uri", "sip:doubango@example.com"),//==> /resource-lists/list[@name="Ennemies"]/entry[@uri="sip:doubango@example.com"]
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>===Find entry's display-name with {uri='sip:doubango@example.com' and from list->name='Friends' and auid='resource-list' }===</H3>
* @code
#include "txc_api.h
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_ATTR("list", "name", "Friends"),//==> /resource-lists/list[@name="Friends"]
TXC_NODE_SELECT_BY_ATTR("entry", "uri", "sip:doubango@example.com"),//==> /resource-lists/list[@name="Friends"]/entry[@uri="sip:doubango@example.com"]
TXC_NODE_SELECT_BY_NAME("display-name"),//==> /resource-lists/list[@name="Friends"]/entry[@uri="sip:doubango@example.com"]/display-name
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>=== Find entry's display-name with {position='1' and from list->name='Friends' and auid='resource-list'} ===</H3>
* @code
#include "txc_api.h
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_ATTR("list", "name", "Friends"),//==> /resource-lists/list[@name="Friends"]
TXC_NODE_SELECT_BY_POS("entry", 1),//==> /resource-lists/list[@name="Friends"]/entry[1]
TXC_NODE_SELECT_BY_NAME("display-name"),//==> /resource-lists/list[@name="Friends"]/entry[1]/display-name
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>=== Find entry's display-name with {uri='sip:doubango@example.com' and position = '23' and from list->name='Ennemies' and auid='resource-list'} ===</H3>
* @code
#include "txc_api.h
url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_ATTR("list", "name", "Ennemies"),//==> /resource-lists/list[@name="Ennemies"]
TXC_NODE_SELECT_BY_POS_ATTR("entry", 23, "uri", "sip:doubango@example.com"),//==> /resource-lists/list[@name="Ennemies"]/entry[23][@uri="sip:doubango@example.com"]
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*
* <H3>=== Namespace test ===</H3>
* @code
#include "txc_api.h
char *url = txc_node_get_sel(context, ietf_resource_lists,
TXC_NODE_SELECT_BY_NAME("foo"),//==> /foo
TXC_NODE_SELECT_BY_NAME("a:bar"),//==> /foo/a:bar
TXC_NODE_SELECT_BY_NAME("b:baz"),//==> /foo/a:bar/b:baz
TXC_NODE_ADD_NAMESPACE("a", "urn:test:namespace1-uri"),//==>/foo/a:bar/b:baz?xmlns(a=urn:test:namespace1-uri)
TXC_NODE_ADD_NAMESPACE("b", "urn:test:namespace2-uri"),//==>/foo/a:bar/b:baz?xmlns(a=urn:test:namespace1-uri)xmlns(b=urn:test:namespace2-uri)
TXC_NODE_SELECT_END()
);
TSK_FREE(url);
* @endcode
* @sa txc_node_get_cust_sel for custom (user defined) requests.
*/
#define TXC_ELEMENT_CONTENT_TYPE "application/xcap-el+xml" /* RFC 4825 subclause 15.2.1 */
static char* __internal_txc_node_get_cust_sel(const char* doc_selector, const char *auid, va_list steps)
{
char *uri = 0;
int step;
char *result=0, *node_root = 0, *_namespace=0, *step_str = 0;
/* check parameters validity */
if(!doc_selector || !auid) return 0;
/* set base uri*/
uri = tsk_strdup(doc_selector);
/* append node root*/
tsk_sprintf(&node_root, "/~~/%s", auid);
tsk_strcat(&uri, node_root);
TSK_FREE(node_root);
while( (step=va_arg(steps, txc_node_step_t)) != 0xFF)
{
step_str = 0;
switch(step)
{
case by_name:
{ /* qname */
const char* qname = va_arg(steps, const char*);
tsk_sprintf(&step_str, "/%s", qname);
tsk_strcat(&uri, (const char*)step_str);
TSK_FREE(step_str);
break;
}
case by_pos:
{ /* qname, position */
const char* qname = va_arg(steps, const char*);
int position = va_arg(steps, int);
tsk_sprintf(&step_str, "/%s%%5B%d%%5D", qname, position);
tsk_strcat(&uri, (const char*)step_str);
TSK_FREE(step_str);
break;
}
case by_attr:
{ /* qname, att_name, att_value */
const char* qname = va_arg(steps, const char*);
char* att_name = tsk_url_encode(va_arg(steps, const char*));
char* att_value = tsk_url_encode(va_arg(steps, const char*));
tsk_sprintf(&step_str, "/%s%%5B@%s=%%22%s%%22%%5D", qname, att_name, att_value);
tsk_strcat(&uri, (const char*)step_str);
TSK_FREE(step_str); TSK_FREE(att_name); TSK_FREE(att_value);
break;
}
case by_pos_attr:
{ /* qname, position, att_name, att_value */
const char* qname = va_arg(steps, const char*);
int position = va_arg(steps, int);
char* att_name = tsk_url_encode(va_arg(steps, const char*));
char* att_value = tsk_url_encode(va_arg(steps, const char*));
tsk_sprintf(&step_str, "/%s%%5B%d%%5D%%5B@%s=%%22%s%%22%%5D", qname, position, att_name, att_value);
tsk_strcat(&uri, (const char*)step_str);
TSK_FREE(step_str); TSK_FREE(att_name); TSK_FREE(att_value);
break;
}
case 0xF0:
{ /* prefix ns */
const char* prefix = va_arg(steps, const char*);
const char* ns = va_arg(steps, const char*);
tsk_sprintf(&step_str, "%sxmlns(%s=%%22%s%%22)", _namespace?"":"%3F",prefix, ns);
tsk_strcat(&_namespace, (const char*)step_str);
TSK_FREE(step_str);
break;
}
default: break;
}/* switch */
}
/* add namespace and free it*/
tsk_strcat(&uri, (const char*)_namespace);
TSK_FREE(_namespace);
return uri;
}
/**@ingroup txc_node_group
* Create a custom XCAP node selector URI as per <a href="http://tools.ietf.org/html/rfc4825#section-6.3">RFC 4825 subclause 6.3</a>
* @param doc_selector The XCAP document selector URI. The HTTP URI containing the XCAP root and document selector, resulting in the selection of a specific document.
* As a result, performing a GET against the document URI would retrieve the document. This URI can be retrieved using @ref txc_doc_get_cust_sel or
* @ref TXC_DOC_GET_SEL or @ref TXC_DOC_GET_SEL2.
* @param auid The Application Unique ID. unique identifier within the namespace of application unique IDs created by this specification
* that differentiates XCAP resources accessed by one application from XCAP resources accessed by another.
* For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>
* @param ... The node selection steps. MUST be @ref TXC_NODE_SELECT_BY_NAME or @ref TXC_NODE_SELECT_BY_POS or @ref TXC_NODE_SELECT_BY_ATTR or @ref TXC_NODE_SELECT_BY_POS_ATTR
* or @ref TXC_NODE_ADD_NAMESPACE and end with @ref TXC_NODE_SELECT_END. For more information please refer to @ref txc_node_page.
* @retval The HTTP URI containing the XCAP root, document selector, node selector separator, and node selector, resulting in the
* selection of a specific XML node. If supplied parameters are not valide this method will return NULL.
* You must free the returned string using TSK_FREE or TSK_SAFE_FREE.
* @sa txc_node_get_sel
*/
char* txc_node_get_cust_sel(const char* doc_selector, const char *auid, ...)
{
va_list args;
char * uri;
va_start(args, auid);
uri = __internal_txc_node_get_cust_sel(doc_selector, auid, args);
va_end(args);
return uri;
}
/**@ingroup txc_node_group
* Create a custom XCAP node selector URI as per <a href="http://tools.ietf.org/html/rfc4825#section-6.3">RFC 4825 subclause 6.3</a>
* @param context The XCAP context with valid xcap-root and xui.
* @param auid_type The Application Unique ID. Unique identifier within the namespace of application unique IDs created by this specification
* that differentiates XCAP resources accessed by one application from XCAP resources accessed by another.
* For more information see <a href="http://tools.ietf.org/html/rfc4825#section-4">RFC 4825 subclause 4</a>
* @param ... The node selection steps. MUST be @ref TXC_NODE_SELECT_BY_NAME or @ref TXC_NODE_SELECT_BY_POS or @ref TXC_NODE_SELECT_BY_ATTR or @ref TXC_NODE_SELECT_BY_POS_ATTR
* or @ref TXC_NODE_ADD_NAMESPACE and end with @ref TXC_NODE_SELECT_END. For more information please refer to @ref txc_node_page.
* @retval The HTTP URI containing the XCAP root, document selector, node selector separator, and node selector, resulting in the
* selection of a specific XML node. If supplied parameters are not valide this method will return NULL.
* You must free the returned string using TSK_FREE or TSK_SAFE_FREE.
* @sa txc_node_get_cust_sel
*/
char* txc_node_get_sel(const txc_context_t* context, const xcap_auid_type_t auid_type, ...)
{
va_list args;
char* doc_selector = 0, *uri = 0;
/* check parameters validity */
if(!context || !context->xui || !context->txc_root) return 0;
/* Get document selector */
doc_selector = TXC_DOC_GET_SEL(context, auid_type);
/* initialize variable arguments */
va_start(args, auid_type);
/* Get full uri */
uri = __internal_txc_node_get_cust_sel(doc_selector, context->auids[auid_type].name, args);
/* free document selector*/
TSK_FREE(doc_selector);
/* reset variable arguments */
va_end(args);
return uri;
}