Browse Source

* Introduced new function xcap_auth_status that is a standalone version
of modules_k/presence pres_auth_status function. This allows checking
of presence authorization status from a sip proxy that does not include
an integrated presence server.

Juha Heinanen 16 years ago
parent
commit
b64b67df7d

+ 4 - 3
modules/utils/Makefile

@@ -9,12 +9,13 @@ auto_gen=
 NAME=utils.so
 LIBS=
 
-DEFS+=-I$(LOCALBASE)/include
-
-LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -lcurl
+DEFS+=-I/usr/include/libxml2 -I$(LOCALBASE)/include/libxml2 \
+      -I$(LOCALBASE)/include
+LIBS+=-L$(SYSBASE)/include/lib -L$(LOCALBASE)/lib -lcurl -lxml2
 
 DEFS+=-DOPENSER_MOD_INTERFACE
 
 SERLIBPATH=../../lib
+SER_LIBS+=$(SERLIBPATH)/srdb1/srdb1
 SER_LIBS+=$(SERLIBPATH)/kmi/kmi
 include ../../Makefile.modules

+ 185 - 87
modules/utils/README

@@ -5,82 +5,128 @@ Juha Heinanen
    TutPro Inc.
 
    Copyright © 2008 Juha Heinanen
-     __________________________________________________________
+     __________________________________________________________________
 
    Table of Contents
 
    1. Admin Guide
 
-        1.1. Overview
-        1.2. Dependencies
+        1. Overview
+        2. Dependencies
 
-              1.2.1. Kamailio Modules
-              1.2.2. External Libraries or Applications
+              2.1. Kamailio Modules
+              2.2. External Libraries or Applications
 
-        1.3. Exported Parameters
+        3. Exported Parameters
 
-              1.3.1. http_query_timeout (int)
-              1.3.2. forward_active (int)
+              3.1. http_query_timeout (int)
+              3.2. forward_active (int)
+              3.3. pres_db_url (string)
+              3.4. xcap_table (string)
 
-        1.4. Exported Functions
+        4. Exported Functions
 
-              1.4.1. http_query(url, result)
+              4.1. http_query(url, result)
+              4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
-        1.5. MI Commands
+        5. MI Commands
 
-              1.5.1. forward_list
-              1.5.2. forward_switch
-              1.5.3. forward_filter
-              1.5.4. forward_proxy
+              5.1. forward_list
+              5.2. forward_switch
+              5.3. forward_filter
+              5.4. forward_proxy
 
-        1.6. Configuration syntax
+        6. Configuration syntax
 
    List of Examples
 
    1.1. Set http_query_timeout parameter
    1.2. Set forward_active parameter
-   1.3. http_query() usage
-   1.4. forward_list usage
-   1.5. forward_switch usage
-   1.6. forward_filter usage
-   1.7. forward_proxy usage
+   1.3. Set pres_db_url parameter
+   1.4. Set xcap_table parameter
+   1.5. http_query() usage
+   1.6. xcap_auth_status() usage
+   1.7. forward_list usage
+   1.8. forward_switch usage
+   1.9. forward_filter usage
+   1.10. forward_proxy usage
 
 Chapter 1. Admin Guide
 
-1.1. Overview
+   Table of Contents
+
+   1. Overview
+   2. Dependencies
+
+        2.1. Kamailio Modules
+        2.2. External Libraries or Applications
+
+   3. Exported Parameters
+
+        3.1. http_query_timeout (int)
+        3.2. forward_active (int)
+        3.3. pres_db_url (string)
+        3.4. xcap_table (string)
+
+   4. Exported Functions
+
+        4.1. http_query(url, result)
+        4.2. xcap_auth_status(watcher_uri, presentity_uri)
+
+   5. MI Commands
+
+        5.1. forward_list
+        5.2. forward_switch
+        5.3. forward_filter
+        5.4. forward_proxy
 
-   This module implements various utility functions that are not
-   SIP related.
+   6. Configuration syntax
 
-   Function http_query allows Kamailio to issue an HTTP GET
-   request and get access to parts of the reply.
+1. Overview
 
-   The forward functionality allows Kamailio to configure
-   forwarding at runtime with FIFO commands. The forwarding is
-   executed in the pre script call back and therefore handled
-   before the routing script is executed on the current message.
-   The callback is not installed on default, thus this
-   functionality has no runtime overhead when its deactivated.
+   This module implements various utility functions that are not SIP
+   related.
 
-1.2. Dependencies
+   Function http_query allows Kamailio to issue an HTTP GET request and
+   get access to parts of the reply.
 
-1.2.1. Kamailio Modules
+   The forward functionality allows Kamailio to configure forwarding at
+   runtime with FIFO commands. The forwarding is executed in the pre
+   script call back and therefore handled before the routing script is
+   executed on the current message. The callback is not installed on
+   default, thus this functionality has no runtime overhead when its
+   deactivated.
+
+   Function xcap_auth_status can be used to check from presence server
+   database, if watcher is authorized to subscribe event "presence" of
+   presentity.
+
+2. Dependencies
+
+   2.1. Kamailio Modules
+   2.2. External Libraries or Applications
+
+2.1. Kamailio Modules
 
    The following modules must be loaded before this module:
      * None.
 
-1.2.2. External Libraries or Applications
+2.2. External Libraries or Applications
 
-   The following libraries or applications must be installed
-   before running Kamailio with this module loaded:
+   The following libraries or applications must be installed before
+   running Kamailio with this module loaded:
      * libcurl.
 
-1.3. Exported Parameters
+3. Exported Parameters
+
+   3.1. http_query_timeout (int)
+   3.2. forward_active (int)
+   3.3. pres_db_url (string)
+   3.4. xcap_table (string)
 
-1.3.1. http_query_timeout (int)
+3.1. http_query_timeout (int)
 
