Kaynağa Gözat

modules_k/rls: added DB only mode to rls

- By using DB only mode RLS can be distributed across many Kamailio
  servers for scaling and resilience.
- This change has been in use internally at Crocodile RCS for some time,
  but it is extensive.
- The DB only mode changes have been made in a way that changes the pre-
  existing (hash-table based) mode of operation as little as possible.
  This original mode of operation SHOULD be unaffected by this change.
- This enhancement was made by Paul Pankhurst at Crocodile RCS.
- Also contains a small bug-fix to RLS indices by Hugh Waite.
- I have also exported the RLS API for use in app_lua
pd 14 yıl önce
ebeveyn
işleme
7665c7947f

+ 215 - 158
modules_k/rls/README

@@ -1,3 +1,4 @@
+
 Resource List Server
 
 Anca-Maria Vamanu
@@ -8,8 +9,8 @@ Edited by
 
 Anca-Maria Vamanu
 
-   Copyright © 2007 Voice Sistem SRL
-     __________________________________________________________________
+   Copyright © 2007 Voice Sistem SRL
+     _________________________________________________________________
 
    Table of Contents
 
@@ -24,26 +25,29 @@ Anca-Maria Vamanu
         3. Parameters
 
               3.1. db_url(str)
-              3.2. xcap_table(str)
-              3.3. rlsubs_table(str)
-              3.4. rlpres_table(str)
-              3.5. clean_period (int)
-              3.6. waitn_time (int)
-              3.7. max_expires (int)
-              3.8. hash_size (int)
-              3.9. xcap_root (str)
-              3.10. integrated_xcap_server (int)
-              3.11. to_presence_code (int)
-              3.12. rls_event (str)
-              3.13. outbound_proxy (str)
-              3.14. server_address (str)
-              3.15. max_notify_body_length (int)
+              3.2. xcap_db_url(str)
+              3.3. db_mode(int)
+              3.4. xcap_table(str)
+              3.5. rlsubs_table(str)
+              3.6. rlpres_table(str)
+              3.7. clean_period (int)
+              3.8. waitn_time (int)
+              3.9. max_expires (int)
+              3.10. expires_offset (int)
+              3.11. hash_size (int)
+              3.12. xcap_root (str)
+              3.13. integrated_xcap_server (int)
+              3.14. to_presence_code (int)
+              3.15. rls_event (str)
+              3.16. outbound_proxy (str)
+              3.17. server_address (str)
+              3.18. max_notify_body_length (int)
 
         4. Functions
 
-              4.1. rls_handle_subscribe()
-              4.2. rls_handle_notify()
-              4.3. rls_update_subs(uri, event)
+              4.1. rls_handle_subscribe() 
+              4.2. rls_handle_notify() 
+              4.3. rls_update_subs(uri, event) 
 
         5. Installation
 
@@ -52,23 +56,26 @@ Anca-Maria Vamanu
    List of Examples
 
    1.1. Set db_url parameter
-   1.2. Set xcap_table parameter
-   1.3. Set rlsubs_table parameter
-   1.4. Set rlpres_table parameter
-   1.5. Set clean_period parameter
-   1.6. Set waitn_time parameter
-   1.7. Set max_expires parameter
-   1.8. Set hash_size parameter
-   1.9. Set hash_size parameter
-   1.10. Set integrated_xcap_server parameter
-   1.11. Set to_presence_code parameter
-   1.12. Set rls_event parameter
-   1.13. Set outbound_proxy parameter
-   1.14. Set server_address parameter
-   1.15. Set max_notify_body_length parameter
-   1.16. rls_handle_subscribe usage
-   1.17. rls_handle_notify usage
-   1.18. rls_update_subs usage
+   1.2. Set xcap_db_url parameter
+   1.3. Set db_mode parameter
+   1.4. Set xcap_table parameter
+   1.5. Set rlsubs_table parameter
+   1.6. Set rlpres_table parameter
+   1.7. Set clean_period parameter
+   1.8. Set waitn_time parameter
+   1.9. Set max_expires parameter
+   1.10. Set expires_offset parameter
+   1.11. Set hash_size parameter
+   1.12. Set hash_size parameter
+   1.13. Set integrated_xcap_server parameter
+   1.14. Set to_presence_code parameter
+   1.15. Set rls_event parameter
+   1.16. Set outbound_proxy parameter
+   1.17. Set server_address parameter
+   1.18. Set max_notify_body_length parameter
+   1.19. rls_handle_subscribe usage
+   1.20. rls_handle_notify usage
+   1.21. rls_update_subs usage
 
 Chapter 1. Admin Guide
 
@@ -83,57 +90,60 @@ Chapter 1. Admin Guide
    3. Parameters
 
         3.1. db_url(str)
-        3.2. xcap_table(str)
-        3.3. rlsubs_table(str)
-        3.4. rlpres_table(str)
-        3.5. clean_period (int)
-        3.6. waitn_time (int)
-        3.7. max_expires (int)
-        3.8. hash_size (int)
-        3.9. xcap_root (str)
-        3.10. integrated_xcap_server (int)
-        3.11. to_presence_code (int)
-        3.12. rls_event (str)
-        3.13. outbound_proxy (str)
-        3.14. server_address (str)
-        3.15. max_notify_body_length (int)
+        3.2. xcap_db_url(str)
+        3.3. db_mode(int)
+        3.4. xcap_table(str)
+        3.5. rlsubs_table(str)
+        3.6. rlpres_table(str)
+        3.7. clean_period (int)
+        3.8. waitn_time (int)
+        3.9. max_expires (int)
+        3.10. expires_offset (int)
+        3.11. hash_size (int)
+        3.12. xcap_root (str)
+        3.13. integrated_xcap_server (int)
+        3.14. to_presence_code (int)
+        3.15. rls_event (str)
+        3.16. outbound_proxy (str)
+        3.17. server_address (str)
+        3.18. max_notify_body_length (int)
 
    4. Functions
 
-        4.1. rls_handle_subscribe()
-        4.2. rls_handle_notify()
-        4.3. rls_update_subs(uri, event)
+        4.1. rls_handle_subscribe() 
+        4.2. rls_handle_notify() 
+        4.3. rls_update_subs(uri, event) 
 
    5. Installation
 
 1. Overview
 
-   The modules is a Resource List Server implementation following the
+   The  modules  is  a  Resource List Server implementation following the
    specification in RFC 4662 and RFC 4826.
 
-   The server is independent from local presence servers, retrieving
+   The  server  is  independent  from  local presence servers, retrieving
    presence information with Subscribe-Notify messages.
 
-   The module uses the presence module as a library, as it requires a
-   resembling mechanism for handling Subscribe. Therefore, in case the
-   local presence server is not collocated on the same machine with the RL
-   server, the presence module should be loaded in a library mode only
+   The  module  uses  the  presence module as a library, as it requires a
+   resembling  mechanism  for  handling Subscribe. Therefore, in case the
+   local  presence  server is not collocated on the same machine with the
+   RL server, the presence module should be loaded in a library mode only
    (see doc for presence module).
 
-   It handles subscription to lists in an event independent way.The
-   default event is presence, but if some other events are to be handled
-   by the server, they should be added using the module parameter
+   It  handles  subscription  to  lists  in  an event independent way.The
+   default  event is presence, but if some other events are to be handled
+   by  the  server,  they  should  be  added  using  the module parameter
    "rls_events".
 
-   It works with XCAP server for storage. There is also the possibility to
-   configure it to work in an integrated_xcap server mode, when it only
-   queries database for the resource lists documents. This is useful in a
-   small architecture when all the clients use an integrated server and
-   there are no references to exterior documents in their lists.
+   It  works  with XCAP server for storage. There is also the possibility
+   to  configure  it  to  work in an integrated_xcap server mode, when it
+   only queries database for the resource lists documents. This is useful
+   in  a small architecture when all the clients use an integrated server
+   and there are no references to exterior documents in their lists.
 
-   The same as presence module, it has a caching mode with periodical
-   update in database for subscribe information. The information retrieved
-   with Notify messages is stored in database only.
+   The  same  as  presence  module, it has a caching mode with periodical
+   update   in   database  for  subscribe  information.  The  information
+   retrieved with Notify messages is stored in database only.
 
 2. Dependencies
 
@@ -156,219 +166,266 @@ Chapter 1. Admin Guide
 3. Parameters
 
    3.1. db_url(str)
-   3.2. xcap_table(str)
-   3.3. rlsubs_table(str)
-   3.4. rlpres_table(str)
-   3.5. clean_period (int)
-   3.6. waitn_time (int)
-   3.7. max_expires (int)
-   3.8. hash_size (int)
-   3.9. xcap_root (str)
-   3.10. integrated_xcap_server (int)
-   3.11. to_presence_code (int)
-   3.12. rls_event (str)
-   3.13. outbound_proxy (str)
-   3.14. server_address (str)
-   3.15. max_notify_body_length (int)
+   3.2. xcap_db_url(str)
+   3.3. db_mode(int)
+   3.4. xcap_table(str)
+   3.5. rlsubs_table(str)
+   3.6. rlpres_table(str)
+   3.7. clean_period (int)
+   3.8. waitn_time (int)
+   3.9. max_expires (int)
+   3.10. expires_offset (int)
+   3.11. hash_size (int)
+   3.12. xcap_root (str)
+   3.13. integrated_xcap_server (int)
+   3.14. to_presence_code (int)
+   3.15. rls_event (str)
+   3.16. outbound_proxy (str)
+   3.17. server_address (str)
+   3.18. max_notify_body_length (int)
 
 3.1. db_url(str)
 
    The database url.
 
-   Default value is “mysql://openser:openserrw@localhost/openser�.
+   Default value is "mysql://openser:openserrw@localhost/openser". 
 
    Example 1.1. Set db_url parameter
 ...
 modparam("rls", "db_url", "dbdriver://username:password@dbhost/dbname")
 ...
 
-3.2. xcap_table(str)
+3.2. xcap_db_url(str)
+
+   The  xcap  database  url. This parameter only needs to be specified if
+   the rls db and integerated xcap server db have different urls.
+
+   Default value is a mirror of the "db_url" setting. 
+
+   Example 1.2. Set xcap_db_url parameter
+...
+modparam("rls", "xcap_db_url", "dbdriver://username:password@dbhost/dbname")
+...
+
+3.3. db_mode(int)
+
+   The  module  supports  2  modes  of operation, high speed memory based
+   storage  (mode 0), and database only (mode 2) where all data is stored
+   in a database, allowing scalability at the expense of speed. Mode 1 is
+   reserved.
 
-   The name of the xcap table in which the integrated server or the
-   xcap_client module writes. If integrated_xcap_server parameter not set,
-   the name of the table must be the same as the one set for the
+   Default value is "0" 
+
+   Example 1.3. Set db_mode parameter
+...
+modparam("rls", "db_mode", 2)
+...
+
+3.4. xcap_table(str)
+
+   The  name  of  the  xcap  table  in which the integrated server or the
+   xcap_client  module  writes.  If  integrated_xcap_server parameter not
+   set,  the  name  of  the table must be the same as the one set for the
    xcap_client module.
 
-   Default value is “xcap�.
+   Default value is "xcap". 
 
-   Example 1.2. Set xcap_table parameter
+   Example 1.4. Set xcap_table parameter
 ...
 modparam("rls", "xcap_table", "xcaps");
 ...
 
-3.3. rlsubs_table(str)
+3.5. rlsubs_table(str)
 
    The name of the db table where resource lists subscription information
    is stored.
 
-   Default value is “rls_watchers�.
+   Default value is "rls_watchers". 
 
-   Example 1.3. Set rlsubs_table parameter
+   Example 1.5. Set rlsubs_table parameter
 ...
 modparam("rls", "rlsubs_table", "rls_subscriptions")
 ...
 
-3.4. rlpres_table(str)
+3.6. rlpres_table(str)
 
-   The name of the db table where notified event specific information is
+   The  name of the db table where notified event specific information is
    stored.
 
-   Default value is “rls_presentity�.
+   Default value is "rls_presentity". 
 
-   Example 1.4. Set rlpres_table parameter
+   Example 1.6. Set rlpres_table parameter
 ...
 modparam("rls", "rlpres_table", "rls_notify")
 ...
 
-3.5. clean_period (int)
+3.7. clean_period (int)
 
    The period at which to check for expired information.
 
-   Default value is “100�.
+   Default value is "100". 
 
-   Example 1.5. Set clean_period parameter
+   Example 1.7. Set clean_period parameter
 ...
 modparam("rls", "clean_period", 100)
 ...
 
-3.6. waitn_time (int)
+3.8. waitn_time (int)
 
-   The timer period at which the server should attempt to send Notifies
-   with the updated presence state of the subscribed list or watcher
+   The  timer  period at which the server should attempt to send Notifies
+   with  the  updated  presence  state  of the subscribed list or watcher
    information.
 
-   Default value is “50�.
+   Default value is "50". 
 
-   Example 1.6. Set waitn_time parameter
+   Example 1.8. Set waitn_time parameter
 ...
 modparam("rls", "waitn_time", 10)
 ...
 
-3.7. max_expires (int)
+3.9. max_expires (int)
 
    The maximum accepted expires for a subscription to a list.
 
-   Default value is “7200�.
+   Default value is "7200". 
 
-   Example 1.7. Set max_expires parameter
+   Example 1.9. Set max_expires parameter
 ...
 modparam("rls", "max_expires", 10800)
 ...
 
