2
0
Эх сурвалжийг харах

Added a set of shared libraries with useful functions and common data structures.
Short description is in lib/README, more documentation will be added soon.

Vaclav Kubart 20 жил өмнө
parent
commit
1c24f8ebc2
65 өөрчлөгдсөн 6997 нэмэгдсэн , 0 устгасан
  1. 30 0
      lib/Makefile
  2. 126 0
      lib/Makefile.defs
  3. 44 0
      lib/Makefile.ser
  4. 51 0
      lib/Makefile.ser.defs
  5. 18 0
      lib/README
  6. 12 0
      lib/cds/Makefile
  7. 6 0
      lib/cds/Makefile.ser
  8. 138 0
      lib/cds/dlink.c
  9. 100 0
      lib/cds/dlink.h
  10. 157 0
      lib/cds/dstring.c
  11. 64 0
      lib/cds/dstring.h
  12. 173 0
      lib/cds/hash_table.c
  13. 77 0
      lib/cds/hash_table.h
  14. 53 0
      lib/cds/list.h
  15. 52 0
      lib/cds/logger.h
  16. 165 0
      lib/cds/memory.c
  17. 47 0
      lib/cds/memory.h
  18. 151 0
      lib/cds/msg_queue.c
  19. 73 0
      lib/cds/msg_queue.h
  20. 55 0
      lib/cds/ptr_vector.c
  21. 42 0
      lib/cds/ptr_vector.h
  22. 221 0
      lib/cds/serialize.c
  23. 74 0
      lib/cds/serialize.h
  24. 189 0
      lib/cds/sstr.c
  25. 93 0
      lib/cds/sstr.h
  26. 46 0
      lib/cds/sync.h
  27. 119 0
      lib/cds/vector.c
  28. 63 0
      lib/cds/vector.h
  29. 12 0
      lib/presence/Makefile
  30. 6 0
      lib/presence/Makefile.ser
  31. 37 0
      lib/presence/client_notify_info.c
  32. 46 0
      lib/presence/client_notify_info.h
  33. 114 0
      lib/presence/domain_maintainer.c
  34. 53 0
      lib/presence/domain_maintainer.h
  35. 51 0
      lib/presence/notifier.h
  36. 352 0
      lib/presence/notifier_domain.c
  37. 110 0
      lib/presence/notifier_domain.h
  38. 97 0
      lib/presence/pidf.c
  39. 34 0
      lib/presence/pidf.h
  40. 100 0
      lib/presence/pres_doc.c
  41. 66 0
      lib/presence/pres_doc.h
  42. 76 0
      lib/presence/qsa.c
  43. 46 0
      lib/presence/qsa.h
  44. 58 0
      lib/presence/subscriber.h
  45. 42 0
      lib/presence/subscription_info.h
  46. 12 0
      lib/xcap/Makefile
  47. 8 0
      lib/xcap/Makefile.ser
  48. 107 0
      lib/xcap/common_policy.h
  49. 386 0
      lib/xcap/parse_pres_rules.c
  50. 33 0
      lib/xcap/parse_pres_rules.h
  51. 339 0
      lib/xcap/pres_rules.c
  52. 48 0
      lib/xcap/pres_rules.h
  53. 562 0
      lib/xcap/resource_list.c
  54. 48 0
      lib/xcap/resource_list.h
  55. 419 0
      lib/xcap/resource_lists_parser.c
  56. 100 0
      lib/xcap/resource_lists_parser.h
  57. 284 0
      lib/xcap/rls_services_parser.c
  58. 70 0
      lib/xcap/rls_services_parser.h
  59. 189 0
      lib/xcap/test_pres_rules.c
  60. 265 0
      lib/xcap/test_rls.c
  61. 117 0
      lib/xcap/xcap_client.c
  62. 47 0
      lib/xcap/xcap_client.h
  63. 40 0
      lib/xcap/xcap_result_codes.h
  64. 132 0
      lib/xcap/xml_utils.c
  65. 52 0
      lib/xcap/xml_utils.h

+ 30 - 0
lib/Makefile

@@ -0,0 +1,30 @@
+# variables to change
+
+INCLUDES += -I$(CURDIR)
+LIBS     += -L$(CURDIR)/cds -L$(CURDIR)/qsa
+
+####################################
+# make rules
+
+export LIBS
+export INCLUDES
+
+SUBDIRS=cds xcap presence
+
+.PHONY: subdirs $(SUBDIRS) 
+
+# clean install tags proper
+
+subdirs:	$(SUBDIRS)
+
+$(SUBDIRS):	
+			@echo "Making $(MAKECMDGOALS) in $@" ; $(MAKE) $(MAKECMDGOALS) -C $@
+
+all:	subdirs
+
+proper:	clean
+
+clean:	subdirs
+
+install:	subdirs
+

+ 126 - 0
lib/Makefile.defs

@@ -0,0 +1,126 @@
+# lib-type may be given from commandline to control 
+# if resulting library will be static or shared
+# possible values: static, shared
+lib-type ?= shared
+
+# install directories
+prefix ?= /usr/local
+bin-dir ?= ${prefix}/bin
+include-dir ?= ${prefix}/include
+lib-dir ?= ${prefix}/lib
+
+# install programs
+install          ?= install
+install-bin      ?= $(install) -m 755
+install-lib      ?= $(install) -m 755
+install-includes ?= $(install) -m 644
+
+# working variables
+SRCS := $(wildcard *.c)
+HDRS := $(wildcard *.h)
+DEP_IN = ${SRCS} ${HDRS}
+OBJS := $(patsubst %.c,%.o,$(SRCS))
+
+####################################
+# make rules
+
+static_lib_name  = lib${NAME}.a
+dynamic_lib_name = lib${NAME}.so
+prg_name = ${NAME}
+
+out_name = ${prg_name}
+
+ifeq ($(TYPE),lib)
+INCLUDES += -I$(CURDIR)/..
+ifeq ($(lib-type),static)
+out_name = ${static_lib_name}
+else
+out_name = ${dynamic_lib_name}
+endif
+endif
+
+default:	${out_name}
+
+#static library
+
+${static_lib_name}:	${OBJS}
+		ar -r $@ ${OBJS}
+
+# dynamic library
+
+${dynamic_lib_name}:	${OBJS}
+		${CC} -shared ${DEFS} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}
+
+# executable
+
+${NAME}:	${OBJS}
+		${CC} ${DEFS} ${CFLAGS} ${INCLUDES} -o $@ ${OBJS} ${LIBS}
+		
+# common rules
+
+%.o:	%.c
+		${CC} ${DEFS} ${CFLAGS} ${INCLUDES} -c $<
+
+.PHONY:	install clean proper
+
+proper: clean
+
+clean:
+		-@rm -f ${prg_name} ${static_lib_name} ${dynamic_lib_name} *.o *.so *.d core core.* *~ tags Makefile.deps
+
+
+ifneq ($(MAKECMDGOALS),proper)
+ifneq ($(MAKECMDGOALS),clean)
+-include $(SRCS:.c=.d)
+endif
+endif
+
+%.d:	%.c
+		@$(CC) -M ${DEFS} $(CFLAGS) $(INCLUDES) $< > $@.$$$$; \
+		sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+		rm -f $@.$$$$
+
+
+# -include Makefile.deps
+#
+# Makefile.deps: ${DEP_IN}
+#		@echo "" > Makefile.deps
+#		@makedepend -fMakefile.deps -- ${DEFS} ${CFLAGS} ${INCLUDES} -- ${DEP_IN} 2>/dev/null
+#		-@rm -f Makefile.deps.bak
+
+# instalation rules
+
+ifeq ($(TYPE),lib)
+
+# library instalation
+
+install:	${out_name} install_dirs
+			$(install-lib) ${out_name} $(lib-dir)
+			@for hdr in ${HDRS} ; do \
+				$(install-includes) $$hdr $(include-dir)/$(NAME); \
+			done
+
+install_dirs:	$(lib-dir) $(include-dir)/$(NAME)
+
+else
+
+# executable instalation
+
+install:	${out_name} install_dirs
+			$(install-bin) ${out_name} $(bin-dir)
+
+install_dirs:	$(bin-dir)
+				
+endif
+
+# creating install directories
+
+$(bin-dir):	
+			mkdir -p $(bin-dir)
+
+$(lib-dir):	
+			mkdir -p $(lib-dir)
+			
+$(include-dir)/$(NAME):	
+			mkdir -p $(include-dir)/$(NAME)
+

+ 44 - 0
lib/Makefile.ser

@@ -0,0 +1,44 @@
+# variables to change
+
+CFLAGS   += -g -Wall
+DEFS     += -DSER
+ser      = $(CURDIR)/..
+
+INCLUDES += -I$(CURDIR) -I$(ser)
+LIBS     += -L$(CURDIR)/cds -L$(CURDIR)/qsa
+
+####################################
+# make rules
+
+include ../Makefile.defs
+
+lib-dir     = lib/ser
+INSTALL-LIB = $(INSTALL-BIN)
+LIBDIR      = $(modules-prefix)/$(lib-dir)
+
+export INSTALL-LIB
+export LIBDIR
+export INCLUDES
+export LIBS
+export CFLAGS
+export DEFS
+
+SUBDIRS=cds xcap presence
+
+.PHONY: subdirs $(SUBDIRS) 
+
+# clean install tags proper
+
+subdirs:	$(SUBDIRS)
+
+$(SUBDIRS):	
+			@echo "Making $(MAKECMDGOALS) in $@" ; $(MAKE) -f Makefile.ser $(MAKECMDGOALS) -C $@
+
+all:	subdirs
+
+proper:	clean
+
+clean:	subdirs
+
+install:	subdirs
+

+ 51 - 0
lib/Makefile.ser.defs

@@ -0,0 +1,51 @@
+# working variables
+
+SRCS := $(wildcard *.c)
+HDRS := $(wildcard *.h)
+DEP_IN = $(SRCS) $(HDRS)
+OBJS := $(patsubst %.c,%.o,$(SRCS))
+
+# static libraries
+
+ifeq ($(OUT_TYPE),static-lib)
+
+$(OUT_NAME):	$(OBJS)
+		ar -r $@ $(OBJS)
+
+install:	$(OUT_NAME)
+
+endif
+
+# dynamic libraries
+
+ifeq ($(OUT_TYPE),lib)
+$(OUT_NAME):	$(OBJS)
+		$(CC) -shared $(DEFS) $(CFLAGS) $(INCLUDES) -o $@ $(OBJS) $(LIBS)
+
+install:	$(OUT_NAME)
+			$(INSTALL-TOUCH) $(LIBDIR)/$(OUT_NAME)
+			$(INSTALL-LIB) $(OUT_NAME) $(LIBDIR)
+endif
+
+# common rules 
+
+%.o:	%.c
+		$(CC) $(DEFS) $(CFLAGS) $(INCLUDES) -c $<
+
+.PHONY:	clean install proper
+
+proper: clean
+
+clean:
+		-@rm -f $(OUT_NAME) *.o *.so *.d core core.* *~ Makefile.deps
+
+
+ifneq ($(MAKECMDGOALS),clean)
+-include $(SRCS:.c=.d)
+endif
+
+%.d:	%.c
+		@$(CC) -M $(DEFS) $(CFLAGS) $(INCLUDES) $< > $@.$$$$; \
+		sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
+		rm -f $@.$$$$
+

+ 18 - 0
lib/README

@@ -0,0 +1,18 @@
+Libraries common to modules:
+---------------------------
+
+cds - Common Data Structures (basic string operations, dynamic string,
+      vector, message queue, ...)
+
+presence - Library holding common structures and functions abaut presence
+           (API for internal subscriptions, common presence structures,
+           common presence data formats)
+           requires internal libraries: cds
+
+xcap - Common XCAP operations and structures (XCAP authorization documents
+       and XCAP resource lists processing)
+       requires external libraries: libxml2, libcurl3
+       requires internal libraries: cds
+
+Used by modules: pa, rls, dialog, rpa
+

+ 12 - 0
lib/cds/Makefile

@@ -0,0 +1,12 @@
+DEFS     += 
+INCLUDES +=
+LIBS     +=
+
+# name of result executable or library
+NAME = cds
+
+# TYPE=lib => shared or static library, executable otherwise
+TYPE = lib
+
+include ../Makefile.defs
+

+ 6 - 0
lib/cds/Makefile.ser

@@ -0,0 +1,6 @@
+LIBNAME  = cds
+OUT_NAME = libcds.so
+OUT_TYPE = lib
+
+include ../Makefile.ser.defs
+

+ 138 - 0
lib/cds/dlink.c

@@ -0,0 +1,138 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <cds/dlink.h>
+#include <cds/memory.h>
+#include <stdlib.h>
+
+dlink_element_t *dlink_element_alloc(int _data_length)
+{
+	dlink_element_t *e = (dlink_element_t*)cds_malloc(_data_length + sizeof(dlink_element_t)); /* shm */
+	if (e) {
+		e->data_length = _data_length;
+		e->next = NULL;
+		e->prev = NULL;
+	}
+	return e;
+}
+
+void dlink_element_free(dlink_element_t *e)
+{
+	if (e) cds_free(e); /* shm */
+}
+
+/* dlink_element_t *dlink_element_alloc_pkg(int _data_length)
+{
+	dlink_element_t *e = (dlink_element_t*)DLINK_PKG_ALLOC(_data_length + sizeof(dlink_element_t));
+	if (e) {
+		e->data_length = _data_length;
+		e->next = NULL;
+		e->prev = NULL;
+	}
+	return e;
+}
+
+void dlink_element_free_pkg(dlink_element_t *e) 
+{
+	if (e) DLINK_PKG_FREE(e);
+} */
+
+char* dlink_element_data(dlink_element_t *e)
+{
+	if (e) return e->data;
+	else return NULL;
+}
+
+
+void dlink_init(dlink_t *l) 
+{
+	if (l) {
+		l->first = NULL;
+		l->last = NULL;
+	}
+}
+
+void dlink_add(dlink_t *l, dlink_element_t *e)
+{
+	if ( (!l) || (!e) ) return;
+	
+	e->next = NULL;
+	if (!l->last) {
+		l->first = e;
+		e->prev = NULL;
+	}
+	else {
+		l->last->next = e;
+		e->prev = l->last;
+	}
+	l->last = e;
+}
+
+void dlink_remove(dlink_t *l, dlink_element_t *e)
+{
+	if ((!l) || (!e)) return;
+
+	if (e == l->first) l->first = e->next;
+	if (e == l->last) l->last = e->prev;
+	
+	if (e->prev) e->prev->next = e->next;
+	if (e->next) e->next->prev = e->prev;
+	
+	e->next = NULL;
+	e->prev = NULL;
+}
+
+dlink_element_t *dlink_start_walk(dlink_t *l) { if (l) return l->first; else return NULL; }
+dlink_element_t *dlink_next_element(dlink_element_t *e) { if (e) return e->next; else return NULL; }
+dlink_element_t *dlink_prev_element(dlink_element_t *e) { if (e) return e->prev; else return NULL; }
+
+dlink_element_t *dlink_last_element(dlink_t *l) 
+{
+	if (l) return l->last;
+	else return NULL;
+}
+
+void dlink_destroy(dlink_t *l)
+{
+	dlink_element_t *e,*n;
+	e = dlink_start_walk(l);
+	while (e) {
+		n = dlink_next_element(e);
+		dlink_element_free(e);
+		e = n;
+	}
+}
+/*
+void dlink_destroy_pkg(dlink_t *l)
+{
+	dlink_element_t *e,*n;
+	e = dlink_start_walk(l);
+	while (e) {
+		n = dlink_next_element(e);
+		dlink_element_free_pkg(e);
+		e = n;
+	}
+}
+*/