-   Defines in seconds how long Kamailio waits response from HTTP
-   server.
+   Defines in seconds how long Kamailio waits response from HTTP server.
 
    Default value is "4".
 
@@ -89,7 +135,7 @@ Chapter 1. Admin Guide
 modparam("utils", "http_query_timeout", 2)
 ...
 
-1.3.2. forward_active (int)
+3.2. forward_active (int)
 
    Defines if the forwarding callback should be installed.
 
@@ -97,104 +143,156 @@ modparam("utils", "http_query_timeout", 2)
 
    Example 1.2. Set forward_active parameter
                                         ...
-                                        modparam("utils", "forward_activ
-e", 1)
+                                        modparam("utils", "forward_active", 1)
                                         ...
 
-1.4. Exported Functions
+3.3. pres_db_url (string)
+
+   Defines presence server database URL. If not given, xcap_auth_status
+   function is disabled.
+
+   There is no default value.
+
+   Example 1.3. Set pres_db_url parameter
+...
+modparam("utils", "pres_db_url", "mysql://foo:secret@localhost/pres")
+...
+
+3.4. xcap_table (string)
+
+   Defines name of xcap table in presence server database.
+
+   Default value is "xcap".
+
+   Example 1.4. Set xcap_table parameter
+...
+modparam("utils", "xcap_table", "pres_xcap")
+...
+
+4. Exported Functions
+
+   4.1. http_query(url, result)
+   4.2. xcap_auth_status(watcher_uri, presentity_uri)
 
-1.4.1.  http_query(url, result)
+4.1.  http_query(url, result)
 
-   Sends HTTP GET request according to URL given in "url"
-   parameter, which is a string that may contain pseudo variables.
+   Sends HTTP GET request according to URL given in "url" parameter, which
+   is a string that may contain pseudo variables.
 
-   If HTTP server returns a class 2xx or 3xx reply, first line of
-   reply's body (if any) is stored in "result" parameter, which
-   must be a writable pseudo variable.
+   If HTTP server returns a class 2xx or 3xx reply, first line of reply's
+   body (if any) is stored in "result" parameter, which must be a writable
+   pseudo variable.
 
-   Function returns reply code of HTTP reply or -1 if something
-   went wrong.
+   Function returns reply code of HTTP reply or -1 if something went
+   wrong.
 
    This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE,
    FAILURE_ROUTE, and BRANCH_ROUTE.
 
-   Example 1.3. http_query() usage
+   Example 1.5. http_query() usage
 ...
-http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&f_ur
-i=$(fu{s.escape.param})",
+http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&f_uri=$(fu{s
+.escape.param})",
            "$var(result)")
 switch ($retcode) {
        ...
 }
 ...
 
