Selaa lähdekoodia

lib/xcap: relocated to archive

Daniel-Constantin Mierla 9 kuukautta sitten
vanhempi
commit
e41d172481

+ 15 - 0
src/lib/xcap/ChangeLog

@@ -0,0 +1,15 @@
+2006-08-02
+	* added xcap_query_params_t serialization
+
+2006-04-01 (?)
+	* xcap queries goes through xcap module if compiled with SER (removes
+	dependency on libcurl3 for PA module)
+
+2006-03-30
+	* corrected bug (library couldn't be compiled)
+
+2006-03-29
+	* added message authorization functions
+
+2006-03-24
+	* optimized XCAP document access - each process has its own curl handle

+ 21 - 0
src/lib/xcap/Makefile

@@ -0,0 +1,21 @@
+
+# example library makefile
+#
+
+include ../../Makefile.defs
+auto_gen=
+NAME:=ser_xcap
+MAJOR_VER=0
+MINOR_VER=1
+BUGFIX_VER=0
+DEFS+=-DSER
+libxml2_includes=-I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2 \
+					-I$(LOCALBASE)/include
+libxml2_libs=-L$(LOCALBASE)/lib -lxml2
+INCLUDES= -I$(CURDIR)/.. -I$(CURDIR)/../.. $(libxml2_includes) 
+LIBS=$(libxml2_libs)
+SERLIBPATH=..
+SER_LIBS=$(SERLIBPATH)/cds/ser_cds
+
+include ../../Makefile.libs
+

+ 12 - 0
src/lib/xcap/Makefile.nonser

@@ -0,0 +1,12 @@
+DEFS     += 
+INCLUDES += -I/usr/include/libxml2 -I/usr/local/include/libxml2 -I/usr/local/include
+LIBS     += -L/usr/local/lib -lxml2 -lcurl -lcds
+
+# name of result executable or library
+NAME = xcap
+
+# TYPE=lib => shared or static library, executable otherwise
+TYPE = lib
+
+include ../Makefile.defs
+

+ 238 - 0
src/lib/xcap/common_policy.c

@@ -0,0 +1,238 @@
+#include <xcap/common_policy.h>
+
+cp_unknown_t *create_unknown(int data_size)
+{
+	cp_unknown_t *u = cds_malloc(sizeof(cp_unknown_t) + data_size);
+	u->next = NULL;
+	return u;
+}
+
+/* ------- freeing used memory for common-rules ------- */
+
+static void free_identity(cp_identity_t *id)
+{
+	cp_id_t *i, *ni;
+	cp_domain_t *d, *nd;
+	cp_except_t *e, *ne;
+	cp_except_domain_t *ed, *ned;
+
+	if(!id)
+		return;
+
+	i = id->ids;
+	while(i) {
+		ni = i->next;
+		str_free_content(&i->entity);
+		cds_free(i);
+		i = ni;
+	}
+
+	d = id->domains;
+	while(d) {
+		nd = d->next;
+		str_free_content(&d->domain);
+		cds_free(d);
+		d = nd;
+	}
+
+	e = id->excepts;
+	while(e) {
+		ne = e->next;
+		str_free_content(&e->entity);
+		cds_free(e);
+		e = ne;
+	}
+
+	if(id->any_identity) {
+		d = id->any_identity->domains;
+		while(d) {
+			nd = d->next;
+			str_free_content(&d->domain);
+			cds_free(d);
+			d = nd;
+		}
+
+		ed = id->any_identity->except_domains;
+		while(ed) {
+			ned = ed->next;
+			str_free_content(&ed->domain);
+			cds_free(ed);
+			ed = ned;
+		}
+	}
+
+	cds_free(id);
+}
+
+static void free_conditions(cp_conditions_t *c)
+{
+	cp_sphere_t *s, *n;
+	if(!c)
+		return;
+	if(c->validity)
+		cds_free(c->validity);
+	if(c->identity)
+		free_identity(c->identity);
+	s = c->spheres;
+	while(s) {
+		n = s->next;
+		str_free_content(&s->value);
+		cds_free(s);
+		s = n;
+	}
+	cds_free(c);
+}
+
+
+static void free_transformations(cp_transformations_t *t)
+{
+	cp_unknown_t *u, *nu;
+
+	if(!t)
+		return;
+
+	u = t->unknown;
+	while(u) {
+		nu = u->next;
+		cds_free(u);
+		u = nu;
+	}
+	cds_free(t);
+}
+
+void free_cp_rule(cp_rule_t *r, cp_free_actions_func free_actions)
+{
+	if(!r)
+		return;
+	if(r->conditions)
+		free_conditions(r->conditions);
+	if(r->actions)
+		free_actions(r->actions);
+	if(r->transformations)
+		free_transformations(r->transformations);
+	str_free_content(&r->id);
+	cds_free(r);
+}
+
+void free_common_rules(cp_ruleset_t *r, cp_free_actions_func free_actions)
+{
+	cp_rule_t *rule, *n;
+
+	if(!r)
+		return;
+	rule = r->rules;
+	while(rule) {
+		n = rule->next;
+		free_cp_rule(rule, free_actions);
+		rule = n;
+	}
+	cds_free(r);
+}
+
+static void parse_uri(const str_t *uri, str_t *user, str_t *domain)
+{
+	char *a;
+	char *d;
+	str_t s;
+
+	str_clear(user);
+	str_clear(domain);
+	if(uri->len > 0) {
+		d = str_strchr(uri, ':');
+		if(d) {
+			s.s = d + 1;
+			s.len = uri->len - (s.s - uri->s);
+		} else
+			s = *uri;
+		a = str_strchr(&s, '@');
+		if(a) {
+			user->s = s.s;
+			user->len = a - s.s;
+		}
+		domain->s = s.s + user->len;
+		if(a)
+			domain->s++;
+		domain->len = uri->len - (domain->s - uri->s);
+
+		/*		TRACE_LOG("parse uri \'%.*s\': user=\'%.*s\' domain=\'%.*s\'\n",
+				FMT_STR(*uri), FMT_STR(*user), FMT_STR(*domain));*/
+	}
+}
+
+
+/* returns 1 if rule is used for uri */
+int is_rule_for_uri(cp_rule_t *rule, const str_t *uri)
+{
+	cp_identity_t *id;
+	int ok = 0;
+	str_t domain, user;
+	str_t d_, u_;
+	cp_domain_t *d;
+	cp_id_t *i;
+	cp_except_t *e;
+	cp_except_domain_t *ed;
+
+	if(!rule)
+		return 0;
+	if(!rule->conditions)
+		return 1;
+	id = rule->conditions->identity;
+	if(!id)
+		return 0;
+
+	parse_uri(uri, &user, &domain);
+
+	i = id->ids;
+	while(i) {
+		parse_uri(&i->entity, &u_, &d_);
+		/*		TRACE_LOG("comparing uris \'%.*s\' \'%.*s\' "
+				"domains \'%.*s\' \'%.*s\'\n",
+				FMT_STR(user), FMT_STR(u_),
+				FMT_STR(domain), FMT_STR(d_));*/
+		if(str_case_equals(&user, &u_) == 0) {
+			if(str_nocase_equals(&domain, &d_) == 0) {
+				/*				TRACE_LOG("id found\n");*/
+				return 1;
+			}
+		}
+		i = i->next;
+	}
+
+	d = id->domains;
+	while(d) {
+		/*		TRACE_LOG("comparing domains \'%.*s\' \'%.*s\'\n",
+				FMT_STR(domain), FMT_STR(d->domain));*/
+		if(str_nocase_equals(&domain, &d->domain) == 0)
+			ok = 1;
+		d = d->next;
+	}
+	if(ok) {
+		e = id->excepts;
+		while(e) {
+			if(str_case_equals(&user, &e->entity) == 0)
+				return 0; /* excepts matched */
+			e = e->next;
+		}
+		/*		TRACE_LOG("domain found and excepts not matched\n");*/
+		return 1;
+	}
+
+	if(id->any_identity) {
+		d = id->any_identity->domains;
+		while(d) {
+			if(str_nocase_equals(&domain, &d->domain) == 0) {
+				/*				TRACE_LOG("domain matches for anonymous\n");*/
+				return 1;
+			}
+			d = d->next;
+		}
+
+		ed = id->any_identity->except_domains;
+		while(ed) {
+			if(str_nocase_equals(&domain, &d->domain) == 0)
+				return 0;
+			ed = ed->next;
+		}
+	}
+	return 0;
+}

+ 129 - 0
src/lib/xcap/common_policy.h

@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __COMMON_POLICY
+#define __COMMON_POLICY
+
+#include <cds/sstr.h>
+#include <time.h>
+
+typedef struct
+{
+	time_t from;
+	time_t to;
+} cp_validity_t;
+
+typedef struct _cp_domain_t
+{
+	struct _cp_domain_t *next;
+	str_t domain;
+} cp_domain_t;
+
+typedef struct _cp_except_domain_t
+{
+	struct _cp_except_domain_t *next;
+	str_t domain;
+} cp_except_domain_t;
+
+typedef struct _cp_except_t
+{
+	struct _cp_except_t *next;
+	str_t entity;
+} cp_except_t;
+
+typedef struct _cp_unknown_t
+{
+	struct _cp_unknown_t *next;
+
+	char data[1]; /* elements from external schemes */
+} cp_unknown_t;
+
+typedef struct
+{
+	cp_unknown_t *unknown; /* elements from external schemes */
+} cp_actions_t;
+
+typedef struct
+{
+	cp_unknown_t *unknown; /* elements from external schemes */
+} cp_transformations_t;
+
+typedef struct _cp_id_t
+{
+	struct _cp_id_t *next;
+	str_t entity;
+} cp_id_t;
+
+typedef struct
+{
+	cp_domain_t *domains;
+	cp_except_domain_t *except_domains;
+} cp_any_identity_t;
+
+typedef struct
+{
+	cp_id_t *ids;
+	cp_domain_t *domains;
+	cp_except_t *excepts;
+	cp_any_identity_t *any_identity;
+} cp_identity_t;
+
+typedef struct _cp_sphere_t
+{
+	struct _cp_sphere_t *next;
+	str_t value;
+} cp_sphere_t;
+
+typedef struct
+{
+	cp_validity_t *validity;
+	cp_identity_t *identity;
+	cp_sphere_t *spheres;
+} cp_conditions_t;
+
+typedef struct _cp_rule_t
+{
+	struct _cp_rule_t *next;
+
+	cp_conditions_t *conditions;
+	cp_actions_t *actions;
+	cp_transformations_t *transformations;
+	str_t id;
+} cp_rule_t;
+
+typedef struct
+{
+	cp_rule_t *rules;
+} cp_ruleset_t;
+
+cp_unknown_t *create_unknown(int data_size);
+
+typedef void(cp_free_actions_func)(cp_actions_t *a);
+
+void free_cp_rule(cp_rule_t *r, cp_free_actions_func free_actions);
+void free_common_rules(cp_ruleset_t *r, cp_free_actions_func free_actions);
+int is_rule_for_uri(cp_rule_t *rule, const str_t *uri);
+
+#endif

+ 4 - 0
src/lib/xcap/doc/Makefile

@@ -0,0 +1,4 @@
+docs = xcap.xml
+
+docbook_dir = ../../../../doc/docbook
+include $(docbook_dir)/Makefile

+ 34 - 0
src/lib/xcap/doc/xcap.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE book PUBLIC '-//OASIS//DTD DocBook XML V4.2//EN'
+'http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd'[
+	<!ENTITY % local.common.attrib "xml:base  CDATA  #IMPLIED">
+]>
+
+<book lang="en">
+<bookinfo>
+	<title>XCAP operations (libxcap)</title>
+	<author><firstname>Václav</firstname><surname>Kubart</surname></author>
+	<abstract><para>Description of helper XCAP library.
+	</para></abstract>
+</bookinfo>
+
+<preface><title>Preface</title>
+<para>This library contains functions for manipulating data using XCAP protocol.
+</para>
+
+<section id="libxcap.dependencies"><title>Dependencies</title>
+<para>
+<itemizedlist>
+	<listitem><para><application>libcds</application> (distributed with SER)</para></listitem>
+	<listitem><para><application>libxml2</application> (external library for
+	parsing XML documents)</para></listitem>
+	<listitem><para><application>libcurl3</application> (external library for
+	HTTP operations, used only in nonSER version!)</para></listitem>
+</itemizedlist>
+</para>
+</section>
+
+</preface>
+
+</book>

+ 128 - 0
src/lib/xcap/msg_rules.c

@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <xcap/msg_rules.h>
+#include <xcap/parse_msg_rules.h>
+#include <xcap/xcap_result_codes.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/list.h>
+#include <cds/sstr.h>
+#include <string.h>
+
+int get_msg_rules(const str_t *username, const str_t *filename,
+		xcap_query_params_t *xcap_params, msg_rules_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	char *uri = NULL;
+	int res = RES_OK;
+
+	uri = xcap_uri_for_users_document(
+			xcap_doc_im_rules, username, filename, xcap_params);
+	if(!uri) {
+		/* can't create XCAP uri */
+		ERROR_LOG("can't build XCAP uri\n");
+		return RES_XCAP_QUERY_ERR;
+	}
+
+	res = xcap_query(uri, xcap_params, &data, &dsize);
+	if(res != RES_OK) {
+		DEBUG_LOG("XCAP problems for uri \'%s\'\n", uri);
+		if(data)
+			cds_free(data);
+		cds_free(uri);
+		return RES_XCAP_QUERY_ERR;
+	}
+	cds_free(uri);
+
+	/* parse input data */
+	res = parse_msg_rules(data, dsize, dst);
+	if(res != RES_OK) {
+		ERROR_LOG("Error occurred during document parsing!\n");
+	}
+
+	if(data)
+		cds_free(data);
+	return res;
+}
+
+int get_msg_rules_action(
+		cp_ruleset_t *r, const str_t *wuri, msg_handling_t *dst_action)
+{
+	int res = 1; /* rule not found */
+	cp_rule_t *rule;
+	msg_handling_t a = msg_handling_block;
+	msg_handling_t aa;
+
+	if(!r)
+		return -1;
+
+	rule = r->rules;
+	while(rule) {
+		DEBUG_LOG("TRYING rule %.*s for uri %.*s\n", FMT_STR(rule->id),
+				FMT_STR(*wuri));
+		if(is_rule_for_uri(rule, wuri)) {
+			DEBUG_LOG("rule %.*s matches for uri %.*s\n", FMT_STR(rule->id),
+					FMT_STR(*wuri));
+
+			if(!rule->actions)
+				continue;
+			if(!rule->actions->unknown)
+				continue;
+			aa = *(msg_handling_t *)(rule->actions->unknown->data);
+			if(aa > a)
+				a = aa;
+			res = 0;
+		}
+		rule = rule->next;
+	}
+	if(dst_action && (res == 0))
+		*dst_action = a;
+
+	return res;
+}
+
+void free_msg_actions(cp_actions_t *a)
+{
+	cp_unknown_t *u, *nu;
+
+	if(!a)
+		return;
+
+	u = a->unknown;
+	while(u) {
+		nu = u->next;
+		cds_free(u);
+		u = nu;
+	}
+	cds_free(a);
+}
+
+void free_msg_rules(cp_ruleset_t *r)
+{
+	free_common_rules(r, free_msg_actions);
+}

+ 52 - 0
src/lib/xcap/msg_rules.h

@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __MSG_RULES_H
+#define __MSG_RULES_H
+
+#include <cds/sstr.h>
+#include <xcap/xcap_client.h>
+#include <xcap/common_policy.h>
+
+typedef cp_ruleset_t msg_rules_t;
+
+/* Type defining action for pres_rules */
+typedef enum
+{
+	msg_handling_block,
+	/*	msg_handling_confirm, */
+	msg_handling_allow
+} msg_handling_t;
+
+int get_msg_rules(const str_t *username, const str_t *filename,
+		xcap_query_params_t *xcap_params, msg_rules_t **dst);
+void free_msg_rules(cp_ruleset_t *r);
+void free_msg_actions(cp_actions_t *a);
+
+/* returns 0 if rule found, 1 if not found and -1 on error */
+int get_msg_rules_action(
+		msg_rules_t *r, const str_t *wuri, msg_handling_t *dst_action);
+
+#endif

+ 361 - 0
src/lib/xcap/parse_common_rules.c

@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <xcap/parse_common_rules.h>
+#include <xcap/xcap_result_codes.h>
+
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/list.h>
+#include <string.h>
+
+#include <xcap/xml_utils.h>
+
+char *common_policy_ns = NULL;
+
+static int read_sphere(xmlNode *n, cp_sphere_t **dst)
+{
+	*dst = (cp_sphere_t *)cds_malloc(sizeof(cp_sphere_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+	(*dst)->next = NULL;
+
+	str_dup_zt(&(*dst)->value, get_node_value(n));
+	return RES_OK;
+}
+
+static int read_validity(xmlNode *n, cp_validity_t **dst)
+{
+	const char *from, *to;
+	*dst = (cp_validity_t *)cds_malloc(sizeof(cp_validity_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+
+	from = get_node_value(find_node(n, "from", common_policy_ns));
+	to = get_node_value(find_node(n, "to", common_policy_ns));
+
+	(*dst)->from = xmltime2time(from);
+	(*dst)->to = xmltime2time(to);
+	return RES_OK;
+}
+
+static int read_id(xmlNode *n, cp_id_t **dst)
+{
+	*dst = (cp_id_t *)cds_malloc(sizeof(cp_id_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+	(*dst)->next = NULL;
+
+	get_str_attr(n, "entity", &(*dst)->entity);
+	if((*dst)->entity.len == 0) {
+		/* hack - eyeBeams format differs from draft ! */
+		str_dup_zt(&(*dst)->entity, get_node_value(n));
+	}
+
+	return RES_OK;
+}
+
+static int read_domain(xmlNode *n, cp_domain_t **dst)
+{
+	*dst = (cp_domain_t *)cds_malloc(sizeof(cp_domain_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+	(*dst)->next = NULL;
+
+	get_str_attr(n, "domain", &(*dst)->domain);
+	return RES_OK;
+}
+
+static int read_except(xmlNode *n, cp_except_t **dst)
+{
+	*dst = (cp_except_t *)cds_malloc(sizeof(cp_except_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+	(*dst)->next = NULL;
+
+	get_str_attr(n, "entity", &(*dst)->entity);
+	return RES_OK;
+}
+
+static int read_except_domain(xmlNode *n, cp_except_domain_t **dst)
+{
+	*dst = (cp_except_domain_t *)cds_malloc(sizeof(cp_except_domain_t));
+	if(!*dst)
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+	(*dst)->next = NULL;
+
+	get_str_attr(n, "domain", &(*dst)->domain);
+	return RES_OK;
+}
+
+static int read_any_identity(xmlNode *an, cp_any_identity_t **dst)
+{
+	cp_domain_t *domain, *last_domain = NULL;
+	cp_except_domain_t *except, *last_except = NULL;
+	xmlNode *n;
+	int res = RES_OK;
+
+	*dst = (cp_any_identity_t *)cds_malloc(sizeof(cp_any_identity_t));
+	if(!*dst)
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+
+	n = an->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "domain", common_policy_ns) >= 0) {
+				res = read_domain(n, &domain);
+				if(res != 0)
+					break;
+				LINKED_LIST_ADD((*dst)->domains, last_domain, domain);
+			} else if(cmp_node(n, "except-domain", common_policy_ns) >= 0) {
+				res = read_except_domain(n, &except);
+				if(res != 0)
+					break;
+				LINKED_LIST_ADD((*dst)->except_domains, last_except, except);
+			}
+		}
+
+		n = n->next;
+	}
+	return res;
+}
+
+static int read_identity(xmlNode *idn, cp_identity_t **dst)
+{
+	cp_id_t *id, *last_id = NULL;
+	cp_domain_t *domain, *last_domain = NULL;
+	cp_except_t *except, *last_except = NULL;
+	xmlNode *n;
+	int res = RES_OK;
+
+	*dst = (cp_identity_t *)cds_malloc(sizeof(cp_identity_t));
+	if(!*dst)
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(**dst));
+
+	n = idn->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "id", common_policy_ns) >= 0) {
+				res = read_id(n, &id);
+				if(res != 0)
+					break;
+				LINKED_LIST_ADD((*dst)->ids, last_id, id);
+			} else if(cmp_node(n, "domain", common_policy_ns) >= 0) {
+				res = read_domain(n, &domain);
+				if(res != 0)
+					break;
+				LINKED_LIST_ADD((*dst)->domains, last_domain, domain);
+			} else if(cmp_node(n, "except", common_policy_ns) >= 0) {
+				res = read_except(n, &except);
+				if(res != 0)
+					break;
+				LINKED_LIST_ADD((*dst)->excepts, last_except, except);
+			} else if(cmp_node(n, "any-identity", common_policy_ns) >= 0) {
+				res = read_any_identity(n, &(*dst)->any_identity);
+				if(res != 0)
+					break;
+			}
+		}
+
+		n = n->next;
+	}
+
+	return res;
+}
+
+static int read_conditions(xmlNode *cn, cp_conditions_t **dst)
+{
+	xmlNode *n;
+	int res = RES_OK;
+	cp_sphere_t *sphere, *last_sphere = NULL;
+	if((!cn) || (!dst))
+		return RES_INTERNAL_ERR;
+
+	*dst = (cp_conditions_t *)cds_malloc(sizeof(cp_conditions_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(cp_conditions_t));
+
+	n = cn->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "validity", common_policy_ns) >= 0) {
+				res = read_validity(n, &(*dst)->validity);
+				if(res != 0)
+					break;
+			} else {
+				if(cmp_node(n, "identity", common_policy_ns) >= 0) {
+					res = read_identity(n, &(*dst)->identity);
+					if(res != 0)
+						break;
+				} else {
+					if(cmp_node(n, "sphere", common_policy_ns) >= 0) {
+						res = read_sphere(n, &sphere);
+						if(res != 0)
+							break;
+						LINKED_LIST_ADD((*dst)->spheres, last_sphere, sphere);
+					}
+					/* else process other elements ? */
+				}
+			}
+		}
+		n = n->next;
+	}
+
+	return res;
+}
+
+static int read_transformations(xmlNode *tn, cp_transformations_t **dst)
+{
+	int res = RES_OK;
+	if((!tn) || (!dst))
+		return RES_INTERNAL_ERR;
+
+	*dst = (cp_transformations_t *)cds_malloc(sizeof(cp_transformations_t));
+	if(!*dst)
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(cp_transformations_t));
+
+	DEBUG_LOG("transformations for pres_rules not used\n");
+
+	return res;
+}
+
+static int read_rule(xmlNode *rn, cp_rule_t **dst,
+		cp_read_actions_func read_actions, cp_free_actions_func free_actions)
+{
+	xmlNode *n;
+	int res = RES_OK;
+	if((!rn) || (!dst))
+		return RES_INTERNAL_ERR;
+
+	*dst = (cp_rule_t *)cds_malloc(sizeof(cp_rule_t));
+	if(!*dst)
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(cp_rule_t));
+
+	get_str_attr(rn, "id", &(*dst)->id);
+
+	n = find_node(rn, "actions", common_policy_ns);
+	if(n && (res == 0) && read_actions)
+		res = read_actions(n, &(*dst)->actions);
+
+	n = find_node(rn, "conditions", common_policy_ns);
+	if(n && (res == 0))
+		res = read_conditions(n, &(*dst)->conditions);
+
+	n = find_node(rn, "transformations", common_policy_ns);
+	if(n && (res == 0))
+		res = read_transformations(n, &(*dst)->transformations);
+
+	if(res != 0) {
+		free_cp_rule(*dst, free_actions);
+		*dst = NULL;
+		return res;
+	}
+
+	return 0;
+}
+
+static int read_common_rules(xmlNode *root, cp_ruleset_t **dst,
+		cp_read_actions_func read_actions, cp_free_actions_func free_actions)
+{
+	cp_ruleset_t *rs = NULL;
+	cp_rule_t *r, *last = NULL;
+	xmlNode *n;
+	int res = RES_OK;
+
+	if(!dst)
+		return RES_INTERNAL_ERR;
+	else
+		*dst = NULL;
+	if(!root)
+		return RES_INTERNAL_ERR;
+
+	if(cmp_node(root, "ruleset", common_policy_ns) < 0) {
+		ERROR_LOG("document is not a ruleset \n");
+		return RES_INTERNAL_ERR;
+	}
+
+	rs = (cp_ruleset_t *)cds_malloc(sizeof(cp_ruleset_t));
+	if(!rs)
+		return RES_MEMORY_ERR;
+	*dst = rs;
+	memset(rs, 0, sizeof(*rs));
+
+
+	/* read rules in ruleset */
+	n = root->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "rule", common_policy_ns) >= 0) {
+				res = read_rule(n, &r, read_actions, free_actions);
+				if(res == 0) {
+					if(r)
+						LINKED_LIST_ADD(rs->rules, last, r);
+				} else
+					break;
+			}
+		}
+		n = n->next;
+	}
+
+	return res;
+}
+
+int parse_common_rules(const char *data, int dsize, cp_ruleset_t **dst,
+		cp_read_actions_func read_actions, cp_free_actions_func free_actions)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	if(dst)
+		*dst = NULL;
+	doc = xmlReadMemory(data, dsize, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return RES_INTERNAL_ERR;
+	}
+
+	res = read_common_rules(
+			xmlDocGetRootElement(doc), dst, read_actions, free_actions);
+	if((res != RES_OK) && (dst)) {
+		/* may be set => must be freed */
+		free_common_rules(*dst, free_actions);
+		*dst = NULL;
+	}
+
+	xmlFreeDoc(doc);
+	return res;
+}