+ 100 - 0
lib/cds/dlink.h

@@ -0,0 +1,100 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DLINK_H
+#define __DLINK_H
+
+#include <stdio.h>
+
+/** 
+ * \defgroup dlink Universal double linked lists
+ *
+ */
+
+/**
+ * One element of dynamic linked list. Each element 
+ * can carry an arbitrary data element, which is allocated 
+ * together with extra data needed for linking 
+ * (pointers to next and previous elements).
+ */
+typedef struct dlink_element {
+	struct dlink_element *next;
+	struct dlink_element *prev;
+	
+	int data_length;
+	/** data array of unspecified size */
+	char data[1];
+} dlink_element_t;
+
+dlink_element_t *dlink_element_alloc(int _data_length);
+void dlink_element_free(dlink_element_t *e);
+/* dlink_element_t *dlink_element_alloc_pkg(int _data_length);
+void dlink_element_free_pkg(dlink_element_t *e); */
+char* dlink_element_data(dlink_element_t *e);
+
+/**
+ * Structure carying information about linked list.
+ */
+typedef struct dlink {
+	/** Pointer to the first element of this list. */
+	dlink_element_t *first;
+	
+	/** Pointer to the last element of this list due 
+	 * to more effective adding to the end of the list */	
+	dlink_element_t *last;
+
+	/* TODO: add some members for monitoring, ...
+	 * add hash map?
+	 */
+} dlink_t;
+
+/**
+ * Initializes dlink structure - clears pointers to the
+ * start and end of the link and so on.
+ */
+void dlink_init(dlink_t *l);
+
+/** destroys all elements in shared memory */
+void dlink_destroy(dlink_t *l);
+
+/* destroys all elements in pkg memory */
+/* void dlink_destroy_pkg(dlink_t *l); */
+
+/** Adds one (only one!) element e to the end of the link l. */
+void dlink_add(dlink_t *l, dlink_element_t *e);
+
+/** Removes an element e from the link. */
+void dlink_remove(dlink_t *l, dlink_element_t *e);
+
+/** Thiss method initiates walking through the list.
+ * It returns a pointer to the first element of the link. */
+dlink_element_t *dlink_start_walk(dlink_t *l);
+
+dlink_element_t *dlink_last_element(dlink_t *l);
+
+dlink_element_t *dlink_next_element(dlink_element_t *e);
+dlink_element_t *dlink_prev_element(dlink_element_t *e);
+
+#endif

+ 157 - 0
lib/cds/dstring.c

@@ -0,0 +1,157 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+
+static dstr_buff_t *get_current_buffer(dstring_t *dstr) 
+{
+	dstr_buff_t *buff;
+	buff = (dstr_buff_t*)dlink_element_data(dlink_last_element(&dstr->buffers));
+	return buff;
+}
+
+static dstr_buff_t *add_new_buffer(dstring_t *dstr) 
+{
+	dstr_buff_t *buff = NULL;
+	dlink_element_t *e;
+	
+	/* e = dlink_element_alloc_pkg(sizeof(dstr_buff_t) + dstr->buff_size); */
+	e = dlink_element_alloc(sizeof(dstr_buff_t) + dstr->buff_size);
+	if (e) {
+		buff = (dstr_buff_t*)dlink_element_data(e);
+		buff->len = dstr->buff_size;
+		buff->used = 0;
+		dlink_add(&dstr->buffers, e);
+	}
+	return buff;
+}
+
+int dstr_append(dstring_t *dstr, const char *s, int len)
+{
+	int size;
+	dstr_buff_t *buff;
+	
+	if (len == 0) return 0; /*append empty string*/
+	
+	buff = get_current_buffer(dstr);
+	if (!buff) buff = add_new_buffer(dstr);
+	while ((len > 0) && (buff)) {
+		size = buff->len - buff->used;
+		if (size > len) size = len;
+		memcpy(buff->data + buff->used, s, size);
+		buff->used += size;
+		len -= size;
+		s += size;
+		dstr->len += size;
+		if (len > 0) buff = add_new_buffer(dstr);
+	}
+	if (!buff) return -1;
+	return 0;
+}
+
+int dstr_append_zt(dstring_t *dstr, const char *s)
+{
+	if (!dstr) return -1;
+	if (!s) return 0; /*append empty string*/
+	return dstr_append(dstr, s, strlen(s));
+}
+
+int dstr_append_str(dstring_t *dstr, const str_t *s)
+{
+	if (!dstr) return -1;
+	if (!s) return 0; /*append empty string*/
+	return dstr_append(dstr, s->s, s->len);
+}
+
+int dstr_get_data_length(dstring_t *dstr)
+{
+	if (!dstr) return 0;
+	else return dstr->len;
+}
+
+int dstr_get_data(dstring_t *dstr, char *dst)
+{
+	dlink_element_t *e;
+	dstr_buff_t* buff;
+	
+	if (!dstr) return -1;
+	e = dlink_start_walk(&dstr->buffers);
+	while (e) {
+		buff = (dstr_buff_t*)dlink_element_data(e);
+		memcpy(dst, buff->data, buff->used);
+		dst += buff->used;
+		e = dlink_next_element(e);
+	}
+	return 0;
+}
+
+int dstr_get_str(dstring_t *dstr, str_t *dst)
+{
+	int res = 0;
+	
+	if (!dst) return -1;
+	dst->len = dstr_get_data_length(dstr);
+	if (dst->len > 0) {
+		dst->s = (char*)cds_malloc(dst->len);
+		if (!dst->s) {
+			res = -1;
+			dst->len = 0;
+			dst->s = NULL;
+		}
+		else res = dstr_get_data(dstr, dst->s);
+	} else dst->s = NULL;
+
+	return res;
+}
+
+
+int dstr_init(dstring_t *dstr, int buff_size)
+{
+	if (!dstr) return -1;
+	dstr->buff_size = buff_size;
+	dstr->len = 0;
+	dlink_init(&dstr->buffers);
+	return 0;
+}
+
+int dstr_destroy(dstring_t *dstr)
+{
+	dlink_element_t *e,*n;
+	if (!dstr) return -1;
+	/* dlink_destroy(&dstr->buffers); */
+	e = dlink_start_walk(&dstr->buffers);
+	while (e) {
+		n = dlink_next_element(e);
+		dlink_remove(&dstr->buffers, e);
+		dlink_element_free(e);
+		/* dlink_element_free_pkg(e); */
+		e = n;
+	}
+	return 0;
+}
+

+ 64 - 0
lib/cds/dstring.h

@@ -0,0 +1,64 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DSTRING_H
+#define __DSTRING_H
+
+#include <cds/sstr.h>
+#include <cds/dlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct dstr_buff {
+	int len;
+	int used;
+	char data[1];
+} dstr_buff_t;
+
+/** Dynamic string structure. It is used
+ * for muliple appends of any strings. */
+typedef struct dstring {
+	dlink_t buffers;
+	/** the length of whole string */
+	int len;
+	int buff_size;
+} dstring_t;
+
+int dstr_append_zt(dstring_t *dstr, const char *s);
+int dstr_append(dstring_t *dstr, const char *s, int len);
+int dstr_append_str(dstring_t *dstr, const str_t *s);
+int dstr_get_data_length(dstring_t *dstr);
+int dstr_get_data(dstring_t *dstr, char *dst);
+int dstr_get_str(dstring_t *dstr, str_t *dst);
+int dstr_init(dstring_t *dstr, int buff_size);
+int dstr_destroy(dstring_t *dstr);
+
+#ifdef __cplusplus
+}
+#endif
+	
+#endif

+ 173 - 0
lib/cds/hash_table.c

@@ -0,0 +1,173 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <cds/hash_table.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int ht_init(hash_table_t *ht, hash_func_t hash_func, key_cmp_func_t cmp_keys, int size)
+{
+	if (!ht) return -1;
+	if ((!hash_func) || (!cmp_keys)) return -1;
+
+	ht->cslots = (ht_cslot_t*)malloc(size * sizeof(ht_cslot_t));
+	if (!ht->cslots) return -1;
+	memset(ht->cslots, 0, size * sizeof(ht_cslot_t));
+
+	ht->size = size;
+	ht->hash = hash_func;
+	ht->cmp = cmp_keys;
+
+	ht->find_cnt = 0;
+	ht->cmp_cnt = 0;
+	ht->nocmp_cnt = 0;
+	ht->missed_cnt = 0;
+	return 0;
+}
+
+void ht_destroy(hash_table_t *ht)
+{
+	ht_element_t *e, *n;
+	int i;
+	
+	if (!ht) return;
+	if (ht->cslots) {
+		for (i = 0; i < ht->size; i++) {
+			e = ht->cslots[i].first;
+			while (e) {
+				n = e->next;
+				free(e);
+				e = n;
+			}
+		}
+		free(ht->cslots);
+	}
+	ht->cslots = NULL;
+}
+
+int ht_add(hash_table_t *ht, ht_key_t key, ht_data_t data)
+{
+	int h;
+	ht_element_t *new_e;
+	
+	if (!ht) return -1;
+	new_e = (ht_element_t*)malloc(sizeof(ht_element_t));
+	if (!new_e) return -1;
+	new_e->next = NULL;
+	new_e->key = key;
+	new_e->data = data;
+	
+	h = ht->hash(key) % ht->size;
+	if (h < 0) h = -h;
+	
+	if (!ht->cslots[h].last) {
+		ht->cslots[h].first = new_e;
+	}
+	else {
+		ht->cslots[h].last->next = new_e;
+	}
+
+	ht->cslots[h].cnt++;
+	ht->cslots[h].last = new_e;
+	return 0;
+}
+
+ht_data_t ht_find(hash_table_t *ht, ht_key_t key)
+{
+	int h;
+	ht_element_t *e;
+
+	if (!ht) return NULL;
+	
+	ht->find_cnt++;	//monitor
+	
+	h = ht->hash(key) % ht->size;
+	if (h < 0) h = -h;
+	e = ht->cslots[h].first;
+	if (!e) ht->nocmp_cnt++;	//monitor
+	while (e) {
+		ht->cmp_cnt++;	//monitor
+		if (ht->cmp(e->key, key) == 0) return e->data;
+		e = e->next;
+	}
+	
+	ht->missed_cnt++;	//monitor
+	return NULL;
+}
+
+ht_data_t ht_remove(hash_table_t *ht, ht_key_t key)
+{
+	int h;
+	ht_element_t *e,*p;
+	ht_data_t data;
+	
+	if (!ht) return NULL;
+	h = ht->hash(key) % ht->size;
+	if (h < 0) h = -h;
+	e = ht->cslots[h].first;
+	p = NULL;
+	while (e) {
+		if (ht->cmp(e->key, key) == 0) {
+			if (p) p->next = e->next;
+			else ht->cslots[h].first = e->next;
+			ht->cslots[h].cnt--;
+			if (!e->next) ht->cslots[h].last = p;
+			data = e->data;
+			free(e);
+			return data;
+		}
+		p = e;
+		e = e->next;
+	}
+	return NULL;
+}
+
+void ht_get_statistic(hash_table_t *ht, ht_statistic_t *s)
+{
+	if (!s) return;
+	if (!ht) {
+		s->find_cnt = 0;
+		s->cmp_cnt = 0;
+		s->nocmp_cnt = 0;
+		s->missed_cnt = 0;
+	}
+	else {
+		s->find_cnt = ht->find_cnt;
+		s->cmp_cnt = ht->cmp_cnt;
+		s->nocmp_cnt = ht->nocmp_cnt;
+		s->missed_cnt = ht->missed_cnt;
+	}
+}
+
+void ht_clear_statistic(hash_table_t *ht)
+{
+	if (!ht) return;
+	
+	ht->find_cnt = 0;
+	ht->cmp_cnt = 0;
+	ht->nocmp_cnt = 0;
+	ht->missed_cnt = 0;
+}

+ 77 - 0
lib/cds/hash_table.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __HASH_TABLE_H
+#define __HASH_TABLE_H
+
+typedef struct ht_statistic {
+	int find_cnt;
+	/** count of comparations during find operations */
+	int cmp_cnt;
+	/** count of finds which started in empty slot (-> no compares) */
+	int nocmp_cnt;
+	/** count of finds returning NULL */
+	int missed_cnt;
+} ht_statistic_t;
+
+typedef const void* ht_key_t;
+typedef void* ht_data_t;
+
+typedef int (*hash_func_t)(ht_key_t k);
+typedef int (*key_cmp_func_t)(ht_key_t a, ht_key_t b);
+
+typedef struct ht_element {
+	ht_key_t key;
+	ht_data_t data;
+	struct ht_element *next;
+} ht_element_t;
+
+typedef struct ht_cslot {
+	ht_element_t *first;
+	ht_element_t *last;
+	int cnt;
+} ht_cslot_t;
+
+typedef struct hash_table {
+	hash_func_t hash;
+	key_cmp_func_t cmp;
+	ht_cslot_t *cslots;
+	int size;
+
+	int find_cnt;
+	int cmp_cnt;
+	int nocmp_cnt;
+	int missed_cnt;
+} hash_table_t;
+
+int ht_init(hash_table_t *ht, hash_func_t hash_func, key_cmp_func_t cmp_keys, int size);
+void ht_destroy(hash_table_t *ht);
+int ht_add(hash_table_t *ht, ht_key_t key, ht_data_t data);
+ht_data_t ht_remove(hash_table_t *ht, ht_key_t key);
+ht_data_t ht_find(hash_table_t *ht, ht_key_t key);
+void ht_get_statistic(hash_table_t *ht, ht_statistic_t *s);
+void ht_clear_statistic(hash_table_t *ht);
+
+#endif