-1.5. MI Commands
+4.2.  xcap_auth_status(watcher_uri, presentity_uri)
+
+   Function checks from presence server database if watcher is authorized
+   to subscribe event "presence" of presentity. Sphere checking is not
+   included.
+
+   Both watcher_uri and presentity_uri are pseudo variables. Function
+   returns ACTIVE_STATUS, if subscription is allowed and PENDING_STATUS,
+   TERMINATED_STATUS, or WAITING_STATUS otherwise. See
+   presence/subscribe.h for the corresponding integer codes. In case of
+   error, function returns -1.
+
+   Function can be used from REQUEST_ROUTE.
+
+   Example 1.6. xcap_auth_status() usage
+...
+if (method=="MESSAGE") {
+    xcap_auth_status("$fu", $ru");
+    if ($retcode == 1) {
+        t_relay();
+    } else {
+        send_reply("403", "Forbidden");
+    }
+}
+...
+
+5. MI Commands
+
+   5.1. forward_list
+   5.2. forward_switch
+   5.3. forward_filter
+   5.4. forward_proxy
 
-1.5.1. forward_list
+5.1. forward_list
 
    List active forward rules.
 
    No parameters.
 
-   Example 1.4. forward_list usage
+   Example 1.7. forward_list usage
 ...
 kamctl fifo forward_list
 id switch                         filter proxy
  0    off      REGISTER:INVITE:SUBSCRIBE host-a.domain-a:5060
 ...
 
-1.5.2. forward_switch
+5.2. forward_switch
 
-   This command can be used to activate or deactivate forwarding
-   rules. The syntax of this configuration string is described in
-   1.6. (switch_setting_list).
+   This command can be used to activate or deactivate forwarding rules.
+   The syntax of this configuration string is described in 1.6.
+   (switch_setting_list).
 
-   Example 1.5. forward_switch usage
+   Example 1.8. forward_switch usage
 ...
 kamctl fifo sp_forward_switch 0=on
 ...
 
-1.5.3. forward_filter
+5.3. forward_filter
 
-   Can be used to specify the filter for a certain id. Messages
-   will only be forwarded if one of the filters matches the
-   message.
+   Can be used to specify the filter for a certain id. Messages will only
+   be forwarded if one of the filters matches the message.
 
-   There are special filters and regular filters. Special filters
-   are:
+   There are special filters and regular filters. Special filters are:
      * REQUEST (matches on every request)
      * REPLY (matches on every reply)
 
-   Regular filters are arbitrary strings not containing the
-   delimiter ':'. They are matched against the request method
-   names of the sip messages. The syntax of this configuration
-   string is described in 1.6. (filter_setting_list).
+   Regular filters are arbitrary strings not containing the delimiter ':'.
+   They are matched against the request method names of the sip messages.
+   The syntax of this configuration string is described in 1.6.
+   (filter_setting_list).
 
-   Example 1.6. forward_filter usage
+   Example 1.9. forward_filter usage
 ...
 kamctl fifo sp_forward_filter 0=REGISTER:INVITE
 ...
 
-1.5.4. forward_proxy
+5.4. forward_proxy
 
-   This command can be used to configure forwarding rules.
-   Specifies the destination for a certain id. Messages will be
-   forwarded to this destination if the preconditions hold
-   (matching id, filter, and switch). The syntax of this
-   configuration string is described in 1.6. (proxy_setting_list).
+   This command can be used to configure forwarding rules. Specifies the
+   destination for a certain id. Messages will be forwarded to this
+   destination if the preconditions hold (matching id, filter, and
+   switch). The syntax of this configuration string is described in 1.6.
+   (proxy_setting_list).
 
-   Example 1.7. forward_proxy usage
+   Example 1.10. forward_proxy usage
 ...
 kamctl fifo sp_forward_proxy 0=host-c.domain-c:5060
 ...
 
-1.6. Configuration syntax
+6. Configuration syntax
 
    This grammar specify the usable configuration syntax
-     * switch_setting_list ::= switch_setting { "," switch_setting
-       }
-     * filter_setting_list ::= switch_setting { "," switch_setting
-       }
+     * switch_setting_list ::= switch_setting { "," switch_setting }
+     * filter_setting_list ::= switch_setting { "," switch_setting }
      * proxy_setting_list ::= proxy_setting { "," proxy_setting }
      * switch_setting ::= id "=" switch
      * filter_setting ::= id "=" filter_list

+ 1 - 1
modules/utils/doc/utils.xml

@@ -23,7 +23,7 @@
 		</author>
 	</authorgroup>
 	<copyright>
-		<year>2008</year>
+		<year>2008-2009</year>
 		<holder>Juha Heinanen</holder>
 	</copyright>
 	</bookinfo>

+ 86 - 3
modules/utils/doc/utils_admin.xml

@@ -31,6 +31,11 @@
 	default, thus this functionality has no runtime overhead when its
 	deactivated.
 	</para>
+	<para>
+	Function xcap_auth_status can be used to check from presence
+	server database, if watcher is authorized to subscribe event
+	<quote>presence</quote> of presentity.
+	</para>
 	</section>
 	<section>
 	<title>Dependencies</title>
@@ -41,7 +46,8 @@
 			<itemizedlist>
 			<listitem>
 			<para>
-				<emphasis>None</emphasis>.
+				<emphasis>a database module if
+	xcap_auth_status function is enabled</emphasis>.
 			</para>
 			</listitem>
 			</itemizedlist>
@@ -74,7 +80,8 @@
 			</para>
 			<para>
 			<emphasis>
-				Default value is <quote>4</quote>.
+				Default value is null, i.e.,
+				xcap_auth_status function is disabled.
 			</emphasis>
 			</para>
 			<example>
@@ -105,7 +112,45 @@ modparam("utils", "http_query_timeout", 2)
 				</programlisting>
 			</example>
 		</section>
-
+		<section>
+			<title><varname>pres_db_url</varname> (string)</title>
+			<para>
+			Defines presence server database URL.  If not
+			given, xcap_auth_status function is disabled.
+			</para>
+			<para>
+			<emphasis>
+				There is no default value.
+			</emphasis>
+			</para>
+			<example>
+			<title>Set <varname>pres_db_url</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("utils", "pres_db_url", "mysql://foo:secret@localhost/pres")
+...
+				</programlisting>
+			</example>
+		</section>
+		<section>
+			<title><varname>xcap_table</varname> (string)</title>
+			<para>
+			Defines name of xcap table in presence server database.
+			</para>
+			<para>
+			<emphasis>
+				Default value is <quote>xcap</quote>.
+			</emphasis>
+			</para>
+			<example>
+			<title>Set <varname>xcap_table</varname> parameter</title>
+				<programlisting format="linespecific">
+...
+modparam("utils", "xcap_table", "pres_xcap")
+...
+				</programlisting>
+			</example>
+		</section>
 	</section>
 
 	<section>
@@ -142,6 +187,44 @@ http_query("http://tutpro.com/index.php?r_uri=$(ru{s.escape.param})&amp;f_uri=$(
 switch ($retcode) {
        ...
 }
+...
+				</programlisting>
+			</example>
+		</section>
+		<section>
+			<title>
+				<function moreinfo="none">xcap_auth_status(watcher_uri, presentity_uri)</function>
+			</title>
+			<para>
+			Function checks from presence server database if
+			watcher is authorized to subscribe event
+			<quote>presence</quote> of presentity.  Sphere
+			checking is not included.
+			</para>
+			<para>
+			Both watcher_uri and presentity_uri are
+			pseudo variables. Function returns
+			ACTIVE_STATUS, if subscription is 
+			allowed and PENDING_STATUS, TERMINATED_STATUS,
+			or WAITING_STATUS otherwise. See
+			presence/subscribe.h for the corresponding integer
+			codes. In case of error, function returns -1.
+	    	        </para>
+			<para>
+			Function can be used from REQUEST_ROUTE.
+			</para>
+			<example>
+				<title><function>xcap_auth_status()</function> usage</title>
+				<programlisting format="linespecific">
+...
+if (method=="MESSAGE") {
+    xcap_auth_status("$fu", $ru");
+    if ($retcode == 1) {
+        t_relay();
+    } else {
+        send_reply("403", "Forbidden");
+    }
+}
 ...
 				</programlisting>
 			</example>

+ 195 - 0
modules/utils/pidf.c

@@ -0,0 +1,195 @@
+/*
+ * $Id: pidf.c 1953 2007-04-04 08:50:33Z anca_vamanu $
+ *
+ * presence module - presence server implementation
+ *
+ * Copyright (C) 2006 Voice Sistem S.R.L.
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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
+ *
+ * History:
+ * --------
+ *  2007-04-14  initial version (anca)
+ */
+
+/*! \file
+ * \brief Kamailio Presence_XML ::  PIDF handling
+ * \ingroup presence_xml
+ */
+
+/**
+ * make strptime available
+ * use 600 for 'Single UNIX Specification, Version 3'
+ * _XOPEN_SOURCE creates conflict in header definitions in Solaris
+ */
+#ifndef __OS_solaris
+	#define _XOPEN_SOURCE 600          /* glibc2 on linux, bsd */
+#else
+	#define _XOPEN_SOURCE_EXTENDED 1   /* solaris */
+#endif
+
+#include <time.h>
+
+#undef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE_EXTENDED
+
+#include <string.h>
+#include <stdlib.h>
+#include <libxml/parser.h>
+#include "../../dprint.h"
+#include "pidf.h"
+
+xmlAttrPtr xmlNodeGetAttrByName(xmlNodePtr node, const char *name)
+{
+	xmlAttrPtr attr = node->properties;
+	while (attr) {
+		if (xmlStrcasecmp(attr->name, (unsigned char*)name) == 0)
+			return attr;
+		attr = attr->next;
+	}
+	return NULL;
+}
+
+char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name)
+{
+	xmlAttrPtr attr = xmlNodeGetAttrByName(node, name);
+	if (attr)
+		return (char*)xmlNodeGetContent(attr->children);
+	else
+		return NULL;
+}
+
+xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name)
+{
+	xmlNodePtr cur = node->children;
+	while (cur) {
+		if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0)
+			return cur;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name,
+															const char *ns)
+{
+	xmlNodePtr cur = node;
+	while (cur) {
+		xmlNodePtr match = NULL;
+		if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0) {
+			if (!ns || (cur->ns && xmlStrcasecmp(cur->ns->prefix,
+							(unsigned char*)ns) == 0))
+				return cur;
+		}
+		match = xmlNodeGetNodeByName(cur->children, name, ns);
+		if (match)
+			return match;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+char *xmlNodeGetNodeContentByName(xmlNodePtr root, const char *name,
+		const char *ns)
+{
+	xmlNodePtr node = xmlNodeGetNodeByName(root, name, ns);
+	if (node)
+		return (char*)xmlNodeGetContent(node->children);
+	else
+		return NULL;
+}
+
+xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns)
+{
+	xmlNodePtr cur = doc->children;
+	return xmlNodeGetNodeByName(cur, name, ns);
+}
+
+char *xmlDocGetNodeContentByName(xmlDocPtr doc, const char *name, 
+		const char *ns)
+{
+	xmlNodePtr node = xmlDocGetNodeByName(doc, name, ns);
+	if (node)
+		return (char*)xmlNodeGetContent(node->children);
+	else
+		return NULL;
+}
+
+time_t xml_parse_dateTime(char* xml_time_str)
+{
+	struct tm tm;
+	char * p;
+	int h, m;
+	char h1, h2, m1, m2;
+	int sign= 1;
+	signed int timezone_diff= 0;
+
+	p= strptime(xml_time_str, "%F", &tm);
+	if(p== NULL)
+	{
+		printf("error: failed to parse time\n");
+		return 0;
+	}
+	p++;
+	p= strptime(p, "%T", &tm);
+	if(p== NULL)
+	{
+		printf("error: failed to parse time\n");
+		return 0;
+	}
+	
+	if(*p== '\0')
+		goto done;
+
+	if(*p== '.')
+	{
+		p++;
+		/* read the fractionar part of the seconds*/
+		while(*p!= '\0' && *p>= '0' && *p<= '9')
+		{
+			p++;
+		}
+	}
+
+	if(*p== '\0')
+		goto done;
+
+	
+	/* read time zone */
+
+	if(*p== 'Z')
+	{
+		goto done;
+	}
+
+	if(*p== '+')
+		sign= -1;
+
+	p++;
+
+	sscanf(p, "%c%c:%c%c", &h1, &h2, &m1, &m2);
+	
+	h= (h1- '0')*10+ h2- '0';
+	m= (m1- '0')*10+ m2- '0';
+
+	timezone_diff= sign* ((m+ h* 60)* 60);
+
+done:
+	return (mktime(&tm) + timezone_diff);	
+}
+
+

+ 53 - 0
modules/utils/pidf.h

@@ -0,0 +1,53 @@
+/*
+ * $Id: pidf.h 1401 2006-12-14 11:12:42Z anca_vamanu $
+ *
+ * presence module - presence server implementation
+ *
+ * Copyright (C) 2006 Voice Sistem S.R.L.
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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
+ *
+ * History:
+ * --------
+ *  2006-08-15  initial version (anca)
+ */
+
+/*! \file
+ * \brief Kamailio Presence_XML :: PIDF handling
+ * \ref pidf.c
+ * \ingroup presence_xml
+ */
+
+
+#ifndef UTILS_PIDF_H
+#define UTILS_PIDF_H
+
+#include "../../str.h"
+#include <libxml/parser.h>
+
+xmlNodePtr xmlNodeGetNodeByName(xmlNodePtr node, const char *name,
+															const char *ns);
+xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns);
+xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name);
+
+char *xmlNodeGetNodeContentByName(xmlNodePtr root, const char *name,
+		const char *ns);
+char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name);
+
+time_t xml_parse_dateTime(char* xml_time_str);
+
+#endif 