+ 40 - 0
src/lib/xcap/parse_common_rules.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __PARSE_COMMON_RULES_H
+#define __PARSE_COMMON_RULES_H
+
+#include <xcap/pres_rules.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+typedef int(cp_read_actions_func)(xmlNode *an, cp_actions_t **dst);
+
+int parse_common_rules(const char *data, int dsize, cp_ruleset_t **dst,
+		cp_read_actions_func read_actions, cp_free_actions_func free_actions);
+
+/* extern char *common_policy_ns; */
+
+#endif

+ 95 - 0
src/lib/xcap/parse_msg_rules.c

@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <xcap/parse_common_rules.h>
+#include <xcap/parse_msg_rules.h>
+#include <xcap/xcap_result_codes.h>
+
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/list.h>
+#include <string.h>
+
+#include <xcap/xml_utils.h>
+
+char *msg_rules_ns = NULL;
+
+static int str2msg_handling(const char *s, msg_handling_t *dst)
+{
+	if(!s)
+		return RES_INTERNAL_ERR;
+
+	if(strcmp(s, "allow") == 0) {
+		*dst = msg_handling_allow;
+		return 0;
+	}
+	if(strcmp(s, "block") == 0) {
+		*dst = msg_handling_block;
+		return 0;
+	}
+	/*	if (strcmp(s, "polite-block") == 0) {
+		*dst = msg_handling_polite_block;
+		return 0;
+	}
+	if (strcmp(s, "confirm") == 0) {
+		*dst = msg_handling_confirm;
+		return 0;
+	}*/
+	ERROR_LOG("invalid im-handling value: \'%s\'\n", s);
+	return RES_INTERNAL_ERR;
+}
+
+static int read_msg_actions(xmlNode *an, cp_actions_t **dst)
+{
+	xmlNode *n;
+	const char *s;
+	int res = RES_OK;
+	if((!an) || (!dst))
+		return RES_INTERNAL_ERR;
+
+	*dst = (cp_actions_t *)cds_malloc(sizeof(cp_actions_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(cp_actions_t));
+
+	n = find_node(an, "im-handling", msg_rules_ns);
+	if(n) {
+		/* may be only one sub-handling node? */
+		s = get_node_value(n);
+		(*dst)->unknown = create_unknown(sizeof(msg_handling_t));
+		if(!(*dst)->unknown)
+			return RES_MEMORY_ERR;
+		res = str2msg_handling(s, (msg_handling_t *)(*dst)->unknown->data);
+	}
+
+	return res;
+}
+
+int parse_msg_rules(const char *data, int dsize, cp_ruleset_t **dst)
+{
+	return parse_common_rules(
+			data, dsize, dst, read_msg_actions, free_msg_actions);
+}

+ 34 - 0
src/lib/xcap/parse_msg_rules.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __PARSE_MSG_RULES_H
+#define __PARSE_MSG_RULES_H
+
+#include <xcap/msg_rules.h>
+#include <xcap/parse_common_rules.h>
+
+int parse_msg_rules(const char *data, int dsize, cp_ruleset_t **dst);
+
+#endif

+ 94 - 0
src/lib/xcap/parse_pres_rules.c

@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <xcap/parse_pres_rules.h>
+#include <xcap/xcap_result_codes.h>
+
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/list.h>
+#include <string.h>
+
+#include <xcap/xml_utils.h>
+
+char *pres_rules_ns = NULL;
+
+static int str2sub_handling(const char *s, sub_handling_t *dst)
+{
+	if(!s)
+		return RES_INTERNAL_ERR;
+
+	if(strcmp(s, "allow") == 0) {
+		*dst = sub_handling_allow;
+		return 0;
+	}
+	if(strcmp(s, "block") == 0) {
+		*dst = sub_handling_block;
+		return 0;
+	}
+	if(strcmp(s, "polite-block") == 0) {
+		*dst = sub_handling_polite_block;
+		return 0;
+	}
+	if(strcmp(s, "confirm") == 0) {
+		*dst = sub_handling_confirm;
+		return 0;
+	}
+	ERROR_LOG("invalid sub-handling value: \'%s\'\n", s);
+	return RES_INTERNAL_ERR;
+}
+
+static int read_pres_actions(xmlNode *an, cp_actions_t **dst)
+{
+	xmlNode *n;
+	const char *s;
+	int res = RES_OK;
+	if((!an) || (!dst))
+		return RES_INTERNAL_ERR;
+
+	*dst = (cp_actions_t *)cds_malloc(sizeof(cp_actions_t));
+	if(!(*dst))
+		return RES_MEMORY_ERR;
+	memset(*dst, 0, sizeof(cp_actions_t));
+
+	n = find_node(an, "sub-handling", pres_rules_ns);
+	if(n) {
+		/* may be only one sub-handling node? */
+		s = get_node_value(n);
+		(*dst)->unknown = create_unknown(sizeof(sub_handling_t));
+		if(!(*dst)->unknown)
+			return RES_MEMORY_ERR;
+		res = str2sub_handling(s, (sub_handling_t *)(*dst)->unknown->data);
+	}
+
+	return res;
+}
+
+int parse_pres_rules(const char *data, int dsize, cp_ruleset_t **dst)
+{
+	return parse_common_rules(
+			data, dsize, dst, read_pres_actions, free_pres_actions);
+}

+ 34 - 0
src/lib/xcap/parse_pres_rules.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __PARSE_PRES_RULES_H
+#define __PARSE_PRES_RULES_H
+
+#include <xcap/pres_rules.h>
+#include <xcap/parse_common_rules.h>
+
+int parse_pres_rules(const char *data, int dsize, cp_ruleset_t **dst);
+
+#endif

+ 134 - 0
src/lib/xcap/pres_rules.c

@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <xcap/pres_rules.h>
+#include <xcap/parse_pres_rules.h>
+#include <xcap/xcap_result_codes.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/list.h>
+#include <cds/sstr.h>
+#include <string.h>
+
+int get_pres_rules(const str_t *username, const str_t *filename,
+		xcap_query_params_t *xcap_params, cp_ruleset_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	char *uri = NULL;
+	int res = RES_OK;
+
+	if(dst)
+		*dst = NULL;
+
+	uri = xcap_uri_for_users_document(
+			xcap_doc_pres_rules, username, filename, xcap_params);
+	if(!uri) {
+		/* can't create XCAP uri */
+		ERROR_LOG("can't build XCAP uri\n");
+		return RES_XCAP_QUERY_ERR;
+	}
+
+	res = xcap_query(uri, xcap_params, &data, &dsize);
+	if(res != RES_OK) {
+		DEBUG_LOG("XCAP problems for uri \'%s\'\n", uri);
+		if(data)
+			cds_free(data);
+		cds_free(uri);
+		return RES_XCAP_QUERY_ERR;
+	}
+	cds_free(uri);
+
+	/* parse input data */
+	res = parse_pres_rules(data, dsize, dst);
+	if(res != RES_OK) {
+		ERROR_LOG("Error occurred during parsing pres-rules for %.*s!\n",
+				str_len(username), username ? username->s : "");
+	}
+
+	if(data)
+		cds_free(data);
+	return res;
+}
+
+int get_pres_rules_action(
+		cp_ruleset_t *r, const str_t *wuri, sub_handling_t *dst_action)
+{
+	int res = 1; /* rule not found */
+	cp_rule_t *rule;
+	sub_handling_t a = sub_handling_block;
+	sub_handling_t aa;
+
+	if(!r)
+		return -1;
+
+	rule = r->rules;
+	while(rule) {
+		DEBUG_LOG("TRYING rule %.*s for uri %.*s\n", FMT_STR(rule->id),
+				FMT_STR(*wuri));
+		if(is_rule_for_uri(rule, wuri)) {
+			DEBUG_LOG("rule %.*s matches for uri %.*s\n", FMT_STR(rule->id),
+					FMT_STR(*wuri));
+
+			if(!rule->actions)
+				continue;
+			if(!rule->actions->unknown)
+				continue;
+			aa = *(sub_handling_t *)(rule->actions->unknown->data);
+			if(aa > a)
+				a = aa;
+			res = 0;
+		}
+		rule = rule->next;
+	}
+	if(dst_action && (res == 0))
+		*dst_action = a;
+
+	return res;
+}
+
+/* ------- freeing used memory for pres-rules ------- */
+
+void free_pres_actions(cp_actions_t *a)
+{
+	cp_unknown_t *u, *nu;
+
+	if(!a)
+		return;
+
+	u = a->unknown;
+	while(u) {
+		nu = u->next;
+		cds_free(u);
+		u = nu;
+	}
+	cds_free(a);
+}
+
+void free_pres_rules(cp_ruleset_t *r)
+{
+	free_common_rules(r, free_pres_actions);
+}

+ 53 - 0
src/lib/xcap/pres_rules.h

@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __PRES_RULES_H
+#define __PRES_RULES_H
+
+#include <cds/sstr.h>
+#include <xcap/xcap_client.h>
+#include <xcap/common_policy.h>
+
+typedef cp_ruleset_t presence_rules_t;
+
+/* Type defining action for pres_rules */
+typedef enum
+{
+	sub_handling_block,
+	sub_handling_confirm,
+	sub_handling_polite_block,
+	sub_handling_allow
+} sub_handling_t;
+
+int get_pres_rules(const str_t *username, const str_t *filename,
+		xcap_query_params_t *xcap_params, cp_ruleset_t **dst);
+void free_pres_rules(cp_ruleset_t *r);
+void free_pres_actions(cp_actions_t *a);
+
+/* returns 0 if rule found, 1 if not found and -1 on error */
+int get_pres_rules_action(
+		cp_ruleset_t *r, const str_t *wuri, sub_handling_t *dst_action);
+
+#endif

+ 864 - 0
src/lib/xcap/resource_list.c

@@ -0,0 +1,864 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <cds/dstring.h>
+#include <xcap/xcap_client.h>
+#include <xcap/resource_list.h>
+#include <xcap/resource_lists_parser.h>
+#include <xcap/rls_services_parser.h>
+#include <xcap/xcap_result_codes.h>
+#include <libxml/parser.h>
+#include <cds/logger.h>
+
+#define STR_OK(s) (s) ? (s) : ""
+
+typedef struct _traversed_list_t
+{
+	struct _traversed_list_t *next;
+	char *uri;
+} traversed_list_t;
+
+typedef struct
+{
+	const str_t *xcap_root;
+	xcap_query_params_t *xcap_params;
+	traversed_list_t *traversed;
+	traversed_list_t *traversed_last;
+	flat_list_t *flat;
+	flat_list_t *flat_last;
+} process_params_t;
+
+void canonicalize_uri(const str_t *uri, str_t *dst)
+{
+	/* TODO: do the operation according to draft-ietf-simple-xcap-list-usage-05.txt */
+
+	if(!dst)
+		return;
+	if(!uri) {
+		dst->len = 0;
+		dst->s = NULL;
+		return;
+	}
+	if(uri->len > 0) {
+		dst->s = (char *)cds_malloc(uri->len);
+		if(!dst->s)
+			dst->len = 0;
+		else {
+			memcpy(dst->s, uri->s, uri->len);
+			dst->len = uri->len;
+		}
+	} else {
+		dst->len = 0;
+		dst->s = NULL;
+	}
+	/* DEBUG_LOG("canonicalized uri: \'%.*s\'\n", dst->len, dst->s); */
+}
+
+char *xcap_uri_for_rls_resource(const str_t *xcap_root, const str_t *uri)
+{
+	dstring_t s;
+	int l;
+	str_t c_uri;
+	char *dst = NULL;
+
+	if(!xcap_root)
+		return NULL;
+	dstr_init(&s, 2 * xcap_root->len + 32);
+	dstr_append_str(&s, xcap_root);
+	if(xcap_root->s[xcap_root->len - 1] != '/')
+		dstr_append(&s, "/", 1);
+	dstr_append_zt(
+			&s, "rls-services/global/index/~~/rls-services/service[@uri=%22");
+	canonicalize_uri(uri, &c_uri);
+	dstr_append_str(&s, &c_uri);
+	if(c_uri.s)
+		cds_free(c_uri.s);
+
+	dstr_append_zt(&s, "%22]");
+	l = dstr_get_data_length(&s);
+	if(l > 0) {
+		dst = (char *)cds_malloc(l + 1);
+		if(dst) {
+			dstr_get_data(&s, dst);
+			dst[l] = 0;
+		}
+	}
+	dstr_destroy(&s);
+	return dst;
+}
+
+char *xcap_uri_for_rls_services(const str_t *xcap_root)
+{
+	dstring_t s;
+	int l;
+	char *dst = NULL;
+
+	if(!xcap_root)
+		return NULL;
+	dstr_init(&s, 2 * xcap_root->len + 32);
+	dstr_append_str(&s, xcap_root);
+	if(xcap_root->s[xcap_root->len - 1] != '/')
+		dstr_append(&s, "/", 1);
+	dstr_append_zt(&s, "rls-services/global/index");
+
+	l = dstr_get_data_length(&s);
+	if(l > 0) {
+		dst = (char *)cds_malloc(l + 1);
+		if(dst) {
+			dstr_get_data(&s, dst);
+			dst[l] = 0;
+		}
+	}
+	dstr_destroy(&s);
+	return dst;
+}
+
+void free_flat_list(flat_list_t *list)
+{
+	flat_list_t *f, *e;
+	e = list;
+	while(e) {
+		f = e->next;
+		if(e->uri)
+			cds_free(e->uri);
+		free_display_names(e->names);
+		cds_free(e);
+		e = f;
+	}
+}
+
+void free_traversed_list(traversed_list_t *list)
+{
+	traversed_list_t *f, *e;
+	e = list;
+	while(e) {
+		f = e->next;
+		if(e->uri)
+			cds_free(e->uri);
+		cds_free(e);
+		e = f;
+	}
+}
+
+/* ------- helper functions (doing flat list) ------- */
+
+/* absolute uri from ref (RFC 3986, section 5.2) */
+static char *relative2absolute_uri(const str_t *xcap_root, const char *relative)
+{
+	int len;
+	int root_len = 0;
+	int rel_len = 0;
+	int slash_len = 0;
+	char *dst = NULL;
+
+	if(xcap_root) {
+		root_len = xcap_root->len;
+		if(xcap_root->s[root_len - 1] != '/')
+			slash_len = 1;
+	}
+	if(relative)
+		rel_len = strlen(relative);
+	len = root_len + slash_len + rel_len + 1;
+
+	dst = (char *)cds_malloc(len);
+	if(!dst)
+		return NULL;
+
+	if(xcap_root)
+		memcpy(dst, xcap_root->s, root_len);
+	if(slash_len)
+		dst[root_len] = '/';
+	if(relative)
+		memcpy(dst + root_len + slash_len, relative, rel_len);
+	dst[len - 1] = 0;
+
+	return dst;
+}
+
+static display_name_t *duplicate_display_name(display_name_t *src)
+{
+	display_name_t *n;
+	if(!src)
+		return NULL;
+	n = (display_name_t *)cds_malloc(sizeof(*n));
+	if(!n)
+		return NULL;
+	memset(n, 0, sizeof(*n));
+	if(src->name)
+		n->name = zt_strdup(src->name);
+	if(src->lang)
+		n->lang = zt_strdup(src->lang);
+	return n;
+}
+
+int add_entry_to_flat(process_params_t *params, entry_t *entry)
+{
+	flat_list_t *f;
+	display_name_t *d, *n, *last;
+	char *uri;
+
+	if(!entry)
+		return -1;
+	uri = entry->uri;
+	if(!uri)
+		return -1; /* can't be added */
+
+	/* try to find the uri in the flat list first */
+	f = params->flat;
+	while(f) {
+		if(strcmp(f->uri, uri) == 0)
+			return 1; /* not significant for the caller */
+		f = f->next;
+	}
+
+	f = (flat_list_t *)cds_malloc(sizeof(flat_list_t));
+	if(!f)
+		return -1;
+	memset(f, 0, sizeof(*f));
+	f->uri = zt_strdup(uri);
+	f->next = NULL;
+
+	if(params->flat_last)
+		params->flat_last->next = f;
+	else
+		params->flat = f;
+	params->flat_last = f;
+
+	/* add all entry's names */
+	last = NULL;
+	d = SEQUENCE_FIRST(entry->display_names);
+	while(d) {
+		n = duplicate_display_name(d);
+		if(n)
+			SEQUENCE_ADD(f->names, last, n);
+		d = SEQUENCE_NEXT(d);
+	}
+
+	return 0;
+}
+
+int add_uri_to_traversed(process_params_t *params, const char *uri)
+{
+	traversed_list_t *f;
+
+	if(!uri)
+		return -1; /* can't be added */
+
+	/* try to find the uri in the flat list first */
+	f = params->traversed;
+	while(f) {
+		if(!f->uri)
+			continue;
+		if(strcmp(f->uri, uri) == 0)
+			return 1; /* this should be taken as an error */
+		f = f->next;
+	}
+
+	f = (traversed_list_t *)cds_malloc(sizeof(traversed_list_t));
+	if(!f)
+		return -1;
+	f->uri = zt_strdup(uri);
+	f->next = NULL;
+
+	if(params->traversed_last)
+		params->traversed_last->next = f;
+	else
+		params->traversed = f;
+	params->traversed_last = f;
+
+	return 0;
+}
+
+/* ------- processing functions (doing flat list) ------- */
+
+static int process_list(list_t *list, process_params_t *params);
+
+static int process_entry(entry_t *entry, process_params_t *params)
+{
+	if(!entry)
+		return RES_OK;
+	if(!entry->uri)
+		return RES_OK;
+
+	/* DEBUG_LOG("processing entry with uri \'%s\'\n", STR_OK(entry->uri)); */
+
+	add_entry_to_flat(params, entry);
+	return RES_OK;
+}
+
+static int process_entry_ref(entry_ref_t *entry_ref, process_params_t *params)
+{
+	char *data = NULL;
+	int dsize = 0;
+	entry_t *entry = NULL;
+	char *xcap_uri;
+	int res;
+
+	/* DEBUG_LOG("processing entry-ref with ref \'%s\'\n", STR_OK(entry_ref->ref)); */
+
+	if(!entry_ref)
+		return RES_OK;
+	if(!entry_ref->ref)
+		return RES_OK;
+
+	if(add_uri_to_traversed(params, entry_ref->ref) != 0) {
+		/* It is existing yet? */
+		ERROR_LOG("Duplicate URI in traversed set\n");
+		return RES_BAD_GATEWAY_ERR; /* 502 Bad GW */
+	}
+
+	/* XCAP query for the ref uri */
+	xcap_uri = relative2absolute_uri(params->xcap_root, entry_ref->ref);
+	res = xcap_query(xcap_uri, params->xcap_params, &data, &dsize);
+	if(res != 0) {
+		ERROR_LOG(
+				"XCAP problems for uri \'%s\'\n", xcap_uri ? xcap_uri : "???");
+		if(data)
+			cds_free(data);
+		if(xcap_uri)
+			cds_free(xcap_uri);
+		return RES_BAD_GATEWAY_ERR; /* 502 Bad GW */
+	}
+	if(xcap_uri)
+		cds_free(xcap_uri);
+
+	/* parse document as an entry element */
+	if(parse_entry_xml(data, dsize, &entry) != 0) {
+		ERROR_LOG("Parsing problems!\n");
+		if(entry)
+			free_entry(entry);
+		if(data)
+			cds_free(data);
+		return RES_BAD_GATEWAY_ERR; /* 502 Bad GW */
+	}
+	if(data)
+		cds_free(data);
+	if(!entry)
+		return RES_INTERNAL_ERR; /* ??? */
+
+	res = process_entry(entry, params);
+	free_entry(entry);
+	return res;
+}
+
+static int process_external(external_t *external, process_params_t *params)
+{
+	char *data = NULL;
+	int dsize = 0;
+	list_t *list = NULL;
+	int res;
+
+	/* DEBUG_LOG("processing external with anchor \'%s\'\n", STR_OK(external->anchor)); */
+
+	if(!external)
+		return RES_OK;
+	if(!external->anchor)
+		return RES_OK;
+
+	if(add_uri_to_traversed(params, external->anchor) != 0) {
+		/* It is existing yet? */
+		ERROR_LOG("Duplicate URI in traversed set\n");
+		return RES_BAD_GATEWAY_ERR; /* 502 Bad GW */
+	}
+
+	/* XCAP query for the ref uri */
+	res = xcap_query(external->anchor, params->xcap_params, &data, &dsize);
+	if(res != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n",
+				external->anchor ? external->anchor : "???");
+		if(data)
+			cds_free(data);
+		return RES_BAD_GATEWAY_ERR; /* 502 Bad GW */
+	}
+
+	/* parse document as an entry element */
+	if(parse_list_xml(data, dsize, &list) != 0) {
+		ERROR_LOG("Parsing problems!\n");
+		if(list)
+			free_list(list);
+		if(data)
+			cds_free(data);
+		return RES_BAD_GATEWAY_ERR; /* 502 Bad GW */
+	}
+	if(data)
+		cds_free(data);
+	if(!list)
+		return RES_INTERNAL_ERR; /* ??? */
+
+	res = process_list(list, params);
+
+	free_list(list);
+	return res;
+}
+
+static int process_list(list_t *list, process_params_t *params)
+{
+	list_content_t *e;
+	int res = 0;
+
+	if(!list)
+		return RES_INTERNAL_ERR;
+	/* DEBUG_LOG("processing list \'%s\'\n", STR_OK(list->name)); */
+
+	e = SEQUENCE_FIRST(list->content);
+
+	while(e) {
+		switch(e->type) {
+			case lct_list:
+				res = process_list(e->u.list, params);
+				break;
+			case lct_entry:
+				res = process_entry(e->u.entry, params);
+				break;
+			case lct_entry_ref:
+				res = process_entry_ref(e->u.entry_ref, params);
+				break;
+			case lct_external:
+				res = process_external(e->u.external, params);
+				break;
+		}
+		if(res != 0)
+			break;
+		e = SEQUENCE_NEXT(e);
+	}
+
+	return res;
+}
+
+static int process_resource_list(const char *rl_uri, process_params_t *params)
+{
+	char *data = NULL;
+	int dsize = 0;
+	int res = 0;
+	list_t *list = NULL;
+
+	/* DEBUG_LOG("processing resource list\n"); */
+
+	/* do an xcap query */
+	if(xcap_query(rl_uri, params->xcap_params, &data, &dsize) != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n", rl_uri ? rl_uri : "???");
+		if(data)
+			cds_free(data);
+		return RES_BAD_GATEWAY_ERR; /* -> 502 Bad GW */
+	}
+
+	/* parse query result */
+	if(parse_list_xml(data, dsize, &list) != 0) {
+		if(data)
+			cds_free(data);
+		return RES_BAD_GATEWAY_ERR; /* -> 502 Bad GW */
+	}
+	if(data) {
+		cds_free(data);
+	}
+	if(!list)
+		return RES_INTERNAL_ERR; /* ??? */
+
+	res = process_list(list, params);
+	if(list) {
+		free_list(list);
+	}
+
+	return res;
+}
+
+static int create_flat_list(
+		service_t *srv, xcap_query_params_t *xcap_params, flat_list_t **dst)
+{
+	process_params_t params;
+	int res = -1;
+	if(!srv)
+		return RES_INTERNAL_ERR;
+
+	params.xcap_params = xcap_params;
+	params.flat = NULL;
+	params.flat_last = NULL;
+	params.traversed = NULL;
+	params.traversed_last = NULL;
+
+	if(srv->content_type == stc_list) {
+		res = process_list(srv->content.list, &params);
+	} else {
+		res = process_resource_list(srv->content.resource_list, &params);
+	}
+	if(dst)
+		*dst = params.flat;
+
+	free_traversed_list(params.traversed);
+
+	return res;
+}
+
+/* ------- helper functions for rls examining ------- */
+
+/** compare str_t and zero terminated string */
+static int str_strcmp(const str_t *a, const char *b)
+{
+	int i;
+
+	if(!a) {
+		if(!b)
+			return 0;
+		else
+			return 1;
+	}
+	if(!a->s) {
+		if(!b)
+			return 0;
+		else
+			return 1;
+	}
+	if(!b)
+		return -1;
+	for(i = 0; i < a->len; i++) {
+		if(a->s[i] != b[i])
+			return -1;
+		if(b[i] == 0)
+			break;
+	}
+	if(i == a->len)
+		return 0;
+	else
+		return 1;
+}
+
+static int verify_package(service_t *srv, const str_t *package)
+{
+	package_t *e;
+
+	if(!package)
+		return 0;
+	if(!package->len)
+		return 0;
+	if(!package->s)
+		return 0;
+	if(!srv)
+		return 1;
+
+	if(srv->packages) {
+		e = SEQUENCE_FIRST(srv->packages->package);
+		while(e) {
+			if(str_strcmp(package, e->name) == 0)
+				return 0;
+			e = SEQUENCE_NEXT(e);
+		}
+		ERROR_LOG("Unsupported package \"%.*s\"\n", package->len, package->s);
+		return -1;
+	}
+	return 0;
+}
+
+static service_t *find_service(rls_services_t *rls, const str_t *uri)
+{
+	service_t *srv;
+
+	if(!rls)
+		return NULL;
+
+	srv = SEQUENCE_FIRST(rls->rls_services);
+	while(srv) {
+		/* TRACE_LOG("comparing %s to %.*s\n", srv->uri, FMT_STR(*uri)); */
+		if(str_strcmp(uri, srv->uri) == 0)
+			return srv;
+		srv = SEQUENCE_NEXT(srv);
+	}
+	return NULL;
+}
+
+/* ------- rls examining ------- */
+
+int get_rls(const str_t *uri, xcap_query_params_t *xcap_params,
+		const str_t *package, flat_list_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	service_t *service = NULL;
+	char *xcap_uri = NULL;
+	str_t *filename = NULL;
+	int res;
+
+	if(!dst)
+		return RES_INTERNAL_ERR;
+
+	/* get basic document */
+	xcap_uri = xcap_uri_for_global_document(
+			xcap_doc_rls_services, filename, xcap_params);
+	if(!xcap_uri) {
+		ERROR_LOG("can't get XCAP uri\n");
+		return RES_XCAP_QUERY_ERR;
+	}
+
+	res = xcap_query(xcap_uri, xcap_params, &data, &dsize);
+	if(res != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n", xcap_uri);
+		if(data) {
+			cds_free(data);
+		}
+		cds_free(xcap_uri);
+		return RES_XCAP_QUERY_ERR;
+	}
+	cds_free(xcap_uri);
+
+	/* parse document as a service element in rls-sources */
+	if(parse_service(data, dsize, &service) != 0) {
+		ERROR_LOG("Parsing problems!\n");
+		if(service)
+			free_service(service);
+		if(data) {
+			cds_free(data);
+		}
+		return RES_XCAP_PARSE_ERR;
+	}
+	/*	DEBUG_LOG("%.*s\n", dsize, data);*/
+	if(data)
+		cds_free(data);
+
+	if(!service) {
+		DEBUG_LOG("Empty service!\n");
+		return RES_XCAP_QUERY_ERR;
+	}
+
+	/* verify the package */
+	if(verify_package(service, package) != 0) {
+		free_service(service);
+		return RES_BAD_EVENT_PACKAGE_ERR;
+	}
+
+	/* create flat document */
+	res = create_flat_list(service, xcap_params, dst);
+	if(res != RES_OK) {
+		ERROR_LOG("Flat list creation error\n");
+		free_service(service);
+		free_flat_list(*dst);
+		*dst = NULL;
+		return res;
+	}
+	free_service(service);
+
+	return RES_OK;
+}
+
+int get_rls_from_full_doc(const str_t *uri,
+		/* const str_t *filename,  */
+		xcap_query_params_t *xcap_params, const str_t *package,
+		flat_list_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	rls_services_t *rls = NULL;
+	service_t *service = NULL;
+	str_t curi;
+	int res;
+	char *xcap_uri = NULL;
+	str_t *filename = NULL;
+
+	if(!dst)
+		return RES_INTERNAL_ERR;
+
+
+	/* get basic document */
+	xcap_uri = xcap_uri_for_global_document(
+			xcap_doc_rls_services, filename, xcap_params);
+	if(!xcap_uri) {
+		ERROR_LOG("can't get XCAP uri\n");
+		return -1;
+	}
+
+	res = xcap_query(xcap_uri, xcap_params, &data, &dsize);
+	if(res != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n", xcap_uri);
+		if(data) {
+			cds_free(data);
+		}
+		cds_free(xcap_uri);
+		return RES_XCAP_QUERY_ERR;
+	}
+	cds_free(xcap_uri);
+
+	/* parse document as a service element in rls-sources */
+	if(parse_rls_services_xml(data, dsize, &rls) != 0) {
+		ERROR_LOG("Parsing problems!\n");
+		if(rls)
+			free_rls_services(rls);
+		if(data) {
+			cds_free(data);
+		}
+		return RES_XCAP_PARSE_ERR;
+	}
+	/*	DEBUG_LOG("%.*s\n", dsize, data);*/
+	if(data)
+		cds_free(data);
+
+	/* try to find given service according to uri */
+	canonicalize_uri(uri, &curi);
+	service = find_service(rls, &curi);
+	if(!service)
+		DEBUG_LOG("Service %.*s not found!\n", FMT_STR(curi));
+	str_free_content(&curi);
+
+	if(!service) {
+		if(rls)
+			free_rls_services(rls);
+		return RES_XCAP_QUERY_ERR;
+	}
+
+	/* verify the package */
+	if(verify_package(service, package) != 0) {
+		free_rls_services(rls);
+		return RES_BAD_EVENT_PACKAGE_ERR;
+	}
+
+	/* create flat document */
+	res = create_flat_list(service, xcap_params, dst);
+	if(res != RES_OK) {
+		ERROR_LOG("Flat list creation error\n");
+		free_rls_services(rls);
+		free_flat_list(*dst);
+		*dst = NULL;
+		return res;
+	}
+	free_rls_services(rls);
+
+	return RES_OK;
+}
+
+static list_t *find_list(list_t *root, const char *name)
+{
+	list_content_t *c;
+
+	if(!root)
+		return root;
+	if(!name)
+		return root;
+	if(!*name)
+		return root; /* empty name = whole doc */
+
+	c = root->content;
+	while(c) {
+		if(c->type == lct_list) {
+			if(c->u.list) {
+				if(strcmp(name, c->u.list->name) == 0)
+					return c->u.list;
+			}
+		}
+		c = SEQUENCE_NEXT(c);
+	}
+
+	ERROR_LOG("list \'%s\' not found\n", name);
+
+	return NULL;
+}
+
+/* catches and processes user's resource list as rls-services document */
+int get_resource_list_from_full_doc(const str_t *user, const str_t *filename,
+		xcap_query_params_t *xcap_params, const char *list_name,
+		flat_list_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	service_t *service = NULL;
+	list_t *list = NULL, *right = NULL;
+	int res;
+	char *uri = NULL;
+
+	if(!dst)
+		return RES_INTERNAL_ERR;
+
+	/* get basic document */
+	uri = xcap_uri_for_users_document(
+			xcap_doc_resource_lists, user, filename, xcap_params);
+	if(!uri) {
+		ERROR_LOG("can't get XCAP uri\n");
+		return -1;
+	}
+	DEBUG_LOG("XCAP uri \'%s\'\n", uri);
+	res = xcap_query(uri, xcap_params, &data, &dsize);
+	if(res != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n", uri);
+		if(data) {
+			cds_free(data);
+		}
+		cds_free(uri);
+		return RES_XCAP_QUERY_ERR;
+	}
+	cds_free(uri);
+
+	/* parse document as a list element in resource-lists */
+	if(parse_as_list_content_xml(data, dsize, &list) != 0) {
+		ERROR_LOG("Parsing problems!\n");
+		if(list)
+			free_list(list);
+		if(data) {
+			cds_free(data);
+		}
+		return RES_XCAP_PARSE_ERR;
+	}
+	/*	DEBUG_LOG("%.*s\n", dsize, data);*/
+	if(data)
+		cds_free(data);
+
+	/* rs -> list */
+
+	if(!list) {
+		ERROR_LOG("Empty resource list!\n");
+		*dst = NULL;
+		return 0; /* this is not error! */
+				  /* return RES_INTERNAL_ERR; */
+	}
+
+	/* search for right list element */
+	right = find_list(list, list_name);
+
+	service = (service_t *)cds_malloc(sizeof(*service));
+	if(!service) {
+		ERROR_LOG("Can't allocate memory!\n");
+		return RES_MEMORY_ERR;
+	}
+	memset(service, 0, sizeof(*service));
+	service->content_type = stc_list;
+	service->content.list = right;
+	/*service->uri = ??? */
+
+	/* create flat document */
+	res = create_flat_list(service, xcap_params, dst);
+
+	service->content.list =
+			list; /* free whole document not only "right" list */
+	free_service(service);
+
+	if(res != RES_OK) {
+		ERROR_LOG("Flat list creation error\n");
+		free_flat_list(*dst);
+		*dst = NULL;
+		return res;
+	}
+
+	return RES_OK;
+}

