Module: sip-router Branch: master Commit: 5e8aab47d4b52a30f5f3e1984f5eeb6dd0e529a3 URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=5e8aab47...
Author: pd peter.dunkley@crocodile-rcs.com Committer: pd peter.dunkley@crocodile-rcs.com Date: Fri Aug 5 17:20:36 2011 +0100
modules_k/rls: Added support for XPath within rl-services documents
- RLS was recently updated to support rl-services index documents that "point" to resource-lists. However, that support only extended to indexes that pointed to entire resource-list documents.
This change enables support for resource lists that "point" to specific nodes within a document.
For example, the following rl-services document would now be supported:
<?xml version="1.0" encoding="UTF-8"?> <rls-services xmlns="urn:ietf:params:xml:ns:rls-services"> <service uri="sip:alice_all@pd-laptop-linux.croc.internal"> <resource-list>http://server.example.net:5060/xcap-root/resource-lists/users/sip:alice@exam...</resource-list> <packages> <package>presence</package> </packages> </service> </rls-services>
---
modules_k/rls/notify.c | 121 +++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 114 insertions(+), 7 deletions(-)
diff --git a/modules_k/rls/notify.c b/modules_k/rls/notify.c index dd1e58e..e964520 100644 --- a/modules_k/rls/notify.c +++ b/modules_k/rls/notify.c @@ -48,6 +48,8 @@ #include "../../lib/kcore/hash_func.h" #include "rls.h" #include "notify.h" +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h>
typedef struct res_param { @@ -1131,6 +1133,7 @@ int parse_xcap_uri(char *uri, str *host, unsigned short *port, str *path) return 1; }
+#define MAX_PATH_LEN 127 int rls_get_resource_list(str *rl_uri, str *username, str *domain, xmlNodePtr *rl_node, xmlDocPtr *xmldoc) { @@ -1144,6 +1147,12 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain, db_val_t *row_vals; int xcap_col; str body; + int checked = 0; + str root, path = {0, 0}; + char path_str[MAX_PATH_LEN + 1]; + xmlXPathContextPtr xpathCtx = NULL; + xmlXPathObjectPtr xpathObj = NULL; +
if (rl_uri==NULL || username==NULL || domain==NULL) { @@ -1151,6 +1160,56 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain, return -1; }
+ LM_DBG("rl_uri: %.*s", rl_uri->len, rl_uri->s); + + root.s = rl_uri->s; + root.len = rl_uri->len; + while (checked < rl_uri->len) + { + if (checked < rl_uri->len - 3 && strncmp(rl_uri->s + checked, "/~~", 3) == 0) + { + root.len = checked; + checked += 3; + break; + } + checked++; + } + LM_DBG("doc: %.*s", root.len, root.s); + + memset (path_str, '\0', MAX_PATH_LEN + 1); + path.s = path_str; + path.len = 0; + while (checked < rl_uri->len && path.len <= MAX_PATH_LEN) + { + if (rl_uri->s[checked] == '/') + { + strcat(path.s, "/xmlns:"); + path.len += 7; + checked++; + } + else if (checked <= rl_uri->len - 3 && strncmp(rl_uri->s + checked, "%5b", 3) == 0) + { + path.s[path.len++] = '['; + checked += 3; + } + else if (checked <= rl_uri->len - 3 && strncmp(rl_uri->s + checked, "%5d", 3) == 0) + { + path.s[path.len++] = ']'; + checked += 3; + } + else if (checked <= rl_uri->len - 3 && strncmp(rl_uri->s + checked, "%22", 3) == 0) + { + path.s[path.len++] = '"'; + checked += 3; + } + else + { + path.s[path.len++] = rl_uri->s[checked]; + checked++; + } + } + LM_DBG("path: %.*s", path.len, path.s); + query_cols[n_query_cols] = &str_username_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; @@ -1172,7 +1231,7 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain, query_cols[n_query_cols] = &str_doc_uri_col; query_vals[n_query_cols].type = DB1_STR; query_vals[n_query_cols].nul = 0; - query_vals[n_query_cols].val.str_val = *rl_uri; + query_vals[n_query_cols].val.str_val = root; n_query_cols++;
if(rls_dbf.use_table(rls_db, &rls_xcap_table) < 0) @@ -1187,8 +1246,8 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain, if(rls_dbf.query(rls_db, query_cols, 0, query_vals, result_cols, n_query_cols, n_result_cols, 0, &result)<0) { - LM_ERR("failed querying table xcap for document [rl_uri]=%.*s\n", - rl_uri->len, rl_uri->s); + LM_ERR("failed querying table xcap for document: %.*s\n", + root.len, root.s); if(result) rls_dbf.free_result(rls_db, result); return -1; @@ -1225,19 +1284,67 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain, goto error; }
- *rl_node = XMLDocGetNodeByName(*xmldoc,"resource-lists", NULL); - if(rl_node==NULL) + if (path.len == 0) { - LM_ERR("no resource-lists node in XML document\n"); - goto error; + /* No path specified - use all resource-lists. */ + *rl_node = XMLDocGetNodeByName(*xmldoc,"resource-lists", NULL); + if(rl_node==NULL) + { + LM_ERR("no resource-lists node in XML document\n"); + goto error; + } } + else if (path.s != NULL) + { + xpathCtx = xmlXPathNewContext(*xmldoc); + if (xpathCtx == NULL) + { + LM_ERR("unable to create new XPath context"); + goto error; + } + + if (xmlXPathRegisterNs(xpathCtx, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:resource-lists") != 0) + { + LM_ERR("unable to register xmlns\n"); + goto error; + } + + xpathObj = xmlXPathEvalExpression(BAD_CAST path.s, xpathCtx); + if (xpathObj == NULL) + { + LM_ERR("unable to evaluate path\n"); + goto error; + }
+ if (xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr <= 0) + { + LM_ERR("no nodes found\n"); + goto error; + } + if (xpathObj->nodesetval->nodeTab[0] != NULL && xpathObj->nodesetval->nodeTab[0]->type != XML_ELEMENT_NODE) + { + LM_ERR("no nodes of the correct type found\n"); + goto error; + + } + + *rl_node = xpathObj->nodesetval->nodeTab[0]; + + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + } + rls_dbf.free_result(rls_db, result); return 1;
error: if(result!=NULL) rls_dbf.free_result(rls_db, result); + if(xpathObj!=NULL) + xmlXPathFreeObject(xpathObj); + + if(xpathCtx!=NULL) + xmlXPathFreeContext(xpathCtx); if(xmldoc!=NULL) xmlFreeDoc(*xmldoc);