+ 53 - 0
lib/cds/list.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LIST_H
+#define __LIST_H
+
+#define DOUBLE_LINKED_LIST_ADD(first,last,e)	do { \
+		if (last) last->next = e; \
+		else first = e; \
+		e->next = NULL; \
+		e->prev = last; \
+		last = e; \
+	} while (0)
+
+#define DOUBLE_LINKED_LIST_REMOVE(first,last,e)	do { \
+		if (e->next) e->next->prev = e->prev; \
+		else last = e->prev; \
+		if (e->prev) e->prev->next = e->next; \
+		else first = e->next; \
+		e->next = NULL; \
+		e->prev = NULL; \
+	} while (0)
+
+#define LINKED_LIST_ADD(first,last,e)	do { \
+		if (last) last->next = e; \
+		else first = e; \
+		e->next = NULL; \
+		last = e; \
+	} while (0)
+
+#endif

+ 52 - 0
lib/cds/logger.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LOGGER_H
+#define __LOGGER_H
+
+#ifndef SER
+
+#include <stdio.h>
+
+#define ERROR_LOG(a,args...)		do{printf(a,##args);}while(0)
+#define DEBUG_LOG(a,args...)		do{printf(a,##args);}while(0)
+#define TRACE_LOG(a,args...)		do{printf(a,##args);}while(0)
+#define WARN_LOG(a,args...)			do{printf(a,##args);}while(0)
+#define FLUSH_LOG()					do{fflush(stdout);}while(0)
+
+#else
+/* TODO: logging for SER */
+
+#include "dprint.h"
+
+#define ERROR_LOG(a,args...)		LOG(L_ERR,a,##args)
+#define DEBUG_LOG(a,args...)		LOG(L_ERR,a,##args)
+#define TRACE_LOG(a,args...)		LOG(L_ERR,a,##args)
+#define WARN_LOG(a,args...)			LOG(L_WARN,a,##args)
+#define FLUSH_LOG()					do{}while(0)
+
+#endif
+
+#endif

+ 165 - 0
lib/cds/memory.c

@@ -0,0 +1,165 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Common Data Structures - functions for memory allocation and deallocation
+ * and may be other memory management. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <cds/memory.h>
+
+#ifdef SER
+
+#include <mem/mem.h>
+#include <mem/shm_mem.h>
+
+static void* shm_malloc_x(unsigned int size);
+static void shm_free_x(void *ptr);
+
+cds_malloc_func cds_malloc = shm_malloc_x;
+cds_free_func cds_free = shm_free_x;
+
+#else
+
+cds_malloc_func cds_malloc = malloc;
+cds_free_func cds_free = free;
+
+#endif
+
+void cds_set_memory_functions(cds_malloc_func _malloc, cds_free_func _free)
+{
+	cds_malloc = _malloc;
+	cds_free = _free;
+}
+
+#ifdef SER
+
+static void* shm_malloc_x(unsigned int size)
+{
+	return shm_malloc(size);
+}
+
+static void shm_free_x(void *ptr)
+{
+	shm_free(ptr);
+}
+
+#endif
+
+/*
+#ifdef SER
+
+static gen_lock_t *mem_mutex = NULL;
+int *allocated_cnt = NULL;
+
+#else
+
+static int allocated_cnt = 0;
+
+#endif
+
+void debug_mem_init()
+{
+#ifdef SER
+	mem_mutex = lock_alloc();
+	allocated_cnt = shm_malloc(sizeof(int));
+	*allocated_cnt = 0;
+	debug_print_allocated_mem();
+#else
+	allocated_cnt = 0;
+#endif
+}
+
+void *debug_malloc(int size)
+{
+#ifdef SER
+	void *m = NULL;
+	lock_get(mem_mutex);
+	if (allocated_cnt) (*allocated_cnt)++;
+	lock_release(mem_mutex);
+	m = shm_malloc(size);
+	LOG(L_INFO, "debug_malloc(): %p\n", m);
+	return m;
+#else
+	allocated_cnt++;
+	return malloc(size);
+#endif
+}
+
+void debug_free(void *block)
+{
+#ifdef SER
+	LOG(L_INFO, "debug_free(): %p\n", block);
+	shm_free(block);
+	lock_get(mem_mutex);
+	if (allocated_cnt) (*allocated_cnt)--;
+	lock_release(mem_mutex);
+#else
+	free(block);
+	allocated_cnt--;
+#endif
+}
+
+void *debug_malloc_ex(int size, const char *file, int line)
+{
+#ifdef SER
+	void *m = NULL;
+	lock_get(mem_mutex);
+	if (allocated_cnt) (*allocated_cnt)++;
+	lock_release(mem_mutex);
+	m = shm_malloc(size);
+	LOG(L_INFO, "ALLOC: %s:%d -> %p\n", file, line, m);
+	return m;
+#else
+	allocated_cnt++;
+	return malloc(size);
+#endif
+}
+
+void debug_free_ex(void *block, const char *file, int line)
+{
+#ifdef SER
+	LOG(L_INFO, "FREE: %s:%d -> %p\n", file, line, block);
+	shm_free(block);
+	lock_get(mem_mutex);
+	if (allocated_cnt) (*allocated_cnt)--;
+	lock_release(mem_mutex);
+#else
+	free(block);
+	allocated_cnt--;
+#endif
+}
+
+void debug_print_allocated_mem()
+{
+#ifdef SER
+	lock_get(mem_mutex);
+	LOG(L_INFO, "There are allocated: %d memory blocks\n", *allocated_cnt);
+	lock_release(mem_mutex);
+#else
+	printf("There are allocated: %d memory blocks\n", allocated_cnt);
+#endif
+}
+*/

+ 47 - 0
lib/cds/memory.h

@@ -0,0 +1,47 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CDS_MEMORY_H
+#define __CDS_MEMORY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void*(*cds_malloc_func)(unsigned int size);
+typedef void(*cds_free_func)(void *ptr);
+
+extern cds_malloc_func cds_malloc;
+extern cds_free_func cds_free;
+
+void cds_set_memory_functions(cds_malloc_func _malloc, cds_free_func _free);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+

+ 151 - 0
lib/cds/msg_queue.c

@@ -0,0 +1,151 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <cds/msg_queue.h>
+#include <cds/memory.h>
+
+mq_message_t *create_message_ex(int data_len)
+{
+	mq_message_t *m;
+	if (data_len < 0) data_len = 0;
+	m = cds_malloc(data_len + sizeof(mq_message_t));
+	if (!m) return NULL;
+	m->data_len = data_len;
+	m->data = (((char *)m) + sizeof(mq_message_t));
+	m->next = NULL;
+	m->allocation_style = message_allocated_with_data;
+	return m;
+}
+
+void free_message(mq_message_t *msg)
+{
+	switch (msg->allocation_style) {
+		case message_allocated_with_data: 
+				break;
+		case message_holding_data_ptr: 
+				if (msg->data) cds_free(msg->data);
+				break;
+	}
+	cds_free(msg);
+}
+
+int push_message(msg_queue_t *q, mq_message_t *m)
+{
+	if ((!q) || (!m)) return -1;
+	m->next = NULL;
+	
+	if (q->use_mutex) cds_mutex_lock(&q->q_mutex);
+	if (q->last) q->last->next = m;
+	else {
+		q->first = m;
+		q->last = m;
+	}
+	q->last = m;
+	if (q->use_mutex) cds_mutex_unlock(&q->q_mutex);
+	
+	return 0;
+}
+
+int mq_add_to_top(msg_queue_t *q, mq_message_t *m)
+{
+	if ((!q) || (!m)) return -1;
+	m->next = NULL;
+	
+	if (q->use_mutex) cds_mutex_lock(&q->q_mutex);
+	m->next = q->first;
+	q->first = m;
+	if (!q->last) q->last = m;
+	if (q->use_mutex) cds_mutex_unlock(&q->q_mutex);
+	
+	return 0;
+}
+
+mq_message_t *pop_message(msg_queue_t *q)
+{
+	mq_message_t *m;
+	if (!q) return NULL;
+
+	if (q->use_mutex) cds_mutex_lock(&q->q_mutex);
+	m = q->first;
+	if (m) {
+		if (q->first == q->last) {
+			q->first = NULL;
+			q->last = NULL;
+		}
+		else q->first = m->next;
+		m->next = NULL;
+	}
+	if (q->use_mutex) cds_mutex_unlock(&q->q_mutex);
+		
+	return m;
+}
+
+/** 1 ... empty, 0 ...  NOT empty !! */
+int is_msg_queue_empty(msg_queue_t *q)
+{
+	int res = 1;
+	if (q->use_mutex) cds_mutex_lock(&q->q_mutex);
+	if (q->first) res = 0;
+	if (q->use_mutex) cds_mutex_unlock(&q->q_mutex);
+	return res;
+}
+
+int msg_queue_init(msg_queue_t *q)
+{
+	return msg_queue_init_ex(q, 1);
+}
+
+int msg_queue_init_ex(msg_queue_t *q, int synchronize)
+{
+	if (synchronize) cds_mutex_init(&q->q_mutex);
+	q->use_mutex = synchronize;
+	q->first = NULL;
+	q->last = NULL;
+	return 0;
+}
+
+int msg_queue_destroy(msg_queue_t *q)
+{
+	mq_message_t *m,*n;
+	if (!q) return -1;
+	
+	if (q->use_mutex) cds_mutex_lock(&q->q_mutex);
+	m = q->first;
+	while (m) {
+		n = m->next;
+		free_message(m);
+		m = n;
+	}
+	q->first = NULL;
+	q->last = NULL;
+	if (q->use_mutex) {
+		cds_mutex_unlock(&q->q_mutex);
+		cds_mutex_destroy(&q->q_mutex);
+	}
+	return 0;
+}
+
+

+ 73 - 0
lib/cds/msg_queue.h

@@ -0,0 +1,73 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __MSG_QUEUE_H
+#define __MSG_QUEUE_H
+
+#include <cds/sync.h>
+
+typedef struct mq_message_t {
+	void *data;
+	int data_len;
+	struct mq_message_t *next;
+	enum { 
+		message_allocated_with_data, 
+		message_holding_data_ptr 
+	} allocation_style;
+	char data_buf[1];
+} mq_message_t;
+
+typedef struct msg_queue {
+	mq_message_t *first;
+	mq_message_t *last;
+	cds_mutex_t q_mutex;
+	int use_mutex;
+} msg_queue_t;
+
+/** the space for data is allocated in messages data
+ * (they are automaticaly freed!)! Pointer to allocated
+ * data bytes is in data variable in the message structure. */
+mq_message_t *create_message_ex(int data_len);
+
+/** data must be allocated using cds_malloc and they
+ * are automacicaly freed! */
+mq_message_t *create_message(void *data, int data_len);
+
+/** frees the message and data holding by the message !!!! */
+void free_message(mq_message_t *msg);
+
+int push_message(msg_queue_t *q, mq_message_t *m);
+mq_message_t *pop_message(msg_queue_t *q);
+
+/** 1 ... empty, 0 ...  NOT empty !! */
+int is_msg_queue_empty(msg_queue_t *q);
+
+/** initializes synchronized message queue */
+int msg_queue_init(msg_queue_t *q);
+int msg_queue_init_ex(msg_queue_t *q, int synchronize);
+int msg_queue_destroy(msg_queue_t *q);
+
+#endif
+

+ 55 - 0
lib/cds/ptr_vector.c

@@ -0,0 +1,55 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "ptr_vector.h"
+#include <stdio.h>
+
+int ptr_vector_add(ptr_vector_t *vector, void *ptr)
+{
+	return vector_add(vector, &ptr);
+}
+
+void *ptr_vector_get(ptr_vector_t *vector, int index)
+{
+	void *ptr = NULL;
+	if (vector_get(vector, index, &ptr) != 0) return NULL;
+	return ptr;
+}
+
+int ptr_vector_remove(ptr_vector_t *vector, int index)
+{
+	return vector_remove(vector, index);
+}
+
+void ptr_vector_destroy(ptr_vector_t *vector)
+{
+	return vector_destroy(vector);
+}
+
+int ptr_vector_init(vector_t *vector, int allocation_count)
+{
+	return vector_init(vector, sizeof(void *), allocation_count);
+}
+

+ 42 - 0
lib/cds/ptr_vector.h

@@ -0,0 +1,42 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PTR_VECTOR_H
+#define __PTR_VECTOR_H
+
+#include "vector.h"
+
+typedef vector_t ptr_vector_t;
+
+
+int ptr_vector_add(ptr_vector_t *vector, void *ptr);
+void *ptr_vector_get(ptr_vector_t *vector, int index);
+int ptr_vector_remove(ptr_vector_t *vector, int index);
+void ptr_vector_destroy(ptr_vector_t *vector);
+int ptr_vector_init(vector_t *vector, int allocation_count);
+
+#define ptr_vector_size(v) vector_size(v)
+
+#endif

+ 221 - 0
lib/cds/serialize.c