+ 84 - 9
modules/utils/utils.c

@@ -37,41 +37,45 @@
 #include "../../locking.h"
 #include "../../script_cb.h"
 #include "../../mem/shm_mem.h"
+#include "../../lib/srdb1/db.h"
 
 #include "functions.h"
 #include "conf.h"
+#include "xcap_auth.h"
 
 
 MODULE_VERSION
 
+#define XCAP_TABLE_VERSION  3
 
-/* module parameters */
+/* Module parameter variables */
+int http_query_timeout = 4;
 static int forward_active = 0;
 static int   mp_max_id = 0;
 static char* mp_switch = "";
 static char* mp_filter = "";
 static char* mp_proxy  = "";
+str xcap_table= str_init("xcap");
+str pres_db_url = {0, 0};
 
 /* lock for configuration access */
 static gen_lock_t *conf_lock = NULL;
 
-
 /* FIFO interface functions */
 static struct mi_root* forward_fifo_list(struct mi_root* cmd_tree, void *param);
 static struct mi_root* forward_fifo_switch(struct mi_root* cmd_tree, void* param);
 static struct mi_root* forward_fifo_filter(struct mi_root* cmd_tree, void* param);
 static struct mi_root* forward_fifo_proxy(struct mi_root* cmd_tree, void* param);
 