+ 58 - 0
src/lib/xcap/resource_list.h

@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __RESOURCE_LIST_H
+#define __RESOURCE_LIST_H
+
+#include <xcap/rls_services_parser.h>
+#include <xcap/xcap_client.h>
+#include <cds/sstr.h>
+/* #include <cds/ptr_vector.h> */
+
+/* Functions for downloading the service documents with analyzis
+ * and "flatting" - see draft-ietf-simple-xcap-list-usage */
+
+typedef struct _flat_list_t
+{
+	struct _flat_list_t *next;
+	char *uri;
+	SEQUENCE(display_name_t) names;
+} flat_list_t;
+
+char *xcap_uri_for_rls_resource(const str_t *xcap_root, const str_t *uri);
+void canonicalize_uri(const str_t *uri, str_t *dst);
+int get_rls(const str_t *uri, xcap_query_params_t *xcap_params,
+		const str_t *package, flat_list_t **dst);
+int get_rls_from_full_doc(const str_t *uri,
+		/* const str_t *filename,  */
+		xcap_query_params_t *xcap_params, const str_t *package,
+		flat_list_t **dst);
+int get_resource_list_from_full_doc(const str_t *xcap_root, const str_t *user,
+		xcap_query_params_t *xcap_params, const char *list_name,
+		flat_list_t **dst);
+/* TODO: int get_resource_list(const str_t *xcap_root, const str_t *user, xcap_query_t *xcap_params, const str_t *list_name, flat_list_t **dst); */
+void free_flat_list(flat_list_t *list);
+
+#endif