-3.8. hash_size (int)
+3.10. expires_offset (int)
+
+   This  paramater  only  has an effect when the db_mode is DB_ONLY (mode
+   2).  When  expired  subscribers  are  checked  for  deletion  from the
+   database,  those that have a value in the expires column which is less
+   than  current_time  - expires_offset are matched. Hence when an offset
+   of  zero is used, all those that expire prior the current time will be
+   deleted.  If  an  offset  of 't' is used, only those that expired more
+   than t seconds ago are deleted from the database. Negative offsets are
+   treated as though an offset of zero was specifed.
+
+   Default value is "0". 
+
+   Example 1.10. Set expires_offset parameter
+...
+modparam("rls", "expires_offset", 0)
+...
+
+3.11. hash_size (int)
 
-   The dimension of the hash table used to store subscription to a list.
-   This parameter will be used as the power of 2 when computing table
+   The  dimension of the hash table used to store subscription to a list.
+   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.8. Set hash_size parameter
+   Example 1.11. Set hash_size parameter
 ...
 modparam("rls", "hash_size", 11)
 ...
 
-3.9. xcap_root (str)
+3.12. xcap_root (str)
 
    The address of the xcap server.
 
-   Default value is “NULL�.
+   Default value is "NULL". 
 
-   Example 1.9. Set hash_size parameter
+   Example 1.12. Set hash_size parameter
 ...
 modparam("rls", "xcap_root", "http://192.168.2.132/xcap-root:800")
 ...
 
-3.10. integrated_xcap_server (int)
+3.13. integrated_xcap_server (int)
 
-   This parameter should be set if only integrated xcap servers are used
+   This  parameter should be set if only integrated xcap servers are used
    to store resource lists.
 
-   Default value is “0�.
+   Default value is "0". 
 
-   Example 1.10. Set integrated_xcap_server parameter
+   Example 1.13. Set integrated_xcap_server parameter
 ...
 modparam("rls", "integrated_xcap_server", 1)
 ...
 
-3.11. to_presence_code (int)
+3.14. to_presence_code (int)
 
-   The code to be returned by rls_handle_subscribe function if the
+   The  code  to  be  returned  by  rls_handle_subscribe  function if the
    processed Subscribe is not a resource list Subscribe. This code can be
-   used in an architecture with presence and rls servers collocated on the
-   same machine, to call handle_subscribe on the message causing this
+   used  in  an  architecture with presence and rls servers collocated on
+   the same machine, to call handle_subscribe on the message causing this
    code.
 
-   Default value is “0�.
+   Default value is "0". 
 
-   Example 1.11. Set to_presence_code parameter
+   Example 1.14. Set to_presence_code parameter
 ...
 modparam("rls", "to_presence_code", 10)
 ...
 
-3.12. rls_event (str)
+3.15. rls_event (str)
 
-   The default event that RLS handles is presence. If some other events
-   should also be handled by RLS they should be added using this
+   The  default  event that RLS handles is presence. If some other events
+   should  also  be  handled  by  RLS  they  should  be  added using this
    parameter. It can be set more than once.
 
-   Default value is “"presence"�.
+   Default value is ""presence"". 
 
-   Example 1.12. Set rls_event parameter
+   Example 1.15. Set rls_event parameter
 ...
 modparam("rls", "rls_event", "dialog;sla")
 ...
 
-3.13. outbound_proxy (str)
+3.16. outbound_proxy (str)
 
-   The SIP address where to send RLS subscriptions (outbound proxy address
-   as SIP URI).
+   The  SIP  address  where  to  send  RLS  subscriptions (outbound proxy
+   address as SIP URI).
 
-   Default value is “NULL�.
+   Default value is "NULL". 
 
-   Example 1.13. Set outbound_proxy parameter
+   Example 1.16. Set outbound_proxy parameter
 ...
 modparam("rls", "outbound_proxy", "sip:presence.kamailio.org")
 ...
 
-3.14. server_address (str)
+3.17. server_address (str)
 
-   The address of the server that will be used as a contact in sent
-   Subscribe requests and 200 OK replies for Subscribe requests for RLS.
+   The  address  of  the  server  that  will be used as a contact in sent
+   Subscribe  requests and 200 OK replies for Subscribe requests for RLS.
    It is a mandatory parameter.
 
-   Example 1.14. Set server_address parameter
+   Example 1.17. Set server_address parameter
 ...
 modparam("rls", "server_address", "sip:[email protected]:5060")
 ...
 
-3.15. max_notify_body_length (int)
+3.18. max_notify_body_length (int)
 
    The maximum size that the body of a NOTIFY message may be. If set to 0
    (the default), no size limit is applied. Note that this refers only to
    the body, not the complete NOTIFY message.
 
-   Example 1.15. Set max_notify_body_length parameter
+   Example 1.18. Set max_notify_body_length parameter
 ...
 modparam("rls", "max_notify_body_length", 32000)
 ...
 
 4. Functions
 
-   4.1. rls_handle_subscribe()
-   4.2. rls_handle_notify()
-   4.3. rls_update_subs(uri, event)
+   4.1. rls_handle_subscribe() 
+   4.2. rls_handle_notify() 
+   4.3. rls_update_subs(uri, event) 
 
 4.1.  rls_handle_subscribe()
 
    This function detects if a Subscribe message should be handled by RLS.
-   If not it replies with the configured to_presence_code. If it is, it
-   extracts the dialog info and sends aggregate Notify requests with
+   If  not  it replies with the configured to_presence_code. If it is, it
+   extracts  the  dialog  info  and  sends aggregate Notify requests with
    information for the list.
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.16. rls_handle_subscribe usage
+   Example 1.19. rls_handle_subscribe usage
 ...
 For presence and rls on the same machine:
         modparam("rls", "to_presence_code", 10)
@@ -396,7 +453,7 @@ For rls only:
 
    This function can be used from REQUEST_ROUTE.
 
-   Example 1.17. rls_handle_notify usage
+   Example 1.20. rls_handle_notify usage
 ...
 if(method=="NOTIFY")
     rls_handle_notify();
@@ -404,18 +461,18 @@ if(method=="NOTIFY")
 
 4.3.  rls_update_subs(uri, event)
 
-   This function can be used in configuration to trigger updates to
-   resource list subscriptions (for example, after the contents of a
+   This  function  can  be  used  in  configuration to trigger updates to
+   resource  list  subscriptions  (for  example,  after the contents of a
    resource list has changes).
 
    Parameters:
-     * uri - the uri of the user who made the change and whose resource
+     * uri  -  the uri of the user who made the change and whose resource
        list subscriptions should be updated
      * event - the event package (e.g. presence).
 
    This function can be used from ANY_ROUTE.
 
-   Example 1.18. rls_update_subs usage
+   Example 1.21. rls_update_subs usage
 ...
 Within event_route[xhttp:request]:
         case "PUT":
@@ -433,10 +490,10 @@ Within event_route[xhttp:request]:
 
 5. Installation
 
-   The module requires 2 tables in Kamailio database: rls_presentity and
-   rls_watchers.The SQL syntax to create them can be found in
-   rls-create.sql script in the database directories in the
-   kamailio/scripts folder. You can also find the complete database
+   The  module requires 2 tables in Kamailio database: rls_presentity and
+   rls_watchers.The   SQL   syntax   to  create  them  can  be  found  in
+   rls-create.sql   script   in   the   database   directories   in   the
+   kamailio/scripts  folder.  You  can  also  find  the complete database
    documentation on the project webpage,
    http://www.kamailio.org/docs/db-tables/kamailio-db-devel.html.
 

+ 28 - 0
modules_k/rls/api.h

@@ -0,0 +1,28 @@
+#ifndef RLS_API_H
+#define RLS_API_H
+#include "../../str.h"
+
+typedef int (*rls_handle_subscribe_t)(struct sip_msg*, char*, char*);
+typedef int (*rls_handle_notify_t)(struct sip_msg*, char*, char*);
+
+typedef struct rls_binds {
+	rls_handle_subscribe_t rls_handle_subscribe;
+	rls_handle_notify_t rls_handle_notify;
+} rls_api_t;
+
+typedef int (*bind_rls_f)(rls_api_t*);
+
+int bind_rls(struct rls_binds*);
+
+inline static int rls_load_api(rls_api_t *pxb)
+{
+	bind_rls_f bind_rls_exports;
+	if (!(bind_rls_exports = (bind_rls_f)find_export("bind_rls", 1, 0)))
+	{
+		LM_ERR("Failed to import bind_rls\n");
+		return -1;
+	}
+	return bind_rls_exports(pxb);
+}
+
+#endif /*RLS_API_H*/

+ 70 - 0
modules_k/rls/doc/rls_admin.xml

@@ -118,6 +118,50 @@ modparam("rls", "db_url", "&exampledb;")
 </programlisting>
 		</example>
 	</section>
+
+	<section>
+		<title><varname>xcap_db_url</varname>(str)</title>
+		<para>
+		The xcap database url.
+		This parameter only needs to be specified if the rls db and integerated 
+		xcap server db have different urls. 
+		</para>
+		<para>
+		<emphasis>	Default value is a mirror of the <quote>db_url</quote> setting.	
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>xcap_db_url</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rls", "xcap_db_url", "&exampledb;")
+...
+</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title><varname>db_mode</varname>(int)</title>
+		<para>
+		The module supports 2 modes of operation, high speed memory
+		based storage (mode 0), and database only (mode 2) where all 
+		data is stored in a database, allowing scalability at the expense of speed.
+		Mode 1 is reserved.
+		</para>
+		<para>
+		<emphasis>	Default value is <quote>0</quote> 	
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>db_mode</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rls", "db_mode", 2)
+...
+</programlisting>
+		</example>
+	</section>
+
 	<section>
 		<title><varname>xcap_table</varname>(str)</title>
 		<para>
@@ -233,6 +277,32 @@ modparam("rls", "waitn_time", 10)
 		<programlisting format="linespecific">
 ...
 modparam("rls", "max_expires", 10800)
+...
+		</programlisting>
+		</example>
+	</section>
+
+	<section>
+		<title><varname>expires_offset</varname> (int)</title>
+		<para>
+		This paramater only has an effect when the db_mode is DB_ONLY (mode 2).
+		When expired subscribers are checked for deletion from the database,
+		those that have a value in the expires column which is less than 
+		current_time - expires_offset are matched. Hence when an offset of zero
+		is used, all those that expire prior the current time will be deleted.
+		If an offset of 't' is used, only those that expired more than t seconds
+		ago are deleted from the database. 
+		Negative offsets are treated as though an offset of zero was specifed. 
+		</para>
+		<para>
+		<emphasis>Default value is <quote>0</quote>.
+		</emphasis>
+		</para>
+		<example>
+		<title>Set <varname>expires_offset</varname> parameter</title>
+		<programlisting format="linespecific">
+...
+modparam("rls", "expires_offset", 0)
 ...
 		</programlisting>
 		</example>

+ 56 - 29
modules_k/rls/notify.c

@@ -341,11 +341,23 @@ int agg_body_sendn_update(str* rl_uri, char* boundary_string, str* rlmi_body,
 	pkg_free(body.s);
 	body.s= NULL;
 
-	if(pres_update_shtable(rls_table, hash_code,subs, LOCAL_TYPE)< 0)
+	if (dbmode==RLS_DB_ONLY)
 	{
-		LM_ERR("updating in hash table\n");
-		goto error;
+		if ( update_rlsdb(subs, LOCAL_TYPE) <0 )
+		{
+			LM_ERR( "updating DB\n" );
+			goto error;
+		}
 	}
+	else
+	{
+		if(pres_update_shtable(rls_table, hash_code,subs, LOCAL_TYPE)< 0)
+		{
+			LM_ERR("updating in hash table\n");
+			goto error;
+		}
+	}
+
 	return 0;
 
 error:
@@ -884,7 +896,6 @@ void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps)
 
 	if(ps->code >= 300)
 	{
-		/* delete from database table */
 		db_key_t db_keys[2];
 		db_val_t db_vals[2];
 		unsigned int hash_code;
@@ -896,32 +907,48 @@ void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps)
 		subs.from_tag= ((dialog_id_t*)(*ps->param))->from_tag;
 		subs.callid= ((dialog_id_t*)(*ps->param))->callid;
 
-		if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) 
+		if (dbmode != RLS_DB_ONLY)
 		{
-			LM_ERR("in use_table\n");
-			goto done;
-		}
+			/* delete from database table */
+
+
+			if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) 
+			{
+				LM_ERR("in use_table\n");
+				goto done;
+			}
 		
-		db_keys[0] =&str_to_tag_col;
-		db_vals[0].type = DB1_STR;
-		db_vals[0].nul = 0;
-		db_vals[0].val.str_val = subs.to_tag;
+			db_keys[0] =&str_to_tag_col;
+			db_vals[0].type = DB1_STR;
+			db_vals[0].nul = 0;
+			db_vals[0].val.str_val = subs.to_tag;
 
-		db_keys[1] =&str_callid_col;
-		db_vals[1].type = DB1_STR;
-		db_vals[1].nul = 0;
-		db_vals[1].val.str_val = subs.callid;
+			db_keys[1] =&str_callid_col;
+			db_vals[1].type = DB1_STR;
+			db_vals[1].nul = 0;
+			db_vals[1].val.str_val = subs.callid;
 
 
-		if (rls_dbf.delete(rls_db, db_keys, 0, db_vals, 2) < 0) 
-			LM_ERR("cleaning expired messages\n");	
+			if (rls_dbf.delete(rls_db, db_keys, 0, db_vals, 2) < 0) 
+				LM_ERR("cleaning expired messages\n");	
+		}
 
 		/* delete from cache table */
