presence: rename recently added parameter to the 'standard' db_mode that others uses
[sip-router] / modules_k / presence / presence.c
1 /*
2  * $Id$
3  *
4  * presence module - presence server implementation
5  *
6  * Copyright (C) 2006 Voice Sistem S.R.L.
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * History:
25  * --------
26  *  2006-08-15  initial version (anca)
27  */
28
29 /*! \defgroup presence Presence :: A generic implementation of the SIP event package (PUBLISH, SUBSCRIBE, NOTIFY)
30  *
31  *         The Kamailio presence module is a generic module for SIP event packages, which is much more than presence.
32  *         It is extensible by developing other modules that use the internal developer API.
33  *         Examples:
34  *         - \ref presence_mwi
35  *         - \ref presence_xml
36  */
37
38 /*! \file
39  * \brief Kamailio presence module
40  * 
41  * \ingroup presence 
42  */
43
44
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <sys/types.h>
49 #include <sys/ipc.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <time.h>
53
54 #include "../../lib/srdb1/db.h"
55 #include "../../sr_module.h"
56 #include "../../dprint.h"
57 #include "../../error.h"
58 #include "../../ut.h"
59 #include "../../parser/parse_to.h"
60 #include "../../parser/parse_uri.h" 
61 #include "../../parser/parse_content.h"
62 #include "../../parser/parse_from.h"
63 #include "../../mem/mem.h"
64 #include "../../mem/shm_mem.h"
65 #include "../../usr_avp.h"
66 #include "../../modules/tm/tm_load.h"
67 #include "../../modules/sl/sl.h"
68 #include "../../pt.h"
69 #include "../../lib/kmi/mi.h"
70 #include "../../lib/kcore/hash_func.h"
71 #include "../pua/hash.h"
72 #include "presence.h"
73 #include "publish.h"
74 #include "subscribe.h"
75 #include "event_list.h"
76 #include "bind_presence.h"
77 #include "notify.h"
78 #include "../../mod_fix.h"
79
80 MODULE_VERSION
81
82 #define S_TABLE_VERSION  3
83 #define P_TABLE_VERSION  3
84 #define ACTWATCH_TABLE_VERSION 9
85
86 char *log_buf = NULL;
87 static int clean_period=100;
88 static int db_update_period=100;
89
90 /* database connection */
91 db1_con_t *pa_db = NULL;
92 db_func_t pa_dbf;
93 str presentity_table= str_init("presentity");
94 str active_watchers_table = str_init("active_watchers");
95 str watchers_table= str_init("watchers");
96
97 int library_mode= 0;
98 str server_address= {0, 0};
99 evlist_t* EvList= NULL;
100
101 /* to tag prefix */
102 char* to_tag_pref = "10";
103
104 /* TM bind */
105 struct tm_binds tmb;
106 /* SL API structure */
107 sl_api_t slb;
108
109 /** module functions */
110
111 static int mod_init(void);
112 static int child_init(int);
113 static void destroy(void);
114 int stored_pres_info(struct sip_msg* msg, char* pres_uri, char* s);
115 static int fixup_presence(void** param, int param_no);
116 static int fixup_subscribe(void** param, int param_no);
117 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param);
118 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param);
119 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code,
120                 subs_t** subs_array);
121 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc);
122 static int mi_child_init(void);
123 static int pres_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2);
124 static int w_pres_refresh_watchers(struct sip_msg *msg, char *puri,
125                 char *pevent, char *ptype);
126 static int w_pres_update_watchers(struct sip_msg *msg, char *puri,
127                 char *pevent);
128 static int fixup_refresh_watchers(void** param, int param_no);
129 static int fixup_update_watchers(void** param, int param_no);
130
131 int counter =0;
132 int pid = 0;
133 char prefix='a';
134 int startup_time=0;
135 str db_url = {0, 0};
136 int expires_offset = 0;
137 int max_expires= 3600;
138 int shtable_size= 9;
139 shtable_t subs_htable= NULL;
140 int dbmode = 0;
141 int fallback2db = 0;
142 int sphere_enable= 0;
143 int timeout_rm_subs = 1;
144
145 int phtable_size= 9;
146 phtable_t* pres_htable;
147
148 static cmd_export_t cmds[]=
149 {
150         {"handle_publish",        (cmd_function)handle_publish,          0,
151                 fixup_presence,0, REQUEST_ROUTE},
152         {"handle_publish",        (cmd_function)handle_publish,          1,
153                 fixup_presence, 0, REQUEST_ROUTE},
154         {"handle_subscribe",      (cmd_function)handle_subscribe,        0,
155                 fixup_subscribe,0, REQUEST_ROUTE},
156         {"pres_auth_status",      (cmd_function)pres_auth_status,        2,
157                 fixup_pvar_pvar, fixup_free_pvar_pvar, REQUEST_ROUTE},
158         {"pres_refresh_watchers", (cmd_function)w_pres_refresh_watchers, 3,
159                 fixup_refresh_watchers, 0, ANY_ROUTE},
160         {"pres_update_watchers",  (cmd_function)w_pres_update_watchers,  2,
161                 fixup_update_watchers, 0, ANY_ROUTE},
162         {"bind_presence",         (cmd_function)bind_presence,           1,
163                 0, 0, 0},
164         { 0, 0, 0, 0, 0, 0}
165 };
166
167 static param_export_t params[]={
168         { "db_url",                 STR_PARAM, &db_url.s},
169         { "presentity_table",       STR_PARAM, &presentity_table.s},
170         { "active_watchers_table",  STR_PARAM, &active_watchers_table.s},
171         { "watchers_table",         STR_PARAM, &watchers_table.s},
172         { "clean_period",           INT_PARAM, &clean_period },
173         { "db_update_period",       INT_PARAM, &db_update_period },
174         { "to_tag_pref",            STR_PARAM, &to_tag_pref },
175         { "expires_offset",         INT_PARAM, &expires_offset },
176         { "max_expires",            INT_PARAM, &max_expires },
177         { "server_address",         STR_PARAM, &server_address.s},
178         { "subs_htable_size",       INT_PARAM, &shtable_size},
179         { "pres_htable_size",       INT_PARAM, &phtable_size},
180         { "db_mode",                INT_PARAM, &dbmode},
181         { "fallback2db",            INT_PARAM, &fallback2db},
182         { "enable_sphere_check",    INT_PARAM, &sphere_enable},
183         { "timeout_rm_subs",        INT_PARAM, &timeout_rm_subs},
184     {0,0,0}
185 };
186
187 static mi_export_t mi_cmds[] = {
188         { "refreshWatchers", mi_refreshWatchers,    0,  0,  mi_child_init},
189         { "cleanup",         mi_cleanup,            0,  0,  mi_child_init},
190         {  0,                0,                     0,  0,  0}
191 };
192
193 /** module exports */
194 struct module_exports exports= {
195         "presence",                     /* module name */
196         DEFAULT_DLFLAGS,        /* dlopen flags */
197         cmds,                           /* exported functions */
198         params,                         /* exported parameters */
199         0,                                      /* exported statistics */
200         mi_cmds,                        /* exported MI functions */
201         0,                                      /* exported pseudo-variables */
202         0,                                      /* extra processes */
203         mod_init,                       /* module initialization function */
204         0,                              /* response handling function */
205         (destroy_function) destroy,     /* destroy function */
206         child_init                      /* per-child init function */
207 };
208
209 /**
210  * init module function
211  */
212 static int mod_init(void)
213 {
214         if(register_mi_mod(exports.name, mi_cmds)!=0)
215         {
216                 LM_ERR("failed to register MI commands\n");
217                 return -1;
218         }
219
220         db_url.len = db_url.s ? strlen(db_url.s) : 0;
221         LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len,db_url.s);
222         presentity_table.len = strlen(presentity_table.s);
223         active_watchers_table.len = strlen(active_watchers_table.s);
224         watchers_table.len = strlen(watchers_table.s);
225
226         if(db_url.s== NULL)
227                 library_mode= 1;
228
229         if(library_mode== 1)
230         {
231                 LM_DBG("Presence module used for API library purpose only\n");
232                 EvList= init_evlist();
233                 if(!EvList)
234                 {
235                         LM_ERR("unsuccessful initialize event list\n");
236                         return -1;
237                 }
238                 return 0;
239         }
240
241         if(expires_offset<0)
242                 expires_offset = 0;
243         
244         if(to_tag_pref==NULL || strlen(to_tag_pref)==0)
245                 to_tag_pref="10";
246
247         if(max_expires<= 0)
248                 max_expires = 3600;
249
250         if(server_address.s== NULL)
251                 LM_DBG("server_address parameter not set in configuration file\n");
252         
253         if(server_address.s)
254                 server_address.len= strlen(server_address.s);
255         else
256                 server_address.len= 0;
257
258         /* bind the SL API */
259         if (sl_load_api(&slb)!=0) {
260                 LM_ERR("cannot bind to SL API\n");
261                 return -1;
262         }
263
264         /* load all TM stuff */
265         if(load_tm_api(&tmb)==-1)
266         {
267                 LM_ERR("Can't load tm functions. Module TM not loaded?\n");
268                 return -1;
269         }
270         
271         if(db_url.s== NULL)
272         {
273                 LM_ERR("database url not set!\n");
274                 return -1;
275         }
276
277         /* binding to database module  */
278         if (db_bind_mod(&db_url, &pa_dbf))
279         {
280                 LM_ERR("Database module not found\n");
281                 return -1;
282         }
283         
284
285         if (!DB_CAPABILITY(pa_dbf, DB_CAP_ALL))
286         {
287                 LM_ERR("Database module does not implement all functions"
288                                 " needed by presence module\n");
289                 return -1;
290         }
291
292         pa_db = pa_dbf.init(&db_url);
293         if (!pa_db)
294         {
295                 LM_ERR("Connection to database failed\n");
296                 return -1;
297         }
298         
299         /*verify table versions */
300         if((db_check_table_version(&pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION) < 0) ||
301                 (db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) ||
302                 (db_check_table_version(&pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION) < 0)) {
303                         LM_ERR("error during table version check\n");
304                         return -1;
305         }
306
307         EvList= init_evlist();
308         if(!EvList)
309         {
310                 LM_ERR("initializing event list\n");
311                 return -1;
312         }
313
314         if(shtable_size< 1)
315                 shtable_size= 512;
316         else
317                 shtable_size= 1<< shtable_size;
318
319         subs_htable= new_shtable(shtable_size);
320         if(subs_htable== NULL)
321         {
322                 LM_ERR(" initializing subscribe hash table\n");
323                 return -1;
324         }
325
326         if(dbmode != DB_ONLY)
327         {
328                 if(restore_db_subs()< 0)
329                 {
330                         LM_ERR("restoring subscribe info from database\n");
331                         return -1;
332                 }
333         }
334
335         if(phtable_size< 1)
336                 phtable_size= 256;
337         else
338                 phtable_size= 1<< phtable_size;
339
340         pres_htable= new_phtable();
341         if(pres_htable== NULL)
342         {
343                 LM_ERR("initializing presentity hash table\n");
344                 return -1;
345         }
346
347         if(pres_htable_restore()< 0)
348         {
349                 LM_ERR("filling in presentity hash table from database\n");
350                 return -1;
351         }
352
353         startup_time = (int) time(NULL);
354         
355         if(clean_period>0)
356         {
357                 register_timer(msg_presentity_clean, 0, clean_period);
358                 register_timer(msg_watchers_clean, 0, clean_period);
359         }
360         
361         if(db_update_period>0)
362                 register_timer(timer_db_update, 0, db_update_period);
363
364         if(pa_db)
365                 pa_dbf.close(pa_db);
366         pa_db = NULL;
367         
368         /* for legacy, we also keep the fallback2db parameter, but make sure for consistency */
369         if(fallback2db)
370         {
371                 dbmode = DB_FALLBACK;
372         }
373
374         return 0;
375 }
376
377 /**
378  * Initialize children
379  */
380 static int child_init(int rank)
381 {
382         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
383                 return 0; /* do nothing for the main process */
384
385         pid = my_pid();
386         
387         if(library_mode)
388                 return 0;
389
390         if (pa_dbf.init==0)
391         {
392                 LM_CRIT("child_init: database not bound\n");
393                 return -1;
394         }
395         if (pa_db)
396                 return 0;
397         pa_db = pa_dbf.init(&db_url);
398         if (!pa_db)
399         {
400                 LM_ERR("child %d: unsuccessful connecting to database\n", rank);
401                 return -1;
402         }
403         
404         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)  
405         {
406                 LM_ERR( "child %d:unsuccessful use_table presentity_table\n", rank);
407                 return -1;
408         }
409
410         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)  
411         {
412                 LM_ERR( "child %d:unsuccessful use_table active_watchers_table\n",
413                                 rank);
414                 return -1;
415         }
416
417         if (pa_dbf.use_table(pa_db, &watchers_table) < 0)  
418         {
419                 LM_ERR( "child %d:unsuccessful use_table watchers_table\n", rank);
420                 return -1;
421         }
422
423         LM_DBG("child %d: Database connection opened successfully\n", rank);
424         
425         return 0;
426 }
427
428 static int mi_child_init(void)
429 {
430         if(library_mode)
431                 return 0;
432
433         if (pa_dbf.init==0)
434         {
435                 LM_CRIT("database not bound\n");
436                 return -1;
437         }
438         if (pa_db)
439                 return 0;
440         pa_db = pa_dbf.init(&db_url);
441         if (!pa_db)
442         {
443                 LM_ERR("connecting database\n");
444                 return -1;
445         }
446         
447         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
448         {
449                 LM_ERR( "unsuccessful use_table presentity_table\n");
450                 return -1;
451         }
452
453         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)
454         {
455                 LM_ERR( "unsuccessful use_table active_watchers_table\n");
456                 return -1;
457         }
458
459         if (pa_dbf.use_table(pa_db, &watchers_table) < 0)
460         {
461                 LM_ERR( "unsuccessful use_table watchers_table\n");
462                 return -1;
463         }
464
465         LM_DBG("Database connection opened successfully\n");
466         return 0;
467 }
468
469
470 /*
471  * destroy function
472  */
473 static void destroy(void)
474 {
475         if(subs_htable && pa_db)
476                 timer_db_update(0, 0);
477
478         if(subs_htable)
479                 destroy_shtable(subs_htable, shtable_size);
480         
481         if(pres_htable)
482                 destroy_phtable();
483
484         if(pa_db && pa_dbf.close)
485                 pa_dbf.close(pa_db);
486         
487         destroy_evlist();
488 }
489
490 static int fixup_presence(void** param, int param_no)
491 {
492         pv_elem_t *model;
493         str s;
494
495         if(library_mode)
496         {
497                 LM_ERR("Bad config - you can not call 'handle_publish' function"
498                                 " (db_url not set)\n");
499                 return -1;
500         }
501         if(param_no== 0)
502                 return 0;
503
504         if(*param)
505         {
506                 s.s = (char*)(*param); s.len = strlen(s.s);
507                 if(pv_parse_format(&s, &model)<0)
508                 {
509                         LM_ERR( "wrong format[%s]\n",(char*)(*param));
510                         return E_UNSPEC;
511                 }
512  
513                 *param = (void*)model;
514                 return 0;
515         }
516         LM_ERR( "null format\n");
517         return E_UNSPEC;
518 }
519
520 static int fixup_subscribe(void** param, int param_no)
521 {
522
523         if(library_mode)
524         {
525                 LM_ERR("Bad config - you can not call 'handle_subscribe' function"
526                                 " (db_url not set)\n");
527                 return -1;
528         }
529         return 0;
530 }
531
532 int pres_refresh_watchers(str *pres, str *event, int type)
533 {
534         pres_ev_t *ev;
535         struct sip_uri uri;
536         str *rules_doc= NULL;
537         int result;
538
539         ev= contains_event(event, NULL);
540         if(ev==NULL)
541         {
542                 LM_ERR("wrong event parameter\n");
543                 return -1;
544         }
545
546         if(type==0)
547         {
548                 /* if a request to refresh watchers authorization */
549                 if(ev->get_rules_doc==NULL)
550                 {
551                         LM_ERR("wrong request for a refresh watchers authorization status"
552                                         "for an event that does not require authorization\n");
553                         goto error;
554                 }
555
556                 if(parse_uri(pres->s, pres->len, &uri)<0)
557                 {
558                         LM_ERR("parsing uri [%.*s]\n", pres->len, pres->s);
559                         goto error;
560                 }
561
562                 result= ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
563                 if(result<0 || rules_doc==NULL || rules_doc->s==NULL)
564                 {
565                         LM_ERR("no rules doc found for the user\n");
566                         goto error;
567                 }
568
569                 if(update_watchers_status(*pres, ev, rules_doc)<0)
570                 {
571                         LM_ERR("failed to update watchers\n");
572                         goto error;
573                 }
574
575                 pkg_free(rules_doc->s);
576                 pkg_free(rules_doc);
577                 rules_doc = NULL;
578
579         } else {
580                 /* if a request to refresh notified info */
581                 if(query_db_notify(pres, ev, NULL)< 0)
582                 {
583                         LM_ERR("sending Notify requests\n");
584                         goto error;
585                 }
586
587         }
588         return 0;
589
590 error:
591         if(rules_doc)
592         {
593                 if(rules_doc->s)
594                         pkg_free(rules_doc->s);
595                 pkg_free(rules_doc);
596         }
597         return -1;
598 }
599
600 /*! \brief
601  *  mi cmd: refreshWatchers
602  *                      \<presentity_uri> 
603  *                      \<event>
604  *          \<refresh_type> // can be:  = 0 -> watchers autentification type or
605  *                                                                        != 0 -> publish type //                  
606  *              * */
607
608 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param)
609 {
610         struct mi_node* node= NULL;
611         str pres_uri, event;
612         unsigned int refresh_type;
613
614         LM_DBG("start\n");
615         
616         node = cmd->node.kids;
617         if(node == NULL)
618                 return 0;
619
620         /* Get presentity URI */
621         pres_uri = node->value;
622         if(pres_uri.s == NULL || pres_uri.len== 0)
623         {
624                 LM_ERR( "empty uri\n");
625                 return init_mi_tree(404, "Empty presentity URI", 20);
626         }
627         
628         node = node->next;
629         if(node == NULL)
630                 return 0;
631         event= node->value;
632         if(event.s== NULL || event.len== 0)
633         {
634                 LM_ERR( "empty event parameter\n");
635                 return init_mi_tree(400, "Empty event parameter", 21);
636         }
637         LM_DBG("event '%.*s'\n",  event.len, event.s);
638         
639         node = node->next;
640         if(node == NULL)
641                 return 0;
642         if(node->value.s== NULL || node->value.len== 0)
643         {
644                 LM_ERR( "empty refresh type parameter\n");
645                 return init_mi_tree(400, "Empty refresh type parameter", 28);
646         }
647         if(str2int(&node->value, &refresh_type)< 0)
648         {
649                 LM_ERR("converting string to int\n");
650                 goto error;
651         }
652
653         if(node->next!= NULL)
654         {
655                 LM_ERR( "Too many parameters\n");
656                 return init_mi_tree(400, "Too many parameters", 19);
657         }
658
659         if(pres_refresh_watchers(&pres_uri, &event, refresh_type)<0)
660                 return 0;
661         
662         return init_mi_tree(200, "OK", 2);
663
664 error:
665         return 0;
666 }
667
668 /* 
669  *  mi cmd: cleanup
670  *              * */
671
672 static struct mi_root* mi_cleanup(struct mi_root* cmd, void* param)
673 {
674         LM_DBG("mi_cleanup:start\n");
675         
676         (void)msg_watchers_clean(0,0);
677         (void)msg_presentity_clean(0,0);
678                 
679         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
680 }
681
682 int pres_update_status(subs_t subs, str reason, db_key_t* query_cols,
683         db_val_t* query_vals, int n_query_cols, subs_t** subs_array)
684 {
685         db_key_t update_cols[5];
686         db_val_t update_vals[5];
687         int n_update_cols= 0;
688         int u_status_col, u_reason_col, q_wuser_col, q_wdomain_col;
689         int status;
690         query_cols[q_wuser_col=n_query_cols]= &str_watcher_username_col;
691         query_vals[n_query_cols].nul= 0;
692         query_vals[n_query_cols].type= DB1_STR;
693         n_query_cols++;
694
695         query_cols[q_wdomain_col=n_query_cols]= &str_watcher_domain_col;
696         query_vals[n_query_cols].nul= 0;
697         query_vals[n_query_cols].type= DB1_STR;
698         n_query_cols++;
699
700         update_cols[u_status_col= n_update_cols]= &str_status_col;
701         update_vals[u_status_col].nul= 0;
702         update_vals[u_status_col].type= DB1_INT;
703         n_update_cols++;
704
705         update_cols[u_reason_col= n_update_cols]= &str_reason_col;
706         update_vals[u_reason_col].nul= 0;
707         update_vals[u_reason_col].type= DB1_STR;
708         n_update_cols++;
709
710         status= subs.status;
711         if(subs.event->get_auth_status(&subs)< 0)
712         {
713                 LM_ERR( "getting status from rules document\n");
714                 return -1;
715         }
716         LM_DBG("subs.status= %d\n", subs.status);
717         if(get_status_str(subs.status)== NULL)
718         {
719                 LM_ERR("wrong status: %d\n", subs.status);
720                 return -1;
721         }
722
723         if(subs.status!= status || reason.len!= subs.reason.len ||
724                 (reason.s && subs.reason.s && strncmp(reason.s, subs.reason.s,
725                                                                                           reason.len)))
726         {
727                 /* update in watchers_table */
728                 query_vals[q_wuser_col].val.str_val= subs.from_user; 
729                 query_vals[q_wdomain_col].val.str_val= subs.from_domain; 
730
731                 update_vals[u_status_col].val.int_val= subs.status;
732                 update_vals[u_reason_col].val.str_val= subs.reason;
733                 
734                 if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
735                 {
736                         LM_ERR( "in use_table\n");
737                         return -1;
738                 }
739
740                 if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
741                                         update_vals, n_query_cols, n_update_cols)< 0)
742                 {
743                         LM_ERR( "in sql update\n");
744                         return -1;
745                 }
746                 /* save in the list all affected dialogs */
747                 /* if status switches to terminated -> delete dialog */
748                 if(update_pw_dialogs(&subs, subs.db_flag, subs_array)< 0)
749                 {
750                         LM_ERR( "extracting dialogs from [watcher]=%.*s@%.*s to"
751                                 " [presentity]=%.*s\n", subs.from_user.len, subs.from_user.s,
752                                 subs.from_domain.len, subs.from_domain.s, subs.pres_uri.len,
753                                 subs.pres_uri.s);
754                         return -1;
755                 }
756         }
757     return 0;
758 }
759
760 int pres_db_delete_status(subs_t* s)
761 {
762     int n_query_cols= 0;
763     db_key_t query_cols[5];
764     db_val_t query_vals[5];
765
766     if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
767     {
768         LM_ERR("sql use table failed\n");
769         return -1;
770     }
771
772     query_cols[n_query_cols]= &str_event_col;
773     query_vals[n_query_cols].nul= 0;
774     query_vals[n_query_cols].type= DB1_STR;
775     query_vals[n_query_cols].val.str_val= s->event->name ;
776     n_query_cols++;
777
778     query_cols[n_query_cols]= &str_presentity_uri_col;
779     query_vals[n_query_cols].nul= 0;
780     query_vals[n_query_cols].type= DB1_STR;
781     query_vals[n_query_cols].val.str_val= s->pres_uri;
782     n_query_cols++;
783
784     query_cols[n_query_cols]= &str_watcher_username_col;
785     query_vals[n_query_cols].nul= 0;
786     query_vals[n_query_cols].type= DB1_STR;
787     query_vals[n_query_cols].val.str_val= s->from_user;
788     n_query_cols++;
789
790     query_cols[n_query_cols]= &str_watcher_domain_col;
791     query_vals[n_query_cols].nul= 0;
792     query_vals[n_query_cols].type= DB1_STR;
793     query_vals[n_query_cols].val.str_val= s->from_domain;
794     n_query_cols++;
795
796     if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols)< 0)
797     {
798         LM_ERR("sql delete failed\n");
799         return -1;
800     }
801     return 0;
802
803 }
804
805 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc)
806 {
807         subs_t subs;
808         db_key_t query_cols[6], result_cols[5];
809         db_val_t query_vals[6];
810         int n_result_cols= 0, n_query_cols = 0;
811         db1_res_t* result= NULL;
812         db_row_t *row;
813         db_val_t *row_vals ;
814         int i;
815         str w_user, w_domain, reason= {0, 0};
816         unsigned int status;
817         int status_col, w_user_col, w_domain_col, reason_col;
818         subs_t* subs_array= NULL,* s;
819         unsigned int hash_code;
820         int err_ret= -1;
821         int n= 0;
822
823         typedef struct ws
824         {
825                 int status;
826                 str reason;
827                 str w_user;
828                 str w_domain;
829         }ws_t;
830         ws_t* ws_list= NULL;
831
832     LM_DBG("start\n");
833
834         if(ev->content_type.s== NULL)
835         {
836                 ev= contains_event(&ev->name, NULL);
837                 if(ev== NULL)
838                 {
839                         LM_ERR("wrong event parameter\n");
840                         return 0;
841                 }
842         }
843
844         subs.pres_uri= pres_uri;
845         subs.event= ev;
846         subs.auth_rules_doc= rules_doc;
847
848         /* update in watchers_table */
849         query_cols[n_query_cols]= &str_presentity_uri_col;
850         query_vals[n_query_cols].nul= 0;
851         query_vals[n_query_cols].type= DB1_STR;
852         query_vals[n_query_cols].val.str_val= pres_uri;
853         n_query_cols++;
854
855         query_cols[n_query_cols]= &str_event_col;
856         query_vals[n_query_cols].nul= 0;
857         query_vals[n_query_cols].type= DB1_STR;
858         query_vals[n_query_cols].val.str_val= ev->name;
859         n_query_cols++;
860
861         result_cols[status_col= n_result_cols++]= &str_status_col;
862         result_cols[reason_col= n_result_cols++]= &str_reason_col;
863         result_cols[w_user_col= n_result_cols++]= &str_watcher_username_col;
864         result_cols[w_domain_col= n_result_cols++]= &str_watcher_domain_col;
865
866         if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
867         {
868                 LM_ERR( "in use_table\n");
869                 goto done;
870         }
871
872         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols,n_query_cols,
873                                 n_result_cols, 0, &result)< 0)
874         {
875                 LM_ERR( "in sql query\n");
876                 goto done;
877         }
878         if(result== NULL)
879                 return 0;
880
881         if(result->n<= 0)
882         {
883                 err_ret= 0;
884                 goto done;
885         }
886
887     LM_DBG("found %d record-uri in watchers_table\n", result->n);
888         hash_code= core_hash(&pres_uri, &ev->name, shtable_size);
889         subs.db_flag= hash_code;
890
891     /*must do a copy as sphere_check requires database queries */
892         if(sphere_enable)
893         {
894         n= result->n;
895                 ws_list= (ws_t*)pkg_malloc(n * sizeof(ws_t));
896                 if(ws_list== NULL)
897                 {
898                         LM_ERR("No more private memory\n");
899                         goto done;
900                 }
901                 memset(ws_list, 0, n * sizeof(ws_t));
902
903                 for(i= 0; i< result->n ; i++)
904                 {
905                         row= &result->rows[i];
906                         row_vals = ROW_VALUES(row);
907
908                         status= row_vals[status_col].val.int_val;
909         
910                         reason.s= (char*)row_vals[reason_col].val.string_val;
911                         reason.len= reason.s?strlen(reason.s):0;
912
913                         w_user.s= (char*)row_vals[w_user_col].val.string_val;
914                         w_user.len= strlen(w_user.s);
915
916                         w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
917                         w_domain.len= strlen(w_domain.s);
918
919                         if(reason.len)
920                         {
921                                 ws_list[i].reason.s = (char*)pkg_malloc(reason.len* sizeof(char));
922                                 if(ws_list[i].reason.s== NULL)
923                                 {  
924                                         LM_ERR("No more private memory\n");
925                                         goto done;
926                                 }
927                                 memcpy(ws_list[i].reason.s, reason.s, reason.len);
928                                 ws_list[i].reason.len= reason.len;
929                         }
930                         else
931                                 ws_list[i].reason.s= NULL;
932             
933                         ws_list[i].w_user.s = (char*)pkg_malloc(w_user.len* sizeof(char));
934                         if(ws_list[i].w_user.s== NULL)
935                         {
936                                 LM_ERR("No more private memory\n");
937                                 goto done;
938
939                         }
940                         memcpy(ws_list[i].w_user.s, w_user.s, w_user.len);
941                         ws_list[i].w_user.len= w_user.len;
942                 
943                          ws_list[i].w_domain.s = (char*)pkg_malloc(w_domain.len* sizeof(char));
944                         if(ws_list[i].w_domain.s== NULL)
945                         {
946                                 LM_ERR("No more private memory\n");
947                                 goto done;
948                         }
949                         memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len);
950                         ws_list[i].w_domain.len= w_domain.len;
951                         
952                         ws_list[i].status= status;
953                 }
954
955                 pa_dbf.free_result(pa_db, result);
956                 result= NULL;
957
958                 for(i=0; i< n; i++)
959                 {
960                         subs.from_user = ws_list[i].w_user;
961                         subs.from_domain = ws_list[i].w_domain;
962                         subs.status = ws_list[i].status;
963                         memset(&subs.reason, 0, sizeof(str));
964
965                         if( pres_update_status(subs, reason, query_cols, query_vals,
966                                         n_query_cols, &subs_array)< 0)
967                         {
968                                 LM_ERR("failed to update watcher status\n");
969                                 goto done;
970                         }
971
972                 }
973         
974                 for(i=0; i< n; i++)
975                 {
976                         pkg_free(ws_list[i].w_user.s);
977                         pkg_free(ws_list[i].w_domain.s);
978                         if(ws_list[i].reason.s)
979                                 pkg_free(ws_list[i].reason.s);
980                 }
981                 ws_list= NULL;
982
983                 goto send_notify;
984
985         }
986         
987         for(i = 0; i< result->n; i++)
988         {
989                 row= &result->rows[i];
990                 row_vals = ROW_VALUES(row);
991
992                 status= row_vals[status_col].val.int_val;
993         
994                 reason.s= (char*)row_vals[reason_col].val.string_val;
995                 reason.len= reason.s?strlen(reason.s):0;
996
997                 w_user.s= (char*)row_vals[w_user_col].val.string_val;
998                 w_user.len= strlen(w_user.s);
999
1000                 w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
1001                 w_domain.len= strlen(w_domain.s);
1002
1003                 subs.from_user= w_user;
1004                 subs.from_domain= w_domain;
1005                 subs.status= status;
1006                 memset(&subs.reason, 0, sizeof(str));
1007
1008                 if( pres_update_status(subs,reason, query_cols, query_vals,
1009                                         n_query_cols, &subs_array)< 0)
1010                 {
1011                         LM_ERR("failed to update watcher status\n");
1012                         goto done;
1013                 }
1014     }
1015
1016         pa_dbf.free_result(pa_db, result);
1017         result= NULL;
1018
1019 send_notify:
1020
1021         s= subs_array;
1022
1023         while(s)
1024         {
1025
1026                 if(notify(s, NULL, NULL, 0)< 0)
1027                 {
1028                         LM_ERR( "sending Notify request\n");
1029                         goto done;
1030                 }
1031
1032         /* delete from database also */
1033         if(s->status== TERMINATED_STATUS)
1034         {
1035             if(pres_db_delete_status(s)<0)
1036             {
1037                 err_ret= -1;
1038                 LM_ERR("failed to delete terminated dialog from database\n");
1039                 goto done;
1040             }
1041         }
1042
1043         s= s->next;
1044         }
1045
1046         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
1047         return 0;
1048
1049 done:
1050         if(result)
1051                 pa_dbf.free_result(pa_db, result);
1052         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
1053         if(ws_list)
1054         {
1055                 for(i= 0; i< n; i++)
1056                 {
1057                         if(ws_list[i].w_user.s)
1058                                 pkg_free(ws_list[i].w_user.s);
1059                         else
1060                                 break;
1061                         if(ws_list[i].w_domain.s)
1062                                 pkg_free(ws_list[i].w_domain.s);
1063                         if(ws_list[i].reason.s)
1064                                 pkg_free(ws_list[i].reason.s);
1065                 }
1066         }
1067         return err_ret;
1068 }
1069
1070 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array)
1071 {
1072         subs_t* s, *ps, *cs;
1073         int i= 0;
1074
1075     LM_DBG("start\n");
1076         lock_get(&subs_htable[hash_code].lock);
1077         
1078     ps= subs_htable[hash_code].entries;
1079         
1080         while(ps && ps->next)
1081         {
1082                 s= ps->next;
1083
1084                 if(s->event== subs->event && s->pres_uri.len== subs->pres_uri.len &&
1085                         s->from_user.len== subs->from_user.len && 
1086                         s->from_domain.len==subs->from_domain.len &&
1087                         strncmp(s->pres_uri.s, subs->pres_uri.s, subs->pres_uri.len)== 0 &&
1088                         strncmp(s->from_user.s, subs->from_user.s, s->from_user.len)== 0 &&
1089                         strncmp(s->from_domain.s,subs->from_domain.s,s->from_domain.len)==0)
1090                 {
1091                         i++;
1092                         s->status= subs->status;
1093                         s->reason= subs->reason;
1094                         s->db_flag= UPDATEDB_FLAG;
1095
1096                         cs= mem_copy_subs(s, PKG_MEM_TYPE);
1097                         if(cs== NULL)
1098                         {
1099                                 LM_ERR( "copying subs_t stucture\n");
1100                 lock_release(&subs_htable[hash_code].lock);
1101                 return -1;
1102                         }
1103                         cs->expires-= (int)time(NULL);
1104                         cs->next= (*subs_array);
1105                         (*subs_array)= cs;
1106                         if(subs->status== TERMINATED_STATUS)
1107                         {
1108                                 ps->next= s->next;
1109                                 shm_free(s->contact.s);
1110                 shm_free(s);
1111                 LM_DBG(" deleted terminated dialog from hash table\n");
1112             }
1113                         else
1114                                 ps= s;
1115
1116                         printf_subs(cs);
1117                 }
1118                 else
1119                         ps= s;
1120         }
1121         
1122     LM_DBG("found %d matching dialogs\n", i);
1123     lock_release(&subs_htable[hash_code].lock);
1124         
1125     return 0;
1126 }
1127
1128 static int pres_auth_status(struct sip_msg* _msg, char* _sp1, char* _sp2)
1129 {
1130     pv_spec_t *sp;
1131     pv_value_t pv_val;
1132     str watcher_uri, presentity_uri, event;
1133     struct sip_uri uri;
1134     pres_ev_t* ev;
1135     str* rules_doc = NULL;
1136     subs_t subs;
1137     int res;
1138
1139     sp = (pv_spec_t *)_sp1;
1140
1141     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
1142         if (pv_val.flags & PV_VAL_STR) {
1143             watcher_uri = pv_val.rs;
1144             if (watcher_uri.len == 0 || watcher_uri.s == NULL) {
1145                 LM_ERR("missing watcher uri\n");
1146                 return -1;
1147             }
1148         } else {
1149             LM_ERR("watcher pseudo variable value is not string\n");
1150             return -1;
1151         }
1152     } else {
1153         LM_ERR("cannot get watcher pseudo variable value\n");
1154         return -1;
1155     }
1156
1157     sp = (pv_spec_t *)_sp2;
1158
1159     if (sp && (pv_get_spec_value(_msg, sp, &pv_val) == 0)) {
1160         if (pv_val.flags & PV_VAL_STR) {
1161             presentity_uri = pv_val.rs;
1162             if (presentity_uri.len == 0 || presentity_uri.s == NULL) {
1163                 LM_DBG("missing presentity uri\n");
1164                 return -1;
1165             }
1166         } else {
1167             LM_ERR("presentity pseudo variable value is not string\n");
1168             return -1;
1169         }
1170     } else {
1171         LM_ERR("cannot get presentity pseudo variable value\n");
1172         return -1;
1173     }
1174
1175     event.s = "presence";
1176     event.len = 8;
1177
1178     ev = contains_event(&event, NULL);
1179     if (ev == NULL) {
1180         LM_ERR("event is not registered\n");
1181         return -1;
1182     }
1183     if (ev->get_rules_doc == NULL) {
1184         LM_DBG("event does not require authorization");
1185         return ACTIVE_STATUS;
1186     }
1187     if (parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
1188         LM_ERR("failed to parse presentity uri\n");
1189         return -1;
1190     }
1191     res = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
1192     if ((res < 0) || (rules_doc == NULL) || (rules_doc->s == NULL)) {
1193         LM_DBG( "no xcap rules doc found for presentity uri\n");
1194         return PENDING_STATUS;
1195     }
1196
1197     if (parse_uri(watcher_uri.s, watcher_uri.len, &uri) < 0) {
1198         LM_ERR("failed to parse watcher uri\n");
1199         goto err;
1200     }
1201
1202     subs.from_user = uri.user;
1203     subs.from_domain = uri.host;
1204     subs.pres_uri = presentity_uri;
1205     subs.auth_rules_doc = rules_doc;
1206     if (ev->get_auth_status(&subs) < 0) {
1207         LM_ERR( "getting status from rules document\n");
1208         goto err;
1209     }
1210     LM_DBG("auth status of watcher <%.*s> on presentity <%.*s> is %d\n",
1211            watcher_uri.len, watcher_uri.s, presentity_uri.len, presentity_uri.s,
1212            subs.status);
1213     pkg_free(rules_doc->s);
1214     pkg_free(rules_doc);
1215     return subs.status;
1216
1217  err:
1218     pkg_free(rules_doc->s);
1219     pkg_free(rules_doc);
1220     return -1;
1221 }
1222
1223 /**
1224  * wrapper for pres_refresh_watchers to use in config
1225  */
1226 static int w_pres_refresh_watchers(struct sip_msg *msg, char *puri,
1227                 char *pevent, char *ptype)
1228 {
1229         str pres_uri;
1230         str event;
1231         int refresh_type;
1232
1233         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri)!=0)
1234         {
1235                 LM_ERR("invalid uri parameter");
1236                 return -1;
1237         }
1238
1239         if(fixup_get_svalue(msg, (gparam_p)pevent, &event)!=0)
1240         {
1241                 LM_ERR("invalid uri parameter");
1242                 return -1;
1243         }
1244
1245         if(fixup_get_ivalue(msg, (gparam_p)ptype, &refresh_type)!=0)
1246         {
1247                 LM_ERR("no type value\n");
1248                 return -1;
1249         }
1250
1251         if(pres_refresh_watchers(&pres_uri, &event, refresh_type)<0)
1252                 return -1;
1253
1254         return 1;
1255 }
1256
1257 /**
1258  * fixup for w_pres_refresh_watchers
1259  */
1260 static int fixup_refresh_watchers(void** param, int param_no)
1261 {
1262         if(param_no==1)
1263         {
1264                 return fixup_spve_null(param, 1);
1265         } else if(param_no==2) {
1266                 return fixup_spve_null(param, 1);
1267         } else if(param_no==3) {
1268                 return fixup_igp_null(param, 1);
1269         }
1270         return 0;
1271 }
1272
1273
1274 /**
1275  * wrapper for update_watchers_status to use in config
1276  */
1277 static int w_pres_update_watchers(struct sip_msg *msg, char *puri,
1278                 char *pevent)
1279 {
1280         str pres_uri;
1281         str event;
1282         pres_ev_t* ev;
1283         struct sip_uri uri;
1284         str* rules_doc = NULL;
1285         int ret;
1286
1287         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri)!=0)
1288         {
1289                 LM_ERR("invalid uri parameter");
1290                 return -1;
1291         }
1292
1293         if(fixup_get_svalue(msg, (gparam_p)pevent, &event)!=0)
1294         {
1295                 LM_ERR("invalid uri parameter");
1296                 return -1;
1297         }
1298
1299         ev = contains_event(&event, NULL);
1300         if(ev==NULL)
1301         {
1302                 LM_ERR("event %.*s is not registered\n",
1303                                 event.len, event.s);
1304                 return -1;
1305         }
1306         if(ev->get_rules_doc==NULL)
1307         {
1308                 LM_DBG("event  %.*s does not provide rules doc API\n",
1309                                 event.len, event.s);
1310                 return -1;
1311         }
1312         if(parse_uri(pres_uri.s, pres_uri.len, &uri)<0)
1313         {
1314                 LM_ERR("failed to parse presentity uri [%.*s]\n",
1315                                 pres_uri.len, pres_uri.s);
1316                 return -1;
1317         }
1318         ret = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
1319         if((ret < 0) || (rules_doc==NULL) || (rules_doc->s==NULL))
1320         {
1321                 LM_DBG("no xcap rules doc found for presentity uri [%.*s]\n",
1322                                 pres_uri.len, pres_uri.s);
1323                 if(rules_doc != NULL)
1324                         pkg_free(rules_doc);
1325                 return -1;
1326         }
1327         ret = 1;
1328         if(update_watchers_status(pres_uri, ev, rules_doc)<0)
1329         {
1330                 LM_ERR("updating watchers in presence\n");
1331                 ret = -1;
1332         }
1333
1334         pkg_free(rules_doc->s);
1335         pkg_free(rules_doc);
1336
1337         return ret;
1338 }
1339
1340 /**
1341  * fixup for w_pres_update_watchers
1342  */
1343 static int fixup_update_watchers(void** param, int param_no)
1344 {
1345         if(param_no==1)
1346         {
1347                 return fixup_spve_null(param, 1);
1348         } else if(param_no==2) {
1349                 return fixup_spve_null(param, 1);
1350         }
1351         return 0;
1352 }