+ 486 - 0
src/lib/xcap/resource_lists_parser.c

@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <xcap/resource_lists_parser.h>
+#include <xcap/xml_utils.h>
+#include <cds/logger.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <cds/sstr.h>
+
+static char rl_namespace[] = "urn:ietf:params:xml:ns:resource-lists";
+
+static int read_entry_ref(xmlNode *entry_node, entry_ref_t **dst)
+{
+	xmlAttr *a;
+	const char *a_val;
+
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (entry_ref_t *)cds_malloc(sizeof(entry_ref_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(entry_ref_t));
+
+	/* get attributes */
+	a = find_attr(entry_node->properties, "ref");
+	if(a) {
+		a_val = get_attr_value(a);
+		if(a_val)
+			(*dst)->ref = zt_strdup(a_val);
+	}
+	return 0;
+}
+
+static int read_name(xmlNode *name_node, display_name_t **dst)
+{
+	xmlAttr *a;
+	const char *a_val;
+
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (display_name_t *)cds_malloc(sizeof(display_name_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(display_name_t));
+
+	/* get attributes */
+	a = find_attr(name_node->properties, "lang");
+	if(a) {
+		a_val = get_attr_value(a);
+		if(a_val)
+			(*dst)->lang = zt_strdup(a_val);
+	}
+
+	a_val = get_node_value(name_node);
+	if(a_val)
+		(*dst)->name = zt_strdup(a_val);
+
+	return 0;
+}
+
+static int read_names(xmlNode *entry_node, display_name_t **dst)
+{
+	xmlNode *n;
+	display_name_t *name, *last;
+	int res = 0;
+
+	last = NULL;
+	*dst = NULL;
+	n = entry_node->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "display-name", rl_namespace) >= 0) {
+				res = read_name(n, &name);
+				if(res == 0) {
+					if(name) {
+						SEQUENCE_ADD((*dst), last, name);
+						name = NULL;
+					}
+				} else
+					break;
+			}
+		}
+		n = n->next;
+	}
+	return res;
+}
+
+static int read_entry(xmlNode *entry_node, entry_t **dst)
+{
+	xmlAttr *a;
+	const char *a_val;
+
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (entry_t *)cds_malloc(sizeof(entry_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(entry_t));
+
+	/* get attributes */
+	a = find_attr(entry_node->properties, "uri");
+	if(a) {
+		a_val = get_attr_value(a);
+		if(a_val)
+			(*dst)->uri = zt_strdup(a_val);
+	}
+
+	return read_names(entry_node, &((*dst)->display_names));
+}
+
+static int read_external(xmlNode *entry_node, external_t **dst)
+{
+	xmlAttr *a;
+	const char *a_val;
+
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (external_t *)cds_malloc(sizeof(external_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(external_t));
+
+	/* get attributes */
+	a = find_attr(entry_node->properties, "anchor");
+	if(a) {
+		a_val = get_attr_value(a);
+		if(a_val)
+			(*dst)->anchor = zt_strdup(a_val);
+	}
+	return 0;
+}
+
+int read_list(xmlNode *list_node, list_t **dst, int read_content_only)
+{
+	int res = 0;
+	xmlAttr *a;
+	const char *a_val;
+	xmlNode *n;
+	list_content_t *l, *last_l;
+
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (list_t *)cds_malloc(sizeof(list_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(list_t));
+
+	/* get attributes */
+	if(!read_content_only) {
+		a = find_attr(list_node->properties, "name");
+		if(a) {
+			a_val = get_attr_value(a);
+			if(a_val)
+				(*dst)->name = zt_strdup(a_val);
+		}
+	}
+
+	/* read entries */
+	last_l = NULL;
+	n = list_node->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			l = (list_content_t *)cds_malloc(sizeof(list_content_t));
+			if(!l)
+				return -1;
+			memset(l, 0, sizeof(*l));
+
+			if(cmp_node(n, "list", rl_namespace) >= 0) {
+				res = read_list(n, &l->u.list, 0);
+				if(res == 0) {
+					if(l->u.list) {
+						l->type = lct_list;
+						SEQUENCE_ADD((*dst)->content, last_l, l);
+						l = NULL;
+					}
+				} else
+					break;
+			}
+
+			if(cmp_node(n, "entry", rl_namespace) >= 0) {
+				res = read_entry(n, &l->u.entry);
+				if(res == 0) {
+					if(l->u.entry) {
+						l->type = lct_entry;
+						SEQUENCE_ADD((*dst)->content, last_l, l);
+						l = NULL;
+					}
+				} else
+					break;
+			}
+
+			if(cmp_node(n, "entry-ref", rl_namespace) >= 0) {
+				res = read_entry_ref(n, &l->u.entry_ref);
+				if(res == 0) {
+					if(l->u.entry_ref) {
+						l->type = lct_entry_ref;
+						SEQUENCE_ADD((*dst)->content, last_l, l);
+						l = NULL;
+					}
+				} else
+					break;
+			}
+
+			if(cmp_node(n, "external", rl_namespace) >= 0) {
+				res = read_external(n, &l->u.external);
+				if(res == 0) {
+					if(l->u.external) {
+						l->type = lct_external;
+						SEQUENCE_ADD((*dst)->content, last_l, l);
+						l = NULL;
+					}
+				} else
+					break;
+			}
+
+			if(l) {
+				cds_free(l);
+				l = NULL;
+			}
+		}
+		n = n->next;
+	}
+
+	return 0;
+}
+
+static int read_resource_lists(xmlNode *root, resource_lists_t **dst)
+{
+	resource_lists_t *rl;
+	/* xmlAttr *a; */
+	xmlNode *n;
+	list_t *l, *last_l;
+	int res = 0;
+
+	if(!dst)
+		return -1;
+	else
+		*dst = NULL;
+	if(!root)
+		return -1;
+
+	if(cmp_node(root, "resource-lists", rl_namespace) < 0) {
+		ERROR_LOG("document is not a resource-lists\n");
+		return -1;
+	}
+
+	rl = (resource_lists_t *)cds_malloc(sizeof(resource_lists_t));
+	if(!rl)
+		return -2;
+	*dst = rl;
+	rl->lists = NULL;
+
+	last_l = NULL;
+	n = root->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "list", rl_namespace) >= 0) {
+				res = read_list(n, &l, 0);
+				if(res == 0) {
+					if(l)
+						SEQUENCE_ADD(rl->lists, last_l, l);
+				} else
+					break;
+			}
+		}
+		n = n->next;
+	}
+
+	return res;
+}
+
+int parse_resource_lists_xml(
+		const char *data, int data_len, resource_lists_t **dst)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	if(dst)
+		*dst = NULL;
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return -1;
+	}
+
+	res = read_resource_lists(xmlDocGetRootElement(doc), dst);
+
+	xmlFreeDoc(doc);
+	return res;
+}
+
+int parse_list_xml(const char *data, int data_len, list_t **dst)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	if(dst)
+		*dst = NULL;
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return -1;
+	}
+
+	res = read_list(xmlDocGetRootElement(doc), dst, 0);
+
+	xmlFreeDoc(doc);
+	return res;
+}
+
+int parse_as_list_content_xml(const char *data, int data_len, list_t **dst)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	if(dst)
+		*dst = NULL;
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return -1;
+	}
+
+	res = read_list(xmlDocGetRootElement(doc), dst, 1);
+
+	xmlFreeDoc(doc);
+	return res;
+}
+
+int parse_entry_xml(const char *data, int data_len, entry_t **dst)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	if(dst)
+		*dst = NULL;
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return -1;
+	}
+
+	res = read_entry(xmlDocGetRootElement(doc), dst);
+
+	xmlFreeDoc(doc);
+	return res;
+}
+
+void free_display_name(display_name_t *n)
+{
+	if(!n)
+		return;
+	if(n->name)
+		cds_free(n->name);
+	if(n->lang)
+		cds_free(n->lang);
+	cds_free(n);
+}
+
+void free_display_names(display_name_t *sequence_first)
+{
+	display_name_t *d, *n;
+
+	if(!sequence_first)
+		return;
+
+	d = SEQUENCE_FIRST(sequence_first);
+	while(d) {
+		n = SEQUENCE_NEXT(d);
+		free_display_name(d);
+		d = n;
+	}
+}
+
+void free_entry(entry_t *e)
+{
+	if(!e)
+		return;
+
+	if(e->uri)
+		cds_free(e->uri);
+	free_display_names(e->display_names);
+
+	cds_free(e);
+}
+
+void free_entry_ref(entry_ref_t *e)
+{
+	if(!e)
+		return;
+	if(e->ref)
+		cds_free(e->ref);
+	cds_free(e);
+}
+
+void free_external(external_t *e)
+{
+	if(!e)
+		return;
+	if(e->anchor)
+		cds_free(e->anchor);
+	cds_free(e);
+}
+
+void free_list(list_t *l)
+{
+	list_content_t *e, *f;
+
+	if(!l)
+		return;
+
+	if(l->name)
+		cds_free(l->name);
+
+	e = SEQUENCE_FIRST(l->content);
+	while(e) {
+		switch(e->type) {
+			case lct_list:
+				free_list(e->u.list);
+				break;
+			case lct_entry:
+				free_entry(e->u.entry);
+				break;
+			case lct_entry_ref:
+				free_entry_ref(e->u.entry_ref);
+				break;
+			case lct_external:
+				free_external(e->u.external);
+				break;
+		}
+		f = e;
+		e = SEQUENCE_NEXT(e);
+		/* TRACE_LOG("freeing %p\n", f); */
+		cds_free(f);
+	}
+	cds_free(l);
+}
+
+
+void free_resource_lists(resource_lists_t *rl)
+{
+	list_t *e, *f;
+	if(!rl)
+		return;
+
+	e = SEQUENCE_FIRST(rl->lists);
+	while(e) {
+		f = SEQUENCE_NEXT(e);
+		free_list(e);
+		e = f;
+	}
+	cds_free(rl);
+}