-		hash_code= core_hash(&subs.callid, &subs.to_tag , hash_size);
-
-		if(pres_delete_shtable(rls_table,hash_code, subs.to_tag)< 0)
+		if (dbmode == RLS_DB_ONLY)
 		{
-			LM_ERR("record not found in hash table\n");
+			if (delete_rlsdb(&subs.callid, &subs.to_tag, NULL) < 0 )
+			{
+				LM_ERR( "unable to delete record from DB\n" );
+			}
+		}
+		else
+		{
+			hash_code= core_hash(&subs.callid, &subs.to_tag , hash_size);
+
+			if(pres_delete_shtable(rls_table,hash_code, subs.to_tag)< 0)
+			{
+				LM_ERR("record not found in hash table\n");
+			}
 		}
 	}	
 
@@ -960,7 +987,7 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
 			{
 				if (rls_integrated_xcap_server == 1
 					&& (hostname.len == 0
-						|| check_self(&hostname, port, PROTO_NONE) == 1))
+						|| check_self(&hostname, 0, PROTO_NONE) == 1))
 				{
 					LM_DBG("fetching local <resource-list/>\n");
 					if (rls_get_resource_list(&rl_uri, &username, &domain, &rl_node, &rl_doc)>0)
@@ -1234,7 +1261,7 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain,
 	query_vals[n_query_cols].val.str_val = root;
 	n_query_cols++;
 
-	if(rls_dbf.use_table(rls_db, &rls_xcap_table) < 0)
+	if(rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)
 	{
 		LM_ERR("in use_table-[table]=%.*s\n",
 			rls_xcap_table.len, rls_xcap_table.s);
@@ -1243,20 +1270,20 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain,
 
 	result_cols[xcap_col= n_result_cols++] = &str_doc_col;
 
-	if(rls_dbf.query(rls_db, query_cols, 0, query_vals, result_cols,
+	if(rls_xcap_dbf.query(rls_xcap_db, query_cols, 0, query_vals, result_cols,
 				n_query_cols, n_result_cols, 0, &result)<0)
 	{
 		LM_ERR("failed querying table xcap for document: %.*s\n",
 				root.len, root.s);
 		if(result)
-			rls_dbf.free_result(rls_db, result);
+			rls_xcap_dbf.free_result(rls_xcap_db, result);
 		return -1;
 	}
 
 	if(result->n<=0)
 	{
 		LM_DBG("No rl document found\n");
-		rls_dbf.free_result(rls_db, result);
+		rls_xcap_dbf.free_result(rls_xcap_db, result);
 		return -1;
 	}
 
@@ -1334,12 +1361,12 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain,
 		xmlXPathFreeContext(xpathCtx);
 	}
 	
-	rls_dbf.free_result(rls_db, result);
+	rls_xcap_dbf.free_result(rls_xcap_db, result);
 	return 1;
 
 error:
 	if(result!=NULL)
-		rls_dbf.free_result(rls_db, result);
+		rls_xcap_dbf.free_result(rls_xcap_db, result);
 	if(xpathObj!=NULL)
 		xmlXPathFreeObject(xpathObj);
 	

+ 34 - 12
modules_k/rls/resource_notify.c

@@ -93,25 +93,47 @@ void get_dialog_from_did(char* did, subs_t **dialog, unsigned int *hash_code)
             "resource list Subscribe dialog indentifier(rlsubs did)\n");
         return;
 	}
-    *hash_code= core_hash(&callid, &to_tag, hash_size);
-    
-    lock_get(&rls_table[*hash_code].lock);
-    s= pres_search_shtable(rls_table,callid,to_tag,from_tag,*hash_code);
-    if(s== NULL)
+
+	if (dbmode == RLS_DB_ONLY)
 	{
-        LM_ERR("record not found in hash_table [rlsubs_did]= %s\n",
-                did);
-        lock_release(&rls_table[*hash_code].lock);
-        return;
+		*dialog = get_dialog_rlsdb(callid,to_tag,from_tag);
+
+		if(*dialog==NULL)
+		{
+			LM_ERR("record not retrieved from db [rlsubs_did]= %s\n", did);
+			return;
+		}
+	}
+	else
+	{
+		*hash_code= core_hash(&callid, &to_tag, hash_size);
+
+		lock_get(&rls_table[*hash_code].lock);
+		s= pres_search_shtable(rls_table,callid,to_tag,from_tag,*hash_code);
+
+		if(s== NULL)
+		{
+			LM_ERR("record not found in hash_table [rlsubs_did]= %s\n",
+					did);
+			lock_release(&rls_table[*hash_code].lock);
+			return;
+		}
+
+		/* save dialog info */
+		*dialog= pres_copy_subs(s, PKG_MEM_TYPE);
 	}
 
-    /* save dialog info */
-    *dialog= pres_copy_subs(s, PKG_MEM_TYPE);
     if(*dialog== NULL)
 	{
         LM_ERR("while copying subs_t structure\n");
 	}
-    lock_release(&rls_table[*hash_code].lock);
+	else
+	{
+		dump_dialog( *dialog );
+	}
+
+	if (dbmode != RLS_DB_ONLY)
+		lock_release(&rls_table[*hash_code].lock);
 	
 }
 

+ 193 - 23
modules_k/rls/rls.c

@@ -54,24 +54,32 @@
 #include "rls.h"
 #include "notify.h"
 #include "resource_notify.h"
+#include "api.h"
 
 MODULE_VERSION
 
 #define P_TABLE_VERSION 1
 #define W_TABLE_VERSION 1
+#define X_TABLE_VERSION 4
 
 /** database connection */
 db1_con_t *rls_db = NULL;
 db_func_t rls_dbf;
+db1_con_t *rls_xcap_db = NULL;
+db_func_t rls_xcap_dbf;
+db1_con_t *rls2_db = NULL;
+db_func_t rls2_dbf;
 
 /** modules variables */
 str rls_server_address = {0, 0};
+int rls_expires_offset=0;
 int waitn_time = 10;
 str rlsubs_table = str_init("rls_watchers");
 str rlpres_table = str_init("rls_presentity");
 str rls_xcap_table = str_init("xcap");
 
 str db_url = str_init(DEFAULT_DB_URL);
+str xcap_db_url = str_init("");
 int hash_size = 512;
 shtable_t rls_table;
 int pid;
@@ -93,6 +101,17 @@ xmlNodeGetNodeContentByName_t XMLNodeGetNodeContentByName;
 xmlNodeGetAttrContentByName_t XMLNodeGetAttrContentByName;
 
 /* functions imported from presence to handle subscribe hash table */
+extern shtable_t rls_new_shtable(int hash_size);
+extern void rls_destroy_shtable(shtable_t htable, int hash_size);
+extern int rls_insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs);
+extern subs_t* rls_search_shtable(shtable_t htable,str callid,str to_tag,
+		str from_tag,unsigned int hash_code);
+extern int rls_delete_shtable(shtable_t htable,unsigned int hash_code,str to_tag);
+extern int rls_update_shtable(shtable_t htable,unsigned int hash_code, 
+		subs_t* subs, int type);
+extern void rls_update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
+	int htable_size, int no_lock, handle_expired_func_t handle_expired_func);
+
 new_shtable_t pres_new_shtable;
 insert_shtable_t pres_insert_shtable;
 search_shtable_t pres_search_shtable;
@@ -107,6 +126,7 @@ int to_presence_code = 1;
 int rls_max_expires = 7200;
 int rls_reload_db_subs = 0;
 int rls_max_notify_body_len = 0;
+int dbmode = 0;
 
 /* functions imported from xcap_client module */
 xcapGetNewDoc_t xcap_GetNewDoc = 0;
@@ -176,12 +196,15 @@ static cmd_export_t cmds[]=
 			0, 0, REQUEST_ROUTE},
 	{"rls_update_subs",       (cmd_function)rls_update_subs,	2,
 			fixup_update_subs, 0, ANY_ROUTE},
+	{"bind_rls",              (cmd_function)bind_rls,		1,
+			0, 0, 0},
 	{0, 0, 0, 0, 0, 0 }
 };
 
 static param_export_t params[]={
 	{ "server_address",         STR_PARAM,   &rls_server_address.s           },
 	{ "db_url",                 STR_PARAM,   &db_url.s                       },
+	{ "xcap_db_url",            STR_PARAM,   &xcap_db_url.s                  },
 	{ "rlsubs_table",           STR_PARAM,   &rlsubs_table.s                 },
 	{ "rlpres_table",           STR_PARAM,   &rlpres_table.s                 },
 	{ "xcap_table",             STR_PARAM,   &rls_xcap_table.s               },
@@ -196,6 +219,8 @@ static param_export_t params[]={
 	{ "outbound_proxy",         STR_PARAM,   &rls_outbound_proxy.s           },
 	{ "reload_db_subs",         INT_PARAM,   &rls_reload_db_subs             },
 	{ "max_notify_body_length", INT_PARAM,	 &rls_max_notify_body_len	     },
+	{ "db_mode",                INT_PARAM,	 &dbmode			 },
+	{ "expires_offset",         INT_PARAM,	 &rls_expires_offset		 },
 	{0,                         0,           0                               }
 };
 
@@ -232,6 +257,12 @@ static int mod_init(void)
 
 	LM_DBG("start\n");
 
+	if (dbmode <RLS_DB_DEFAULT || dbmode > RLS_DB_ONLY)
+	{
+		LM_ERR( "Invalid dbmode-set to default mode\n" );
+		dbmode = 0;
+	}
+
 	if(rls_server_address.s==NULL)
 	{
 		LM_ERR("server_address parameter not set in configuration file\n");
@@ -304,14 +335,35 @@ static int mod_init(void)
 	pres_contains_event = pres.contains_event;
 	pres_search_event   = pres.search_event;
 	pres_get_ev_list    = pres.get_event_list;
-	pres_new_shtable    = pres.new_shtable;
-	pres_destroy_shtable= pres.destroy_shtable;
-	pres_insert_shtable = pres.insert_shtable;
-	pres_delete_shtable = pres.delete_shtable;
-	pres_update_shtable = pres.update_shtable;
-	pres_search_shtable = pres.search_shtable;
+
+	if (rls_expires_offset < 0 ) 
+	{
+		LM_ERR( "Negative expires_offset, defaulted to zero\n" );
+		rls_expires_offset = 0; 
+	}
+
+	if (dbmode == RLS_DB_ONLY)
+	{
+		pres_new_shtable    = rls_new_shtable;
+		pres_destroy_shtable= rls_destroy_shtable;
+		pres_insert_shtable = rls_insert_shtable;
+		pres_delete_shtable = rls_delete_shtable;
+		pres_update_shtable = rls_update_shtable;
+		pres_search_shtable = rls_search_shtable;
+		pres_update_db_subs = rls_update_db_subs;
+	}
+	else
+	{
+		pres_new_shtable    = pres.new_shtable;
+		pres_destroy_shtable= pres.destroy_shtable;
+		pres_insert_shtable = pres.insert_shtable;
+		pres_delete_shtable = pres.delete_shtable;
+		pres_update_shtable = pres.update_shtable;
+		pres_search_shtable = pres.search_shtable;
+		pres_update_db_subs = pres.update_db_subs;
+	}
+
 	pres_copy_subs      = pres.mem_copy_subs;
-	pres_update_db_subs = pres.update_db_subs;
 	pres_extract_sdialog_info= pres.extract_sdialog_info;
 
 	if(!pres_contains_event || !pres_get_ev_list || !pres_new_shtable ||
@@ -328,57 +380,112 @@ static int mod_init(void)
 	rls_xcap_table.len= strlen(rls_xcap_table.s);
 	db_url.len = db_url.s ? strlen(db_url.s) : 0;
 	LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len, db_url.s);
+
+	xcap_db_url.len = xcap_db_url.s ? strlen(xcap_db_url.s) : 0;
+
+	if(xcap_db_url.len==0)
+	{
+		xcap_db_url.s = db_url.s;
+		xcap_db_url.len = db_url.len;
+	}
+
+	LM_DBG("db_url=%s/%d/%p\n", ZSW(xcap_db_url.s), xcap_db_url.len, xcap_db_url.s);
 	
 	/* binding to mysql module  */
+
+	/* rls2_db handle is to ensure that there are no unwanted interactions
+	   between the original database reads and the DB_ONLY mode stuff */
+
+	if (db_bind_mod(&db_url, &rls2_dbf))
+	{
+		LM_ERR("Database module not found\n");
+		return -1;
+	}
+
 	if (db_bind_mod(&db_url, &rls_dbf))
 	{
 		LM_ERR("Database module not found\n");
 		return -1;
 	}
-	
+
+	if (db_bind_mod(&xcap_db_url, &rls_xcap_dbf))
+	{
+		LM_ERR("Database module not found\n");
+		return -1;
+	}
+
 	if (!DB_CAPABILITY(rls_dbf, DB_CAP_ALL)) {
 		LM_ERR("Database module does not implement all functions"
 				" needed by the module\n");
 		return -1;
 	}
 
+	if (!DB_CAPABILITY(rls_xcap_dbf, DB_CAP_ALL)) {
+		LM_ERR("Database module does not implement all functions"
+				" needed by the module\n");
+		return -1;
+	}
+
 	rls_db = rls_dbf.init(&db_url);
 	if (!rls_db)
 	{
 		LM_ERR("while connecting database\n");
 		return -1;
 	}
+
+	rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
+	if (!rls_xcap_db)
+	{
+		LM_ERR("while connecting database\n");
+		return -1;
+	}
+
 	/* verify table version */
 	if((db_check_table_version(&rls_dbf, rls_db, &rlsubs_table, W_TABLE_VERSION) < 0) ||
 		(db_check_table_version(&rls_dbf, rls_db, &rlpres_table, P_TABLE_VERSION) < 0)) {
 			LM_ERR("error during table version check.\n");
 			return -1;
 	}
-	
-	if(hash_size<=1)
-		hash_size= 512;
-	else
-		hash_size = 1<<hash_size;
 
-	rls_table= pres_new_shtable(hash_size);
-	if(rls_table== NULL)
+	/* verify table version */
+	if(db_check_table_version(&rls_xcap_dbf, rls_xcap_db, &rls_xcap_table, X_TABLE_VERSION) < 0)
 	{
-		LM_ERR("while creating new hash table\n");
-		return -1;
+			LM_ERR("error during table version check.\n");
+			return -1;
 	}
-	if(rls_reload_db_subs!=0)
+
+	if (dbmode != RLS_DB_ONLY)
 	{
-		if(rls_restore_db_subs()< 0)
+		if(hash_size<=1)
+			hash_size= 512;
+		else
+			hash_size = 1<<hash_size;
+
+		rls_table= pres_new_shtable(hash_size);
+		if(rls_table== NULL)
 		{
-			LM_ERR("while restoring rl watchers table\n");
+			LM_ERR("while creating new hash table\n");
 			return -1;
 		}
+		if(rls_reload_db_subs!=0)
+		{
+			if(rls_restore_db_subs()< 0)
+			{
+				LM_ERR("while restoring rl watchers table\n");
+				return -1;
+			}
+		}
 	}
 
 	if(rls_db)
 		rls_dbf.close(rls_db);
 	rls_db = NULL;
 
+	if(rls_xcap_db)
+		rls_xcap_dbf.close(rls_xcap_db);
+	rls_xcap_db = NULL;
+
+
 	if(waitn_time<= 0)
 		waitn_time= 5;
 	
@@ -460,10 +567,13 @@ static int mod_init(void)
 	}
 	register_timer(timer_send_notify,0, waitn_time);
 	
-	register_timer(rls_presentity_clean, 0, clean_period);
-	
-	register_timer(rlsubs_table_update, 0, clean_period);
+	if (clean_period > 0)
+	{
+		register_timer(rls_presentity_clean, 0, clean_period);
 	
+		register_timer(rlsubs_table_update, 0, clean_period);
+	}
+
 	return 0;
 }
 
