Selaa lähdekoodia

* Module: presence

Introduced a dew function auth_status() that can be used to check from
script if a watcher is allowed to subscriber event 'presence' of a
presentity.
Juha Heinanen 16 vuotta sitten
vanhempi
commit
c737bb20f2

+ 127 - 101
modules_k/presence/README

@@ -1,19 +1,28 @@
-
 Presence Module
 
 Anca-Maria Vamanu
 
    voice-system.ro
 
+Juha Heinanen
+
+   TutPro Inc.
+
 Edited by
 
 Anca-Maria Vamanu
 
+Edited by
+
+Juha Heinanen
+
    Copyright © 2006 voice-system.ro
+
+   Copyright © 2009 Juha Heinanen
    Revision History
-   Revision $Revision$ $Date: 2008-08-06 12:08:33 +0200
-   (Wed, 06 Aug 2008) $
-     _________________________________________________________
+   Revision $Revision: 4594 $ $Date: 2008-08-06 13:08:33 +0300
+                              (Wed, 06 Aug 2008) $
+     __________________________________________________________
 
    Table of Contents
 
@@ -44,33 +53,34 @@ Anca-Maria Vamanu
 
         1.4. Exported Functions
 
-              1.4.1. handle_publish(char* sender_uri) 
-              1.4.2. handle_subscribe() 
+              1.4.1. handle_publish(char* sender_uri)
+              1.4.2. handle_subscribe()
+              1.4.3. auth_status(watcher_uri, presentity_uri)
 
         1.5. Exported MI Functions
 
-              1.5.1. refreshWatchers 
-              1.5.2. cleanup 
+              1.5.1. refreshWatchers
+              1.5.2. cleanup
 
         1.6. Installation
 
    2. Developer Guide
 
-        2.1. bind_presence(presence_api_t* api) 
-        2.2. add_event 
-        2.3. get_rules_doc 
-        2.4. get_auth_status 
-        2.5. apply_auth_nbody 
-        2.6. agg_nbody 
-        2.7. free_body 
-        2.8. aux_body_processing 
-        2.9. aux_free_body 
-        2.10. evs_publ_handl 
-        2.11. evs_subs_handl 
-        2.12. contains_event 
-        2.13. get_event_list 
-        2.14. update_watchers_status 
-        2.15. get_sphere 
+        2.1. bind_presence(presence_api_t* api)
+        2.2. add_event
+        2.3. get_rules_doc
+        2.4. get_auth_status
+        2.5. apply_auth_nbody
+        2.6. agg_nbody
+        2.7. free_body
+        2.8. aux_body_processing
+        2.9. aux_free_body
+        2.10. evs_publ_handl
+        2.11. evs_subs_handl
+        2.12. contains_event
+        2.13. get_event_list
+        2.14. update_watchers_status
+        2.15. get_sphere
 
    List of Examples
 
@@ -90,6 +100,7 @@ Anca-Maria Vamanu
    1.14. Set enable_sphere_check parameter
    1.15. handle_publish usage
    1.16. handle_subscribe usage
+   1.17. auth_status usage
    2.1. presence_api_t structure
 
 Chapter 1. Admin Guide
@@ -104,19 +115,18 @@ Chapter 1. Admin Guide
    presence, presence.winfo, dialog;sla from the presence_xml
    module and message-summary from the presence_mwi module.
 
-   The module uses database storage and memory caching (to
-   improve performance). The SIP SUBSCRIBE dialog information is
-   stored in memory and is periodically updated in the database,
-   while for PUBLISH only the presence or absence of stored info
-   for a certain resource is maintained in memory to avoid
-   unnecessary, costly database operations. It is possible to
-   disable in-memory caching by configurng a fallback to database
-   mode (by setting module parameter "fallback2db"). In this
-   mode, in case a searched record is not found in cache, the
-   search is continued in database. This is useful for an
-   architecture in which processing and memory load might be
-   divided on several Kamailio instances, maybe on different
-   servers using the same database.
+   The module uses database storage and memory caching (to improve
+   performance). The SIP SUBSCRIBE dialog information is stored in
+   memory and is periodically updated in the database, while for
+   PUBLISH only the presence or absence of stored info for a
+   certain resource is maintained in memory to avoid unnecessary,
+   costly database operations. It is possible to disable in-memory
+   caching by configurng a fallback to database mode (by setting
+   module parameter "fallback2db"). In this mode, in case a
+   searched record is not found in cache, the search is continued
+   in database. This is useful for an architecture in which
+   processing and memory load might be divided on several Kamailio
+   instances, maybe on different servers using the same database.
 
    The module implements several API functions, that can be used
    by other modules. In fact, it can be used only as a resource