+ 115 - 0
src/lib/xcap/resource_lists_parser.h

@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __RESOURCE_LISTS_PARSER_H
+#define __RESOURCE_LISTS_PARSER_H
+
+#include <xcap/xml_utils.h>
+#include <cds/memory.h>
+
+typedef struct _display_name_t
+{
+	SEQUENCE_ABLE(struct _display_name_t)
+	char *name;
+	char *lang;
+} display_name_t;
+
+typedef struct
+{
+	char *uri;
+	SEQUENCE(display_name_t) display_names;
+} entry_t;
+
+typedef struct
+{
+	char *anchor;
+	/* SEQUENCE(display_name_t) display_names; */
+} external_t;
+
+typedef struct
+{
+	char *ref;
+	/* SEQUENCE(display_name_t) display_names; */
+} entry_ref_t;
+
+typedef enum
+{
+	lct_list,
+	lct_entry,
+	lct_entry_ref,
+	lct_external
+} list_content_type_t;
+
+struct _list_t;
+
+typedef struct _list_content_t
+{
+	SEQUENCE_ABLE(struct _list_content_t)
+
+	list_content_type_t type;
+	union
+	{
+		struct _list_t *list;
+		entry_t *entry;
+		entry_ref_t *entry_ref;
+		external_t *external;
+	} u;
+} list_content_t;
+
+typedef struct _list_t
+{
+	SEQUENCE_ABLE(struct _list_t)
+
+	/*	entry_t *entries;*/
+	char *display_name;
+
+	SEQUENCE(list_content_t) content;
+
+	char *name;
+} list_t;
+
+typedef struct
+{
+	/* list_t *lists; */
+	SEQUENCE(list_t) lists;
+
+} resource_lists_t;
+
+int parse_resource_lists_xml(
+		const char *data, int data_len, resource_lists_t **dst);
+int parse_list_xml(const char *data, int data_len, list_t **dst);
+int parse_as_list_content_xml(const char *data, int data_len, list_t **dst);
+int parse_entry_xml(const char *data, int data_len, entry_t **dst);
+void free_resource_lists(resource_lists_t *rl);
+void free_list(list_t *l);
+void free_entry(entry_t *e);
+void free_display_names(display_name_t *sequence_first);
+
+/* if read_content_only set then the root element need not to be a list element
+ * it may be whatever, but content is parsed as if it is list (useful for reading
+ * resource-list as list */
+int read_list(xmlNode *list_node, list_t **dst, int read_content_only);
+
+#endif