@@ -0,0 +1,221 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <cds/serialize.h>
+#include <cds/logger.h>
+
+int init_input_sstream(sstream_t *ss, char *data_in, int data_len)
+{
+	if (!ss) return -1;
+	
+	ss->type = sstream_in;
+	ss->in.len = data_len;
+	ss->in.s = data_in;
+	ss->in_pos = 0;
+	return 0;
+}
+
+int init_output_sstream(sstream_t *ss, int out_buff_resize)
+{
+	if (!ss) return -1;
+	
+	ss->type = sstream_out;
+	str_clear(&ss->in);
+	ss->in_pos = 0;
+	dstr_init(&ss->out, out_buff_resize);
+	return 0;
+}
+
+int get_serialized_sstream(sstream_t *ss, str_t *dst)
+{
+	if (ss->type == sstream_out) return dstr_get_str(&ss->out, dst);
+	else return -1; /* no output for input stream */
+}
+
+int sstream_get(sstream_t *ss, char *c)
+{
+	/* if (!is_input_sstream(ss)) return -1;  */ /* optimalization */
+	/* if (!c) return -1; */ /* dangerous optimalization */
+	if (ss->in_pos < ss->in.len) {
+		*c = ss->in.s[ss->in_pos++];
+		return 0;
+	}
+	else return 1;
+}
+
+int sstream_put_str(sstream_t *ss, str_t *s)
+{
+	/* if (is_input_sstream(ss)) return -1;  */ /* dangerous optimalization */
+	return dstr_append_str(&ss->out, s);
+}
+
+/* returns a part of string of given length - it is NOT a copy !!! */
+int sstream_get_str_ex(sstream_t *ss, int len, str_t *dst)
+{
+	int l;
+	int res = 0;
+	
+	if (!is_input_sstream(ss)) return -1;
+	if (!dst) return -1;
+
+	if (len == 0) {
+		str_clear(dst);
+		return 0;
+	}
+	
+	l = ss->in.len - ss->in_pos;
+	dst->s = ss->in.s + ss->in_pos;
+
+	if (len > l) {
+		dst->len = l;
+		res = 1; /* not whole requested string is returned ! */
+	}
+	else dst->len = len;
+	ss->in_pos += dst->len;
+	
+	return 0;
+}
+
+/* returns a copy of string from input buffer */
+int sstream_get_str(sstream_t *ss, int len, str_t *dst)
+{
+	str_t tmp;
+	int res = sstream_get_str_ex(ss, len, &tmp);
+	if (res >= 0) str_dup(dst, &tmp);
+	return res;
+}
+
+int sstream_put_zt(sstream_t *ss, const char *s)
+{
+	/* if (!is_input_sstream(ss)) return -1;  */ /* dangerous optimalization */
+	return dstr_append_zt(&ss->out, s);
+}
+
+int sstream_put(sstream_t *ss, const char *s, int len)
+{
+	/* if (!is_input_sstream(ss)) return -1;  */ /* dangerous optimalization */
+	return dstr_append(&ss->out, s, len);
+}
+
+void destroy_sstream(sstream_t *ss)
+{
+	if (ss->type == sstream_out) dstr_destroy(&ss->out);
+}
+
+/*****************************************************************/
+
+int serialize_int(sstream_t *ss, int *num)
+{
+	char sep = ':';
+	
+	if (!num) return -1;
+	
+	if (is_input_sstream(ss)) {
+		char c;
+		int first = 1;
+		int sign = 1; /* positive */
+		
+		*num = 0;
+		while (sstream_get(ss, &c) == 0) {
+			if (c == sep) break;
+			if ((c >= '0') && (c <= '9')) *num = 10 * (*num) + (c - '0');
+			else {
+				switch (c) {
+					case '-': 
+						if (first) sign = -1;
+						else return -1;
+					case '+': 
+						if (!first) return -1;
+					default: 
+						return -1; /* unknown character */
+				}
+			}
+			first = 0;
+		}
+		*num = sign * (*num);
+	}
+	else {
+		char tmp[32];
+
+		sprintf(tmp, "%d%c", *num, sep);
+		sstream_put_zt(ss, tmp);
+	}
+	return 0;
+}
+
+int serialize_uint(sstream_t *ss, unsigned int *num)
+{
+	char sep = ':';
+	
+	if (!num) return -1;
+	
+	if (is_input_sstream(ss)) {
+		char c;
+		
+		*num = 0;
+		while (sstream_get(ss, &c) == 0) {
+			if (c == sep) break;
+			if ((c >= '0') && (c <= '9')) *num = 10 * (*num) + (c - '0');
+			else return -1; /* unknown character */
+		}
+	}
+	else {
+		char tmp[32];
+
+		sprintf(tmp, "%u%c", *num, sep);
+		sstream_put_zt(ss, tmp);
+	}
+	return 0;
+}
+
+int serialize_str(sstream_t *ss, str_t *s)
+{
+	int res = 0;
+	
+	if (!s) return -1; 
+	
+	if (serialize_int(ss, &s->len) != 0) return -1;
+	if (is_input_sstream(ss)) {
+		if (s->len == 0) s->s = NULL;
+		else res = sstream_get_str(ss, s->len, s); /* duplicates read string */
+	}
+	else res = sstream_put(ss, s->s, s->len);
+
+	return res;
+}
+
+int serialize_char(sstream_t *ss, char *c)
+{
+	if (!c) return -1;
+	if (is_input_sstream(ss)) return sstream_get(ss, c);
+	else return sstream_put(ss, c, 1);
+}
+
+int serialize_uchar(sstream_t *ss, unsigned char *c)
+{
+	if (!c) return -1;
+	if (is_input_sstream(ss)) return sstream_get(ss, (char *)c);
+	else return sstream_put(ss, (char *)c, 1);
+}

+ 74 - 0
lib/cds/serialize.h