@@ -149,7 +159,7 @@ Chapter 1. Admin Guide
    Otherwise, it is used as a 'library', for its exported
    functions.
 
-   Default value is "NULL". 
+   Default value is "NULL".
 
    Example 1.1. Set db_url parameter
 ...
@@ -162,7 +172,7 @@ modparam("presence", "db_url",
    The name of the db table where PUBLISH presence information is
    stored.
 
-   Default value is "presentity". 
+   Default value is "presentity".
 
    Example 1.2. Set presentity_table parameter
 ...
@@ -174,7 +184,7 @@ modparam("presence", "presentity_table", "presentity")
    The name of the db table where active subscription information
    is stored.
 
-   Default value is "active_watchers". 
+   Default value is "active_watchers".
 
    Example 1.3. Set active_watchers_table parameter
 ...
@@ -185,7 +195,7 @@ modparam("presence", "active_watchers_table", "active_watchers")
 
    The name of the db table where subscription states are stored.
 
-   Default value is "watchers". 
+   Default value is "watchers".
 
    Example 1.4. Set watchers_table parameter
 ...
@@ -198,7 +208,7 @@ modparam("presence", "watchers_table", "watchers")
    messages stored in database.
 
    Default value is "100". A zero or negative value disables this
-   activity. 
+   activity.
 
    Example 1.5. Set clean_period parameter
 ...
@@ -211,7 +221,7 @@ modparam("presence", "clean_period", 100)
    the database.
 
    Default value is "100". A zero or negative value disables
-   synchronization. 
+   synchronization.
 
    Example 1.6. Set db_update_period parameter
 ...
@@ -220,10 +230,10 @@ modparam("presence", "db_update_period", 100)
 
 1.3.7. to_tag_pref (str)
 
-   The prefix used when generating to_tag when sending replies
-   for SUBSCRIBE requests.
+   The prefix used when generating to_tag when sending replies for
+   SUBSCRIBE requests.
 
-   Default value is "10". 
+   Default value is "10".
 
    Example 1.7. Set to_tag_pref parameter
 ...
@@ -232,12 +242,12 @@ modparam("presence", "to_tag_pref", 'pres')
 
 1.3.8. expires_offset (int)
 
-   The value in seconds that should be subtracted from the
-   expires value when sending a 200OK for a publish. It is used
-   for forcing the client cu send an update before the old
-   publish expires.
+   The value in seconds that should be subtracted from the expires
+   value when sending a 200OK for a publish. It is used for
+   forcing the client cu send an update before the old publish
+   expires.
 
-   Default value is "0". 
+   Default value is "0".
 
    Example 1.8. Set expires_offset parameter
 ...
@@ -249,7 +259,7 @@ modparam("presence", "expires_offset", 10)
    The the maximum admissible expires value for PUBLISH/SUBSCRIBE
    message (in seconds).
 
-   Default value is "3600". 
+   Default value is "3600".
 
    Example 1.9. Set max_expires parameter
 ...
@@ -259,8 +269,8 @@ modparam("presence", "max_expires", 3600)
 1.3.10. server_address (str)
 
    The presence server address which will become the value of
-   Contact header filed for 200OK replies to Subscribe and
-   Publish and in Notify messages.
+   Contact header filed for 200OK replies to Subscribe and Publish
+   and in Notify messages.
 
    Example 1.10. Set server_address parameter
 ...
@@ -270,10 +280,10 @@ modparam("presence", "server_address", "sip:10.10.10.10:5060")
 1.3.11. fallback2db (int)
 
    Setting this parameter enables a fallback to db mode of
-   operation. In this mode, in case a searched record is not
-   found in cache, the search is continued in database. Useful
-   for an architecture in which processing and memory load might
-   be divided on more servers using the same database.
+   operation. In this mode, in case a searched record is not found
+   in cache, the search is continued in database. Useful for an
+   architecture in which processing and memory load might be
+   divided on more servers using the same database.
 
    Example 1.11. Set fallback2db parameter
 ...
@@ -286,7 +296,7 @@ modparam("presence", "fallback2db", 1)
    dialogs. This parameter will be used as the power of 2 when
    computing table size.
 
-   Default value is "9 (512)". 
+   Default value is "9 (512)".
 
    Example 1.12. Set subs_htable_size parameter
 ...
@@ -299,7 +309,7 @@ modparam("presence", "subs_htable_size", 11)
    This parameter will be used as the power of 2 when computing
    table size.
 
-   Default value is "9 (512)". 
+   Default value is "9 (512)".
 
    Example 1.13. Set pres_htable_size parameter
 ...
@@ -308,14 +318,14 @@ modparam("presence", "pres_htable_size", 11)
 
 1.3.14. enable_sphere_check (int)
 
-   This parameter is a flag that should be set if permission
-   rules include sphere checking. The sphere information is
-   expected to be present in the RPID body published by the
-   presentity. The flag is introduced as this check requires
-   extra processing that should be avoided if this feature is not
-   supported by the clients.
+   This parameter is a flag that should be set if permission rules
+   include sphere checking. The sphere information is expected to
+   be present in the RPID body published by the presentity. The
+   flag is introduced as this check requires extra processing that
+   should be avoided if this feature is not supported by the
+   clients.
 
-   Default value is "0 ". 
+   Default value is "0 ".
 
    Example 1.14. Set enable_sphere_check parameter
 ...
@@ -379,6 +389,25 @@ if(method=="SUBSCRIBE")
     handle_subscribe();
 ...
 
+1.4.3.  auth_status(watcher_uri, presentity_uri)
+
+   The function checks if watcher is authorized to subscribe
+   presence of presentity. 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.
+
+   This function can be used from REQUEST_ROUTE.
+
+   Example 1.17. auth_status usage
+...
+if((method=="MESSAGE") && (auth_status("$fu", $ru"))) {
+    t_relay();
+}
+...
+
 1.5. Exported MI Functions
 
 1.5.1.  refreshWatchers
@@ -394,8 +423,7 @@ if(method=="SUBSCRIBE")
      * event : the event package
      * refresh type : it distinguishes between the two different
        types of events that can trigger a refresh:
-          + a change in watchers authentication: refresh type= 0
-            ;
+          + a change in watchers authentication: refresh type= 0 ;
           + a statical update in published state (either through
             direct update in db table or by modifying the pidf
             manipulation document, if pidf_manipulation parameter
@@ -422,7 +450,6 @@ if(method=="SUBSCRIBE")
                 :cleanup:fifo_reply
                 _empty_line_
 
-
 1.6. Installation
 
    The module requires 3 tables in the Kamailio database:
@@ -435,8 +462,8 @@ if(method=="SUBSCRIBE")
 
 Chapter 2. Developer Guide
 
-   The module provides the following functions that can be used
-   in other Kamailio modules.
+   The module provides the following functions that can be used in
+   other Kamailio modules.
 
 2.1.  bind_presence(presence_api_t* api)
 
@@ -515,21 +542,21 @@ typedef struct pres_ev
         publ_handling_t  * evs_publ_handl;
         subs_handling_t  * evs_subs_handl;
         free_body_t* free_body;
-    /* sometimes it is necessary that a module make changes for a body
-for each
-     * active watcher (e.g. setting the "version" parameter in an XML d
-ocument.
-     * If a module registers the aux_body_processing callback, it gets
-called for
-     * each watcher. It either gets the body received by the PUBLISH, o
-r the body
+    /* sometimes it is necessary that a module make changes for a body f
+or each
+     * active watcher (e.g. setting the "version" parameter in an XML do
+cument.
+     * If a module registers the aux_body_processing callback, it gets c
+alled for
+     * each watcher. It either gets the body received by the PUBLISH, or
+ the body
      * generated by the agg_nbody function.
-     * The module can deceide if it makes a copy of the original body,
-which is then
-     * manipulated, or if it works directly in the original body. If th
-e module makes a
-     * copy of the original body, it also has to register the aux_free_
-body() to
+     * The module can deceide if it makes a copy of the original body, w
+hich is then
+     * manipulated, or if it works directly in the original body. If the
+ module makes a
+     * copy of the original body, it also has to register the aux_free_b
+ody() to
      * free this "per watcher" body.
      */
     aux_body_processing_t* aux_body_processing;
@@ -573,8 +600,8 @@ typedef int (is_allowed_t)(struct subscription* subs);
    This parameter should be a function to be called for an event
    that requires authorization, when constructing final body. The
    authorization document is taken from the auth_rules_doc field
-   of the subs_t structure given as a parameter. It is called
-   only if the req_auth field is not 0.
+   of the subs_t structure given as a parameter. It is called only
+   if the req_auth field is not 0.
 
    Filed type:
 ...
@@ -586,9 +613,8 @@ typedef int (apply_auth_t)(str* , struct subscription*, str** );
    If present, this field marks that the events requires
    aggregation of states. This function receives a body array and
    should return the final body. If not present, it is considered
-   that the event does not require aggregation and the most
-   recent published information is used when constructing
-   Notifies.
+   that the event does not require aggregation and the most recent
+   published information is used when constructing Notifies.
 
    Filed type:
 ...
@@ -600,9 +626,9 @@ str** body_array, int n, int off_index);
 
    This field must be field in if subsequent processing is
    performed on the info from database before being inserted in
-   Notify message body(if agg_nbody or apply_auth_nbody fields
-   are filled in). It should match the allocation function used
-   when processing the body.
+   Notify message body(if agg_nbody or apply_auth_nbody fields are
+   filled in). It should match the allocation function used when
+   processing the body.
 
    Filed type:
 ...
@@ -613,16 +639,16 @@ typedef void(free_body_t)(char* body);
 
    This field must be set if the module needs to manipulate the
    NOTIFY body for each watcher. E.g. if the XML body includes a
-   'version' parameter which will be increased for each NOTIFY,
-   on a "per watcher" basis. The module can either allocate a new
+   'version' parameter which will be increased for each NOTIFY, on
+   a "per watcher" basis. The module can either allocate a new
    buffer for the new body an return it (aux_free_body function
    must be set too) or it manipualtes the original body directly
    and returns NULL.
 
    Filed type:
 ...
-typedef str* (aux_body_processing_t)(struct subscription *subs, str* bo
-dy);
+typedef str* (aux_body_processing_t)(struct subscription *subs, str* bod
+y);
 ..
 
 2.9.  aux_free_body
@@ -706,7 +732,7 @@ str* rules_doc);
 typedef char* (*pres_get_sphere_t)(str* pres_uri);
 ...
 
-   This function searches for a sphere definition in the
-   published information if this has type RPID. If not found
-   returns NULL. (the return value is allocated in private memory
-   and should be freed)
+   This function searches for a sphere definition in the published
+   information if this has type RPID. If not found returns NULL.
+   (the return value is allocated in private memory and should be
+   freed)

+ 21 - 2
modules_k/presence/doc/presence.xml

@@ -28,6 +28,14 @@
 		</otheraddr>
 		</address>
 	    </author>
+	    <author>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<affiliation><orgname>TutPro Inc.</orgname></affiliation>
+		<address>
+		<email>[email protected]</email>
+		</address>
+	    </author>
 	    <editor>
 		<firstname>Anca-Maria</firstname>
 		<surname>Vamanu</surname>
@@ -35,15 +43,26 @@
 		    <email>[email protected]</email>
 		</address>
 	    </editor>
+	    <editor>
+		<firstname>Juha</firstname>
+		<surname>Heinanen</surname>
+		<address>
+		    <email>[email protected]</email>
+		</address>
+	    </editor>
 	</authorgroup>
 	<copyright>
 	    <year>2006</year>
 	    <holder>&voicesystem;</holder>
 	</copyright>
+	<copyright>
+	    <year>2009</year>
+	    <holder>Juha Heinanen</holder>
+	</copyright>
 	<revhistory>
 	    <revision>
-		<revnumber>$Revision$</revnumber>
-		<date>$Date$</date>
+		<revnumber>$Revision: 4594 $</revnumber>
+		<date>$Date: 2008-08-06 13:08:33 +0300 (Wed, 06 Aug 2008) $</date>
 	    </revision>
 	</revhistory>
   </bookinfo>

+ 30 - 0
modules_k/presence/doc/presence_admin.xml

@@ -449,6 +449,36 @@ modparam("presence", "enable_sphere_check", 1)
 if(method=="SUBSCRIBE")
     handle_subscribe();
 ...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title>
+		<function moreinfo="none">auth_status(watcher_uri, presentity_uri)</function>
+		</title>
+		<para>
+		The function checks if watcher is authorized to subscribe
+		presence of presentity.  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>
+		This function can be used from REQUEST_ROUTE.
+		</para>
+
+		<example>
+		<title><function>auth_status</function> usage</title>
+		<programlisting format="linespecific">
+...
+if((method=="MESSAGE") &amp;&amp; (auth_status("$fu", $ru"))) {
+    t_relay();
+}
+...
 </programlisting>
 		</example>
 	</section>

+ 96 - 0
modules_k/presence/presence.c

@@ -74,6 +74,7 @@
 #include "event_list.h"
 #include "bind_presence.h"
 #include "notify.h"
+#include "../../mod_fix.h"
 
 MODULE_VERSION
 
@@ -117,6 +118,7 @@ static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param);
 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array);
 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc);
 static int mi_child_init(void);
+static int auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2);
 
 int counter =0;
 int pid = 0;