+ 305 - 0
src/lib/xcap/rls_services_parser.c

@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <xcap/rls_services_parser.h>
+#include <xcap/xml_utils.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <cds/sstr.h>
+#include <cds/logger.h>
+
+static char rls_namespace[] = "urn:ietf:params:xml:ns:rls-services";
+/*
+static int read_entry(xmlNode *entry_node, entry_t **dst)
+{
+	xmlAttr *a;
+	const char *a_val;
+
+	/ * allocate memory and prepare empty node * /
+	if (!dst) return -1;
+	*dst = (entry_t*)cds_malloc(sizeof(entry_t));
+	if (!(*dst)) return -2;
+	memset(*dst, 0, sizeof(entry_t));
+
+	/ * get attributes * /
+	a = find_attr(entry_node->properties, "uri");
+	if (a) {
+		a_val = get_attr_value(a);
+		if (a_val) (*dst)->uri = zt_strdup(a_val);
+	}
+	return 0;
+}*/
+
+static int read_package(xmlNode *n, package_t **dst)
+{
+	const char *name;
+	if(!dst)
+		return -1;
+
+	*dst = (package_t *)cds_malloc(sizeof(package_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(package_t));
+
+	name = get_node_value(n);
+	if(name)
+		(*dst)->name = zt_strdup(name);
+	return 0;
+}
+
+static int read_packages(xmlNode *list_node, packages_t **dst)
+{
+	int res = 0;
+	xmlNode *n;
+	package_t *p, *last;
+
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (packages_t *)cds_malloc(sizeof(packages_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(packages_t));
+
+	/* read packages */
+	n = list_node->children;
+	last = NULL;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "package", rls_namespace) >= 0) {
+				res = read_package(n, &p);
+				if((res == 0) && p) {
+					SEQUENCE_ADD((*dst)->package, last, p);
+				}
+			}
+		}
+		n = n->next;
+	}
+
+	return 0;
+}
+
+int read_service(xmlNode *list_node, service_t **dst)
+{
+	int res = 0;
+	xmlAttr *a;
+	const char *a_val;
+	xmlNode *n;
+	int first_node;
+
+	DEBUG_LOG("read_service(): called\n");
+	/* allocate memory and prepare empty node */
+	if(!dst)
+		return -1;
+	*dst = (service_t *)cds_malloc(sizeof(service_t));
+	if(!(*dst))
+		return -2;
+	memset(*dst, 0, sizeof(service_t));
+
+	/* get attributes */
+	a = find_attr(list_node->properties, "uri");
+	if(a) {
+		a_val = get_attr_value(a);
+		if(a_val)
+			(*dst)->uri = zt_strdup(a_val);
+	}
+
+	/* read child nodes */
+	n = list_node->children;
+	first_node = 1;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(first_node) {
+				/* element must be list or resource-list */
+				if(cmp_node(n, "list", rls_namespace) >= 0) {
+					res = read_list(n, &(*dst)->content.list, 0);
+					if((res == 0) && ((*dst)->content.list)) {
+						(*dst)->content_type = stc_list;
+					} else
+						return -1;
+				} else if(cmp_node(n, "resource-list", rls_namespace) >= 0) {
+					a_val = get_node_value(n);
+					if(a_val)
+						(*dst)->content.resource_list = zt_strdup(a_val);
+					else
+						(*dst)->content.resource_list = NULL;
+					(*dst)->content_type = stc_resource_list;
+				} else
+					return -1;
+
+				first_node = 0;
+			} else { /* packages node */
+				if(cmp_node(n, "packages", rls_namespace) >= 0) {
+					res = read_packages(n, &(*dst)->packages);
+				}
+				break;
+			}
+		}
+		n = n->next;
+	}
+
+	return 0;
+}
+
+static int read_rls_services(xmlNode *root, rls_services_t **dst)
+{
+	/* xmlAttr *a; */
+	xmlNode *n;
+	service_t *l, *last_l;
+	int res = 0;
+
+	if(!root)
+		return -1;
+	if(!dst)
+		return -1;
+
+	if(cmp_node(root, "rls-services", rls_namespace) < 0) {
+		ERROR_LOG("document is not a rls-services\n");
+		return -1;
+	}
+
+	*dst = (rls_services_t *)cds_malloc(sizeof(rls_services_t));
+	if(!(*dst))
+		return -2;
+	(*dst)->rls_services = NULL;
+
+	last_l = NULL;
+	n = root->children;
+	while(n) {
+		if(n->type == XML_ELEMENT_NODE) {
+			if(cmp_node(n, "service", rls_namespace) >= 0) {
+				res = read_service(n, &l);
+				if(res == 0) {
+					if(l)
+						SEQUENCE_ADD((*dst)->rls_services, last_l, l);
+				} else
+					break;
+			}
+		}
+		n = n->next;
+	}
+
+	return res;
+}
+
+int parse_rls_services_xml(const char *data, int data_len, rls_services_t **dst)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return -1;
+	}
+
+	res = read_rls_services(xmlDocGetRootElement(doc), dst);
+
+	xmlFreeDoc(doc);
+	return res;
+}
+
+int parse_service(const char *data, int data_len, service_t **dst)
+{
+	int res = 0;
+	xmlDocPtr doc; /* the resulting document tree */
+
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
+	if(doc == NULL) {
+		ERROR_LOG("can't parse document\n");
+		return -1;
+	}
+
+	res = read_service(xmlDocGetRootElement(doc), dst);
+
+	xmlFreeDoc(doc);
+	return res;
+}
+
+static void free_package(package_t *p)
+{
+	if(!p)
+		return;
+	if(p->name)
+		cds_free(p->name);
+	cds_free(p);
+}
+
+static void free_packages(packages_t *p)
+{
+	package_t *e, *f;
+	if(!p)
+		return;
+
+	e = SEQUENCE_FIRST(p->package);
+	while(e) {
+		f = SEQUENCE_NEXT(e);
+		free_package(e);
+		e = f;
+	}
+	cds_free(p);
+}
+
+void free_service(service_t *s)
+{
+	if(!s)
+		return;
+
+	if(s->uri)
+		cds_free(s->uri);
+
+	switch(s->content_type) {
+		case stc_list:
+			free_list(s->content.list);
+			break;
+		case stc_resource_list:
+			cds_free(s->content.resource_list);
+			break;
+	}
+
+	free_packages(s->packages);
+
+	cds_free(s);
+}
+
+void free_rls_services(rls_services_t *rls)
+{
+	service_t *e, *f;
+	if(!rls)
+		return;
+
+	e = SEQUENCE_FIRST(rls->rls_services);
+	while(e) {
+		f = SEQUENCE_NEXT(e);
+		free_service(e);
+		e = f;
+	}
+	cds_free(rls);
+}