@@ -0,0 +1,74 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SERIALIZE_H
+#define __SERIALIZE_H
+
+/* serialization/deserialization data structures and functions */
+
+#include <cds/dstring.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+	dstring_t out; /* output string */
+	str_t in; /* input string */
+	int in_pos; /* position in input */
+	enum { sstream_in, sstream_out } type;
+} sstream_t;
+
+#define is_input_sstream(ss)	(ss->type == sstream_in)
+
+int init_input_sstream(sstream_t *ss, char *data_in, int data_len);
+int init_output_sstream(sstream_t *ss, int out_buff_resize);
+int get_serialized_sstream(sstream_t *ss, str_t *dst);
+void destroy_sstream(sstream_t *ss);
+
+int sstream_put(sstream_t *ss, const char *s, int len);
+int sstream_put_str(sstream_t *ss, str_t *s);
+int sstream_put_zt(sstream_t *ss, const char *s);
+
+int sstream_get(sstream_t *ss, char *c);
+
+/* returns a part of string of given length - it is NOT a copy !!! */
+int sstream_get_str_ex(sstream_t *ss, int len, str_t *dst);
+
+/* returns a copy of string from input buffer */
+int sstream_get_str(sstream_t *ss, int len, str_t *dst);
+
+
+int serialize_int(sstream_t *ss, int *num);
+int serialize_uint(sstream_t *ss, unsigned int *num);
+int serialize_char(sstream_t *ss, char *c);
+int serialize_uchar(sstream_t *ss, unsigned char *c);
+int serialize_str(sstream_t *ss, str_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 189 - 0
lib/cds/sstr.c

@@ -0,0 +1,189 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <cds/sstr.h>
+#include <cds/memory.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+/** returns 1 if the string is empty */
+int is_str_empty(const str_t *s)
+{
+	if (!s) return 1;
+	if ((!s->s) || (s->len < 1)) return 1;
+	return 0;
+}
+
+int str_cmp_zt(const str_t *a, const char *b)
+{
+	int i;
+	
+	if (!a) {
+		if (b) return 1;
+		else return 0;
+	}
+	
+	for (i = 0; (i < a->len) && (b[i]); i++) {
+		if (a->s[i] < b[i]) return -1;
+		if (a->s[i] > b[i]) return 1;
+	}
+	if (i < a->len) return 1;
+	return 0;
+}
+
+int str_prefix(const str_t *a, const str_t *b)
+{
+	int i;
+	if (!b) return 0;
+	if (!a) return -1;
+
+	if (b->len > a->len) return -1;
+	for (i = 0; i < b->len; i++) {
+		if (a->s[i] != b->s[i]) return -1;
+	}
+	return 0;
+}
+
+str_t zt2str(char *str)
+{
+	str_t s;
+
+	s.s = str;
+	if (str) s.len = strlen(str);
+	else s.len = 0;
+	return s;
+}
+
+int str_dup(str_t* dst, const str_t* src)
+{
+	if (!dst) return -1;
+
+	dst->len = 0;
+	dst->s = NULL;
+	if (!src) return 0;
+	if ( (!src->s) || (src->len < 1)) return 0;
+
+	dst->s = cds_malloc(src->len);
+	if (!dst->s) return -1;
+	memcpy(dst->s, src->s, src->len);
+	dst->len = src->len;
+	return 0;
+}
+
+str_t *str_dup_new(const str_t* src)
+{
+	str_t *dst = cds_malloc(sizeof(str_t));
+	if (dst) str_dup(dst, src);
+	return dst;
+}
+
+int str_dup_zt(str_t* dst, const char* src)
+{
+	int len;
+	if (!dst) return -1;
+
+	dst->len = 0;
+	dst->s = NULL;
+	if (!src) return 0;
+	len = strlen(src);
+	if (len < 1) return 0;
+
+	dst->s = cds_malloc(len);
+	if (!dst->s) return -1;
+	memcpy(dst->s, src, len);
+	dst->len = len;
+	return 0;
+}
+
+char *zt_strdup(const char* src)
+{
+	int len;
+	char *dst;
+
+	len = strlen(src);
+	if (len < 0) return NULL;
+
+	dst = cds_malloc(len + 1);
+	if (dst) memcpy(dst, src, len + 1);
+	return dst;
+}
+
+int str_nocase_equals(const str_t *a, const str_t *b)
+{
+	int i;
+	
+	if (!a) {
+		if (!b) return 0;
+		else return (b->len == 0) ? 0 : 1;
+	}
+	if (!b) return (a->len == 0) ? 0 : 1;
+	if (a->len != b->len) return 1;
+	
+	for (i = 0; i < a->len; i++) 
+		if (tolower(a->s[i]) != tolower(b->s[i])) return 1;
+	return 0;
+}
+
+int str_case_equals(const str_t *a, const str_t *b)
+{
+	int i;
+	
+	if (!a) {
+		if (!b) return 0;
+		else return (b->len == 0) ? 0 : 1;
+	}
+	if (!b) return (a->len == 0) ? 0 : 1;
+	if (a->len != b->len) return 1;
+	
+	for (i = 0; i < a->len; i++) 
+		if (a->s[i] != b->s[i]) return 1;
+	return 0;
+}
+
+void str_free_content(str_t *s)
+{
+	if (!s) return;
+	if ((s->len > 0) && (s->s)) cds_free(s->s);
+	s->len = 0;
+	s->s = NULL;
+}
+
+void str_free(str_t *s)
+{
+	if (s) {
+		str_free_content(s);
+		cds_free(s);
+	}
+}
+
+void str_clear(str_t *s)
+{
+	if (s) {
+		s->s = NULL;
+		s->len = 0;
+	}
+}
+

+ 93 - 0
lib/cds/sstr.h

@@ -0,0 +1,93 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SIMPLE_STR_H
+#define __SIMPLE_STR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* If compiled for SER, use ser internal strings ! */
+#ifdef SER
+
+#include "str.h"	
+typedef str str_t;
+
+#else
+
+typedef struct {
+	char *s;
+	int len;
+} str_t;
+
+#endif
+
+#define FMT_STR(str)	(str).len,((str).s ? (str).s : "")	
+
+/** transalate zero-terminated string to str_t (both uses the input buffer!)*/
+str_t zt2str(char *str);
+
+/** returns 1 if the string is empty */
+int is_str_empty(const str_t *s);
+
+/** duplicate string into given destination */
+int str_dup(str_t* dst, const str_t* src);
+
+/** duplicate string into newly allocated destination */
+str_t *str_dup_new(const str_t* src);
+
+/** duplicate zero-terminated string */
+int str_dup_zt(str_t* dst, const char* src);
+
+/** duplicate zero-terminated string to zero-terminated string */
+char *zt_strdup(const char*src);
+
+/** frees string content if allocated */
+void str_free_content(str_t *s);
+
+/** frees string content if allocated and then the string itself */
+void str_free(str_t *s);
+
+/** case sensitive comparation - returns 0 if equal, nonzero otherwise */
+int str_case_equals(const str_t *a, const str_t *b);
+/** case insensitive comparation - returns 0 if equal, nonzero otherwise */
+int str_nocase_equals(const str_t *a, const str_t *b);
+
+/** compare str_t and zero terminated string */
+int str_cmp_zt(const str_t *a, const char *b); /* renamed sz_cmp */
+
+/** is b prefix of a */
+int str_prefix(const str_t *a, const str_t *b); /* ss_start */
+
+/* #define ss_cmp(const str_t *a, const str_t *b) ((a->len == b->len)?sz_cmp(a, b->s):(-1)) */
+
+void str_clear(str_t *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 46 - 0
lib/cds/sync.h

@@ -0,0 +1,46 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CDS_SYNC_H
+#define __CDS_SYNC_H
+
+#ifdef SER
+#	include <locking.h>
+#	define cds_mutex_t			gen_lock_t
+#	define cds_mutex_init(m)	lock_init(m)
+#	define cds_mutex_destroy(m)	lock_destroy(m)
+#	define cds_mutex_lock(m)	lock_get(m)
+#	define cds_mutex_unlock(m)	lock_release(m)
+#else
+#	include <pthread.h>
+#	include <stdlib.h>
+#	define cds_mutex_t				pthread_mutex_t
+#	define cds_mutex_init(m)		pthread_mutex_init(m, NULL)
+#	define cds_mutex_destroy(m)		pthread_mutex_destroy(m)
+#	define cds_mutex_lock(m)		pthread_mutex_lock(m)
+#	define cds_mutex_unlock(m)		pthread_mutex_unlock(m)
+#endif
+
+#endif

+ 119 - 0
lib/cds/vector.c

@@ -0,0 +1,119 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <cds/memory.h>
+#include <cds/vector.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int vector_add(vector_t *vector, void *element)
+{
+	if (vector->element_count >= vector->allocated_count) {
+		void *new_data;
+		int new_size = vector->allocated_count + vector->allocation_count;
+		if (new_size <= vector->allocated_count) return -1;
+	
+		new_data = (void *)cds_malloc(vector->element_size * new_size);
+		if (!new_data) return -1;
+		if (vector->data) {
+			memcpy(new_data, vector->data, 
+					vector->element_size * vector->allocated_count);
+			cds_free(vector->data);
+		}
+		vector->data = new_data;
+		vector->allocated_count = new_size;
+	}
+	memcpy(vector->data + (vector->element_count * vector->element_size), 
+			element, vector->element_size);
+	vector->element_count++;
+	
+	return 0;
+}
+
+int vector_remove(vector_t *vector, int index)
+{
+	int cnt;
+	if (index >= vector->element_count) return -1;
+	
+	cnt = vector->element_count - index - 1;
+	if (cnt > 0) {
+		memmove(vector->data + (index * vector->element_size), 
+			vector->data + ((index + 1) * vector->element_size),
+			cnt *  vector->element_size);
+	}
+	vector->element_count--;
+	
+	return 0;
+}
+
+int vector_get(vector_t *vector, int index, void *element_dst)
+{
+	if (index >= vector->element_count) return -1;
+	
+	memcpy(element_dst, vector->data + (index * vector->element_size), vector->element_size);
+
+	return 0;
+}
+
+void* vector_get_ptr(vector_t *vector, int index)
+{
+	if (index >= vector->element_count) return NULL;
+	else return vector->data + (index * vector->element_size);
+}
+
+void vector_destroy(vector_t *vector)
+{
+	if (vector) {
+		if (vector->data) cds_free(vector->data);
+		vector->data = NULL;
+		vector->allocation_count = 0;
+		vector->element_count = 0;
+	}
+}
+
+int vector_init(vector_t *vector, int element_size, int allocation_count)
+{
+	if (!vector) return -1;
+	vector->element_size = element_size;
+	vector->element_count = 0;
+	vector->allocation_count = allocation_count;
+	vector->data = (void *)cds_malloc(element_size * allocation_count);
+	if (!vector->data) {
+		vector->allocated_count = 0;
+		return -1;
+	}
+	else {
+		vector->allocated_count = allocation_count;
+		return 0;
+	}
+}
+
+int vector_test(void)
+{
+	/*TODO: do tests for vector_t - all "methods" must be called */
+	return 0;
+}

+ 63 - 0
lib/cds/vector.h

@@ -0,0 +1,63 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __VECTOR_H
+#define __VECTOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Structure representing dynamic array of elements of
+ * equal size. */
+typedef struct {
+	int element_size;
+	/** the number of used elements */
+	int element_count;
+	/** the number of allocated elements */
+	int allocated_count;
+	/** number of elements allocated together (better than allocation 
+	 * for each element separately) */
+	int allocation_count;
+	void *data;
+} vector_t;
+
+int vector_add(vector_t *vector, void *element);
+int vector_get(vector_t *vector, int index, void *element_dst);
+void* vector_get_ptr(vector_t *vector, int index);
+int vector_remove(vector_t *vector, int index);
+void vector_destroy(vector_t *vector);
+int vector_init(vector_t *vector, int element_size, int allocation_count);
+
+/** testing function - returns 0 if no errors */
+int vector_test(void);
+
+#define vector_size(v) (v)->element_count
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 12 - 0
lib/presence/Makefile

@@ -0,0 +1,12 @@
+DEFS     += 
+INCLUDES +=
+LIBS     += -lcds
+
+# name of result executable or library
+NAME = presence
+
+# TYPE=lib => shared or static library, executable otherwise
+TYPE = lib
+
+include ../Makefile.defs
+

+ 6 - 0
lib/presence/Makefile.ser

@@ -0,0 +1,6 @@
+LIBNAME  = presence
+OUT_NAME = libpresence.so
+OUT_TYPE = lib
+
+include ../Makefile.ser.defs
+

+ 37 - 0
lib/presence/client_notify_info.c

@@ -0,0 +1,37 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <presence/client_notify_info.h>
+
+#include <cds/memory.h>
+#include <cds/sstr.h>
+
+void free_client_notify_info_content(client_notify_info_t *info)
+{
+	str_free_content(&info->package);
+	str_free_content(&info->record_id);
+	str_free_content(&info->notifier);
+}
+

+ 46 - 0
lib/presence/client_notify_info.h

@@ -0,0 +1,46 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __CLIENT_NOTIFY_INFO_H
+#define __CLIENT_NOTIFY_INFO_H
+
+/** This structure is sent via message queue
+ * to client. It must contain all information
+ * for processing the status info. */
+
+#include <cds/sstr.h>
+
+typedef struct {
+	str_t package;
+	str_t record_id;
+	str_t notifier;
+	void *data;
+	int data_len;
+} client_notify_info_t;
+
+
+void free_client_notify_info_content(client_notify_info_t *info);
+
+#endif

+ 114 - 0
lib/presence/domain_maintainer.c

@@ -0,0 +1,114 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <presence/domain_maintainer.h>
+#include <cds/ptr_vector.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+
+domain_maintainer_t *create_domain_maintainer()
+{
+	domain_maintainer_t *dm;
+
+	dm = (domain_maintainer_t*)cds_malloc(sizeof(domain_maintainer_t));
+	if (dm) {
+		ptr_vector_init(&dm->registered_domains, 8);
+		cds_mutex_init(&dm->mutex);
+	}
+	return dm;
+}
+
+void destroy_domain_maintainer(domain_maintainer_t *dm) 
+{
+	int i, cnt;
+	notifier_domain_t *d;
+	
+	if (!dm) return;
+
+	cnt = ptr_vector_size(&dm->registered_domains);
+	for (i = 0; i < cnt; i++) {
+		d = ptr_vector_get(&dm->registered_domains, i);
+		if (!d) continue;
+		destroy_notifier_domain(d);
+	}
+	ptr_vector_destroy(&dm->registered_domains);
+	cds_mutex_destroy(&dm->mutex);
+	cds_free(dm);
+}
+
+static notifier_domain_t *find_domain_nolock(domain_maintainer_t *dm, const str_t *name)
+{
+	notifier_domain_t *d = NULL;
+	int i, cnt;
+	
+	cnt = ptr_vector_size(&dm->registered_domains);
+	for (i = 0; i < cnt; i++) {
+		d = ptr_vector_get(&dm->registered_domains, i);
+		if (!d) continue;
+		if (str_case_equals(&d->name, name) == 0) return d;
+	}
+	return NULL;
+}
+
+static notifier_domain_t *add_domain_nolock(domain_maintainer_t *dm, const str_t *name)
+{
+	notifier_domain_t *d = create_notifier_domain(name);
+	
+	if (d) {
+		ptr_vector_add(&dm->registered_domains, d);
+		return d;
+	}
+	else return NULL;
+}
+
+notifier_domain_t *find_notifier_domain(domain_maintainer_t *dm, const str_t *name)
+{
+	notifier_domain_t *d = NULL;
+	
+	if (!dm) return NULL;
+	cds_mutex_lock(&dm->mutex);
+	d = find_domain_nolock(dm, name);
+	cds_mutex_unlock(&dm->mutex);
+	return d;
+}
+
+notifier_domain_t *register_notifier_domain(domain_maintainer_t *dm, const str_t *name)
+{
+	notifier_domain_t *d = NULL;
+	
+	if (!dm) return NULL;
+	
+	cds_mutex_lock(&dm->mutex);
+	d = find_domain_nolock(dm, name);
+	if (!d) d = add_domain_nolock(dm, name);
+	cds_mutex_unlock(&dm->mutex);
+	return d;
+}
+
+void release_notifier_domain(domain_maintainer_t *dm, notifier_domain_t *domain)
+{
+	/* TODO: decrement "domain counter", if 0 => destroy domain */
+}
+

+ 53 - 0
lib/presence/domain_maintainer.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __DOMAIN_MAINTAINER_H
+#define __DOMAIN_MAINTAINER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <presence/notifier_domain.h>
+#include <cds/ptr_vector.h>
+#include <cds/sync.h>
+
+typedef struct {
+	ptr_vector_t registered_domains;
+	cds_mutex_t mutex;
+} domain_maintainer_t;
+
+	
+domain_maintainer_t *create_domain_maintainer();
+void destroy_domain_maintainer(domain_maintainer_t *dm);
+
+notifier_domain_t *register_notifier_domain(domain_maintainer_t *dm, const str_t *name);
+void release_notifier_domain(domain_maintainer_t *dm, notifier_domain_t *domain);
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 51 - 0
lib/presence/notifier.h

@@ -0,0 +1,51 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __NOTIFIER_H
+#define __NOTIFIER_H
+
+/* Notifier functions for notifier_domain */
+
+#include <presence/notifier_domain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Returns the created notifier. Indicates error if NULL. */
+notifier_t *register_notifier(
+	notifier_domain_t *domain,
+	const str_t *package,
+	server_subscribe_func subscribe,
+	server_unsubscribe_func unsubscribe,
+	void *user_data);
+
+void unregister_notifier(notifier_domain_t *domain, notifier_t *info);
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 352 - 0
lib/presence/notifier_domain.c

@@ -0,0 +1,352 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/sync.h>
+#include <stdio.h>
+#include <presence/notifier_domain.h>
+#include <presence/notifier.h>
+#include <presence/subscriber.h>
+#include <cds/list.h>
+
+static void free_notifier(notifier_t *info);
+static void free_subscription(subscription_t *s);
+
+/* -------- package functions -------- */
+
+static notifier_package_t *find_package(notifier_domain_t *d, const str_t *name)
+{
+	notifier_package_t *p;
+
+	if (!d) return NULL;
+	p = d->first_package;
+	while (p) {
+		if (str_case_equals(name, &p->name) == 0) return p;
+		p = p->next;
+	}
+	return NULL;
+}
+
+static void add_package(notifier_domain_t *d, notifier_package_t *p)
+{
+	p->domain = d;
+	DOUBLE_LINKED_LIST_ADD(d->first_package, d->last_package, p);
+}
+
+static notifier_package_t *create_package(const str_t *name)
+{
+	notifier_package_t *p = (notifier_package_t*)cds_malloc(sizeof(notifier_package_t));
+	if (p) {
+		p->first_subscription = NULL;
+		p->last_subscription = NULL;
+		p->first_notifier = NULL;
+		p->last_notifier = NULL;
+		p->next = NULL;
+		p->prev = NULL;
+		p->domain = NULL;
+		str_dup(&p->name, name);
+	}
+	return p;
+}
+
+/** finds existing package or adds new if not exists */
+static notifier_package_t *get_package(notifier_domain_t *d, const str_t *name)
+{
+	notifier_package_t *p = NULL;
+	
+	if (is_str_empty(name)) return NULL;
+	
+	p = find_package(d, name);
+	if (!p) {
+		p = create_package(name);
+		if (p) add_package(d, p);
+	}
+	return p;
+}
+	
+static void destroy_package(notifier_package_t *p) 
+{
+	notifier_t *e, *n;
+	subscription_t *s, *ns;
+	
+	/* release all subscriptions  */
+	s = p->first_subscription;
+	while (s) {
+		ns = s->next;
+		/* unsubscribe(p->domain, s) */
+		/* release_subscription(s); */
+		free_subscription(s);
+		s = ns;
+	}
+	
+	/* release all registered notifiers */
+	e = p->first_notifier;
+	while (e) {
+		n = e->next;
+		free_notifier(e);
+		/* maybe: call some notifier callback ? */
+		e = n;
+	}
+	p->first_notifier = NULL;
+	p->last_notifier = NULL;
+	str_free_content(&p->name);
+
+	cds_free(p);
+}
+
+/* -------- Helper functions -------- */
+
+static void free_notifier(notifier_t *info)
+{
+	cds_free(info);
+}
+
+static void free_subscription(subscription_t *s)
+{
+	str_free_content(&s->record_id);
+	str_free_content(&s->subscriber_id);
+	cds_free(s);
+}
+
+/*static void add_server_subscription(notifier_t *n, subscription_t *s)
+{
+	server_subscription_t server_s;
+	
+	server_s.notifier_data = NULL;
+	if (n->subscribe(n, &s->record_id, s, &server_s.notifier_data) == 0) {
+		server_s.notifier = n;
+		vector_add(&s->server_subscriptions, &server_s);
+	}
+	else ERROR_LOG("subscription not accepted by notifier %p\n", n);
+}
+			
+static void remove_notifier_from_subscription(subscription_t *s, notifier_t *n)
+{
+	int cnt,i;
+
+	cnt = vector_size(&s->server_subscriptions);
+	for (i = 0; i < cnt; i++) {
+		ss = vector_get_ptr(&s->server_subscriptions, i);
+		if (!ss) continue;
+		/ * FIXME: call n->unsubsribe ??? 
+		 * NO this is called from unregister which is initiated
+		 * by the notifier (may be synchronized there!) * /
+		if (ss->notifier == n) ss->notifier = NULL; / * "zombie" * /
+	}
+}
+*/
+
+/* -------- Domain initialization/destruction functions -------- */
+
+/** Creates a new domain using cds memory functions. */
+notifier_domain_t *create_notifier_domain(const str_t *name)
+{
+	notifier_domain_t *d = (notifier_domain_t*)cds_malloc(sizeof(notifier_domain_t));
+	if (d) {
+		d->first_package = NULL;
+		d->last_package = NULL;
+		str_dup(&d->name, name);
+		cds_mutex_init(&d->mutex);
+	}
+	return d;
+}
+
+/** Destroys domain and whole information stored in internal
+ * structures. If there are any subscribers, they are unsubscribed,
+ * if there are any notifiers, they are unregistered. */
+void destroy_notifier_domain(notifier_domain_t *domain)
+{
+	notifier_package_t *p, *n;
+	
+	lock_notifier_domain(domain);
+	
+	/* remove packages */
+	p = domain->first_package;
+	while (p) {
+		n = p->next;
+		destroy_package(p);
+		p = n;
+	}
+	domain->first_package = NULL;
+	domain->last_package = NULL;
+	
+	unlock_notifier_domain(domain);
+	
+	str_free_content(&domain->name);
+	cds_mutex_destroy(&domain->mutex);
+	cds_free(domain);
+}
+
+/* -------- Notifier functions -------- */
+
+/* Returns the id of created notifier. Indicates error if less than 0 */
+notifier_t *register_notifier(
+	notifier_domain_t *domain,
+	const str_t *package,
+	server_subscribe_func subscribe,
+	server_unsubscribe_func unsubscribe,
+	void *user_data)
+{
+	notifier_t *info;
+	notifier_package_t *p;
+	subscription_t *s;
+
+	lock_notifier_domain(domain);
+	p = get_package(domain, package);
+	if (!p) {
+		unlock_notifier_domain(domain);
+		return NULL;
+	}
+		
+	info = cds_malloc(sizeof(notifier_t));
+	if (!info) return info;
+
+	info->subscribe = subscribe;
+	info->unsubscribe = unsubscribe;
+	info->user_data = user_data;
+	info->package = p;
+	DEBUG_LOG("registered notifier for %.*s\n", FMT_STR(*package));
+
+	DOUBLE_LINKED_LIST_ADD(p->first_notifier, p->last_notifier, info);
+	
+	/* go through all subscriptions for package and 
+	 * add them to this notifier */
+	s = p->first_subscription;
+	while (s) {
+		info->subscribe(info, s);
+		s = s->next;
+	}
+	
+	unlock_notifier_domain(domain);
+	
+	return info;
+}
+
+void unregister_notifier(notifier_domain_t *domain, notifier_t *info)
+{
+	notifier_package_t *p;
+
+	/* maybe: test if the NOTIFIER is registered before unregistration */
+
+	lock_notifier_domain(domain);
+	
+	p = info->package;
+	if (p) {
+		/* subscription_t *s;
+		s = p->first_subscription;
+		while (s) {
+			info->unsubscribe(info, s);
+			s = s->next;
+		}*/
+
+		DOUBLE_LINKED_LIST_REMOVE(p->first_notifier, p->last_notifier, info);
+		/* DEBUG_LOG("UNregistered notifier for %.*s\n", FMT_STR(p->name)); */
+		free_notifier(info);
+	}
+	unlock_notifier_domain(domain);
+}
+
+/* -------- Subscriber functions -------- */
+
+/* If a notifier publishing watched state registeres after subscibe
+ * call, it receives the subscription automaticaly too! */
+subscription_t *subscribe(notifier_domain_t *domain, 
+		str_t *package,
+		str_t *record_id,
+		str_t *subscriber_id,
+		msg_queue_t *dst,
+		void *subscriber_data)
+{
+	subscription_t *s;
+	notifier_t *e;
+	notifier_package_t *p;
+	int cnt = 0;
+
+	lock_notifier_domain(domain);
+	p = get_package(domain, package);
+	if (!p) {
+		ERROR_LOG("can't find package for subscription\n");
+		unlock_notifier_domain(domain);
+		return NULL;
+	}
+	
+	s = cds_malloc(sizeof(subscription_t));
+	if (!s) {
+		ERROR_LOG("can't allocate memory\n");
+		return s;
+	}
+
+	s->package = p;
+	s->dst = dst;
+	s->subscriber_data = subscriber_data;
+	str_dup(&s->record_id, record_id);
+	str_dup(&s->subscriber_id, subscriber_id);
+
+	DOUBLE_LINKED_LIST_ADD(p->first_subscription, p->last_subscription, s);
+
+	/* browse all notifiers in given package and subscribe to them
+	 * and add them to notifiers list */
+	cnt = 0;
+	e = p->first_notifier;
+	while (e) {
+		cnt++;
+		e->subscribe(e, s);
+		e = e->next;
+	}
+	unlock_notifier_domain(domain);
+	DEBUG_LOG("subscribed to %d notifier(s)\n", cnt);
+	
+	return s;
+}
+
+/** Destroys an existing subscription */
+void unsubscribe(notifier_domain_t *domain, subscription_t *s)
+{
+	notifier_package_t *p;
+	notifier_t *e;
+
+	lock_notifier_domain(domain);
+	
+	/* maybe: test if the SUBSCRIBER is subscribed before unsubsc. */
+	p = s->package;
+	if (!p) {
+		unlock_notifier_domain(domain);
+		return;
+	}
+
+	DOUBLE_LINKED_LIST_REMOVE(p->first_subscription, p->last_subscription, s);
+	
+	e = p->first_notifier;
+	while (e) {
+		e->unsubscribe(e, s);
+		e = e->next;
+	}
+	
+	unlock_notifier_domain(domain);
+	
+	free_subscription(s);
+}
+

+ 110 - 0
lib/presence/notifier_domain.h

@@ -0,0 +1,110 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __NOTIFIER_DOMAIN_H
+#define __NOTIFIER_DOMAIN_H
+
+#include <cds/sstr.h>
+#include <cds/ptr_vector.h>
+#include <cds/sync.h>
+#include <cds/msg_queue.h>
+
+#include <presence/client_notify_info.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _subscription_t;
+typedef struct _subscription_t subscription_t;
+struct _notifier_package_t;
+typedef struct _notifier_package_t notifier_package_t;
+struct _notifier_t;
+typedef struct _notifier_t notifier_t;
+struct _notifier_domain_t;
+typedef struct _notifier_domain_t notifier_domain_t;
+
+/* typedef void (*client_notify_func)(client_notify_info_t *info); */
+
+/** Internal structure holding informations about
+ * created client subscriptions.
+ */
+struct _subscription_t {
+	/* client_notify_func notify; */
+	msg_queue_t *dst;
+	str_t record_id;
+	str_t subscriber_id;
+	notifier_package_t *package;
+	void *subscriber_data;
+	struct _subscription_t *prev, *next;
+};
+
+typedef int (*server_subscribe_func)(notifier_t *n, subscription_t *subscription);
+
+typedef void (*server_unsubscribe_func)(notifier_t *n, subscription_t *subscription);
+
+/** Internal structure storing registered notifiers. */
+struct _notifier_t {
+	server_subscribe_func subscribe;
+	server_unsubscribe_func unsubscribe;
+	void *user_data; /* private data for this notifier */
+	notifier_package_t *package;
+	struct _notifier_t *prev, *next; 
+};
+
+struct _notifier_package_t {
+	str_t name;
+	/* maybe: serialize and deserialize methods */
+	notifier_domain_t *domain;
+	notifier_t *first_notifier, *last_notifier; /* notifiers are linked in theirs package! */
+	subscription_t *first_subscription, *last_subscription;
+	notifier_package_t *next, *prev;
+};
+
+struct _notifier_domain_t {
+	cds_mutex_t mutex;
+	str_t name;
+	notifier_package_t *first_package, *last_package;
+};
+
+/* -------- Domain initialization/destruction functions -------- */
+
+/** Creates a new domain using cds memory functions. */
+notifier_domain_t *create_notifier_domain(const str_t *name);
+
+/** Destroys domain and whole information stored in internal
+ * structures. If there are any subscribers, they are unsubscribed,
+ * if there are any notifiers, they are unregistered. */
+void destroy_notifier_domain(notifier_domain_t *domain);
+
+#define lock_notifier_domain(d) cds_mutex_lock(&(d->mutex))
+#define unlock_notifier_domain(d) cds_mutex_unlock(&(d->mutex))
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 97 - 0
lib/presence/pidf.c

@@ -0,0 +1,97 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <presence/pidf.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+
+static void doc_add_tuple(dstring_t *buf, presentity_info_t *p, presence_tuple_info_t *t)
+{
+	DEBUG_LOG("doc_add_tuple()\n");
+	
+	dstr_append_zt(buf, "\t<tuple id=\"");
+	dstr_append_str(buf, &t->contact);
+	dstr_append_zt(buf, "\">\n");
+	
+	if (t->status == presence_tuple_open) dstr_append_zt(buf, "\t\t<status><basic>open</basic></status>\n");
+	else dstr_append_zt(buf, "\t\t<status><basic>closed</basic></status>\n");
+	
+	dstr_append_zt(buf, "\t\t<contact>");
+	dstr_append_str(buf, &t->contact);
+	dstr_append_zt(buf, "</contact>\n");
+
+	dstr_append_zt(buf, "\t</tuple>\n");
+}
+
+static void doc_add_presentity(dstring_t *buf, presentity_info_t *p)
+{
+	presence_tuple_info_t *t;
+
+	DEBUG_LOG("doc_add_presentity()\n");
+	dstr_append_zt(buf, "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\" entity=\"sip:");
+	dstr_append_str(buf, &p->presentity);
+	dstr_append_zt(buf, "\">\n");
+	
+	DEBUG_LOG("doc_add_presentity(): adding tuples\n");
+	t = p->first_tuple;
+	while (t) {
+		doc_add_tuple(buf, p, t);
+		t = t->next;
+	}
+	dstr_append_zt(buf, "</presence>");
+}
+
+		
+int create_pidf_document(presentity_info_t *p, str_t *dst, str_t *dst_content_type)
+{
+	dstring_t buf;
+	
+	if (!dst) return -1;
+	
+	str_clear(dst);
+	if (dst_content_type) str_clear(dst_content_type);
+
+	if (!p) return -1;
+	
+	if (dst_content_type) 
+		str_dup_zt(dst_content_type, "application/pidf+xml;charset=\"UTF-8\"");
+
+	if (!p->first_tuple) return 0;	/* no tuples => nothing to say */ 
+	
+	dstr_init(&buf, 2048);
+	
+	dstr_append_zt(&buf, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+	doc_add_presentity(&buf, p);
+	
+	dst->len = dstr_get_data_length(&buf);
+	dst->s = cds_malloc(dst->len);
+	if (!dst->s) dst->len = 0;
+	else dstr_get_data(&buf, dst->s);
+	dstr_destroy(&buf);
+	
+	return 0;
+}
+

+ 34 - 0
lib/presence/pidf.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PRESENCE_PIDF_H
+#define __PRESENCE_PIDF_H
+
+#include <cds/sstr.h>
+#include <presence/pres_doc.h>
+
+int create_pidf_document(presentity_info_t *p, str_t *dst, str_t *dst_content_type);
+
+#endif

+ 100 - 0
lib/presence/pres_doc.c

@@ -0,0 +1,100 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <presence/pres_doc.h>
+#include <cds/memory.h>
+#include <cds/logger.h>
+#include <cds/list.h>
+
+#include <string.h>
+
+presentity_info_t *create_presentity_info(const str_t *presentity)
+{
+	presentity_info_t *p;
+	int len = 0;
+	
+	if (!is_str_empty(presentity)) len = presentity->len;
+	p = (presentity_info_t*)cds_malloc(sizeof(presentity_info_t) + len);
+	if (!p) {
+		ERROR_LOG("can't allocate memory for presentity info\n");
+		return p;
+	}
+	p->presentity.len = len;
+	if (len > 0) {
+		p->presentity.s = p->presentity_data;
+		memcpy(p->presentity.s, presentity->s, len);
+	}
+	else p->presentity.s = NULL;
+	p->first_tuple = NULL;
+	p->last_tuple = NULL;
+	
+	return p;
+}
+
+presence_tuple_info_t *create_tuple_info(const str_t *contact, presence_tuple_status_t status)
+{
+	presence_tuple_info_t *t;
+	t = (presence_tuple_info_t*)cds_malloc(sizeof(*t));
+	if (!t) {
+		ERROR_LOG("can't allocate memory for presence tuple info\n");
+		return t;
+	}
+	/* str_clear(&t->contact.s); */
+	str_dup(&t->contact, contact);
+	str_clear(&t->extra_status);
+	t->prev = NULL;
+	t->next = NULL;
+	t->status = status;
+	t->priority = 0.0;
+	t->expires = 0;
+	return t;
+}
+
+void add_tuple_info(presentity_info_t *p, presence_tuple_info_t *t)
+{
+	DOUBLE_LINKED_LIST_ADD(p->first_tuple, p->last_tuple, t);
+}
+
+void free_tuple_info(presence_tuple_info_t *t)
+{
+	if (!t) return;
+	str_free_content(&t->contact);
+	str_free_content(&t->extra_status);
+	cds_free(t);
+}
+
+void free_presentity_info(presentity_info_t *p)
+{
+	presence_tuple_info_t *t;
+	
+	if (!p) return;
+	t = p->first_tuple;
+	while (t) {
+		free_tuple_info(t);
+		t = t->next;
+	}
+	cds_free(p);
+}
+

+ 66 - 0
lib/presence/pres_doc.h

@@ -0,0 +1,66 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PRESENCE_INFO_H
+#define __PRESENCE_INFO_H
+
+#include <cds/sstr.h>
+#include <time.h>
+
+typedef enum {
+	presence_tuple_open,
+	presence_tuple_closed
+} presence_tuple_status_t;
+
+typedef enum {
+	presence_auth_rejected,
+	presence_auth_polite_block,
+	presence_auth_unresolved,
+	presence_auth_granted
+} presence_authorization_status_t;
+
+typedef struct _presence_typle_info_t {
+	str_t contact;
+	double priority;
+	time_t expires;
+	presence_tuple_status_t status;
+	str_t extra_status;
+	struct _presence_typle_info_t *next, *prev;
+} presence_tuple_info_t;
+
+typedef struct {
+	str_t presentity; /* do not modify this !*/
+	presence_tuple_info_t *first_tuple, *last_tuple;
+	presence_authorization_status_t auth;
+	char presentity_data[1];
+} presentity_info_t;
+
+presentity_info_t *create_presentity_info(const str_t *presentity);
+presence_tuple_info_t *create_tuple_info(const str_t *contact, presence_tuple_status_t status);
+void add_tuple_info(presentity_info_t *p, presence_tuple_info_t *t);
+void free_presentity_info(presentity_info_t *p);
+
+
+#endif

+ 76 - 0
lib/presence/qsa.c

@@ -0,0 +1,76 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <presence/qsa.h>
+#include <cds/logger.h>
+#include <presence/domain_maintainer.h>
+
+static domain_maintainer_t *dm = NULL;
+static int initialized = 0;
+
+int qsa_initialize()
+{
+	if (!initialized) {
+		dm = create_domain_maintainer();
+		if (dm) initialized = 1;
+		else {
+			ERROR_LOG("qsa_initialize error - can't initialize domain maintainer\n");
+			return -1;
+		}
+		DEBUG_LOG("QSA initialized\n");
+	}
+	return 0;
+}
+
+void qsa_cleanup() 
+{
+	if (initialized && dm) {
+		destroy_domain_maintainer(dm);
+		dm = NULL;
+		initialized = 0;
+	}
+}
+
+notifier_domain_t *qsa_register_domain(const str_t *name)
+{
+	notifier_domain_t *d = NULL;
+
+	if (!dm) {
+		ERROR_LOG("qsa_initialize was not called - can't register domain\n");
+		return NULL;
+	}
+	d = register_notifier_domain(dm, name);
+	return d;
+}
+
+notifier_domain_t *qsa_get_default_domain()
+{
+	return qsa_register_domain(NULL);
+}
+
+void qsa_release_domain(notifier_domain_t *domain)
+{
+	if (dm) release_notifier_domain(dm, domain);
+}

+ 46 - 0
lib/presence/qsa.h

@@ -0,0 +1,46 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __QSA_H
+#define __QSA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <presence/notifier_domain.h>
+	
+int qsa_initialize();
+void qsa_cleanup();
+
+notifier_domain_t *qsa_register_domain(const str_t *name);
+notifier_domain_t *qsa_get_default_domain();
+void qsa_release_domain(notifier_domain_t *domain);
+
+#ifdef __cplusplus
+}
+#endif
+	
+#endif

+ 58 - 0
lib/presence/subscriber.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SUBSCRIBER_H
+#define __SUBSCRIBER_H
+
+/* Subscriber functions for notifier_domain */
+
+#include <presence/notifier_domain.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* If a notifier publishing watched state registeres after subscibe
+ * call, it receives the subscription automaticaly too! */
+/*subscription_t *subscribe(notifier_domain_t *domain, 
+		subscription_t *params);*/
+subscription_t *subscribe(notifier_domain_t *domain, 
+		str_t *package,
+		str_t *record_id,
+		str_t *subscriber_id,
+		msg_queue_t *dst,
+		void *subscriber_data);
+
+/** Destroys an existing subscription */
+void unsubscribe(notifier_domain_t *domain, subscription_t *s);
+
+void set_subscriber_data(subscription_t *s, void *data);
+void *get_subscriber_data(subscription_t *s);
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 42 - 0
lib/presence/subscription_info.h

@@ -0,0 +1,42 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __SUBSCRIPTION_INFO
+#define __SUBSCRIPTION_INFO
+
+#include <presence/notifier_domain.h>
+
+typedef struct _subscription_info_t {
+
+	client_notify_func notify;
+	str_t record_id;
+	str_t package;	
+	subscription_t *subscription;
+	
+	struct _subscription_info_t *prev, *next;
+} subscription_info_t;
+
+#endif
+

+ 12 - 0
lib/xcap/Makefile

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

+ 8 - 0
lib/xcap/Makefile.ser

@@ -0,0 +1,8 @@
+LIBNAME  = xcap
+OUT_NAME = libxcap.so
+OUT_TYPE = lib
+INCLUDES += -I/usr/include/libxml2
+LIBS     += -lxml2 -lcurl
+
+include ../Makefile.ser.defs
+

+ 107 - 0
lib/xcap/common_policy.h

@@ -0,0 +1,107 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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;
+
+#endif

+ 386 - 0
lib/xcap/parse_pres_rules.c

@@ -0,0 +1,386 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 *common_policy_ns = NULL;
+char *pres_rules_ns = NULL;
+
+static 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;
+}
+
+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_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", common_policy_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;
+}
+
+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;
+	(*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;
+	
+	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;
+	(*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;
+	(*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;
+	(*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;
+	(*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;
+	
+	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) {
+				/* FIXME: free existing validity */
+				res = read_validity(n, &(*dst)->validity);
+				if (res != 0) break;
+			}
+			else {
+				if (cmp_node(n, "identity", common_policy_ns) >= 0) {
+					/* FIXME: free existing identity */
+					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));
+
+	WARN_LOG("transformations for pres_rules not used\n");
+
+	return res;
+}
+
+static int read_rule(xmlNode *rn, cp_rule_t **dst)
+{
+	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 = read_actions(n, &(*dst)->actions);
+		if (res != 0) return res;
+	}
+	
+	n = find_node(rn, "conditions", common_policy_ns);
+	if (n) {
+		res = read_conditions(n, &(*dst)->conditions);
+		if (res != 0) return res;
+	}
+	
+	n = find_node(rn, "transformations", common_policy_ns);
+	if (n) {
+		res = read_transformations(n, &(*dst)->transformations);
+		if (res != 0) return res;
+	}
+
+	return res;
+}
+
+static int read_pres_rules(xmlNode *root, cp_ruleset_t **dst)
+{
+	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);
+				if (res == 0) {
+					if (r) LINKED_LIST_ADD(rs->rules, last, r);
+				}
+				else break;
+			}
+		}
+		n = n->next;
+	}
+
+	return res;
+}
+
+int parse_pres_rules(const char *data, int dsize, cp_ruleset_t **dst)
+{
+	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_pres_rules(xmlDocGetRootElement(doc), dst);
+	if ((res != RES_OK) && (dst)) {
+		/* may be set => must be freed */
+		free_pres_rules(*dst);
+		*dst = NULL;
+	}
+
+	xmlFreeDoc(doc);
+	return res;
+}
+