+/* Database connection */
+db1_con_t *pxml_db = NULL;
+db_func_t pxml_dbf;
 
 /* Module management function prototypes */
 static int mod_init(void);
+static int child_init(int);
 static void destroy(void);
 
-
-/* Module parameter variables */
-int http_query_timeout = 4;
-
-
 /* Fixup functions to be defined later */
 static int fixup_http_query(void** param, int param_no);
 static int fixup_free_http_query(void** param, int param_no);
@@ -84,14 +88,18 @@ static cmd_export_t cmds[] = {
     {"http_query", (cmd_function)http_query, 2, fixup_http_query,
      fixup_free_http_query,
      REQUEST_ROUTE|ONREPLY_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
+    {"xcap_auth_status", (cmd_function)xcap_auth_status, 2, fixup_pvar_pvar,
+     fixup_free_pvar_pvar, REQUEST_ROUTE},
     {0, 0, 0, 0, 0, 0}
 };
 
 
 /* Exported parameters */
 static param_export_t params[] = {
+    {"pres_db_url", STR_PARAM, &pres_db_url.s},
+    {"xcap_table", STR_PARAM, &xcap_table.s},
     {"http_query_timeout", INT_PARAM, &http_query_timeout},
-    {"forward_active",     INT_PARAM, &forward_active},
+    {"forward_active", INT_PARAM, &forward_active},
     {0, 0, 0}
 };
 
@@ -116,7 +124,7 @@ struct module_exports exports = {
     mod_init,  /* module initialization function */
     0,         /* response function*/
     destroy,   /* destroy function */
-    0          /* per-child init function */
+    child_init /* per-child init function */
 };
 
 
@@ -209,10 +217,77 @@ static int mod_init(void)
 	} else {
 		LM_INFO("forward functionality disabled");
 	}
+
+	/* presence database */
+	pres_db_url.len = pres_db_url.s ? strlen(pres_db_url.s) : 0;
+	LM_DBG("pres_db_url=%s/%d/%p\n", ZSW(pres_db_url.s), pres_db_url.len,
+	       pres_db_url.s);
+	xcap_table.len = xcap_table.s ? strlen(xcap_table.s) : 0;
+
+	if (pres_db_url.len == 0) {
+	    LM_DBG("xcap_auth_status() function disabled\n");
+	    return 0;
+	}
+
+	/* binding to mysql module */
+	if (db_bind_mod(&pres_db_url, &pxml_dbf)) {
+	    LM_ERR("Database module not found\n");
+	    return -1;
+	}
+	
+	if (!DB_CAPABILITY(pxml_dbf, DB_CAP_ALL)) {
+	    LM_ERR("Database module does not implement all functions"
+		   " needed by xcap_auth_status() function\n");
+	    return -1;
+	}
+
+	pxml_db = pxml_dbf.init(&pres_db_url);
+	if (!pxml_db) {
+	    LM_ERR("while connecting to database\n");
+	    return -1;
+	}
+
+	if (db_check_table_version(&pxml_dbf, pxml_db, &xcap_table,
+				   XCAP_TABLE_VERSION) < 0) {
+	    LM_ERR("error during table version check.\n");
+	    return -1;
+	}
+
+	pxml_dbf.close(pxml_db);
+	pxml_db = NULL;	
+	
 	return 0;
 }
 
 