@@ -476,6 +586,48 @@ static int child_init(int rank)
 		return 0; /* do nothing for the main process */
 
 	LM_DBG("child [%d]  pid [%d]\n", rank, getpid());
+
+	if (rls2_dbf.init==0)
+	{
+		LM_CRIT("database not bound\n");
+		return -1;
+	}
+	rls2_db = rls2_dbf.init(&db_url);
+	if (!rls2_db)
+	{
+		LM_ERR("child %d: Error while connecting database\n",
+				rank);
+		return -1;
+	}
+	if (rls2_dbf.use_table(rls2_db, &rlsubs_table) < 0)  
+	{
+		LM_ERR("child %d: Error in use_table rlsubs_table\n", rank);
+		return -1;
+	}
+
+	if (rls_xcap_dbf.init==0)
+	{
+		LM_CRIT("database not bound\n");
+		return -1;
+	}
+
+	rls_xcap_db = rls_xcap_dbf.init(&xcap_db_url);
+	if (!rls_xcap_db)
+	{
+		LM_ERR("child %d: Error while connecting database\n", rank);
+		return -1;
+	}
+	else
+	{
+		if (rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)  
+		{
+			LM_ERR("child %d: Error in use_table rls_xcap_table\n", rank);
+			return -1;
+		}
+
+		LM_DBG("child %d: Database connection opened successfully\n", rank);
+	}
+
 	if (rls_dbf.init==0)
 	{
 		LM_CRIT("database not bound\n");
@@ -523,6 +675,9 @@ static void destroy(void)
 	}
 	if(rls_db && rls_dbf.close)
 		rls_dbf.close(rls_db);
+
+	if(rls2_db && rls2_dbf.close)
+		rls2_dbf.close(rls2_db);
 }
 
 int handle_expired_record(subs_t* s)
@@ -547,6 +702,8 @@ void rlsubs_table_update(unsigned int ticks,void *param)
 {
 	int no_lock= 0;
 
+	if (dbmode==RLS_DB_ONLY) { delete_expired_subs_rlsdb(); return; }
+
 	if(ticks== 0 && param == NULL)
 		no_lock= 1;
 	
@@ -755,3 +912,16 @@ int add_rls_event(modparam_t type, void* val)
 	return 0;
 
 }
+
+int bind_rls(struct rls_binds *pxb)
+{
+		if (pxb == NULL)
+		{
+				LM_WARN("bind_rls: Cannot load rls API into a NULL pointer\n");
+				return -1;
+		}
+
+		pxb->rls_handle_subscribe = rls_handle_subscribe;
+		pxb->rls_handle_notify = rls_handle_notify;
+		return 0;
+}

+ 19 - 1
modules_k/rls/rls.h

@@ -40,6 +40,10 @@
 #include "../../lib/srdb1/db_con.h"
 #include "../../lib/srdb1/db.h"
 
+#define RLS_DB_DEFAULT 0
+#define RLS_DB_RESERVED 1
+#define RLS_DB_ONLY 2
+
 #define NO_UPDATE_TYPE     -1 
 #define UPDATED_TYPE        1 
 
@@ -79,7 +83,7 @@ typedef struct rls_resource
 	/* the last 2 parameters say if a query in database is needed */
 }rls_res_t;
 
-
+extern int dbmode;
 extern char* xcap_root;
 extern unsigned int xcap_port;
 extern str rls_server_address;
@@ -97,10 +101,13 @@ extern int rls_events;
 extern int to_presence_code;
 extern str rls_outbound_proxy;
 extern int rls_max_notify_body_len;
+extern int rls_expires_offset;
 
 /* database connection */
 extern db1_con_t *rls_db;
 extern db_func_t rls_dbf;
+extern db1_con_t *rls_xcap_db;
+extern db_func_t rls_xcap_dbf;
 
 extern struct tm_binds tmb;
 extern sl_api_t slb;
@@ -137,6 +144,17 @@ extern xcap_nodeSel_add_step_t xcap_AddStep;
 extern xcap_nodeSel_add_terminal_t xcap_AddTerminal;
 extern xcap_nodeSel_free_t xcap_FreeNodeSel;
 
+/* rlsdb functions*/
+int delete_expired_subs_rlsdb( void );
+void dump_dialog( subs_t *s );
+extern int delete_rlsdb( str *callid, str *to_tag, str *from_tag );
+extern int update_rlsdb( subs_t *s, int type );
+extern int update_subs_rlsdb( subs_t *s );
+extern int insert_rlsdb( subs_t *s );
+extern int matches_in_rlsdb( str callid, str to_tag, str from_tag );
+extern int update_all_subs_rlsdb( str *from_user, str *from_domain, str *evt );
+subs_t *get_dialog_rlsdb( str callid, str to_tag, str from_tag );
+
 extern str str_rlsubs_did_col;
 extern str str_resource_uri_col;
 extern str str_updated_col;

+ 1220 - 0
modules_k/rls/rls_db.c