@@ -138,6 +140,7 @@ static cmd_export_t cmds[]=
 	{"handle_publish",  (cmd_function)handle_publish,  0,fixup_presence,0, REQUEST_ROUTE},
 	{"handle_publish",  (cmd_function)handle_publish,  1,fixup_presence, 0, REQUEST_ROUTE},
 	{"handle_subscribe",(cmd_function)handle_subscribe,0,fixup_subscribe,0, REQUEST_ROUTE},
+ 	{"auth_status",     (cmd_function)auth_status, 2, fixup_pvar_pvar, fixup_free_pvar_pvar, REQUEST_ROUTE},
 	{"bind_presence",   (cmd_function)bind_presence,   1,     0,         0,  0},
 	{ 0,                    0,                         0,     0,         0,  0}
 };
@@ -1074,3 +1077,96 @@ static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs
 	
     return 0;
 }
+
+static int auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2)
+{
+    pv_spec_t *sp;
+    pv_value_t pv_val;
+    str watcher_uri, presentity_uri, event;
+    struct sip_uri uri;
+    pres_ev_t* ev;
+    str* rules_doc = NULL;
+    subs_t subs;
+    int res;
+
+    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;
+    }
+
+    event.s = "presence";
+    event.len = 8;
+
+    ev = contains_event(&event, NULL);
+    if (ev == NULL) {
+	LM_ERR("event is not registered\n");
+	return -1;
+    }
+    if (ev->get_rules_doc == NULL) {
+	LM_DBG("event does not require authorization");
+	return ACTIVE_STATUS;
+    }
+    if (parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
+	LM_ERR("failed to parse presentity uri\n");
+	return -1;
+    }
+    res = ev->get_rules_doc(&uri.user, &uri.host, &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 (ev->get_auth_status(&subs) < 0) {
+	LM_ERR( "getting status from rules document\n");
+	goto err;
+    }
+    LM_INFO("subs.status= %d\n", 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;
+}