+ 33 - 0
lib/xcap/parse_pres_rules.h

@@ -0,0 +1,33 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PARSE_PRES_RULES_H
+#define __PARSE_PRES_RULES_H
+
+#include <xcap/pres_rules.h>
+
+int parse_pres_rules(const char *data, int dsize, cp_ruleset_t **dst);
+
+#endif

+ 339 - 0
lib/xcap/pres_rules.c

@@ -0,0 +1,339 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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>
+
+char *xcap_uri_for_pres_rules(const char *xcap_root, const str_t *uri)
+{
+	dstring_t s;
+	int l;
+	char *dst = NULL;
+
+	if (!xcap_root) return NULL;
+	l = strlen(xcap_root);
+	dstr_init(&s, 2 * l + 32);
+	dstr_append(&s, xcap_root, l);
+	if (xcap_root[l - 1] != '/') dstr_append(&s, "/", 1);
+	dstr_append_zt(&s, "pres-rules/users/");
+	dstr_append_str(&s, uri);
+	dstr_append_zt(&s, "/presence-rules.xml");
+	
+	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;
+}
+
+int get_pres_rules(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, cp_ruleset_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	xcap_query_t xcap;
+	int res = RES_OK;
+	
+	if (xcap_params) {
+		xcap = *xcap_params;
+	}
+	else memset(&xcap, 0, sizeof(xcap));
+	
+	xcap.uri = xcap_uri_for_pres_rules(xcap_root, uri);
+	res = xcap_query(&xcap, &data, &dsize);
+	if (res != RES_OK) {
+		ERROR_LOG("get_pres_rules(): XCAP problems for uri \'%s\'\n", xcap.uri ? xcap.uri: "???");
+		if (data) cds_free(data);
+		return RES_XCAP_QUERY_ERR;
+	}
+	if (xcap.uri) cds_free(xcap.uri);
+	
+	/* parse input data */
+	res = parse_pres_rules(data, dsize, dst);
+	if (res != RES_OK) {
+		ERROR_LOG("Error occured during document parsing!\n");
+	}
+
+	if (data) cds_free(data);
+	return res;
+}
+
+static void parse_uri(const str_t *uri, str_t *user, str_t *domain)
+{
+	char *a;
+	char *d;
+	char *s;
+	
+	str_clear(user);
+	str_clear(domain);
+	if (uri->len > 0) {
+		d = strchr(uri->s, ':');
+		if (d) s = d + 1;
+		else s = uri->s;
+		a = strchr(s, '@');
+		if (a) {
+			user->s = s;
+			user->len = a - s;
+		}
+		domain->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; /* FIXME: ??? */
+	id = rule->conditions->identity;
+	if (!id) return 0;
+	
+	parse_uri(uri, &user, &domain);
+	
+	i = id->ids;
+	while (i) {
+		parse_uri(&i->entity, &u_, &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) {
+		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);
+			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;
+}
+
+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) {
+		if (is_rule_for_uri(rule, wuri)) {
+			TRACE_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 ------- */
+
+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_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);
+}
+
+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);
+}
+
+static void free_rule(cp_rule_t *r)
+{
+	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_pres_rules(cp_ruleset_t *r)
+{
+	cp_rule_t *rule, *n;
+	
+	if (!r) return;
+	rule = r->rules;
+	while (rule) {
+		n = rule->next;
+		free_rule(rule);
+		rule = n;
+	}
+	cds_free(r);
+}
+

+ 48 - 0
lib/xcap/pres_rules.h

@@ -0,0 +1,48 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __PRES_RULES_H
+#define __PRES_RULES_H
+
+#include <cds/sstr.h>
+#include <xcap/xcap_client.h>
+#include <xcap/common_policy.h>
+
+/* Type defining action for pres_rules */
+typedef enum {
+	sub_handling_block,
+	sub_handling_confirm,
+	sub_handling_polite_block,
+	sub_handling_allow
+} sub_handling_t;
+
+char *xcap_uri_for_pres_rules(const char *xcap_root, const str_t *uri);
+int get_pres_rules(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, cp_ruleset_t **dst);
+void free_pres_rules(cp_ruleset_t *r);
+
+/* 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

+ 562 - 0
lib/xcap/resource_list.c

@@ -0,0 +1,562 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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 char *xcap_root;
+	xcap_query_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 char *xcap_root, const str_t *uri)
+{
+	dstring_t s;
+	int l;
+	str_t c_uri;
+	char *dst = NULL;
+
+	if (!xcap_root) return NULL;
+	l = strlen(xcap_root);
+	dstr_init(&s, 2 * l + 32);
+	dstr_append(&s, xcap_root, l);
+	if (xcap_root[l - 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;
+}
+
+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) ------- */
+
+static char *relative2absolute_uri(const char *xcap_root, const char *relative)
+{
+	/* FIXME: do absolute uri from ref (RFC 3986, section 5.2) */
+	int len;
+	int root_len = 0;
+	int rel_len = 0;
+	int slash_len = 0;
+	char *dst = NULL;
+	
+	if (xcap_root) {
+		root_len = strlen(xcap_root);
+		len += root_len;
+		if (xcap_root[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, 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;
+	xcap_query_t xcap;
+	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 */
+	if (params->xcap_params) {
+		xcap = *params->xcap_params;
+	}
+	else memset(&xcap, 0, sizeof(xcap));
+	xcap.uri = relative2absolute_uri(params->xcap_root, entry_ref->ref);
+	res = xcap_query(&xcap, &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;
+	xcap_query_t xcap;
+	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 */
+	if (params->xcap_params) {
+		xcap = *params->xcap_params;
+	}
+	else memset(&xcap, 0, sizeof(xcap));
+	xcap.uri = external->anchor;
+	res = xcap_query(&xcap, &data, &dsize);
+	if (res != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n", xcap.uri ? xcap.uri: "???");
+		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;
+	xcap_query_t xcap;
+	list_t *list = NULL;
+
+	/* DEBUG_LOG("processing resource list\n"); */
+
+	/* do an xcap query */
+	if (params->xcap_params) xcap = *params->xcap_params;
+	else memset(&xcap, 0, sizeof(xcap));
+	xcap.uri = (char*)rl_uri;
+	if (xcap_query(&xcap, &data, &dsize) != 0) {
+		ERROR_LOG("XCAP problems for uri \'%s\'\n", xcap.uri ? xcap.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_t *xcap_params, const char *xcap_root, flat_list_t **dst)
+{
+	process_params_t params;
+	int res = -1;
+	if (!srv) return RES_INTERNAL_ERR;
+
+	params.xcap_root = xcap_root;
+	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 */
+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;
+}
+
+/* ------- rls examining ------- */
+
+int get_rls(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, const str_t *package, flat_list_t **dst)
+{
+	char *data = NULL;
+	int dsize = 0;
+	service_t *service = NULL;
+	xcap_query_t xcap;
+	int res;
+
+	if (!dst) return RES_INTERNAL_ERR;
+	
+	if (xcap_params) {
+		xcap = *xcap_params;
+	}
+	else memset(&xcap, 0, sizeof(xcap));
+
+	/* get basic document */
+	xcap.uri = xcap_uri_for_rls_resource(xcap_root, uri);
+	/* DEBUG_LOG("XCAP uri \'%s\'\n", xcap.uri ? xcap.uri: "???"); */
+	res = xcap_query(&xcap, &data, &dsize);
+	if (res != 0) {
+		ERROR_LOG("get_rls(): XCAP problems for uri \'%s\'\n", xcap.uri ? xcap.uri: "???");
+		if (data) {
+			cds_free(data);
+		}
+		if (xcap.uri) cds_free(xcap.uri);
+		return RES_XCAP_QUERY_ERR;
+	}
+	if (xcap.uri) cds_free(xcap.uri);
+	xcap.uri = NULL;
+	
+	/* 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) {
+		ERROR_LOG("Empty service!\n");
+		return RES_INTERNAL_ERR;
+	}
+
+	/* verify the package */
+	if (verify_package(service, package) != 0) {
+		cds_free(service);
+		return RES_BAD_EVENT_PACKAGE_ERR;
+	}
+	
+	/* create flat document */
+	res = create_flat_list(service, &xcap, xcap_root, 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;
+}

+ 48 - 0
lib/xcap/resource_list.h

@@ -0,0 +1,48 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 char *xcap_root, const str_t *uri);
+void canonicalize_uri(const str_t *uri, str_t *dst);
+int get_rls(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, const str_t *package, flat_list_t **dst);
+void free_flat_list(flat_list_t *list);
+
+#endif

+ 419 - 0
lib/xcap/resource_lists_parser.c

@@ -0,0 +1,419 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <xcap/resource_lists_parser.h>
+#include <xcap/xml_utils.h>
+#include <cds/logger.h>
+
+#include <stdio.h>
+#include <string.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 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 */
+	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);
+				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);
+				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);
+
+	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);
+		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);
+}
+

+ 100 - 0
lib/xcap/resource_lists_parser.h

@@ -0,0 +1,100 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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_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);
+int read_list(xmlNode *list_node, list_t **dst);
+
+#endif

+ 284 - 0
lib/xcap/rls_services_parser.c

@@ -0,0 +1,284 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <xcap/rls_services_parser.h>
+#include <xcap/xml_utils.h>
+
+#include <stdio.h>
+#include <string.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;
+	
+	/* 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);
+					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: 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);
+}
+

+ 70 - 0
lib/xcap/rls_services_parser.h

@@ -0,0 +1,70 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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

+ 189 - 0
lib/xcap/test_pres_rules.c

@@ -0,0 +1,189 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <curl/curl.h>
+#include <xcap/xcap_client.h>
+#include <xcap/pres_rules.h>
+#include <xcap/parse_pres_rules.h>
+#include <xcap/common_policy.h>
+#include <cds/sstr.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+
+void trace_conditions(cp_conditions_t *c)
+{
+	cp_sphere_t *s;
+	cp_id_t *i;
+	cp_domain_t *d;
+	cp_except_t *e;
+	
+	printf(" - conditions: \n"); 
+	if (!c) return;
+
+	printf("   +- validity: "); 
+	if (c->validity) 
+		printf("from %s to %s", 
+				ctime(&c->validity->from), 
+				ctime(&c->validity->to));
+	printf("\n");
+	
+	printf("   +- identity: \n"); 
+	if (c->identity) {
+		printf("      +- ids: "); 
+		i = c->identity->ids;
+		while (i) {
+			if (i != c->identity->ids) printf(", ");
+			printf("%.*s", FMT_STR(i->entity));
+			i = i->next;
+		}
+		printf("\n");
+		
+		printf("      +- domains: "); 
+		d = c->identity->domains;
+		while (d) {
+			if (d != c->identity->domains) printf(", ");
+			printf("%.*s", FMT_STR(d->domain));
+			d = d->next;
+		}
+		printf("\n");
+
+		printf("      +- except: "); 
+		e = c->identity->excepts;
+		while (e) {
+			if (e != c->identity->excepts) printf(", ");
+			printf("%.*s", FMT_STR(e->entity));
+			e = e->next;
+		}
+		printf("\n");
+	}
+	
+	printf("   +- spheres: "); 
+	s = c->spheres;
+	while (s) {
+		if (s != c->spheres) printf(", ");
+		printf("%.*s", FMT_STR(s->value));
+		s = s->next;
+	}
+	printf("\n");
+}
+
+void trace_actions(cp_actions_t *a)
+{
+	printf(" - actions: \n"); 
+	if (!a) return;
+	if (a->unknown) {
+		printf("    sub-handling: ");
+		sub_handling_t *sh = (sub_handling_t*)a->unknown->data;
+		switch (*sh) {
+			case sub_handling_block: printf("block"); break;
+			case sub_handling_confirm: printf("confirm"); break;
+			case sub_handling_polite_block: printf("polite block"); break;
+			case sub_handling_allow: printf("allow"); break;
+		}
+		printf("\n");
+	}
+}
+
+void trace_transformations(cp_transformations_t *c)
+{
+	printf(" - transformations: \n"); 
+}
+
+void trace_pres_rules(cp_ruleset_t *rules)
+{
+	cp_rule_t *r;
+	
+	if (!rules) {
+		printf("null ruleset!\n");
+		return;
+	}
+
+	r = rules->rules;
+	while (r) {
+		printf("rule \'%.*s\'\n", FMT_STR(r->id));
+		trace_conditions(r->conditions);
+		trace_actions(r->actions);
+		trace_transformations(r->transformations);
+		r = r->next;
+	}
+	
+}
+		
+void test_rules(cp_ruleset_t *pres_rules, const char *uri)
+{
+	sub_handling_t sh;
+	str_t s = zt2str((char *)uri);
+
+	sh = sub_handling_confirm;
+	get_pres_rules_action(pres_rules, &s, &sh);
+
+	printf("rules for %s: ", uri);
+	switch (sh) {
+		case sub_handling_block: printf("block"); break;
+		case sub_handling_confirm: printf("confirm"); break;
+		case sub_handling_polite_block: printf("polite block"); break;
+		case sub_handling_allow: printf("allow"); break;
+	}
+	printf("\n");
+}
+
+int pres_rules_test(const char *xcap_root, const char *uri)
+{
+	cp_ruleset_t *pres_rules = NULL;
+	xcap_query_t xcap;
+	int res;
+	str_t u;
+	
+	u.s = (char *)uri;
+	u.len = u.s ? strlen(u.s): 0;
+	
+	/* XCAP test */
+	memset(&xcap, 0, sizeof(xcap));
+	xcap.auth_user = "smith";
+	xcap.auth_pass = "pass";
+	xcap.enable_unverified_ssl_peer = 1;
+	res = get_pres_rules(xcap_root, &u, &xcap, &pres_rules);
+	if (res != 0) {
+		printf("XCAP problems!\n");
+		return -1;
+	}
+
+	if (pres_rules) {
+		trace_pres_rules(pres_rules);
+		test_rules(pres_rules, "[email protected]");
+		test_rules(pres_rules, "[email protected]");
+		test_rules(pres_rules, "all:[email protected]");
+
+		free_pres_rules(pres_rules);
+	}
+	
+	return 0;
+}
+