+/* Child initialization function */
+static int child_init(int rank)
+{	
+    if (pres_db_url.len == 0)
+	return 0;
+
+    if (pxml_dbf.init==0) {
+	LM_CRIT("database not bound\n");
+	return -1;
+    }
+
+    pxml_db = pxml_dbf.init(&pres_db_url);
+    if (pxml_db == NULL) {
+	LM_ERR("while connecting database\n");
+	return -1;
+    }
+		
+    if (pxml_dbf.use_table(pxml_db, &xcap_table) < 0) {
+	LM_ERR("in use_table SQL operation\n");
+	return -1;
+    }
+	
+    LM_DBG("database connection opened successfully\n");
+
+    return 0;
+}	
+
+
 static void destroy(void)
 {
 	/* Cleanup curl */

+ 4 - 0
modules/utils/utils.h

@@ -26,7 +26,11 @@
 #define UTILS_H
 
 #include "../../str.h"
+#include "../../lib/srdb1/db.h"
 
 extern int http_query_timeout;
+extern str xcap_table;
+extern db1_con_t *pxml_db;
+extern db_func_t pxml_dbf;
 
 #endif /* UTILS_H */

+ 527 - 0
modules/utils/xcap_auth.c

@@ -0,0 +1,527 @@
+/*
+ * xcap_auth.c
+ *
+ * Copyright (C) 2007 Voice Sistem S.R.L.
+ *
+ * Copyright (C) 2009 Juha Heinanen
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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
+ *
+ * History:
+ * --------
+ *  2007-04-11  initial version (anca)
+ *  2009-06-03  util version (jh)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <libxml/parser.h>
+
+#include "../../str.h"
+#include "../../dprint.h"
+#include "../../pvar.h"
+#include "../../parser/parse_uri.h"
+#include "../../modules_k/presence/subscribe.h"
+#include "../../modules_k/presence/utils_func.h"
+#include "../../modules_k/presence/hash.h"
+#include "../../modules_k/xcap_client/xcap_callbacks.h"
+#include "utils.h"
+#include "pidf.h"
+
+xmlNodePtr get_rule_node(subs_t* subs, xmlDocPtr xcap_tree)
+{
+    str w_uri = {0, 0};
+    char* id = NULL, *domain = NULL, *time_cont= NULL;
+    int apply_rule = -1;
+    xmlNodePtr ruleset_node = NULL, node1= NULL, node2= NULL;
+    xmlNodePtr cond_node = NULL, except_node = NULL;
+    xmlNodePtr identity_node = NULL;
+    xmlNodePtr iden_child;
+    xmlNodePtr validity_node, time_node;
+    time_t t_init, t_fin, t;
+    int valid= 0;
+
+    uandd_to_uri(subs->from_user, subs->from_domain, &w_uri);
+    if (w_uri.s == NULL) {
+	LM_ERR("while creating uri\n");
+	return NULL;
+    }
+    ruleset_node = xmlDocGetNodeByName(xcap_tree, "ruleset", NULL);
+    if (ruleset_node == NULL) {
+	LM_DBG("ruleset_node NULL\n");
+	goto error;
+    }	
+    for (node1 = ruleset_node->children; node1; node1 = node1->next) {
+	if (xmlStrcasecmp(node1->name, (unsigned char*)"text") == 0)
+	    continue;
+
+	/* process conditions */
+	LM_DBG("node1->name= %s\n", node1->name);
+	
+	cond_node = xmlNodeGetChildByName(node1, "conditions");
+	if(cond_node == NULL) {
+	    LM_DBG("cond node NULL\n");
+	    goto error;
+	}
+	LM_DBG("cond_node->name= %s\n", cond_node->name);
+
+	validity_node = xmlNodeGetChildByName(cond_node, "validity");
+	if (validity_node != NULL) {
+	    LM_DBG("found validity tag\n");
+	    
+	    t= time(NULL);
+		
+	    /* search all from-until pair */
+	    for (time_node = validity_node->children; time_node;
+		time_node = time_node->next) {
+		if (xmlStrcasecmp(time_node->name, (unsigned char*)"from")!= 0)
+		    continue;
+
+		time_cont= (char*)xmlNodeGetContent(time_node);
+		t_init= xml_parse_dateTime(time_cont);
+		xmlFree(time_cont);
+		if (t_init< 0) {
+		    LM_ERR("failed to parse xml dateTime\n");
+		    goto error;
+		}
+
+		if (t< t_init) {
+		    LM_DBG("the lower time limit is not respected\n");
+		    continue;
+		}
+				
+		time_node= time_node->next;
+		while (1) {
+		    if (time_node == NULL) {
+			LM_ERR("bad formatted xml doc:until child not found in"
+			       " validity pair\n");
+			goto error;
+		    }
+		    if( xmlStrcasecmp(time_node->name, 
+				      (unsigned char*)"until")== 0)
+			break;
+		    time_node= time_node->next;
+		}
+				
+		time_cont = (char*)xmlNodeGetContent(time_node);
+		t_fin= xml_parse_dateTime(time_cont);
+		xmlFree(time_cont);
+		
+		if (t_fin< 0) {
+		    LM_ERR("failed to parse xml dateTime\n");
+		    goto error;
+		}
+			
+		if (t <= t_fin) {
+		    LM_DBG("the rule is active at this time\n");
+		    valid= 1;
+		}
+			
+	    }
+		
+	    if (!valid) {
+		LM_DBG("the rule is not active at this time\n");
+		continue;
+	    }
+	    
+	}	
+
+	identity_node = xmlNodeGetChildByName(cond_node, "identity");
+	if (identity_node == NULL) {
+	    LM_ERR("didn't find identity tag\n");
+	    goto error;
+	}	
+		
+	iden_child = xmlNodeGetChildByName(identity_node, "one");
+	if(iden_child) {
+	    for (node2 = identity_node->children; node2; node2 = node2->next) {
+		if(xmlStrcasecmp(node2->name, (unsigned char*)"one")!= 0)
+		    continue;
+				
+		id = xmlNodeGetAttrContentByName(node2, "id");	
+		if(id== NULL) {
+		    LM_ERR("while extracting attribute\n");
+		    goto error;
+		}
+		if ((strlen(id)== w_uri.len && 
+		     (strncmp(id, w_uri.s, w_uri.len)==0))) {
+		    apply_rule = 1;
+		    xmlFree(id);
+		    break;
+		}
+		xmlFree(id);
+	    }
+	}	
+
+	/* search for many node*/
+	iden_child = xmlNodeGetChildByName(identity_node, "many");
+	if (iden_child)	{
+	    domain = NULL;
+	    for (node2 = identity_node->children; node2; node2 = node2->next) {
+		if (xmlStrcasecmp(node2->name, (unsigned char*)"many") != 0)
+		    continue;
+	
+		domain = xmlNodeGetAttrContentByName(node2, "domain");
+		if(domain == NULL) {
+		    LM_DBG("No domain attribute to many\n");
+		} else	{
+		    LM_DBG("<many domain= %s>\n", domain);
+		    if((strlen(domain)!= subs->from_domain.len && 
+			strncmp(domain, subs->from_domain.s,
+				subs->from_domain.len) )) {
+			xmlFree(domain);
+			continue;
+		    }	
+		}
+		xmlFree(domain);
+		apply_rule = 1;
+		if (node2->children == NULL)       /* there is no exception */
+		    break;
+
+		for (except_node = node2->children; except_node;
+		     except_node= except_node->next) {
+		    if(xmlStrcasecmp(except_node->name,
+				     (unsigned char*)"except"))
+			continue;
+
+		    id = xmlNodeGetAttrContentByName(except_node, "id");	
+		    if (id != NULL) {
+			if((strlen(id)- 1== w_uri.len && 
+			    (strncmp(id, w_uri.s, w_uri.len)==0))) {
+			    xmlFree(id);
+			    apply_rule = 0;
+			    break;
+			}
+			xmlFree(id);
+		    } else {
+			domain = NULL;
+			domain = xmlNodeGetAttrContentByName(except_node,
+							     "domain");
+			if(domain!=NULL) {
+			    LM_DBG("Found except domain= %s\n- strlen(domain)= %d\n",
+				   domain, (int)strlen(domain));
+			    if (strlen(domain)==subs->from_domain.len &&
+				(strncmp(domain,subs->from_domain.s ,
+					 subs->from_domain.len)==0)) {
+				LM_DBG("except domain match\n");
+				xmlFree(domain);
+				apply_rule = 0;
+				break;
+			    }
+			    xmlFree(domain);
+			}	
+		    }	
+		}
+		if (apply_rule == 1)  /* if a match was found no need to keep searching*/
+		    break;
+	    }
+	}
+	if (apply_rule ==1)
+	    break;
+    }
+
+    LM_DBG("apply_rule= %d\n", apply_rule);
+    if(w_uri.s!=NULL)
+	pkg_free(w_uri.s);
+
+    if( !apply_rule || !node1)
+	return NULL;
+    
+    return node1;
+
+ error:
+    if(w_uri.s)
+	pkg_free(w_uri.s);
+    return NULL;
+}
+
+int pres_watcher_allowed(subs_t* subs)
+{
+    xmlDocPtr xcap_tree= NULL;
+    xmlNodePtr node= NULL,  actions_node = NULL;
+    xmlNodePtr sub_handling_node = NULL;
+    char* sub_handling = NULL;
+	
+    subs->status= PENDING_STATUS;
+    subs->reason.s= NULL;
+    subs->reason.len= 0;
+
+    if (subs->auth_rules_doc== NULL)
+	return 0;
+
+    xcap_tree= xmlParseMemory(subs->auth_rules_doc->s,
+			      subs->auth_rules_doc->len);
+    if (xcap_tree== NULL) {
+	LM_ERR("parsing xml memory\n");
+	return -1;
+    }
+
+    node= get_rule_node(subs, xcap_tree);
+    if (node== NULL)
+	return 0;
+
+    /* process actions */	
+    actions_node = xmlNodeGetChildByName(node, "actions");
+    if (actions_node == NULL) {
+	LM_DBG("actions_node NULL\n");
+	return 0;
+    }
+    LM_DBG("actions_node->name= %s\n", actions_node->name);
+			
+    sub_handling_node = xmlNodeGetChildByName(actions_node, "sub-handling");
+    if (sub_handling_node== NULL) {
+	LM_DBG("sub_handling_node NULL\n");
+	return 0;
+    }
+    sub_handling = (char*)xmlNodeGetContent(sub_handling_node);
+    LM_DBG("sub_handling_node->name= %s\n", sub_handling_node->name);
+    LM_DBG("sub_handling_node->content= %s\n", sub_handling);
+	
+    if (sub_handling == NULL) {
+	LM_ERR("Couldn't get sub-handling content\n");
+	return -1;
+    }
+    if (strncmp((char*)sub_handling, "block", 5) == 0) {
+	subs->status = TERMINATED_STATUS;;
+	subs->reason.s= "rejected";
+	subs->reason.len = 8;
+    } else	
+	if (strncmp((char*)sub_handling, "confirm", 7) == 0) {
+	    subs->status = PENDING_STATUS;
+	} else
+	    if (strncmp((char*)sub_handling , "polite-block", 12) == 0) {
+		subs->status = ACTIVE_STATUS;
+		subs->reason.s= "polite-block";
+		subs->reason.len = 12;
+	    }
+	else
+	    if (strncmp((char*)sub_handling, "allow", 5) == 0) {
+		subs->status = ACTIVE_STATUS;
+		subs->reason.s = NULL;
+	    }
+	    else {
+		LM_ERR("unknown subscription handling action\n");
+		xmlFree(sub_handling);
+		return -1;
+	    }
+
+    xmlFree(sub_handling);
+
+    return 0;
+
+}
+
+int get_rules_doc(str* user, str* domain, int type, str** rules_doc)
+{
+    db_key_t query_cols[5];
+    db_val_t query_vals[5];
+    db_key_t result_cols[3];
+    int n_query_cols = 0;
+    db1_res_t *result = 0;
+    db_row_t *row;
+    db_val_t *row_vals;
+    str body;
+    str* doc= NULL;
+    int n_result_cols= 0, xcap_doc_col;
+    static str tmp1 = str_init("username");
+    static str tmp2 = str_init("domain");
+    static str tmp3 = str_init("doc_type");
+    static str tmp4 = str_init("doc");
+
+    LM_DBG("[user]= %.*s\t[domain]= %.*s", 
+	   user->len, user->s, domain->len, domain->s);
+
+    query_cols[n_query_cols] = &tmp1;
+    query_vals[n_query_cols].type = DB1_STRING;
+    query_vals[n_query_cols].nul = 0;
+    query_vals[n_query_cols].val.str_val = *user;
+    n_query_cols++;
+    
+    query_cols[n_query_cols] = &tmp2;
+    query_vals[n_query_cols].type = DB1_STRING;
+    query_vals[n_query_cols].nul = 0;
+    query_vals[n_query_cols].val.str_val = *domain;
+    n_query_cols++;
+    
+    query_cols[n_query_cols] = &tmp3;
+    query_vals[n_query_cols].type = DB1_INT;
+    query_vals[n_query_cols].nul = 0;
+    query_vals[n_query_cols].val.int_val= type;
+    n_query_cols++;
+
+    result_cols[xcap_doc_col= n_result_cols++] = &tmp4;
+	
+    if (pxml_dbf.use_table(pxml_db, &xcap_table) < 0) {
+	LM_ERR("in use_table-[table]= %.*s\n", xcap_table.len, xcap_table.s);
+	return -1;
+    }
+
+    if (pxml_dbf.query(pxml_db, query_cols, 0 , query_vals, result_cols, 
+		       n_query_cols, 1, 0, &result) < 0) {
+	LM_ERR("while querying table xcap for [user]=%.*s\t[domain]= %.*s\n",
+	       user->len, user->s, domain->len, domain->s);
+	if (result)
+	    pxml_dbf.free_result(pxml_db, result);
+	return -1;
+    }
+
+    if(result == NULL)
+	return -1;
+
+    if (result->n <= 0) {
+	LM_DBG("No document found in db table for [user]=%.*s"
+	       "\t[domain]= %.*s\t[doc_type]= %d\n",user->len, user->s,
+	       domain->len, domain->s, type);
+	pxml_dbf.free_result(pxml_db, result);
+	return 0;
+    }	
+	
+    row = &result->rows[xcap_doc_col];
+    row_vals = ROW_VALUES(row);
+
+    body.s = (char*)row_vals[0].val.string_val;
+    if (body.s== NULL) {
+	LM_ERR("Xcap doc NULL\n");
+	goto error;
+    }	
+    body.len = strlen(body.s);
+    if (body.len== 0) {
+	LM_ERR("Xcap doc empty\n");
+	goto error;
+    }			
+    LM_DBG("xcap document:\n%.*s", body.len,body.s);
+    
+    doc= (str*)pkg_malloc(sizeof(str));
+    if (doc== NULL) {
+	ERR_MEM(PKG_MEM_STR);
+    }
+    doc->s= (char*)pkg_malloc(body.len* sizeof(char));
+    if (doc->s== NULL) {
+	pkg_free(doc);
+	ERR_MEM(PKG_MEM_STR);
+    }
+    memcpy(doc->s, body.s, body.len);
+    doc->len= body.len;
+
+    *rules_doc= doc;
+
+    if (result)
+	pxml_dbf.free_result(pxml_db, result);
+
+    return 0;
+
+error:
+    if (result)
+	pxml_dbf.free_result(pxml_db, result);
+
+    return -1;
+
+}
+
+
+/* 
+ * Checks from presence server xcap table if watcher is authorized
+ * to subscribe event 'presence' of presentity.
+ */
+int xcap_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2)
+{
+    pv_spec_t *sp;
+    pv_value_t pv_val;
+    str watcher_uri, presentity_uri;
+    struct sip_uri uri;
+    str* rules_doc = NULL;
+    subs_t subs;
+    int res;
+
+    if (pxml_db == 0) {
+	LM_ERR("function is disabled, to enable define pres_db_url\n");
+	return -1;
+    }
+
+    sp = (pv_spec_t *)_sp1;
+
+    if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
+	if (pv_val.flags & PV_VAL_STR) {
+	    watcher_uri = pv_val.rs;
+	    if (watcher_uri.len == 0 || watcher_uri.s == NULL) {
+		LM_ERR("missing watcher uri\n");
+		return -1;
+	    }
+	} else {
+	    LM_ERR("watcher pseudo variable value is not string\n");
+	    return -1;
+	}
+    } else {
+	LM_ERR("cannot get watcher pseudo variable value\n");
+	return -1;
+    }
+
+    sp = (pv_spec_t *)_sp2;
+
+    if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
+	if (pv_val.flags & PV_VAL_STR) {
+	    presentity_uri = pv_val.rs;
+	    if (presentity_uri.len == 0 || presentity_uri.s == NULL) {
+		LM_DBG("missing presentity uri\n");
+		return -1;
+	    }
+	} else {
+	    LM_ERR("presentity pseudo variable value is not string\n");
+	    return -1;
+	}
+    } else {
+	LM_ERR("cannot get presentity pseudo variable value\n");
+	return -1;
+    }
+
+    if (parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
+	LM_ERR("failed to parse presentity uri\n");
+	return -1;
+    }
+    res = get_rules_doc(&uri.user, &uri.host, PRES_RULES, &rules_doc);
+    if ((res < 0) || (rules_doc == NULL) || (rules_doc->s == NULL)) {
+	LM_DBG("no xcap rules doc found for presentity uri\n");
+	return PENDING_STATUS;
+    }
+
+    if (parse_uri(watcher_uri.s, watcher_uri.len, &uri) < 0) {
+	LM_ERR("failed to parse watcher uri\n");
+	goto err;
+    }
+
+    subs.from_user = uri.user;
+    subs.from_domain = uri.host;
+    subs.pres_uri = presentity_uri;
+    subs.auth_rules_doc = rules_doc;
+    if (pres_watcher_allowed(&subs) < 0) {
+	LM_ERR("getting status from rules document\n");
+	goto err;
+    }
+    LM_DBG("auth status of watcher <%.*s> on presentity <%.*s> is %d\n",
+	   watcher_uri.len, watcher_uri.s, presentity_uri.len, presentity_uri.s,
+	   subs.status);
+    pkg_free(rules_doc->s);
+    pkg_free(rules_doc);
+    return subs.status;
+
+ err:
+    pkg_free(rules_doc->s);
+    pkg_free(rules_doc);
+    return -1;
+}

+ 38 - 0
modules/utils/xcap_auth.h

@@ -0,0 +1,38 @@
+/*
+ * headers of xcap_auth functions of utils module
+ *
+ * Copyright (C) 2009 Juha Heinanen
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio 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
+ *
+ * Kamailio 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_AUTH_FUNCTIONS_H
+#define XCAP_AUTH_FUNCTIONS_H
+
+#include "../../parser/msg_parser.h"
+
+
+/* 
+ * Checks from presence server xcap table if watcher is authorized
+ * to subscribe event 'presence' of presentity.
+ */
+int xcap_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2);
+
+
+#endif /* XCAP_AUTH_FUNCTIONS_H */