+ 77 - 0
src/lib/xcap/rls_services_parser.h

@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __RLS_SERVICES_PARSER_PARSER_H
+#define __RLS_SERVICES_PARSER_PARSER_H
+
+#include <xcap/xml_utils.h>
+#include <xcap/resource_lists_parser.h>
+
+typedef struct _package_t
+{
+	SEQUENCE_ABLE(struct _package_t)
+	char *name;
+} package_t;
+
+typedef struct _packages_t
+{
+	SEQUENCE(package_t) package;
+} packages_t;
+
+typedef enum
+{
+	stc_list,
+	stc_resource_list,
+} service_content_type_t;
+
+typedef struct _service_t
+{
+	SEQUENCE_ABLE(struct _service_t)
+
+	packages_t *packages;
+
+	service_content_type_t content_type;
+	union
+	{
+		list_t *list;
+		char *resource_list; /* uri */
+	} content;
+
+	char *uri;
+} service_t;
+
+typedef struct
+{
+	SEQUENCE(service_t) rls_services;
+} rls_services_t;
+
+int parse_rls_services_xml(
+		const char *data, int data_len, rls_services_t **dst);
+int parse_service(const char *data, int data_len, service_t **dst);
+void free_rls_services(rls_services_t *rl);
+void free_service(service_t *s);
+int read_service(xmlNode *list_node, service_t **dst);
+
+#endif

+ 437 - 0
src/lib/xcap/xcap_client.c

@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xcap/xcap_client.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/serialize.h>
+
+static const str_t *get_xcap_doc_dir(xcap_document_type_t doc_type)
+{
+	static str_t pres_rules = STR_STATIC_INIT("pres-rules");
+	static str_t im_rules = STR_STATIC_INIT("im-rules");
+	static str_t rls_services = STR_STATIC_INIT("rls-services");
+	static str_t resource_lists = STR_STATIC_INIT("resource-lists");
+
+	switch(doc_type) {
+		case xcap_doc_pres_rules:
+			return &pres_rules;
+		case xcap_doc_im_rules:
+			return &im_rules;
+		case xcap_doc_rls_services:
+			return &rls_services;
+		case xcap_doc_resource_lists:
+			return &resource_lists;
+			/* when new doc_type added, there will be a warning -> add it there */
+	}
+	WARN_LOG("unknown XCAP document type\n");
+	return NULL;
+}
+
+static const str_t *get_default_user_doc(xcap_document_type_t doc_type)
+{
+	static str_t pres_rules = STR_STATIC_INIT("presence-rules.xml");
+	static str_t im_rules = STR_STATIC_INIT("im-rules.xml");
+	static str_t rls_services = STR_STATIC_INIT("rls-services.xml");
+	static str_t resource_lists = STR_STATIC_INIT("resource-list.xml");
+
+	switch(doc_type) {
+		case xcap_doc_pres_rules:
+			return &pres_rules;
+		case xcap_doc_im_rules:
+			return &im_rules;
+		case xcap_doc_rls_services:
+			return &rls_services;
+		case xcap_doc_resource_lists:
+			return &resource_lists;
+			/* when new doc_type added, there will be a warning -> add it there */
+	}
+	WARN_LOG("unknown XCAP document type\n");
+	return NULL;
+}
+
+static int ends_with_separator(str_t *s)
+{
+	if(!is_str_empty(s))
+		if(s->s[s->len - 1] == '/')
+			return 1;
+	return 0;
+}
+
+char *xcap_uri_for_users_document(xcap_document_type_t doc_type,
+		const str_t *username, const str_t *filename,
+		xcap_query_params_t *params)
+{
+	dstring_t s;
+	/* int res = RES_OK; */
+	int l = 0;
+	char *dst = NULL;
+
+	dstr_init(&s, 128);
+	if(params) {
+		dstr_append_str(&s, &params->xcap_root);
+		if(!ends_with_separator(&params->xcap_root))
+			dstr_append(&s, "/", 1);
+	} else
+		dstr_append(&s, "/", 1);
+	dstr_append_str(&s, get_xcap_doc_dir(doc_type));
+	dstr_append_zt(&s, "/users/");
+	dstr_append_str(&s, username);
+	dstr_append(&s, "/", 1);
+	if(filename)
+		dstr_append_str(&s, filename);
+	else {
+		/* default filename if NULL */
+		dstr_append_str(&s, get_default_user_doc(doc_type));
+	}
+	/* res = dstr_get_str(&s, dst); */
+
+	l = dstr_get_data_length(&s);
+	if(l > 0) {
+		dst = (char *)cds_malloc(l + 1);
+		if(dst) {
+			dstr_get_data(&s, dst);
+			dst[l] = 0;
+		} else
+			ERROR_LOG("can't allocate memory (%d bytes)\n", l);
+	}
+
+	dstr_destroy(&s);
+	return dst;
+}
+
+
+char *xcap_uri_for_global_document(xcap_document_type_t doc_type,
+		const str_t *filename, xcap_query_params_t *params)
+{
+	dstring_t s;
+	/* int res = RES_OK; */
+	char *dst = NULL;
+	int l = 0;
+
+	dstr_init(&s, 128);
+	if(params) {
+		dstr_append_str(&s, &params->xcap_root);
+		if(!ends_with_separator(&params->xcap_root))
+			dstr_append(&s, "/", 1);
+	} else
+		dstr_append(&s, "/", 1);
+	dstr_append_str(&s, get_xcap_doc_dir(doc_type));
+	if(filename) {
+		dstr_append_zt(&s, "/global/");
+		dstr_append_str(&s, filename);
+	} else {
+		/* default filename if NULL */
+		dstr_append_zt(&s, "/global/index");
+	}
+	/* res = dstr_get_str(&s, dst); */
+
+	l = dstr_get_data_length(&s);
+	if(l > 0) {
+		dst = (char *)cds_malloc(l + 1);
+		if(dst) {
+			dstr_get_data(&s, dst);
+			dst[l] = 0;
+		}
+	}
+
+	dstr_destroy(&s);
+	return dst;
+}
+
+#ifdef SER
+
+#include "sr_module.h"
+
+int xcap_query(
+		const char *uri, xcap_query_params_t *params, char **buf, int *bsize)
+{
+	static xcap_query_func query = NULL;
+	static int initialized = 0;
+
+	if(!initialized) {
+		query = (xcap_query_func)find_export("xcap_query", 0, -1);
+		initialized = 1;
+		if(!query)
+			WARN_LOG("No XCAP query support! (Missing module?)\n");
+	}
+	if(!query) {
+		/* no function for doing XCAP queries */
+		return -1;
+	}
+
+	/* all XCAP queries are done through XCAP module */
+	return query(uri, params, buf, bsize);
+}
+
+#else /* compiled WITHOUT SER */
+
+#include <curl/curl.h>
+
+static size_t write_data_func(
+		void *ptr, size_t size, size_t nmemb, void *stream)
+{
+	int s = size * nmemb;
+	/*	TRACE_LOG("%d bytes written\n", s);*/
+	if(s != 0) {
+		if(dstr_append((dstring_t *)stream, ptr, s) != 0) {
+			ERROR_LOG("can't append %d bytes into data buffer\n", s);
+			return 0;
+		}
+	}
+	return s;
+}
+
+
+int xcap_query(
+		const char *uri, xcap_query_params_t *params, char **buf, int *bsize)
+{
+	CURLcode res = -1;
+	static CURL *handle = NULL;
+	dstring_t data;
+	char *auth = NULL;
+	int i;
+	long auth_methods;
+
+	if(!uri) {
+		ERROR_LOG("BUG: no uri given\n");
+		return -1;
+	}
+	if(!buf) {
+		ERROR_LOG("BUG: no buf given\n");
+		return -1;
+	}
+
+	i = 0;
+	if(params) {
+		if(params->auth_user.s)
+			i += params->auth_user.len;
+		if(params->auth_pass.s)
+			i += params->auth_pass.len;
+	}
+	if(i > 0) {
+		/* do authentication */
+		auth = (char *)cds_malloc(i + 2);
+		if(!auth)
+			return -1;
+		sprintf(auth, "%s:%s", params->auth_user.s ? params->auth_user.s : "",
+				params->auth_pass.s ? params->auth_pass.s : "");
+	}
+
+	auth_methods = CURLAUTH_BASIC | CURLAUTH_DIGEST;
+
+	dstr_init(&data, 512);
+
+	if(!handle)
+		handle = curl_easy_init();
+	if(handle) {
+		curl_easy_setopt(handle, CURLOPT_URL, uri);
+		/* TRACE_LOG("uri: %s\n", uri ? uri : "<null>"); */
+
+		/* do not store data into a file - store them in memory */
+		curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data_func);
+		curl_easy_setopt(handle, CURLOPT_WRITEDATA, &data);
+
+#ifdef CURLOPT_MUTE
+		/* be quiet */
+		curl_easy_setopt(handle, CURLOPT_MUTE, 1);
+#endif /* CURLOPT_MUTE */
+
+		/* non-2xx => error */
+		curl_easy_setopt(handle, CURLOPT_FAILONERROR, 1);
+
+		/* auth */
+		curl_easy_setopt(handle, CURLOPT_HTTPAUTH,
+				auth_methods); /* TODO possibility of selection */
+		curl_easy_setopt(handle, CURLOPT_NETRC, CURL_NETRC_IGNORED);
+		curl_easy_setopt(handle, CURLOPT_USERPWD, auth);
+
+		/* SSL */
+		if(params) {
+			if(params->enable_unverified_ssl_peer) {
+				curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+				curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0);
+			}
+		}
+
+		/* follow redirects (needed for apache mod_speling - case insesitive names) */
+		curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
+
+		/* Accept headers */
+		res = curl_easy_perform(handle);
+	} else
+		ERROR_LOG("can't initialize curl handle\n");
+	if(res == 0) {
+		*bsize = dstr_get_data_length(&data);
+		if(*bsize) {
+			*buf = (char *)cds_malloc(*bsize);
+			if(!*buf) {
+				ERROR_LOG("can't allocate %d bytes\n", *bsize);
+				res = -1;
+				*bsize = 0;
+			} else
+				dstr_get_data(&data, *buf);
+		}
+	} else
+		DEBUG_LOG("curl error: %d\n", res);
+	dstr_destroy(&data);
+	if(auth)
+		cds_free(auth);
+	return res;
+}
+
+#endif
+
+void free_xcap_params_content(xcap_query_params_t *params)
+{
+	if(params) {
+		str_free_content(&params->xcap_root);
+		str_free_content(&params->auth_user);
+		str_free_content(&params->auth_pass);
+		memset(params, 0, sizeof(*params));
+	}
+}
+
+int dup_xcap_params(xcap_query_params_t *dst, xcap_query_params_t *src)
+{
+	int res = -10;
+
+	if(dst)
+		memset(dst, 0, sizeof(*dst));
+
+	if(src && dst) {
+		res = 0;
+
+		res = str_dup(&dst->xcap_root, &src->xcap_root);
+		if(res == 0)
+			res = str_dup(&dst->auth_user, &src->auth_user);
+		if(res == 0)
+			res = str_dup(&dst->auth_pass, &src->auth_pass);
+
+		if(res != 0)
+			free_xcap_params_content(dst);
+	}
+
+	return res;
+}
+
+int get_inline_xcap_buf_len(xcap_query_params_t *params)
+{
+	int len;
+
+	/* counts the length for data buffer storing values of
+	 * xcap parameter members */
+	if(!params) {
+		ERROR_LOG("BUG: empty params given\n");
+		return 0;
+	}
+
+	len = params->xcap_root.len;
+	len += params->auth_user.len;
+	len += params->auth_pass.len;
+
+	return len;
+}
+
+int dup_xcap_params_inline(
+		xcap_query_params_t *dst, xcap_query_params_t *src, char *data_buffer)
+{
+	int res = -10;
+
+	/* copies structure into existing buffer */
+	if(dst) {
+		memset(dst, 0, sizeof(*dst));
+		res = 0;
+	}
+
+	if(src && dst) {
+		dst->xcap_root.s = data_buffer;
+		str_cpy(&dst->xcap_root, &src->xcap_root);
+
+		dst->auth_user.s = after_str_ptr(&dst->xcap_root);
+		str_cpy(&dst->auth_user, &src->auth_user);
+		dst->auth_pass.s = after_str_ptr(&dst->auth_user);
+		str_cpy(&dst->auth_pass, &src->auth_pass);
+	}
+	return res;
+}
+
+int serialize_xcap_params(sstream_t *ss, xcap_query_params_t *xp)
+{
+	int res = 0;
+
+	if(is_input_sstream(ss)) {
+		memset(xp, 0, sizeof(*xp));
+	}
+	res = serialize_str(ss, &xp->xcap_root) | res;
+	res = serialize_str(ss, &xp->auth_user) | res;
+	res = serialize_str(ss, &xp->auth_pass) | res;
+
+	return res;
+}
+
+int str2xcap_params(xcap_query_params_t *dst, const str_t *src)
+{
+	int res = 0;
+	sstream_t store;
+
+	if(!src)
+		return -1;
+
+	init_input_sstream(&store, src->s, src->len);
+	if(serialize_xcap_params(&store, dst) != 0) {
+		ERROR_LOG("can't de-serialize xcap_params\n");
+		res = -1;
+	}
+	destroy_sstream(&store);
+
+	return res;
+}
+
+int xcap_params2str(str_t *dst, xcap_query_params_t *src)
+{
+	int res = 0;
+	sstream_t store;
+
+	init_output_sstream(&store, 256);
+
+	if(serialize_xcap_params(&store, src) != 0) {
+		ERROR_LOG("can't serialize dialog\n");
+		res = -1;
+	} else {
+		if(get_serialized_sstream(&store, dst) != 0) {
+			ERROR_LOG("can't get serialized data\n");
+			res = -1;
+		}
+	}
+
+	destroy_sstream(&store);
+	return res;
+}