+ 265 - 0
lib/xcap/test_rls.c

@@ -0,0 +1,265 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libxml/parser.h>
+#include <curl/curl.h>
+
+#include <xcap/resource_list.h>
+#include <xcap/resource_lists_parser.h>
+#include <xcap/rls_services_parser.h>
+#include <xcap/xcap_client.h>
+
+#define STR_OK(s)	(s)?(s):""
+
+void print_indent(int indent)
+{
+	int i;
+	
+	for (i = 0; i < indent; i++) printf("  ");
+	if (indent > 0) printf(" + ");
+}
+
+void trace_entry(entry_t *e, int indent)
+{
+	if (!e) return;
+	
+	print_indent(indent);
+	if (e->uri) printf("%s\n", e->uri);
+	else printf("???\n");
+}
+
+void trace_entry_ref(entry_ref_t *e, int indent)
+{
+	if (!e) return;
+	
+	print_indent(indent);
+	if (e->ref) printf("ref: %s\n", e->ref);
+	else printf("ref: ???\n");
+}
+
+void trace_external(external_t *e, int indent)
+{
+	if (!e) return;
+	
+	print_indent(indent);
+	if (e->anchor) printf("ext: %s\n", e->anchor);
+	else printf("ext: ???\n");
+}
+
+void trace_list(list_t *l, int indent)
+{
+	list_content_t *e;
+
+	if (!l) return;
+	
+	print_indent(indent);
+	
+	if (l->name) printf("%s\n", l->name);
+	else printf("???\n");
+
+	e = SEQUENCE_FIRST(l->content);
+	while (e) {
+		switch (e->type) {
+			case lct_list: trace_list(e->u.list, indent + 1); break;
+			case lct_entry: trace_entry(e->u.entry, indent + 1); break;
+			case lct_entry_ref: trace_entry_ref(e->u.entry_ref, indent + 1); break;
+			case lct_external: trace_external(e->u.external, indent + 1); break;
+		}
+		e = SEQUENCE_NEXT(e);
+	}
+}
+
+void trace_resource_lists(resource_lists_t *rl)
+{
+	list_t *e;
+	if (!rl) {
+		printf("empty list\n");
+		return;
+	}
+	
+	e = SEQUENCE_FIRST(rl->lists);
+	while (e) {
+		trace_list(e, 0);
+		e = SEQUENCE_NEXT(e);
+	}
+}
+
+void trace_packages(packages_t *p)
+{
+	package_t *e;
+	int first = 1;
+	
+	printf(" [packages: ");
+	if (p) {
+		e = SEQUENCE_FIRST(p->package);
+		while (e) {
+			if (!first) printf(" ");
+			else first = 0;
+			printf("%s", e->name);
+			e = SEQUENCE_NEXT(e);
+		}
+	}
+	printf("]");
+}
+
+void trace_service(service_t *l, int indent)
+{
+	if (!l) return;
+	
+	print_indent(indent);
+	
+	if (l->uri) printf("%s", l->uri);
+	else printf("???");
+	if (l->packages) trace_packages(l->packages);
+	printf("\n");
+
+	switch (l->content_type) {
+		case stc_list: trace_list(l->content.list, indent + 1); break;
+		case stc_resource_list: print_indent(indent + 1);
+								printf("@ %s\n", STR_OK(l->content.resource_list));
+								break;
+	}
+}
+
+void trace_rls_services(rls_services_t *rl)
+{
+	service_t *e;
+	if (!rl) {
+		printf("empty rls-services\n");
+		return;
+	}
+	
+	e = SEQUENCE_FIRST(rl->rls_services);
+	while (e) {
+		trace_service(e, 0);
+		e = SEQUENCE_NEXT(e);
+	}
+}
+
+void trace_flat_list(flat_list_t *list)
+{
+	flat_list_t *e = list;
+	
+	while (e) {
+		if (e->uri) printf("%s\n", e->uri);
+		else printf("???\n");
+		e = e->next;
+	}
+}
+
+/* -------------------------------------------------------------------------------- */
+
+#if 0
+
+static int xcap_test(const char *xcap_root, const char *uri)
+{
+	char *data = NULL;
+	int dsize = 0;
+	/* resource_lists_t *res_list = NULL; */
+	rls_services_t *rls = NULL;
+	service_t *service = NULL;
+	xcap_query_t xcap;
+	int res;
+	str_t u = zt2str((char *)uri);
+	
+	/* XCAP test */
+	xcap.uri = xcap_uri_for_rls_resource(xcap_root, &u);
+	xcap.auth_user = "smith";
+	xcap.auth_pass = "pass";
+	xcap.enable_unverified_ssl_peer = 1;
+	res = xcap_query(&xcap, &data, &dsize);
+	if (res != 0) {
+		printf("XCAP problems!\n");
+		if (xcap.uri) printf("URI = %s\n", xcap.uri);
+		else printf("XCAP URI not defined!\n");
+		if (data) {
+			printf("%s\n", data);
+			free(data);
+		}
+		return -1;
+	}
+
+/*	printf("%s\n", data);*/
+
+	/* parse input data */
+	/*if (parse_resource_lists_xml(data, dsize, &res_list) != 0) {
+		printf("Error occured during document parsing!\n");
+	}
+	else { 
+		trace_resource_lists(res_list);
+		if (res_list) free_resource_lists(res_list);
+	}*/
+	
+	if (parse_rls_services_xml(data, dsize, &rls) == 0) {
+		trace_rls_services(rls);
+		if (rls) free_rls_services(rls);
+	}
+	else {
+		/* try to take it as a service */
+		if (parse_service(data, dsize, &service) == 0) {
+			if (service) {
+				trace_service(service, 0);
+				free_service(service);
+			}
+		}
+		else {
+			printf("Error occured during document parsing! It is not rls-services nor service.\n");
+			if (dsize > 0) printf("%.*s\n", dsize, data);
+		}
+	}
+
+	if (data) free(data);
+	return 0;
+}
+
+#endif
+
+int test_flat(const char *xcap_root, const char *uri)
+{
+	str_t u = zt2str((char *)uri);
+	xcap_query_t xcap;
+	flat_list_t *list = NULL;
+	str_t p = zt2str("presence");
+	
+	xcap.auth_user = "smith";
+	xcap.auth_pass = "pass";
+	xcap.enable_unverified_ssl_peer = 1;
+	
+	if (get_rls(xcap_root, &u, &xcap, &p, &list) != 0) {
+		if (list) free_flat_list(list);
+		printf("Failed !\n");
+		return -1;
+	}
+
+	trace_flat_list(list);
+	free_flat_list(list);
+	
+	return 0;
+}
+