@@ -0,0 +1,1220 @@
+/*
+ * $Id$
+ *
+ * rls db - RLS database support 
+ *
+ * Copyright (C) 2011 Crocodile RCS Ltd
+ *
+ * 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
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../mem/mem.h"
+#include "../../mem/shm_mem.h"
+#include "../../dprint.h"
+#include "../../lib/srdb1/db.h"
+#include "../../parser/msg_parser.h"
+#include "../../parser/parse_from.h"
+
+#include "rls.h"
+
+#define CONT_COPYDB(buf, dest, source)\
+	do{ \
+	dest.s= (char*)buf+ size;\
+	memcpy(dest.s, source, strlen(source));\
+	dest.len= strlen(source);\
+	size+= strlen(source); \
+	} while(0);
+
+/* database connection */
+extern db1_con_t *rls2_db;
+extern db_func_t rls2_dbf;
+
+extern void update_a_sub(subs_t *subs_copy );
+
+static int rlsdb_debug=0;
+
+/******************************************************************************/
+
+shtable_t rls_new_shtable(int hash_size)
+{
+  LM_ERR( "rls_new_shtable shouldn't be called in RLS_DB_ONLY mode\n" );
+  return(NULL);
+}
+
+/******************************************************************************/
+
+void rls_destroy_shtable(shtable_t htable, int hash_size)
+{
+  LM_ERR( "rls_destroy_shtable shouldn't be called in RLS_DB_ONLY mode\n" );
+}
+
+/******************************************************************************/
+
+int rls_insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs)
+{
+  LM_ERR( "rls_insert_shtable shouldn't be called in RLS_DB_ONLY mode\n" );
+  return(-1);
+}
+
+/******************************************************************************/
+
+subs_t* rls_search_shtable(shtable_t htable,str callid,str to_tag,
+		str from_tag,unsigned int hash_code)
+{
+  LM_ERR( "rls_search_shtable shouldn't be called in RLS_DB_ONLY mode\n" );
+  return(NULL);
+}
+
+/******************************************************************************/
+
+int rls_delete_shtable(shtable_t htable,unsigned int hash_code,str to_tag)
+{
+  LM_ERR( "rls_delete_shtable shouldn't be called in RLS_DB_ONLY mode\n" );
+  return(-1);
+}
+
+/******************************************************************************/
+
+int rls_update_shtable(shtable_t htable,unsigned int hash_code, 
+		subs_t* subs, int type)
+{
+  LM_ERR( "rls_update_shtable shouldn't be called in RLS_DB_ONLY mode\n" );
+  return(-1);
+}
+
+/******************************************************************************/
+
+void rls_update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
+	int htable_size, int no_lock, handle_expired_func_t handle_expired_func)
+{
+  LM_ERR( "rls_update_db_subs shouldn't be called in RLS_DB_ONLY mode\n" );
+}
+
+/******************************************************************************/
+/******************************************************************************/
+
+int delete_expired_subs_rlsdb( void )
+
+{
+	db_key_t query_cols[1];
+	db_val_t query_vals[1];
+	db_op_t query_ops[1];
+	int n_query_cols = 0;
+	int expires_col, rval;
+
+	if (rlsdb_debug) LM_ERR( "delete_expired_subs_rlsdb\n" );
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	query_cols[expires_col= n_query_cols]= &str_expires_col;
+	query_vals[expires_col].type = DB1_INT;
+	query_vals[expires_col].nul = 0;
+	query_vals[expires_col].val.int_val= (int)time(NULL) - rls_expires_offset;
+	query_ops[expires_col]= OP_LT;
+	n_query_cols++;
+
+	rval=rls2_dbf.delete(rls2_db, query_cols, query_ops, query_vals, n_query_cols);
+
+	if (rval < 0)
+	{
+		LM_ERR( "db delete failed for expired subs\n" );
+	}
+/*	else
+	{
+		LM_ERR( "Done\n" );
+	}*/
+
+	return(rval);
+}
+
+/******************************************************************************/
+
+int delete_rlsdb( str *callid, str *to_tag, str *from_tag ) 
+
+{
+ 	int rval;
+	db_key_t query_cols[3];
+	db_val_t query_vals[3];
+	int n_query_cols = 0;
+	int callid_col, totag_col, fromtag_col;
+
+	if (rlsdb_debug) 
+		LM_ERR( "delete_rlsdb callid=%.*s \nto_tag=%.*s \nfrom_tag=%.*s\n",
+		callid?callid->len:0, callid?callid->s:"",
+		to_tag?to_tag->len:0, to_tag?to_tag->s:"",
+		from_tag?from_tag->len:0, from_tag?from_tag->s:"" ); 
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	
+	if (callid)
+	{
+		query_cols[callid_col= n_query_cols] = &str_callid_col;
+		query_vals[callid_col].type = DB1_STR;
+		query_vals[callid_col].nul = 0;
+		query_vals[callid_col].val.str_val= *callid;
+		n_query_cols++;
+	}
+
+	if (to_tag)
+	{
+		query_cols[totag_col= n_query_cols] = &str_to_tag_col;
+		query_vals[totag_col].type = DB1_STR;
+		query_vals[totag_col].nul = 0;
+		query_vals[totag_col].val.str_val= *to_tag;
+		n_query_cols++;
+	}
+
+	if (from_tag)
+	{
+		query_cols[fromtag_col= n_query_cols] = &str_from_tag_col;
+		query_vals[fromtag_col].type = DB1_STR;
+		query_vals[fromtag_col].nul = 0;
+		query_vals[fromtag_col].val.str_val= *from_tag;
+		n_query_cols++;
+	}
+
+	rval = rls2_dbf.delete(rls2_db, query_cols, 0, query_vals, n_query_cols);
+
+	if (rval < 0)
+	{
+		LM_ERR("Can't delete in db\n");
+		return(-1);
+	}
+
+	if (rlsdb_debug) LM_ERR( "done\n" );
+	return(1);
+}
+
+/******************************************************************************/
+
+int update_rlsdb( subs_t *subs, int type)
+
+{
+	db_key_t query_cols[3];
+	db_val_t query_vals[3];
+	db_key_t data_cols[22];
+	db_val_t data_vals[22];
+	int n_query_cols = 0, n_data_cols=0;
+	int callid_col, totag_col, fromtag_col,status_col, event_id_col;
+	int local_cseq_col, remote_cseq_col, expires_col;
+	int contact_col,version_col;
+		
+	
+	if (rlsdb_debug) 
+		LM_ERR( "update_rlsdb callid=%.*s \nto_tag=%.*s \nfrom_tag=%.*s \ntype=%d\n",
+		subs->callid.len, subs->callid.s,
+		subs->to_tag.len, subs->to_tag.s,
+		subs->from_tag.len, subs->from_tag.s, 
+		type );
+
+	if (subs==NULL) return(-1);
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	
+	query_cols[callid_col= n_query_cols] = &str_callid_col;
+	query_vals[callid_col].type = DB1_STR;
+	query_vals[callid_col].nul = 0;
+	query_vals[callid_col].val.str_val= subs->callid;
+	n_query_cols++;
+
+	query_cols[totag_col= n_query_cols] = &str_to_tag_col;
+	query_vals[totag_col].type = DB1_STR;
+	query_vals[totag_col].nul = 0;
+	query_vals[totag_col].val.str_val= subs->to_tag;
+	n_query_cols++;
+
+	query_cols[fromtag_col= n_query_cols] = &str_from_tag_col;
+	query_vals[fromtag_col].type = DB1_STR;
+	query_vals[fromtag_col].nul = 0;
+	query_vals[fromtag_col].val.str_val= subs->from_tag;
+	n_query_cols++;
+
+	if(type & REMOTE_TYPE)
+	{
+		data_cols[expires_col= n_data_cols] =&str_expires_col;
+		data_vals[expires_col].type = DB1_INT;
+		data_vals[expires_col].nul = 0;
+		data_vals[expires_col].val.int_val = subs->expires + (int)time(NULL);
+		n_data_cols++;
+
+		data_cols[remote_cseq_col= n_data_cols]=&str_remote_cseq_col;
+		data_vals[remote_cseq_col].type = DB1_INT;
+		data_vals[remote_cseq_col].nul = 0;
+		data_vals[remote_cseq_col].val.int_val= subs->remote_cseq;
+		n_data_cols++;
+	}
+	else
+	{
+		int retrieved_local_cseq=0;
+		db_key_t result_cols[1] = {&str_local_cseq_col};
+		db1_res_t *result= NULL;
+ 		db_val_t *values;
+		db_row_t *rows;
+		int nr_rows;
+
+	
+		if(rls2_dbf.query(rls2_db, query_cols, 0, query_vals, result_cols, 
+				n_query_cols, 1, 0, &result )< 0)
+		{
+			LM_ERR("Can't query db\n");
+			if(result) rls2_dbf.free_result(rls2_db, result);
+			return(-1);
+		}
+
+		if(result == NULL) return(-1);
+
+		nr_rows = RES_ROW_N(result);
+
+		if (nr_rows == 0)
+		{
+			/* no match */ 
+			LM_ERR( "update_rlsdb: NO MATCH\n" );
+			rls2_dbf.free_result(rls2_db, result);
+			return(-1);
+		}
+
+		if (nr_rows != 1)
+		{
+			LM_ERR( "update_rlsdb: TOO MANY MATCHES=%d\n", nr_rows);
+			rls2_dbf.free_result(rls2_db, result);
+			return(-1);
+		}
+
+
+		/* get the results and fill in return data structure */
+		rows = RES_ROWS(result);
+		values = ROW_VALUES(rows);
+
+		retrieved_local_cseq = VAL_INT(values);
+		rls2_dbf.free_result(rls2_db, result);
+
+		subs->local_cseq = ++retrieved_local_cseq;
+		data_cols[local_cseq_col= n_data_cols]=&str_local_cseq_col;
+		data_vals[local_cseq_col].type = DB1_INT;
+		data_vals[local_cseq_col].nul = 0;
+		data_vals[local_cseq_col].val.int_val= subs->local_cseq;
+		n_data_cols++;
+
+		subs->version++;
+		data_cols[version_col= n_data_cols]=&str_version_col;
+		data_vals[version_col].type = DB1_INT;
+		data_vals[version_col].nul = 0;
+		data_vals[version_col].val.int_val= subs->version;
+		n_data_cols++;
+	}
+	
+
+	data_cols[contact_col= n_data_cols] =&str_contact_col;
+	data_vals[contact_col].type = DB1_STR;
+	data_vals[contact_col].nul = 0;
+	data_vals[contact_col].val.str_val = subs->contact;
+	n_data_cols++;
+
+	data_cols[status_col= n_data_cols] =&str_status_col;
+	data_vals[status_col].type = DB1_INT;
+	data_vals[status_col].nul = 0;
+	data_vals[status_col].val.int_val= subs->status;
+	n_data_cols++;
+
+	data_cols[event_id_col= n_data_cols] = &str_event_id_col;
+	data_vals[event_id_col].type = DB1_STR;
+	data_vals[event_id_col].nul = 0;
+	data_vals[event_id_col].val.str_val = subs->event_id;
+	n_data_cols++;
+
+	/*if(s->db_flag & NO_UPDATEDB_FLAG)
+		s->db_flag= UPDATEDB_FLAG; Note this is a retieve & modify of the flag
+
+	data_cols[db_flag_col= n_data_cols]=&str_db_flag_col;
+	data_vals[db_flag_col].type = DB1_INT;
+	data_vals[db_flag_col].nul = 0;
+	data_vals[db_flag_col].val.int_val= subs->db_flag;
+	n_data_cols++;*/
+
+	if(rls2_dbf.update(rls2_db, query_cols, 0, query_vals,
+                    data_cols,data_vals,n_query_cols,n_data_cols) < 0)
+	{
+		LM_ERR("Failed update db\n");
+		return(-1);
+	}
+
+	if (rlsdb_debug) LM_ERR("Done\n");
+	return(0);
+}
+
+/******************************************************************************/
+
+int update_all_subs_rlsdb( str *from_user, str *from_domain, str *evt )
+
+{
+	db_key_t query_cols[3];
+	db_val_t query_vals[3];
+	db_key_t result_cols[22];
+	int n_query_cols = 0, n_result_cols=0;
+	int callid_col, totag_col, fromtag_col;	
+	int r_pres_uri_col,r_to_user_col,r_to_domain_col;
+	int r_from_user_col,r_from_domain_col,r_callid_col;
+	int r_to_tag_col,r_from_tag_col,r_socket_info_col;
+	int r_event_id_col,r_local_contact_col,r_contact_col;
+	int r_record_route_col, r_reason_col;
+	int r_event_col, r_local_cseq_col, r_remote_cseq_col;
+	int r_status_col, r_version_col;
+	int r_expires_col;
+	db1_res_t *result= NULL;
+ 	db_val_t *values;
+	db_row_t *rows;
+	int nr_rows, size, loop;
+	subs_t *dest;
+	event_t parsed_event;
+	str ev_sname;
+
+
+	if (rlsdb_debug)
+		LM_ERR( "update_all_subs_rlsdb from_user=%.*s \nfrom_domain=%.*s evt=%.*s\n",
+		from_user?from_user->len:0, from_user?from_user->s:"",
+		from_domain?from_domain->len:0, from_domain?from_domain->s:"",
+		evt?evt->len:0, evt?evt->s:"" );
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	
+	query_cols[callid_col= n_query_cols] = &str_watcher_username_col;
+	query_vals[callid_col].type = DB1_STR;
+	query_vals[callid_col].nul = 0;
+	query_vals[callid_col].val.str_val= *from_user;
+	n_query_cols++;
+
+	query_cols[totag_col= n_query_cols] = &str_watcher_domain_col;
+	query_vals[totag_col].type = DB1_STR;
+	query_vals[totag_col].nul = 0;
+	query_vals[totag_col].val.str_val= *from_domain;
+	n_query_cols++;
+
+	query_cols[fromtag_col= n_query_cols] = &str_event_col;
+	query_vals[fromtag_col].type = DB1_STR;
+	query_vals[fromtag_col].nul = 0;
+	query_vals[fromtag_col].val.str_val= *evt;
+	n_query_cols++;
+
+	result_cols[r_pres_uri_col=n_result_cols++] = &str_presentity_uri_col;
+	result_cols[r_to_user_col=n_result_cols++] = &str_to_user_col;
+	result_cols[r_to_domain_col=n_result_cols++] = &str_to_domain_col;
+	result_cols[r_from_user_col=n_result_cols++] = &str_watcher_username_col;
+	result_cols[r_from_domain_col=n_result_cols++] = &str_watcher_domain_col;
+	result_cols[r_callid_col=n_result_cols++] = &str_callid_col;
+	result_cols[r_to_tag_col=n_result_cols++] = &str_to_tag_col;
+	result_cols[r_from_tag_col=n_result_cols++] = &str_from_tag_col;
+	result_cols[r_socket_info_col=n_result_cols++] = &str_socket_info_col;
+	result_cols[r_event_id_col=n_result_cols++] = &str_event_id_col;
+	result_cols[r_local_contact_col=n_result_cols++] = &str_local_contact_col;
+	result_cols[r_contact_col=n_result_cols++] = &str_contact_col;
+	result_cols[r_record_route_col=n_result_cols++] = &str_record_route_col;
+	result_cols[r_reason_col=n_result_cols++] = &str_reason_col;
+	result_cols[r_event_col=n_result_cols++] = &str_event_col;
+	result_cols[r_local_cseq_col=n_result_cols++] = &str_local_cseq_col;
+	result_cols[r_remote_cseq_col=n_result_cols++] = &str_remote_cseq_col;
+	result_cols[r_status_col=n_result_cols++] = &str_status_col;
+	result_cols[r_version_col=n_result_cols++] = &str_version_col;
+	/*result_cols[r_send_on_cback_col=n_result_cols++] = &str_send_on_cback_col;*/
+	result_cols[r_expires_col=n_result_cols++] = &str_expires_col;
+
+
+	if(rls2_dbf.query(rls2_db, query_cols, 0, query_vals, result_cols, 
+				n_query_cols, n_result_cols, 0, &result )< 0)
+	{
+		LM_ERR("Can't query db\n");
+		if(result) rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	if(result == NULL) return(-1);
+
+	nr_rows = RES_ROW_N(result);
+
+	if (nr_rows == 0)
+	{
+		/* no match */ 
+		LM_ERR( "update_all_subs_rlsdb: NO MATCH\n" );
+		rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	if (nr_rows != 1)
+	{
+		LM_ERR( "update_all_subs_rlsdb: TOO MANY MATCHES=%d\n", nr_rows);
+		rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	/* get the results and fill in return data structure */
+	for (loop=0; loop <nr_rows; loop++)
+	{
+		rows = RES_ROWS(result);
+		values = ROW_VALUES(rows);
+
+		size= sizeof(subs_t) +
+			( strlen(VAL_STRING(values+r_pres_uri_col))
+			+ strlen(VAL_STRING(values+r_to_user_col))
+			+ strlen(VAL_STRING(values+r_to_domain_col))
+			+ strlen(VAL_STRING(values+r_from_user_col))
+			+ strlen(VAL_STRING(values+r_from_domain_col))
+			+ strlen(VAL_STRING(values+r_to_tag_col))
+			+ strlen(VAL_STRING(values+r_from_tag_col))
+			+ strlen(VAL_STRING(values+r_callid_col))
+			+ strlen(VAL_STRING(values+r_socket_info_col))
+			+ strlen(VAL_STRING(values+r_local_contact_col))
+			+ strlen(VAL_STRING(values+r_contact_col))
+			+ strlen(VAL_STRING(values+r_record_route_col))
+			+ strlen(VAL_STRING(values+r_event_id_col))
+			+ strlen(VAL_STRING(values+r_reason_col))+ 1)*sizeof(char);
+
+		dest= (subs_t*)pkg_malloc(size);
+	
+		if(dest== NULL)
+		{
+			LM_ERR( "Can't allocate memory\n" );
+			/* tidy up and return >>>>>>>>>>>>>>>>>>>> */
+			rls2_dbf.free_result(rls2_db, result);
+			return(-1);
+		}
+		memset(dest, 0, size);
+		size= sizeof(subs_t);
+
+		CONT_COPYDB(dest, dest->pres_uri, VAL_STRING(values+r_pres_uri_col))
+		CONT_COPYDB(dest, dest->to_user, VAL_STRING(values+r_to_user_col))
+		CONT_COPYDB(dest, dest->to_domain, VAL_STRING(values+r_to_domain_col))
+		CONT_COPYDB(dest, dest->from_user, VAL_STRING(values+r_from_user_col))
+		CONT_COPYDB(dest, dest->from_domain, VAL_STRING(values+r_from_domain_col))
+		CONT_COPYDB(dest, dest->to_tag, VAL_STRING(values+r_to_tag_col))
+		CONT_COPYDB(dest, dest->from_tag, VAL_STRING(values+r_from_tag_col))
+		CONT_COPYDB(dest, dest->callid, VAL_STRING(values+r_callid_col))
+		CONT_COPYDB(dest, dest->sockinfo_str, VAL_STRING(values+r_socket_info_col))
+		CONT_COPYDB(dest, dest->local_contact, VAL_STRING(values+r_local_contact_col))
+		CONT_COPYDB(dest, dest->contact, VAL_STRING(values+r_contact_col))
+		CONT_COPYDB(dest, dest->record_route, VAL_STRING(values+r_record_route_col))
+
+		if(strlen(VAL_STRING(values+r_event_id_col)) > 0)
+			CONT_COPYDB(dest, dest->event_id, VAL_STRING(values+r_event_id_col))
+
+		if(strlen(VAL_STRING(values+r_reason_col)) > 0)
+			CONT_COPYDB(dest, dest->reason, VAL_STRING(values+r_reason_col))
+
+
+		ev_sname.s= (char *)VAL_STRING(values+r_event_col);
+		ev_sname.len= strlen(ev_sname.s);
+		
+		dest->event = pres_contains_event(&ev_sname, &parsed_event);
+
+		if(dest->event == NULL)
+		{
+			LM_ERR("event not found and set to NULL\n");
+		}
+
+		dest->local_cseq= VAL_INT(values+r_local_cseq_col);
+		dest->remote_cseq= VAL_INT(values+r_remote_cseq_col);
+		dest->status= VAL_INT(values+r_status_col);
+		dest->version= VAL_INT(values+r_version_col);
+		/*dest->send_on_cback= VAL_INT(values+r_send_on_cback_col);*/
+		dest->expires= VAL_INT(values+r_expires_col);
+
+		/*dest->db_flag= VAL_INT(values+r_db_flag_col);*/
+		
+		update_a_sub(dest);
+	}
+
+	rls2_dbf.free_result(rls2_db, result);
+	if (rlsdb_debug) LM_ERR( "Done\n" );
+	return(1);	
+}
+
+/******************************************************************************/
+
+int update_subs_rlsdb( subs_t *subs )
+
+{
+	db_key_t query_cols[3];
+	db_val_t query_vals[3];
+	db_key_t data_cols[22];
+	db_val_t data_vals[22];
+	db_key_t result_cols[10];
+	int n_query_cols = 0, n_data_cols=0, n_result_cols=0;
+	int callid_col, totag_col, fromtag_col;
+	int local_cseq_col, expires_col;	
+	int r_remote_cseq=0, r_local_cseq=0, r_version=0;
+	char *r_record_route, *r_pres_uri;
+	db1_res_t *result= NULL;
+ 	db_val_t *values;
+	db_row_t *rows;
+	int nr_rows;
+
+	if (rlsdb_debug) LM_ERR( "update_subs_rlsdb\n" );
+
+	if (subs==NULL) return(-1);
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	
+	query_cols[callid_col= n_query_cols] = &str_callid_col;
+	query_vals[callid_col].type = DB1_STR;
+	query_vals[callid_col].nul = 0;
+	query_vals[callid_col].val.str_val= subs->callid;
+	n_query_cols++;
+
+	query_cols[totag_col= n_query_cols] = &str_to_tag_col;
+	query_vals[totag_col].type = DB1_STR;
+	query_vals[totag_col].nul = 0;
+	query_vals[totag_col].val.str_val= subs->to_tag;
+	n_query_cols++;
+
+	query_cols[fromtag_col= n_query_cols] = &str_from_tag_col;
+	query_vals[fromtag_col].type = DB1_STR;
+	query_vals[fromtag_col].nul = 0;
+	query_vals[fromtag_col].val.str_val= subs->from_tag;
+	n_query_cols++;
+
+	result_cols[n_result_cols++] = &str_remote_cseq_col;
+	result_cols[n_result_cols++] = &str_local_cseq_col;
+	result_cols[n_result_cols++] = &str_version_col;
+	result_cols[n_result_cols++] = &str_presentity_uri_col;
+	result_cols[n_result_cols++] = &str_record_route_col;
+
+	if(rls2_dbf.query(rls2_db, query_cols, 0, query_vals, result_cols, 
+				n_query_cols, n_result_cols, 0, &result )< 0)
+	{
+		LM_ERR("Can't query db\n");
+		if(result) rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	if(result == NULL) return(-1);
+
+	nr_rows = RES_ROW_N(result);
+
+	if (nr_rows == 0)
+	{
+		/* no match */ 
+		LM_ERR( "update_subs_rlsdb: NO MATCH\n" );
+		rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	if (nr_rows != 1)
+	{
+		LM_ERR( "update_subs_rlsdb: TOO MANY MATCHES=%d\n", nr_rows);
+		rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	/* get the results and fill in return data structure */
+	rows = RES_ROWS(result);
+	values = ROW_VALUES(rows);
+
+	r_remote_cseq = VAL_INT(values+0);
+	r_local_cseq = VAL_INT(values+1);
+	r_version = VAL_INT(values+2);
+	r_pres_uri = (char *)VAL_STRING(values+3);
+	r_record_route = (char *)VAL_STRING(values+4);
+	
+	data_cols[expires_col= n_data_cols] = &str_expires_col;
+	data_vals[expires_col].type = DB1_INT;
+	data_vals[expires_col].nul = 0;
+	data_vals[expires_col].val.int_val = subs->expires + (int)time(NULL);
+	n_data_cols++;
+
+	if ( r_remote_cseq >= subs->remote_cseq)
+	{
+		LM_DBG("stored cseq= %d\n", r_remote_cseq);
+		return(401); /*stale cseq code */
+	}
+
+	data_cols[local_cseq_col= n_data_cols] = &str_remote_cseq_col;
+	data_vals[local_cseq_col].type = DB1_INT;
+	data_vals[local_cseq_col].nul = 0;
+	data_vals[local_cseq_col].val.int_val= subs->remote_cseq;
+	n_data_cols++;
+
+	subs->pres_uri.s = (char*)pkg_malloc(strlen(r_pres_uri) * sizeof(char));
+	if(subs->pres_uri.s== NULL)
+	{
+		LM_ERR( "Out of Memory\n" );
+		rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	memcpy(subs->pres_uri.s, r_pres_uri, strlen(r_pres_uri));
+	subs->pres_uri.len= strlen(r_pres_uri);
+
+	if(strlen(r_record_route) > 0)
+	{
+		subs->record_route.s =
+				(char*)pkg_malloc(strlen(r_record_route) * sizeof(char));
+		if(subs->record_route.s==NULL)
+		{
+			LM_ERR( "Out of Memory\n" );
+ 			pkg_free(subs->pres_uri.s);
+			rls2_dbf.free_result(rls2_db, result);
+			return(-1);
+		}
+		memcpy(subs->record_route.s, 
+			r_record_route, strlen(r_record_route));
+		subs->record_route.len= strlen(r_record_route);
+	}
+
+	subs->local_cseq= r_local_cseq;
+	subs->version= r_version;
+
+	rls2_dbf.free_result(rls2_db, result);
+
+
+	/*if(s->db_flag & NO_UPDATEDB_FLAG)
+		s->db_flag= UPDATEDB_FLAG; Note this is a retieve & modify of the flag
+
+	data_cols[db_flag_col= n_data_cols]=&str_db_flag_col;
+	data_vals[db_flag_col].type = DB1_INT;
+	data_vals[db_flag_col].nul = 0;
+	data_vals[db_flag_col].val.int_val= s->db_flag;
+	n_data_cols++;*/
+
+	if(rls2_dbf.update(rls2_db, query_cols, 0, query_vals,
+                    data_cols,data_vals,n_query_cols,n_data_cols) < 0)
+	{
+		LM_ERR("Failed update db\n");
+		return(-1);
+	}
+	
+	if (rlsdb_debug) LM_ERR("Done\n" );
+	return(0);
+}
+
+/******************************************************************************/
+
+int insert_rlsdb( subs_t *s )
+
+{
+	db_key_t data_cols[22];
+	db_val_t data_vals[22];
+	int n_data_cols = 0;
+	int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col;
+	int callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col;
+	int local_cseq_col, remote_cseq_col, expires_col, record_route_col;
+	int contact_col, local_contact_col, version_col,socket_info_col,reason_col;
+		
+	if (rlsdb_debug)
+		LM_ERR( "insert_rlsdb callid=%.*s \nto_tag=%.*s \nfrom_tag=%.*s\n",
+		s->callid.len, s->callid.s,
+		s->to_tag.len, s->to_tag.s,
+		s->from_tag.len, s->from_tag.s );
+
+	if (s==NULL) return(-1);
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	
+	data_cols[pres_uri_col= n_data_cols] = &str_presentity_uri_col;
+	data_vals[pres_uri_col].type = DB1_STR;
+	data_vals[pres_uri_col].nul = 0;
+	data_vals[pres_uri_col].val.str_val= s->pres_uri;
+	n_data_cols++;
+	
+	data_cols[callid_col= n_data_cols] = &str_callid_col;
+	data_vals[callid_col].type = DB1_STR;
+	data_vals[callid_col].nul = 0;
+	data_vals[callid_col].val.str_val= s->callid;
+	n_data_cols++;
+
+	data_cols[totag_col= n_data_cols] = &str_to_tag_col;
+	data_vals[totag_col].type = DB1_STR;
+	data_vals[totag_col].nul = 0;
+	data_vals[totag_col].val.str_val= s->to_tag;
+	n_data_cols++;
+
+	data_cols[fromtag_col= n_data_cols] = &str_from_tag_col;
+	data_vals[fromtag_col].type = DB1_STR;
+	data_vals[fromtag_col].nul = 0;
+	data_vals[fromtag_col].val.str_val= s->from_tag;
+	n_data_cols++;
+
+	data_cols[to_user_col= n_data_cols] = &str_to_user_col;
+	data_vals[to_user_col].type = DB1_STR;
+	data_vals[to_user_col].nul = 0;
+	data_vals[to_user_col].val.str_val = s->to_user;
+	n_data_cols++;
+
+	data_cols[to_domain_col= n_data_cols] = &str_to_domain_col;
+	data_vals[to_domain_col].type = DB1_STR;
+	data_vals[to_domain_col].nul = 0;
+	data_vals[to_domain_col].val.str_val = s->to_domain;
+	n_data_cols++;
+	
+	data_cols[from_user_col= n_data_cols] = &str_watcher_username_col;
+	data_vals[from_user_col].type = DB1_STR;
+	data_vals[from_user_col].nul = 0;
+	data_vals[from_user_col].val.str_val = s->from_user;
+	n_data_cols++;
+
+	data_cols[from_domain_col= n_data_cols] = &str_watcher_domain_col;
+	data_vals[from_domain_col].type = DB1_STR;
+	data_vals[from_domain_col].nul = 0;
+	data_vals[from_domain_col].val.str_val = s->from_domain;
+	n_data_cols++;
+
+	data_cols[event_col= n_data_cols] = &str_event_col;
+	data_vals[event_col].type = DB1_STR;
+	data_vals[event_col].nul = 0;
+	data_vals[event_col].val.str_val = s->event->name;
+	n_data_cols++;	
+
+	data_cols[event_id_col= n_data_cols] = &str_event_id_col;
+	data_vals[event_id_col].type = DB1_STR;
+	data_vals[event_id_col].nul = 0;
+	data_vals[event_id_col].val.str_val = s->event_id;
+	n_data_cols++;
+
+	data_cols[local_cseq_col= n_data_cols]=&str_local_cseq_col;
+	data_vals[local_cseq_col].type = DB1_INT;
+	data_vals[local_cseq_col].nul = 0;
+	data_vals[local_cseq_col].val.int_val= s->local_cseq;
+	n_data_cols++;
+
+	data_cols[remote_cseq_col= n_data_cols]=&str_remote_cseq_col;
+	data_vals[remote_cseq_col].type = DB1_INT;
+	data_vals[remote_cseq_col].nul = 0;
+	data_vals[remote_cseq_col].val.int_val= s->remote_cseq;
+	n_data_cols++;
+
+	data_cols[expires_col= n_data_cols] =&str_expires_col;
+	data_vals[expires_col].type = DB1_INT;
+	data_vals[expires_col].nul = 0;
+	data_vals[expires_col].val.int_val = s->expires + (int)time(NULL);
+	n_data_cols++;
+
+	data_cols[status_col= n_data_cols] =&str_status_col;
+	data_vals[status_col].type = DB1_INT;
+	data_vals[status_col].nul = 0;
+	data_vals[status_col].val.int_val= s->status;
+	n_data_cols++;
+
+	data_cols[reason_col= n_data_cols] =&str_reason_col;
+	data_vals[reason_col].type = DB1_STR;
+	data_vals[reason_col].nul = 0;
+	data_vals[reason_col].val.str_val= s->reason;
+	n_data_cols++;
+
+	data_cols[record_route_col= n_data_cols] =&str_record_route_col;
+	data_vals[record_route_col].type = DB1_STR;
+	data_vals[record_route_col].nul = 0;
+	data_vals[record_route_col].val.str_val = s->record_route;
+	n_data_cols++;
+	
+	data_cols[contact_col= n_data_cols] =&str_contact_col;
+	data_vals[contact_col].type = DB1_STR;
+	data_vals[contact_col].nul = 0;
+	data_vals[contact_col].val.str_val = s->contact;
+	n_data_cols++;
+
+	data_cols[local_contact_col= n_data_cols] =&str_local_contact_col;
+	data_vals[local_contact_col].type = DB1_STR;
+	data_vals[local_contact_col].nul = 0;
+	data_vals[local_contact_col].val.str_val = s->local_contact;
+	n_data_cols++;
+
+	data_cols[socket_info_col= n_data_cols] =&str_socket_info_col;
+	data_vals[socket_info_col].type = DB1_STR;
+	data_vals[socket_info_col].nul = 0;
+	data_vals[socket_info_col].val.str_val= s->sockinfo_str;
+	n_data_cols++;
+
+	data_cols[version_col= n_data_cols]=&str_version_col;
+	data_vals[version_col].type = DB1_INT;
+	data_vals[version_col].nul = 0;
+	data_vals[version_col].val.int_val= s->version;
+	n_data_cols++;
+	
+	/*data_cols[send_on_cback_col= n_data_cols]=&str_send_on_cback_col;
+	data_vals[send_on_cback_col].type = DB1_INT;
+	data_vals[send_on_cback_col].nul = 0;
+	data_vals[send_on_cback_col].val.int_val= s->send_on_cback;
+	n_data_cols++;
+
+	data_cols[db_flag_col= n_data_cols]=&str_db_flag_col;
+	data_vals[db_flag_col].type = DB1_INT;
+	data_vals[db_flag_col].nul = 0;
+	data_vals[db_flag_col].val.int_val= s->db_flag;
+	n_data_cols++;*/
+
+	if(rls2_dbf.insert(rls2_db, data_cols, data_vals, n_data_cols) < 0)
+	{
+		LM_ERR("db insert failed\n");
+		return(-1);
+	}
+
+	if (rlsdb_debug) LM_ERR( "Done\n" );
+	return(0);
+}
+
+/******************************************************************************/
+
+int matches_in_rlsdb( str callid, str to_tag, str from_tag ) 
+
+{
+ 	db1_res_t *result= NULL;
+	db_key_t query_cols[3];
+	db_val_t query_vals[3];
+	db_key_t result_cols[1];
+	int n_query_cols = 0;
+	int callid_col, totag_col, fromtag_col;
+	int rval;
+
+	if (rlsdb_debug)
+		LM_ERR( "matches_in_rlsdb callid=%.*s \nto_tag=%.*s \nfrom_tag=%.*s\n",
+		callid.len, callid.s,
+		to_tag.len, to_tag.s,
+		from_tag.len, from_tag.s );
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(-1);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(-1);
+	}
+	
+	query_cols[callid_col= n_query_cols] = &str_callid_col;
+	query_vals[callid_col].type = DB1_STR;
+	query_vals[callid_col].nul = 0;
+	query_vals[callid_col].val.str_val= callid;
+	n_query_cols++;
+
+	query_cols[totag_col= n_query_cols] = &str_to_tag_col;
+	query_vals[totag_col].type = DB1_STR;
+	query_vals[totag_col].nul = 0;
+	query_vals[totag_col].val.str_val= to_tag;
+	n_query_cols++;
+
+	query_cols[fromtag_col= n_query_cols] = &str_from_tag_col;
+	query_vals[fromtag_col].type = DB1_STR;
+	query_vals[fromtag_col].nul = 0;
+	query_vals[fromtag_col].val.str_val= from_tag;
+	n_query_cols++;
+	
+	result_cols[0]= &str_callid_col; /* should use id column instead here */
+	
+	if(rls2_dbf.query(rls2_db, query_cols, 0, query_vals, result_cols, 
+			n_query_cols, 1, 0, &result )< 0)
+	{
+		LM_ERR("Can't query db\n");
+		if(result) rls2_dbf.free_result(rls2_db, result);
+		return(-1);
+	}
+
+	if(result == NULL) return(-1);
+
+	rval = result->n;
+	rls2_dbf.free_result(rls2_db, result);
+	if (rlsdb_debug) LM_ERR( "Done matches=%d\n", rval );
+	return(rval);
+}
+
+/******************************************************************************/
+
+subs_t *get_dialog_rlsdb( str callid, str to_tag, str from_tag ) 
+
+{
+ 	db_key_t query_cols[3];
+	db_val_t query_vals[3];
+	db_key_t result_cols[22];
+	int n_query_cols = 0, n_result_cols=0;
+	int callid_col, totag_col, fromtag_col;	
+	int r_pres_uri_col,r_to_user_col,r_to_domain_col;
+	int r_from_user_col,r_from_domain_col,r_callid_col;
+	int r_to_tag_col,r_from_tag_col,r_socket_info_col;
+	int r_event_id_col,r_local_contact_col,r_contact_col;
+	int r_record_route_col, r_reason_col;
+	int r_event_col, r_local_cseq_col, r_remote_cseq_col;
+	int r_status_col, r_version_col;
+	int r_expires_col;
+	db1_res_t *result= NULL;
+ 	db_val_t *values;
+	db_row_t *rows;
+	int nr_rows, size, loop;
+	subs_t *dest;
+	event_t parsed_event;
+	str ev_sname;
+
+	if (rlsdb_debug)
+		LM_ERR( "get_dialog_rlsdb callid=%.*s \nto_tag=%.*s \nfrom_tag=%.*s\n",
+		callid.len, callid.s,
+		to_tag.len, to_tag.s,
+		from_tag.len, from_tag.s );
+
+	if(rls2_db == NULL)
+	{
+		LM_ERR("null database connection\n");
+		return(NULL);
+	}
+
+	if(rls2_dbf.use_table(rls2_db, &rlsubs_table)< 0)
+	{
+		LM_ERR("use table failed\n");
+		return(NULL);
+	}
+	
+	query_cols[callid_col= n_query_cols] = &str_callid_col;
+	query_vals[callid_col].type = DB1_STR;
+	query_vals[callid_col].nul = 0;
+	query_vals[callid_col].val.str_val= callid;
+	n_query_cols++;
+
+	query_cols[totag_col= n_query_cols] = &str_to_tag_col;
+	query_vals[totag_col].type = DB1_STR;
+	query_vals[totag_col].nul = 0;
+	query_vals[totag_col].val.str_val= to_tag;
+	n_query_cols++;
+
+	query_cols[fromtag_col= n_query_cols] = &str_from_tag_col;
+	query_vals[fromtag_col].type = DB1_STR;
+	query_vals[fromtag_col].nul = 0;
+	query_vals[fromtag_col].val.str_val= from_tag;
+	n_query_cols++;
+	
+	result_cols[r_pres_uri_col=n_result_cols++] = &str_presentity_uri_col;
+	result_cols[r_to_user_col=n_result_cols++] = &str_to_user_col;
+	result_cols[r_to_domain_col=n_result_cols++] = &str_to_domain_col;
+	result_cols[r_from_user_col=n_result_cols++] = &str_watcher_username_col;
+	result_cols[r_from_domain_col=n_result_cols++] = &str_watcher_domain_col;
+	result_cols[r_callid_col=n_result_cols++] = &str_callid_col;
+	result_cols[r_to_tag_col=n_result_cols++] = &str_to_tag_col;
+	result_cols[r_from_tag_col=n_result_cols++] = &str_from_tag_col;
+	result_cols[r_socket_info_col=n_result_cols++] = &str_socket_info_col;
+	result_cols[r_event_id_col=n_result_cols++] = &str_event_id_col;
+	result_cols[r_local_contact_col=n_result_cols++] = &str_local_contact_col;
+	result_cols[r_contact_col=n_result_cols++] = &str_contact_col;
+	result_cols[r_record_route_col=n_result_cols++] = &str_record_route_col;
+	result_cols[r_reason_col=n_result_cols++] = &str_reason_col;
+	result_cols[r_event_col=n_result_cols++] = &str_event_col;
+	result_cols[r_local_cseq_col=n_result_cols++] = &str_local_cseq_col;
+	result_cols[r_remote_cseq_col=n_result_cols++] = &str_remote_cseq_col;
+	result_cols[r_status_col=n_result_cols++] = &str_status_col;
+	result_cols[r_version_col=n_result_cols++] = &str_version_col;
+	/*result_cols[r_send_on_cback_col=n_result_cols++] = &str_send_on_cback_col;*/
+	result_cols[r_expires_col=n_result_cols++] = &str_expires_col;
+
+
+	if(rls2_dbf.query(rls2_db, query_cols, 0, query_vals, result_cols, 
+				n_query_cols, n_result_cols, 0, &result )< 0)
+	{
+		LM_ERR("Can't query db\n");
+		if(result) rls2_dbf.free_result(rls2_db, result);
+		return(NULL);
+	}
+
+	if(result == NULL) return(NULL);
+
+	nr_rows = RES_ROW_N(result);
+
+	if (nr_rows == 0)
+	{
+		/* no match */ 
+		LM_ERR( "get_dialog_rlsb No matching records\n" );
+		rls2_dbf.free_result(rls2_db, result);
+		return(NULL);
+	}
+
+	if (nr_rows != 1)
+	{
+		LM_ERR( "get_dialog_rlsb multiple matching records\n" );
+		rls2_dbf.free_result(rls2_db, result);
+		return(NULL);
+	}
+
+	/* get the results and fill in return data structure */
+	for (loop=0; loop <nr_rows; loop++)
+	{
+		rows = RES_ROWS(result);
+		values = ROW_VALUES(rows);
+
+		size= sizeof(subs_t) +
+			( strlen(VAL_STRING(values+r_pres_uri_col))
+			+ strlen(VAL_STRING(values+r_to_user_col))
+			+ strlen(VAL_STRING(values+r_to_domain_col))
+			+ strlen(VAL_STRING(values+r_from_user_col))
+			+ strlen(VAL_STRING(values+r_from_domain_col))
+			+ strlen(VAL_STRING(values+r_to_tag_col))
+			+ strlen(VAL_STRING(values+r_from_tag_col))
+			+ strlen(VAL_STRING(values+r_callid_col))
+			+ strlen(VAL_STRING(values+r_socket_info_col))
+			+ strlen(VAL_STRING(values+r_local_contact_col))
+			+ strlen(VAL_STRING(values+r_contact_col))
+			+ strlen(VAL_STRING(values+r_record_route_col))
+			+ strlen(VAL_STRING(values+r_event_id_col))
+			+ strlen(VAL_STRING(values+r_reason_col))+ 1)*sizeof(char);
+
+		dest= (subs_t*)pkg_malloc(size);
+	
+		if(dest== NULL)
+		{
+			LM_ERR( "Can't allocate memory\n" );
+			/* tidy up and return >>>>>>>>>>>>>>>>>>>> */
+			rls2_dbf.free_result(rls2_db, result);
+			return(NULL);
+		}
+		memset(dest, 0, size);
+		size= sizeof(subs_t);
+
+		CONT_COPYDB(dest, dest->pres_uri, VAL_STRING(values+r_pres_uri_col))
+		CONT_COPYDB(dest, dest->to_user, VAL_STRING(values+r_to_user_col))
+		CONT_COPYDB(dest, dest->to_domain, VAL_STRING(values+r_to_domain_col))
+		CONT_COPYDB(dest, dest->from_user, VAL_STRING(values+r_from_user_col))
+		CONT_COPYDB(dest, dest->from_domain, VAL_STRING(values+r_from_domain_col))
+		CONT_COPYDB(dest, dest->to_tag, VAL_STRING(values+r_to_tag_col))
+		CONT_COPYDB(dest, dest->from_tag, VAL_STRING(values+r_from_tag_col))
+		CONT_COPYDB(dest, dest->callid, VAL_STRING(values+r_callid_col))
+		CONT_COPYDB(dest, dest->sockinfo_str, VAL_STRING(values+r_socket_info_col))
+		CONT_COPYDB(dest, dest->local_contact, VAL_STRING(values+r_local_contact_col))
+		CONT_COPYDB(dest, dest->contact, VAL_STRING(values+r_contact_col))
+		CONT_COPYDB(dest, dest->record_route, VAL_STRING(values+r_record_route_col))
+
+		if(strlen(VAL_STRING(values+r_event_id_col)) > 0)
+			CONT_COPYDB(dest, dest->event_id, VAL_STRING(values+r_event_id_col))
+
+		if(strlen(VAL_STRING(values+r_reason_col)) > 0)
+			CONT_COPYDB(dest, dest->reason, VAL_STRING(values+r_reason_col))
+
+
+		ev_sname.s= (char *)VAL_STRING(values+r_event_col);
+		ev_sname.len= strlen(ev_sname.s);
+		
+		dest->event = pres_contains_event(&ev_sname, &parsed_event);
+
+		if(dest->event == NULL)
+		{
+			LM_ERR("event not found and set to NULL\n");
+		}
+
+		dest->local_cseq= VAL_INT(values+r_local_cseq_col);
+		dest->remote_cseq= VAL_INT(values+r_remote_cseq_col);
+		dest->status= VAL_INT(values+r_status_col);
+		dest->version= VAL_INT(values+r_version_col);
+		/*dest->send_on_cback= VAL_INT(values+r_send_on_cback_col);*/
+		dest->expires= VAL_INT(values+r_expires_col);
+
+		/*dest->db_flag= VAL_INT(values+r_db_flag_col);*/
+	}
+
+	rls2_dbf.free_result(rls2_db, result);
+
+	if (rlsdb_debug) LM_ERR( "Done\n" );
+	return(dest);
+}
+
+/******************************************************************************/
+
+void dump_dialog( subs_t *s )
+
+{
+	if (!rlsdb_debug) return;
+	LM_ERR( "pres_rui=%.*s\n", s->pres_uri.len, s->pres_uri.s );
+	LM_ERR( "to_user=%.*s\n", s->to_user.len, s->to_user.s );
+	LM_ERR( "to_domain=%.*s\n", s->to_domain.len, s->to_domain.s );
+	LM_ERR( "from_user=%.*s\n", s->from_user.len, s->from_user.s );
+	LM_ERR( "from_domain=%.*s\n", s->from_domain.len, s->from_domain.s );
+	LM_ERR( "to_tag=%.*s\n", s->to_tag.len, s->to_tag.s );
+	LM_ERR( "from_tag=%.*s\n", s->from_tag.len, s->from_tag.s );
+	LM_ERR( "callid=%.*s\n", s->callid.len, s->callid.s );
+	LM_ERR( "sockinfo_str=%.*s\n", s->sockinfo_str.len, s->sockinfo_str.s );
+	LM_ERR( "local_contact=%.*s\n", s->local_contact.len, s->local_contact.s );
+	LM_ERR( "contact=%.*s\n", s->contact.len, s->contact.s );
+	LM_ERR( "record_route=%.*s\n", s->record_route.len, s->record_route.s );
+	LM_ERR( "event_id=%.*s\n", s->event_id.len, s->event_id.s );
+	LM_ERR( "reason=%.*s\n", s->reason.len, s->reason.s );
+	LM_ERR( "event=%.*s\n", s->event->name.len, s->event->name.s );
+	LM_ERR( "local_cseq=%d\n", s-> local_cseq);
+	LM_ERR( "remote_cseq=%d\n", s->remote_cseq );
+	LM_ERR( "status=%d\n", s->status );
+	LM_ERR( "version=%d\n", s->version );
+	LM_ERR( "expires=%d\n", s->expires );
+	LM_ERR( "send_on_cback=%d\n", s->send_on_cback );
+	LM_ERR( "db_flag=%x\n", s->db_flag );
+}
+
+/******************************************************************************/
+

+ 123 - 56
modules_k/rls/subscribe.c

@@ -154,7 +154,7 @@ int rls_get_service_list(str *service_uri, str *user, str *domain,
 	LM_DBG("searching document for user sip:%.*s@%.*s\n",
 		user->len, user->s, domain->len, domain->s);
 
-	if(rls_dbf.use_table(rls_db, &rls_xcap_table) < 0)
+	if(rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)
 	{
 		LM_ERR("in use_table-[table]= %.*s\n",
 				rls_xcap_table.len, rls_xcap_table.s);
@@ -164,13 +164,13 @@ int rls_get_service_list(str *service_uri, str *user, str *domain,
 	result_cols[xcap_col= n_result_cols++] = &str_doc_col;
 	result_cols[etag_col= n_result_cols++] = &str_etag_col;
 
-	if(rls_dbf.query(rls_db, query_cols, 0 , query_vals, result_cols,
+	if(rls_xcap_dbf.query(rls_xcap_db, query_cols, 0 , query_vals, result_cols,
 				n_query_cols, n_result_cols, 0, &result)<0)
 	{
 		LM_ERR("failed querying table xcap for document [service_uri]=%.*s\n",
 				service_uri->len, service_uri->s);
 		if(result)
-			rls_dbf.free_result(rls_db, result);
+			rls_xcap_dbf.free_result(rls_xcap_db, result);
 		return -1;
 	}
 
@@ -180,7 +180,7 @@ int rls_get_service_list(str *service_uri, str *user, str *domain,
 		
 		if(rls_integrated_xcap_server)
 		{
-			rls_dbf.free_result(rls_db, result);
+			rls_xcap_dbf.free_result(rls_xcap_db, result);
 			return 0;
 		}
 		
@@ -254,7 +254,7 @@ int rls_get_service_list(str *service_uri, str *user, str *domain,
 		*rootdoc = xmldoc;
 	}
 
-	rls_dbf.free_result(rls_db, result);
+	rls_xcap_dbf.free_result(rls_xcap_db, result);
 	if(xcapdoc!=NULL)
 		pkg_free(xcapdoc);
 
@@ -262,7 +262,7 @@ int rls_get_service_list(str *service_uri, str *user, str *domain,
 
 error:
 	if(result!=NULL)
-		rls_dbf.free_result(rls_db, result);
+		rls_xcap_dbf.free_result(rls_xcap_db, result);
 	if(xmldoc!=NULL)
 		xmlFreeDoc(xmldoc);
 	if(xcapdoc!=NULL)
@@ -417,7 +417,7 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2)
 	str* contact = NULL;
 	xmlDocPtr doc = NULL;
 	xmlNodePtr service_node = NULL;
-	unsigned int hash_code;
+	unsigned int hash_code=0;
 	int to_tag_gen = 0;
 	event_t* parsed_event;
 	param_t* ev_param = NULL;
@@ -544,20 +544,33 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2)
 		}
 	} else {
 		/* search if a stored dialog */
-		hash_code = core_hash(&msg->callid->body,
-				&get_to(msg)->tag_value, hash_size);
-		lock_get(&rls_table[hash_code].lock);
-
-		if(pres_search_shtable(rls_table, msg->callid->body,
-				get_to(msg)->tag_value, get_from(msg)->tag_value,
-				hash_code)==NULL)
+		if ( dbmode == RLS_DB_ONLY )
+		{
+			if (matches_in_rlsdb(msg->callid->body,get_to(msg)->tag_value,
+							 get_from(msg)->tag_value ) <= 0 )
+			{
+				LM_DBG("subscription dialog not found for <%.*s>\n",
+						get_from(msg)->uri.len, get_from(msg)->uri.s);
+				goto forpresence;
+			}
+		}
+		else
 		{
+			hash_code = core_hash(&msg->callid->body,
+					&get_to(msg)->tag_value, hash_size);
+			lock_get(&rls_table[hash_code].lock);
+
+			if(pres_search_shtable(rls_table, msg->callid->body,
+					get_to(msg)->tag_value, get_from(msg)->tag_value,
+					hash_code)==NULL)
+			{
+				lock_release(&rls_table[hash_code].lock);
+				LM_DBG("subscription dialog not found for <%.*s>\n",
+						get_from(msg)->uri.len, get_from(msg)->uri.s);
+				goto forpresence;
+			}
 			lock_release(&rls_table[hash_code].lock);
-			LM_DBG("subscription dialog not found for <%.*s>\n",
-					get_from(msg)->uri.len, get_from(msg)->uri.s);
-			goto forpresence;
 		}
-		lock_release(&rls_table[hash_code].lock);
 	}
 
 	/* extract dialog information from message headers */
@@ -572,7 +585,8 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2)
 	if(reply_200(msg, &subs.local_contact, subs.expires)<0)
 		goto error;
 
-	hash_code = core_hash(&subs.callid, &subs.to_tag, hash_size);
+	if (dbmode != RLS_DB_ONLY)
+		hash_code = core_hash(&subs.callid, &subs.to_tag, hash_size);
 
 	if(get_to(msg)->tag_value.s==NULL || get_to(msg)->tag_value.len==0)
 	{ /* initial subscribe */
@@ -581,14 +595,29 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2)
 		if(subs.expires != 0)
 		{
 			subs.version = 1;
-			if(pres_insert_shtable(rls_table, hash_code, &subs)<0)
+			if (dbmode==RLS_DB_ONLY)
+			{
+				rt=insert_rlsdb( &subs );
+			}
+			else
+			{
+				rt=pres_insert_shtable(rls_table, hash_code, &subs);
+			}
+			if (rt<0)
 			{
 				LM_ERR("while adding new subscription\n");
 				goto error;
 			}
 		}
 	} else {
-		rt = update_rlsubs(&subs, hash_code);
+		if (dbmode==RLS_DB_ONLY)
+		{
+			rt=update_subs_rlsdb( &subs );
+		}
+		else
+		{
+			rt = update_rlsubs(&subs, hash_code);
+		}
 		if(rt<0)
 		{
 			LM_ERR("while updating resource list subscription\n");
@@ -634,7 +663,19 @@ int rls_handle_subscribe(struct sip_msg* msg, char* s1, char* s2)
 		LM_ERR("failed sending subscribe requests to resources in list\n");
 		goto error;
 	}
-	remove_expired_rlsubs(&subs, hash_code);
+
+	if (dbmode==RLS_DB_ONLY)
+	{
+		if(subs.expires==0)
+		{
+			LM_ERR( "rls_db removing expired rls subs\n" );
+			delete_rlsdb( &subs.callid, &subs.to_tag, &subs.from_tag );
+		}
+	}
+	else
+	{
+		remove_expired_rlsubs(&subs, hash_code);
+	}
 
 done:
 	if(contact!=NULL)
@@ -693,6 +734,11 @@ int remove_expired_rlsubs( subs_t* subs, unsigned int hash_code)
 	if(subs->expires!=0)
 		return 0;
 
+	if (dbmode == RLS_DB_ONLY)
+	{
+		LM_ERR( "remove_expired_rlsubs called in RLS_DB_ONLY mode\n" );
+	} 
+
 	/* search the record in hash table */
 	lock_get(&rls_table[hash_code].lock);
 
@@ -734,6 +780,11 @@ int update_rlsubs( subs_t* subs, unsigned int hash_code)
 {
 	subs_t* s;
 
+	if (dbmode == RLS_DB_ONLY)
+	{
+		LM_ERR( "update_rlsubs called in RLS_DB_ONLY mode\n" );
+	} 
+
 	/* search the record in hash table */
 	lock_get(&rls_table[hash_code].lock);
 
@@ -886,6 +937,48 @@ int fixup_update_subs(void** param, int param_no)
 	return 0;
 }
 
+void update_a_sub(subs_t *subs_copy )
+
+{
+	xmlDocPtr doc = NULL;
+	xmlNodePtr service_node = NULL;
+
+	if ((subs_copy->expires -= (int)time(NULL)) <= 0)
+	{
+		LM_WARN("found expired subscription for: %.*s\n",
+			subs_copy->pres_uri.len, subs_copy->pres_uri.s);
+		goto done;
+	}
+
+	if(rls_get_service_list(&subs_copy->pres_uri, &subs_copy->from_user,
+				&subs_copy->from_domain, &service_node, &doc)<0)
+	{
+		LM_ERR("failed getting resource list for: %.*s\n",
+			subs_copy->pres_uri.len, subs_copy->pres_uri.s);
+		goto done;
+	}
+
+	if(doc==NULL)
+	{
+		LM_WARN("no document returned for: %.*s\n",
+			subs_copy->pres_uri.len, subs_copy->pres_uri.s);
+		goto done;
+	}
+
+	if(resource_subscriptions(subs_copy, service_node)< 0)
+	{
+		LM_ERR("failed sending subscribe requests to resources in list\n");
+		goto done;
+	}
+
+done:
+	if (doc != NULL)
+		xmlFreeDoc(doc);
+
+	pkg_free(subs_copy);
+}
+
+
 int rls_update_subs(struct sip_msg *msg, char *puri, char *pevent)
 {
 	str uri;
@@ -935,6 +1028,12 @@ int rls_update_subs(struct sip_msg *msg, char *puri, char *pevent)
 		parsed_uri.user.len, parsed_uri.user.s,
 		parsed_uri.host.len, parsed_uri.host.s);
 
+	if (dbmode==RLS_DB_ONLY)
+	{
+		return(update_all_subs_rlsdb(&parsed_uri.user, &parsed_uri.host, &event));
+	}
+
+
 	if (rls_table == NULL)
 	{
 		LM_ERR("rls_table is NULL\n");
@@ -959,9 +1058,7 @@ int rls_update_subs(struct sip_msg *msg, char *puri, char *pevent)
 				subs->event->evp->type == e.type)
 			{
 				subs_t *subs_copy = NULL;
-				xmlDocPtr doc = NULL;
-				xmlNodePtr service_node = NULL;
-	
+
 				LM_DBG("found matching RLS subscription for: %.*s\n",
 					subs->pres_uri.len, subs->pres_uri.s);
 
@@ -972,37 +1069,7 @@ int rls_update_subs(struct sip_msg *msg, char *puri, char *pevent)
 					return -1;
 				}
 
-				if ((subs_copy->expires -= (int)time(NULL)) <= 0)
-				{
-					LM_WARN("found expired subscription for: %.*s\n",
-						subs_copy->pres_uri.len, subs_copy->pres_uri.s);
-					goto loop_done;
-				}
-
-				if(rls_get_service_list(&subs_copy->pres_uri, &subs_copy->from_user,
-							&subs_copy->from_domain, &service_node, &doc)<0)
-				{
-					LM_ERR("failed getting resource list for: %.*s\n",
-						subs_copy->pres_uri.len, subs_copy->pres_uri.s);
-					goto loop_done;
-				}
-				if(doc==NULL)
-				{
-					LM_WARN("no document returned for: %.*s\n",
-						subs_copy->pres_uri.len, subs_copy->pres_uri.s);
-					goto loop_done;
-				}
-
-				if(resource_subscriptions(subs_copy, service_node)< 0)
-				{
-					LM_ERR("failed sending subscribe requests to resources in list\n");
-					goto loop_done;
-				}
-
-loop_done:
-				if (doc != NULL)
-					xmlFreeDoc(doc);
-				pkg_free(subs_copy);
+				update_a_sub(subs_copy);
 			}
 			subs = subs->next;
 		}