+ 85 - 0
src/lib/xcap/xcap_client.h

@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __XCAP_CLIENT_H
+#define __XCAP_CLIENT_H
+
+#include <cds/sstr.h>
+#include <xcap/xcap_result_codes.h>
+
+typedef struct
+{
+	/* "prefix" for XCAP query */
+	str_t xcap_root;
+	/** username for authentication */
+	str_t auth_user;
+	/** password used for authentication */
+	str_t auth_pass;
+	/** Accept unverifiable peers (ignore information
+	 * stored in certificate and trust a certificate
+	 * without know CA). */
+	int enable_unverified_ssl_peer;
+} xcap_query_params_t;
+
+typedef enum
+{
+	xcap_doc_pres_rules,
+	xcap_doc_im_rules,
+	xcap_doc_rls_services,
+	xcap_doc_resource_lists
+} xcap_document_type_t;
+
+char *xcap_uri_for_users_document(xcap_document_type_t doc_type,
+		const str_t *username, const str_t *filename,
+		xcap_query_params_t *params);
+
+char *xcap_uri_for_global_document(xcap_document_type_t doc_type,
+		const str_t *filename, xcap_query_params_t *params);
+
+/** Sends a XCAP query to the destination and using parameters from
+ * query variable a returns received data in output variables buf
+ * and bsize. */
+/* URI is absolute HTTP/HTTPS uri for the query  */
+int xcap_query(
+		const char *uri, xcap_query_params_t *params, char **buf, int *bsize);
+
+typedef int (*xcap_query_func)(
+		const char *uri, xcap_query_params_t *params, char **buf, int *bsize);
+
+void free_xcap_params_content(xcap_query_params_t *params);
+int dup_xcap_params(xcap_query_params_t *dst, xcap_query_params_t *src);
+
+/* counts the length for data buffer storing values of
+ * xcap parameter members */
+int get_inline_xcap_buf_len(xcap_query_params_t *params);
+
+/* copies structure into existing buffer */
+int dup_xcap_params_inline(
+		xcap_query_params_t *dst, xcap_query_params_t *src, char *data_buffer);
+
+int str2xcap_params(xcap_query_params_t *dst, const str_t *src);
+int xcap_params2str(str_t *dst, xcap_query_params_t *src);
+
+#endif

+ 40 - 0
src/lib/xcap/xcap_result_codes.h

@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __XCAP_RESULT_CODES_H
+#define __XCAP_RESULT_CODES_H
+
+/* result codes returned by XCAP operations */
+#define RES_OK 0
+#define RES_INTERNAL_ERR (-1)
+#define RES_MEMORY_ERR (-2)
+#define RES_BAD_EVENT_PACKAGE_ERR (-5)
+#define RES_BAD_GATEWAY_ERR (-6)
+#define RES_XCAP_QUERY_ERR (-7)
+#define RES_XCAP_PARSE_ERR (-8)
+
+#define LAST_XCAP_RES_CODE RES_XCAP_PARSE_ERR
+
+#endif

+ 156 - 0
src/lib/xcap/xml_utils.c

@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <cds/logger.h>
+#include <xcap/xml_utils.h>
+
+int xml_parser_flags = XML_PARSE_NOERROR | XML_PARSE_NOWARNING;
+
+static int str2int(const char *s, int *dst)
+{
+	/* if not null sets the given integer to value */
+	if(!s) {
+		*dst = 0;
+		return -1;
+	} else
+		*dst = atoi(s);
+	return 0;
+}
+
+int get_int_attr(xmlNode *n, const char *attr_name, int *dst)
+{
+	const char *s = get_attr_value(find_attr(n->properties, attr_name));
+	if(!s)
+		return 1;
+	return str2int(s, dst);
+}
+
+int get_str_attr(xmlNode *n, const char *attr_name, str_t *dst)
+{
+	const char *s = get_attr_value(find_attr(n->properties, attr_name));
+	if(!s) {
+		str_clear(dst);
+		return 1;
+	} else
+		return str_dup_zt(dst, s);
+}
+
+int xmlstrcmp(const xmlChar *xmls, const char *name)
+{
+	if(!xmls)
+		return -1;
+	if(!name)
+		return 1;
+	return strcmp((const char *)xmls, name);
+}
+
+/* xmlNode *find_node(xmlNode *parent, const char *name) */
+xmlNode *find_node(xmlNode *parent, const char *name, const char *nspace)
+{
+	if(!parent)
+		return NULL;
+	xmlNode *n = parent->children;
+	while(n) {
+		if(cmp_node(n, name, nspace) >= 0)
+			break;
+		n = n->next;
+	}
+	return n;
+}
+
+const char *find_value(xmlNode *first_child)
+{
+	const char *s = NULL;
+
+	xmlNode *c = first_child;
+	while(c) {
+		if(c->type == XML_TEXT_NODE) {
+			if(c->content)
+				s = (const char *)c->content;
+			break;
+		}
+		c = c->next;
+	}
+
+	return s;
+}
+
+const char *get_node_value(xmlNode *n)
+{
+	if(!n)
+		return NULL;
+	return find_value(n->children);
+}
+
+xmlAttr *find_attr(xmlAttr *first, const char *name)
+{
+	xmlAttr *a = first;
+	while(a) {
+		if(xmlstrcmp(a->name, name) == 0)
+			break;
+		a = a->next;
+	}
+	return a;
+}
+
+const char *get_attr_value(xmlAttr *a)
+{
+	if(!a)
+		return NULL;
+	return find_value(a->children);
+}
+
+int cmp_node(xmlNode *node, const char *name, const char *nspace)
+{
+	if(!node)
+		return -1;
+	if(node->type != XML_ELEMENT_NODE)
+		return -1;
+
+	if(xmlstrcmp(node->name, name) != 0)
+		return -1;
+	if(!nspace)
+		return 0;
+	if(!node->ns) {
+		/* DEBUG_LOG("nemam NS!!!!!!!\n"); */
+		return 1;
+	}
+	if(xmlstrcmp(node->ns->href, nspace) == 0)
+		return 0;
+	return -1;
+}
+
+time_t xmltime2time(const char *xt)
+{
+	/* TODO: translate XML time in input parameter to time_t structure */
+	ERROR_LOG("can't translate xmltime to time_t: not finished yet!\n");
+	return 0;
+}

+ 56 - 0
src/lib/xcap/xml_utils.h

@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2005 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+#include <cds/sstr.h>
+
+int xmlstrcmp(const xmlChar *xmls, const char *name);
+xmlAttr *find_attr(xmlAttr *first, const char *name);
+const char *find_value(xmlNode *first_child);
+const char *get_node_value(xmlNode *n);
+xmlNode *find_node(xmlNode *parent, const char *name, const char *nspace);
+const char *get_attr_value(xmlAttr *a);
+int cmp_node(xmlNode *node, const char *name, const char *nspace);
+int get_int_attr(xmlNode *n, const char *attr_name, int *dst);
+int get_str_attr(xmlNode *n, const char *attr_name, str_t *dst);
+
+time_t xmltime2time(const char *xt);
+
+#define SEQUENCE(type) type *
+#define SEQUENCE_ABLE(type) type *__next;
+#define SEQUENCE_ADD(first, last, e) \
+	do {                             \
+		if(last)                     \
+			last->__next = e;        \
+		else                         \
+			first = e;               \
+		last = e;                    \
+	} while(0);
+#define SEQUENCE_FIRST(first) first
+#define SEQUENCE_NEXT(e) (e)->__next
+
+extern int xml_parser_flags;