+ 117 - 0
lib/xcap/xcap_client.c

@@ -0,0 +1,117 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <xcap/xcap_client.h>
+#include <cds/dstring.h>
+#include <cds/memory.h>
+#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 writen\n", s);*/
+	if (s != 0) {
+		if (dstr_append((dstring_t*)stream, ptr, s) != 0) return 0;
+	}
+	return s;
+}
+
+int xcap_query(xcap_query_t *query, char **buf, int *bsize)
+{
+	CURLcode res = -1;
+	CURL *handle;
+	dstring_t data;
+	char *auth = NULL;
+	int i;
+	long auth_methods;
+	
+	if (!query) return -1;
+	if (!buf) return -1;
+
+	i = 0;
+	if (query->auth_user) i += strlen(query->auth_user);
+	if (query->auth_pass) i += strlen(query->auth_pass);
+	if (i > 0) {
+		/* do authentication */
+		auth = (char *)cds_malloc(i + 2);
+		if (!auth) return -1;
+		sprintf(auth, "%s:%s", query->auth_user ? query->auth_user: "",
+				query->auth_pass ? query->auth_pass: "");
+	}
+
+	auth_methods = CURLAUTH_BASIC | CURLAUTH_DIGEST;
+	
+	dstr_init(&data, 512);
+	
+	handle = curl_easy_init();
+	if (handle) {
+		curl_easy_setopt(handle, CURLOPT_URL, query->uri);
+		
+		/* 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);
+
+		/* be quiet */
+		curl_easy_setopt(handle, CURLOPT_MUTE, 1);
+		
+		/* 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 (query->enable_unverified_ssl_peer) {
+			curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, 0);
+			curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST, 0);
+		}
+		
+		/* Accept headers */
+		
+		res = curl_easy_perform(handle);
+		curl_easy_cleanup(handle);
+	}
+	if (res == 0) {
+		*bsize = dstr_get_data_length(&data);
+		if (*bsize) {
+			*buf = (char*)cds_malloc(*bsize);
+			if (!*buf) {
+				res = -1;
+				*bsize = 0;
+			}
+			else dstr_get_data(&data, *buf);
+		}
+	}
+	dstr_destroy(&data);
+	if (auth) cds_free(auth);
+	return res;
+}
+

+ 47 - 0
lib/xcap/xcap_client.h

@@ -0,0 +1,47 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __XCAP_CLIENT_H
+#define __XCAP_CLIENT_H
+
+typedef struct {
+	/** full HTTP/HTTPS uri for the query */
+	char *uri;
+	/** username for authentication */
+	char *auth_user;
+	/** password used for authentication */
+	char *auth_pass;
+	/** Accept unverifiable peers (ignore information 
+	 * stored in certificate and trust a certificate
+	 * without know CA). */
+	int enable_unverified_ssl_peer;
+} xcap_query_t;
+
+/** Sends a XCAP query to the destination and using parameters from 
+ * query variable a returns received data in output variables buf
+ * and bsize. */
+int xcap_query(xcap_query_t *query, char **buf, int *bsize);
+
+#endif

+ 40 - 0
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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

+ 132 - 0
lib/xcap/xml_utils.c

@@ -0,0 +1,132 @@
+/* 
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+#include <string.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 void str2int(const char *s, int *dst)
+{
+	/* if not null sets the given integer to value */
+	if (!s) return;
+	else *dst = atoi(s);
+}
+
+void get_int_attr(xmlNode *n, const char *attr_name, int *dst)
+{
+	str2int(get_attr_value(find_attr(n->properties, attr_name)), dst);
+}
+
+void 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);
+	else 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 parametr to time_t structure */
+	ERROR_LOG("can't translate xmltime to time_t: not finished yet!\n");
+	return 0;
+}
+

+ 52 - 0
lib/xcap/xml_utils.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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);
+void get_int_attr(xmlNode *n, const char *attr_name, int *dst);
+void 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;