08a440c26e1be59da0a4e578a7e11241a998ac28
[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 openser, a free SIP server.
9  *
10  * openser 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  * openser 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 #include <stdio.h>
30 #include <string.h>
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/ipc.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <time.h>
37
38 #include "../../db/db.h"
39 #include "../../sr_module.h"
40 #include "../../dprint.h"
41 #include "../../error.h"
42 #include "../../ut.h"
43 #include "../../parser/parse_to.h"
44 #include "../../parser/parse_uri.h" 
45 #include "../../parser/parse_content.h"
46 #include "../../parser/parse_from.h"
47 #include "../../mem/mem.h"
48 #include "../../mem/shm_mem.h"
49 #include "../../usr_avp.h"
50 #include "../tm/tm_load.h"
51 #include "../sl/sl_api.h"
52 #include "../../pt.h"
53 #include "../../mi/mi.h"
54 #include "../pua/hash.h"
55 #include "publish.h"
56 #include "subscribe.h"
57 #include "event_list.h"
58 #include "bind_presence.h"
59 #include "notify.h"
60
61 MODULE_VERSION
62
63 #define S_TABLE_VERSION  3
64 #define P_TABLE_VERSION  2
65 #define ACTWATCH_TABLE_VERSION 9
66
67 char *log_buf = NULL;
68 static int clean_period=100;
69
70 /* database connection */
71 db_con_t *pa_db = NULL;
72 db_func_t pa_dbf;
73 str presentity_table= str_init("presentity");
74 str active_watchers_table = str_init("active_watchers");
75 str watchers_table= str_init("watchers");
76
77 int use_db=1;
78 str server_address= {0, 0};
79 evlist_t* EvList= NULL;
80
81 /* to tag prefix */
82 char* to_tag_pref = "10";
83
84 /* TM bind */
85 struct tm_binds tmb;
86 /* SL bind */
87 struct sl_binds slb;
88
89 /** module functions */
90
91 static int mod_init(void);
92 static int child_init(int);
93 static void destroy(void);
94 int stored_pres_info(struct sip_msg* msg, char* pres_uri, char* s);
95 static int fixup_presence(void** param, int param_no);
96 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param);
97 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array);
98 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc);
99 static int mi_child_init(void);
100
101 int counter =0;
102 int pid = 0;
103 char prefix='a';
104 int startup_time=0;
105 str db_url = {0, 0};
106 int expires_offset = 0;
107 int max_expires= 3600;
108 int shtable_size= 9;
109 shtable_t subs_htable= NULL;
110 int fallback2db= 0;
111 int sphere_enable= 0;
112
113 int phtable_size= 9;
114 phtable_t* pres_htable;
115
116 static cmd_export_t cmds[]=
117 {
118         {"handle_publish",  (cmd_function)handle_publish,  0,    0,         0, REQUEST_ROUTE},
119         {"handle_publish",  (cmd_function)handle_publish,  1,fixup_presence,0, REQUEST_ROUTE},
120         {"handle_subscribe",(cmd_function)handle_subscribe,0,     0,        0, REQUEST_ROUTE},
121         {"bind_presence", (cmd_function)bind_presence,     1,     0,        0,  0},
122         {0,                     0,                         0,     0,        0,  0}
123 };
124
125 static param_export_t params[]={
126         { "db_url",                 STR_PARAM, &db_url.s},
127         { "presentity_table",       STR_PARAM, &presentity_table.s},
128         { "active_watchers_table",  STR_PARAM, &active_watchers_table.s},
129         { "watchers_table",         STR_PARAM, &watchers_table.s},
130         { "clean_period",           INT_PARAM, &clean_period },
131         { "to_tag_pref",            STR_PARAM, &to_tag_pref },
132         { "expires_offset",         INT_PARAM, &expires_offset },
133         { "max_expires",            INT_PARAM, &max_expires },
134         { "server_address",         STR_PARAM, &server_address.s},
135         { "subs_htable_size",       INT_PARAM, &shtable_size},
136         { "pres_htable_size",       INT_PARAM, &phtable_size},
137         { "fallback2db",            INT_PARAM, &fallback2db},
138         { "enable_sphere_check",    INT_PARAM, &sphere_enable},
139     {0,0,0}
140 };
141
142 static mi_export_t mi_cmds[] = {
143         { "refreshWatchers", mi_refreshWatchers,    0,  0,  mi_child_init},
144         {  0,                0,                     0,  0,  0}
145 };
146
147 /** module exports */
148 struct module_exports exports= {
149         "presence",                                     /* module name */
150         DEFAULT_DLFLAGS,                        /* dlopen flags */
151         cmds,                                           /* exported functions */
152         params,                                         /* exported parameters */
153         0,                                                      /* exported statistics */
154         mi_cmds,                                        /* exported MI functions */
155         0,                                                      /* exported pseudo-variables */
156         0,                                                      /* extra processes */
157         mod_init,                                       /* module initialization function */
158         (response_function) 0,      /* response handling function */
159         (destroy_function) destroy, /* destroy function */
160         child_init                  /* per-child init function */
161 };
162
163 /**
164  * init module function
165  */
166 static int mod_init(void)
167 {
168         db_url.len = db_url.s ? strlen(db_url.s) : 0;
169         LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len,db_url.s);
170         presentity_table.len = strlen(presentity_table.s);
171         active_watchers_table.len = strlen(active_watchers_table.s);
172         watchers_table.len = strlen(watchers_table.s);
173
174         LM_NOTICE("initializing module ...\n");
175
176         if(db_url.s== NULL)
177         {
178                 use_db= 0;
179                 LM_DBG("presence module used for library purpose only\n");
180                 EvList= init_evlist();
181                 if(!EvList)
182                 {
183                         LM_ERR("unsuccessful initialize event list\n");
184                         return -1;
185                 }
186                 return 0;
187
188         }
189
190         if(expires_offset<0)
191                 expires_offset = 0;
192         
193         if(to_tag_pref==NULL || strlen(to_tag_pref)==0)
194                 to_tag_pref="10";
195
196         if(max_expires<= 0)
197                 max_expires = 3600;
198
199         if(server_address.s== NULL)
200                 LM_DBG("server_address parameter not set in configuration file\n");
201         
202         if(server_address.s)
203                 server_address.len= strlen(server_address.s);
204         else
205                 server_address.len= 0;
206
207         /* load SL API */
208         if(load_sl_api(&slb)==-1)
209         {
210                 LM_ERR("can't load sl functions\n");
211                 return -1;
212         }
213
214         /* load all TM stuff */
215         if(load_tm_api(&tmb)==-1)
216         {
217                 LM_ERR("can't load tm functions\n");
218                 return -1;
219         }
220         
221         /* binding to database module  */
222         if (db_bind_mod(&db_url, &pa_dbf))
223         {
224                 LM_ERR("Database module not found\n");
225                 return -1;
226         }
227         
228
229         if (!DB_CAPABILITY(pa_dbf, DB_CAP_ALL))
230         {
231                 LM_ERR("Database module does not implement all functions"
232                                 " needed by presence module\n");
233                 return -1;
234         }
235
236         pa_db = pa_dbf.init(&db_url);
237         if (!pa_db)
238         {
239                 LM_ERR("connecting to database failed\n");
240                 return -1;
241         }
242         
243         /*verify table versions */
244         if((db_check_table_version(&pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION) < 0) ||
245                 (db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) ||
246                 (db_check_table_version(&pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION) < 0)) {
247                         LM_ERR("error during table version check.\n");
248                         return -1;
249         }
250
251         EvList= init_evlist();
252         if(!EvList)
253         {
254                 LM_ERR("initializing event list\n");
255                 return -1;
256         }
257
258         if(clean_period<=0)
259         {
260                 LM_DBG("wrong clean_period \n");
261                 return -1;
262         }
263
264         if(shtable_size< 1)
265                 shtable_size= 512;
266         else
267                 shtable_size= 1<< shtable_size;
268
269         subs_htable= new_shtable(shtable_size);
270         if(subs_htable== NULL)
271         {
272                 LM_ERR(" initializing subscribe hash table\n");
273                 return -1;
274         }
275         if(restore_db_subs()< 0)
276         {
277                 LM_ERR("restoring subscribe info from database\n");
278                 return -1;
279         }
280
281         if(phtable_size< 1)
282                 phtable_size= 256;
283         else
284                 phtable_size= 1<< phtable_size;
285
286         pres_htable= new_phtable();
287         if(pres_htable== NULL)
288         {
289                 LM_ERR("initializing presentity hash table\n");
290                 return -1;
291         }
292         if(pres_htable_restore()< 0)
293         {
294                 LM_ERR("filling in presentity hash table from database\n");
295                 return -1;
296         }
297
298         startup_time = (int) time(NULL);
299         
300         register_timer(msg_presentity_clean, 0, clean_period);
301         
302         register_timer(msg_watchers_clean, 0, clean_period);
303         
304         register_timer(timer_db_update, 0, clean_period);
305
306         if(pa_db)
307                 pa_dbf.close(pa_db);
308         pa_db = NULL;
309
310         return 0;
311 }
312
313 /**
314  * Initialize children
315  */
316 static int child_init(int rank)
317 {
318         LM_NOTICE("init_child [%d]  pid [%d]\n", rank, getpid());
319
320         pid = my_pid();
321         
322         if(use_db== 0)
323                 return 0;
324
325         if (pa_dbf.init==0)
326         {
327                 LM_CRIT("child_init: database not bound\n");
328                 return -1;
329         }
330         pa_db = pa_dbf.init(&db_url);
331         if (!pa_db)
332         {
333                 LM_ERR("child %d: unsuccessful connecting to database\n", rank);
334                 return -1;
335         }
336         
337         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)  
338         {
339                 LM_ERR( "child %d:unsuccessful use_table presentity_table\n", rank);
340                 return -1;
341         }
342
343         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)  
344         {
345                 LM_ERR( "child %d:unsuccessful use_table active_watchers_table\n",
346                                 rank);
347                 return -1;
348         }
349
350         if (pa_dbf.use_table(pa_db, &watchers_table) < 0)  
351         {
352                 LM_ERR( "child %d:unsuccessful use_table watchers_table\n", rank);
353                 return -1;
354         }
355
356         LM_DBG("child %d: Database connection opened successfully\n", rank);
357         
358         return 0;
359 }
360
361 static int mi_child_init(void)
362 {
363         if(use_db== 0)
364                 return 0;
365
366
367
368
369         if (pa_dbf.init==0)
370         {
371                 LM_CRIT("database not bound\n");
372                 return -1;
373         }
374         pa_db = pa_dbf.init(&db_url);
375         if (!pa_db)
376         {
377                 LM_ERR("connecting database\n");
378                 return -1;
379         }
380         
381         if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
382         {
383                 LM_ERR( "unsuccessful use_table presentity_table\n");
384                 return -1;
385         }
386
387         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)
388         {
389                 LM_ERR( "unsuccessful use_table active_watchers_table\n");
390                 return -1;
391         }
392
393         if (pa_dbf.use_table(pa_db, &watchers_table) < 0)
394         {
395                 LM_ERR( "unsuccessful use_table watchers_table\n");
396                 return -1;
397         }
398
399         LM_DBG("Database connection opened successfully\n");
400         return 0;
401 }
402
403
404 /*
405  * destroy function
406  */
407 static void destroy(void)
408 {
409         LM_NOTICE("destroy module ...\n");
410
411         if(subs_htable && pa_db)
412                 timer_db_update(0, 0);
413
414         if(subs_htable)
415                 destroy_shtable(subs_htable, shtable_size);
416         
417         if(pres_htable)
418                 destroy_phtable();
419
420         if(pa_db && pa_dbf.close)
421                 pa_dbf.close(pa_db);
422         
423         destroy_evlist();
424 }
425
426 static int fixup_presence(void** param, int param_no)
427 {
428         pv_elem_t *model;
429         str s;
430         if(*param)
431         {
432                 s.s = (char*)(*param); s.len = strlen(s.s);
433                 if(pv_parse_format(&s, &model)<0)
434                 {
435                         LM_ERR( "wrong format[%s]\n",(char*)(*param));
436                         return E_UNSPEC;
437                 }
438  
439                 *param = (void*)model;
440                 return 0;
441         }
442         LM_ERR( "null format\n");
443         return E_UNSPEC;
444 }
445
446 /* 
447  *  mi cmd: refreshWatchers
448  *                      <presentity_uri> 
449  *                      <event>
450  *          <refresh_type> // can be:  = 0 -> watchers autentification type or
451  *                                                                        != 0 -> publish type //                  
452  *              * */
453
454 static struct mi_root* mi_refreshWatchers(struct mi_root* cmd, void* param)
455 {
456         struct mi_node* node= NULL;
457         str pres_uri, event;
458         struct sip_uri uri;
459         pres_ev_t* ev;
460         str* rules_doc= NULL;
461         int result;
462         unsigned int refresh_type;
463
464         LM_DBG("start\n");
465         
466         node = cmd->node.kids;
467         if(node == NULL)
468                 return 0;
469
470         /* Get presentity URI */
471         pres_uri = node->value;
472         if(pres_uri.s == NULL || pres_uri.len== 0)
473         {
474                 LM_ERR( "empty uri\n");
475                 return init_mi_tree(404, "Empty presentity URI", 20);
476         }
477         
478         node = node->next;
479         if(node == NULL)
480                 return 0;
481         event= node->value;
482         if(event.s== NULL || event.len== 0)
483         {
484                 LM_ERR( "empty event parameter\n");
485                 return init_mi_tree(400, "Empty event parameter", 21);
486         }
487         LM_DBG("event '%.*s'\n",  event.len, event.s);
488         
489         node = node->next;
490         if(node == NULL)
491                 return 0;
492         if(node->value.s== NULL || node->value.len== 0)
493         {
494                 LM_ERR( "empty event parameter\n");
495                 return init_mi_tree(400, "Empty event parameter", 21);          
496         }
497         if(str2int(&node->value, &refresh_type)< 0)
498         {
499                 LM_ERR("converting string to int\n");
500                 goto error;
501         }
502
503         if(node->next!= NULL)
504         {
505                 LM_ERR( "Too many parameters\n");
506                 return init_mi_tree(400, "Too many parameters", 19);
507         }
508
509         ev= contains_event(&event, NULL);
510         if(ev== NULL)
511         {
512                 LM_ERR( "wrong event parameter\n");
513                 return 0;
514         }
515         
516         if(refresh_type== 0) /* if a request to refresh watchers authorization*/
517         {
518                 if(ev->get_rules_doc== NULL)
519                 {
520                         LM_ERR("wrong request for a refresh watchers authorization status"
521                                         "for an event that does not require authorization\n");
522                         goto error;
523                 }
524                 
525                 if(parse_uri(pres_uri.s, pres_uri.len, &uri)< 0)
526                 {
527                         LM_ERR( "parsing uri\n");
528                         goto error;
529                 }
530
531                 result= ev->get_rules_doc(&uri.user,&uri.host,&rules_doc);
532                 if(result< 0 || rules_doc==NULL || rules_doc->s== NULL)
533                 {
534                         LM_ERR( "no rules doc found for the user\n");
535                         goto error;
536                 }
537         
538                 if(update_watchers_status(pres_uri, ev, rules_doc)< 0)
539                 {
540                         LM_ERR("failed to update watchers\n");
541                         goto error;
542                 }
543
544                 pkg_free(rules_doc->s);
545                 pkg_free(rules_doc);
546                 rules_doc = NULL;
547
548         }
549         else     /* if a request to refresh Notified info */
550         {
551                 if(query_db_notify(&pres_uri, ev, NULL)< 0)
552                 {
553                         LM_ERR("sending Notify requests\n");
554                         goto error;
555                 }
556
557         }
558                 
559         return init_mi_tree(200, "OK", 2);
560
561 error:
562         if(rules_doc)
563         {
564                 if(rules_doc->s)
565                         pkg_free(rules_doc->s);
566                 pkg_free(rules_doc);
567         }
568         return 0;
569 }
570
571
572 int pres_update_status(subs_t subs, str reason, db_key_t* query_cols,
573         db_val_t* query_vals, int n_query_cols, subs_t** subs_array)
574 {
575         db_key_t update_cols[5];
576         db_val_t update_vals[5];
577         int n_update_cols= 0;
578         int u_status_col, u_reason_col, q_wuser_col, q_wdomain_col;
579         int status;
580         query_cols[q_wuser_col=n_query_cols]= &str_watcher_username_col;
581         query_vals[n_query_cols].nul= 0;
582         query_vals[n_query_cols].type= DB_STR;
583         n_query_cols++;
584
585         query_cols[q_wdomain_col=n_query_cols]= &str_watcher_domain_col;
586         query_vals[n_query_cols].nul= 0;
587         query_vals[n_query_cols].type= DB_STR;
588         n_query_cols++;
589
590         update_cols[u_status_col= n_update_cols]= &str_status_col;
591         update_vals[u_status_col].nul= 0;
592         update_vals[u_status_col].type= DB_INT;
593         n_update_cols++;
594
595         update_cols[u_reason_col= n_update_cols]= &str_reason_col;
596         update_vals[u_reason_col].nul= 0;
597         update_vals[u_reason_col].type= DB_STR;
598         n_update_cols++;
599
600         status= subs.status;
601         if(subs.event->get_auth_status(&subs)< 0)
602         {
603                 LM_ERR( "getting status from rules document\n");
604                 return -1;
605         }
606         LM_DBG("subs.status= %d\n", subs.status);
607         if(get_status_str(subs.status)== NULL)
608         {
609                 LM_ERR("wrong status: %d\n", subs.status);
610                 return -1;
611         }
612
613         if(subs.status!= status || reason.len!= subs.reason.len ||
614                 (reason.s && subs.reason.s && strncmp(reason.s, subs.reason.s,
615                                                                                           reason.len)))
616         {
617                 /* update in watchers_table */
618                 query_vals[q_wuser_col].val.str_val= subs.from_user; 
619                 query_vals[q_wdomain_col].val.str_val= subs.from_domain; 
620
621                 update_vals[u_status_col].val.int_val= subs.status;
622                 update_vals[u_reason_col].val.str_val= subs.reason;
623                 
624                 if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
625                 {
626                         LM_ERR( "in use_table\n");
627                         return -1;
628                 }
629
630                 if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
631                                         update_vals, n_query_cols, n_update_cols)< 0)
632                 {
633                         LM_ERR( "in sql update\n");
634                         return -1;
635                 }
636                 /* save in the list all affected dialogs */
637                 /* if status switches to terminated -> delete dialog */
638                 if(update_pw_dialogs(&subs, subs.db_flag, subs_array)< 0)
639                 {
640                         LM_ERR( "extracting dialogs from [watcher]=%.*s@%.*s to"
641                                 " [presentity]=%.*s\n", subs.from_user.len, subs.from_user.s,
642                                 subs.from_domain.len, subs.from_domain.s, subs.pres_uri.len,
643                                 subs.pres_uri.s);
644                         return -1;
645                 }
646         }
647     return 0;
648 }
649
650 int pres_db_delete_status(subs_t* s)
651 {
652     int n_query_cols= 0;
653     db_key_t query_cols[5];
654     db_val_t query_vals[5];
655
656     if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
657     {
658         LM_ERR("sql use table failed\n");
659         return -1;
660     }
661
662     query_cols[n_query_cols]= &str_event_col;
663     query_vals[n_query_cols].nul= 0;
664     query_vals[n_query_cols].type= DB_STR;
665     query_vals[n_query_cols].val.str_val= s->event->name ;
666     n_query_cols++;
667
668     query_cols[n_query_cols]= &str_presentity_uri_col;
669     query_vals[n_query_cols].nul= 0;
670     query_vals[n_query_cols].type= DB_STR;
671     query_vals[n_query_cols].val.str_val= s->pres_uri;
672     n_query_cols++;
673
674     query_cols[n_query_cols]= &str_watcher_username_col;
675     query_vals[n_query_cols].nul= 0;
676     query_vals[n_query_cols].type= DB_STR;
677     query_vals[n_query_cols].val.str_val= s->from_user;
678     n_query_cols++;
679
680     query_cols[n_query_cols]= &str_watcher_domain_col;
681     query_vals[n_query_cols].nul= 0;
682     query_vals[n_query_cols].type= DB_STR;
683     query_vals[n_query_cols].val.str_val= s->from_domain;
684     n_query_cols++;
685
686     if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols)< 0)
687     {
688         LM_ERR("sql delete failed\n");
689         return -1;
690     }
691     return 0;
692
693 }
694
695 int update_watchers_status(str pres_uri, pres_ev_t* ev, str* rules_doc)
696 {
697         subs_t subs;
698         db_key_t query_cols[6], result_cols[5];
699         db_val_t query_vals[6];
700         int n_result_cols= 0, n_query_cols = 0;
701         db_res_t* result= NULL;
702         db_row_t *row;
703         db_val_t *row_vals ;
704         int i;
705         str w_user, w_domain, reason= {0, 0};
706         unsigned int status;
707         int status_col, w_user_col, w_domain_col, reason_col;
708         subs_t* subs_array= NULL,* s;
709         unsigned int hash_code;
710         int err_ret= -1;
711         int n= 0;
712
713         typedef struct ws
714         {
715                 int status;
716                 str reason;
717                 str w_user;
718                 str w_domain;
719         }ws_t;
720         ws_t* ws_list= NULL;
721
722     LM_DBG("start\n");
723
724         if(ev->content_type.s== NULL)
725         {
726                 ev= contains_event(&ev->name, NULL);
727                 if(ev== NULL)
728                 {
729                         LM_ERR("wrong event parameter\n");
730                         return 0;
731                 }
732         }
733
734         subs.pres_uri= pres_uri;
735         subs.event= ev;
736         subs.auth_rules_doc= rules_doc;
737
738         /* update in watchers_table */
739         query_cols[n_query_cols]= &str_presentity_uri_col;
740         query_vals[n_query_cols].nul= 0;
741         query_vals[n_query_cols].type= DB_STR;
742         query_vals[n_query_cols].val.str_val= pres_uri;
743         n_query_cols++;
744
745         query_cols[n_query_cols]= &str_event_col;
746         query_vals[n_query_cols].nul= 0;
747         query_vals[n_query_cols].type= DB_STR;
748         query_vals[n_query_cols].val.str_val= ev->name;
749         n_query_cols++;
750
751         result_cols[status_col= n_result_cols++]= &str_status_col;
752         result_cols[reason_col= n_result_cols++]= &str_reason_col;
753         result_cols[w_user_col= n_result_cols++]= &str_watcher_username_col;
754         result_cols[w_domain_col= n_result_cols++]= &str_watcher_domain_col;
755
756         if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
757         {
758                 LM_ERR( "in use_table\n");
759                 goto done;
760         }
761
762         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols,n_query_cols,
763                                 n_result_cols, 0, &result)< 0)
764         {
765                 LM_ERR( "in sql query\n");
766                 goto done;
767         }
768         if(result== NULL)
769                 return 0;
770
771         if(result->n<= 0)
772         {
773                 err_ret= 0;
774                 goto done;
775         }
776
777     LM_DBG("found %d record-uri in watchers_table\n", result->n);
778         hash_code= core_hash(&pres_uri, &ev->name, shtable_size);
779         subs.db_flag= hash_code;
780
781     /*must do a copy as sphere_check requires database queries */
782         if(sphere_enable)
783         {
784         n= result->n;
785                 ws_list= (ws_t*)pkg_malloc(n * sizeof(ws_t));
786                 if(ws_list== NULL)
787                 {
788                         LM_ERR("No more private memory\n");
789                         goto done;
790                 }
791                 memset(ws_list, 0, n * sizeof(ws_t));
792
793                 for(i= 0; i< result->n ; i++)
794                 {
795                         row= &result->rows[i];
796                         row_vals = ROW_VALUES(row);
797
798                         status= row_vals[status_col].val.int_val;
799         
800                         reason.s= (char*)row_vals[reason_col].val.string_val;
801                         reason.len= reason.s?strlen(reason.s):0;
802
803                         w_user.s= (char*)row_vals[w_user_col].val.string_val;
804                         w_user.len= strlen(w_user.s);
805
806                         w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
807                         w_domain.len= strlen(w_domain.s);
808
809                         if(reason.len)
810                         {
811                                 ws_list[i].reason.s = (char*)pkg_malloc(reason.len* sizeof(char));
812                                 if(ws_list[i].reason.s== NULL)
813                                 {  
814                                         LM_ERR("No more private memory\n");
815                                         goto done;
816                                 }
817                                 memcpy(ws_list[i].reason.s, reason.s, reason.len);
818                                 ws_list[i].reason.len= reason.len;
819                         }
820                         else
821                                 ws_list[i].reason.s= NULL;
822             
823                         ws_list[i].w_user.s = (char*)pkg_malloc(w_user.len* sizeof(char));
824                         if(ws_list[i].w_user.s== NULL)
825                         {
826                                 LM_ERR("No more private memory\n");
827                                 goto done;
828
829                         }
830                         memcpy(ws_list[i].w_user.s, w_user.s, w_user.len);
831                         ws_list[i].w_user.len= w_user.len;
832                 
833                          ws_list[i].w_domain.s = (char*)pkg_malloc(w_domain.len* sizeof(char));
834                         if(ws_list[i].w_domain.s== NULL)
835                         {
836                                 LM_ERR("No more private memory\n");
837                                 goto done;
838                         }
839                         memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len);
840                         ws_list[i].w_domain.len= w_domain.len;
841                         
842                         ws_list[i].status= status;
843                 }
844
845                 pa_dbf.free_result(pa_db, result);
846                 result= NULL;
847
848                 for(i=0; i< n; i++)
849                 {
850                         subs.from_user = ws_list[i].w_user;
851                         subs.from_domain = ws_list[i].w_domain;
852                         subs.status = ws_list[i].status;
853                         memset(&subs.reason, 0, sizeof(str));
854
855                         if( pres_update_status(subs, reason, query_cols, query_vals,
856                                         n_query_cols, &subs_array)< 0)
857                         {
858                                 LM_ERR("failed to update watcher status\n");
859                                 goto done;
860                         }
861
862                 }
863         
864                 for(i=0; i< n; i++)
865                 {
866                         pkg_free(ws_list[i].w_user.s);
867                         pkg_free(ws_list[i].w_domain.s);
868                         if(ws_list[i].reason.s)
869                                 pkg_free(ws_list[i].reason.s);
870                 }
871                 ws_list= NULL;
872
873                 goto send_notify;
874
875         }
876         
877         for(i = 0; i< result->n; i++)
878         {
879                 row= &result->rows[i];
880                 row_vals = ROW_VALUES(row);
881
882                 status= row_vals[status_col].val.int_val;
883         
884                 reason.s= (char*)row_vals[reason_col].val.string_val;
885                 reason.len= reason.s?strlen(reason.s):0;
886
887                 w_user.s= (char*)row_vals[w_user_col].val.string_val;
888                 w_user.len= strlen(w_user.s);
889
890                 w_domain.s= (char*)row_vals[w_domain_col].val.string_val;
891                 w_domain.len= strlen(w_domain.s);
892
893                 subs.from_user= w_user;
894                 subs.from_domain= w_domain;
895                 subs.status= status;
896                 memset(&subs.reason, 0, sizeof(str));
897
898                 if( pres_update_status(subs,reason, query_cols, query_vals,
899                                         n_query_cols, &subs_array)< 0)
900                 {
901                         LM_ERR("failed to update watcher status\n");
902                         goto done;
903                 }
904     }
905
906         pa_dbf.free_result(pa_db, result);
907         result= NULL;
908
909 send_notify:
910
911         s= subs_array;
912
913         while(s)
914         {
915
916                 if(notify(s, NULL, NULL, 0)< 0)
917                 {
918                         LM_ERR( "sending Notify request\n");
919                         goto done;
920                 }
921
922         /* delete from database also */
923         if(s->status== TERMINATED_STATUS)
924         {
925             if(pres_db_delete_status(s)<0)
926             {
927                 err_ret= -1;
928                 LM_ERR("failed to delete terminated dialog from database\n");
929                 goto done;
930             }
931         }
932
933         s= s->next;
934         }
935
936         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
937         return 0;
938
939 done:
940         if(result)
941                 pa_dbf.free_result(pa_db, result);
942         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
943         if(ws_list)
944         {
945                 for(i= 0; i< n; i++)
946                 {
947                         if(ws_list[i].w_user.s)
948                                 pkg_free(ws_list[i].w_user.s);
949                         else
950                                 break;
951                         if(ws_list[i].w_domain.s)
952                                 pkg_free(ws_list[i].w_domain.s);
953                         if(ws_list[i].reason.s)
954                                 pkg_free(ws_list[i].reason.s);
955                 }
956         }
957         return err_ret;
958 }
959
960 static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs_array)
961 {
962         subs_t* s, *ps, *cs;
963         int i= 0;
964
965     LM_DBG("start\n");
966         lock_get(&subs_htable[hash_code].lock);
967         
968     ps= subs_htable[hash_code].entries;
969         
970         while(ps && ps->next)
971         {
972                 s= ps->next;
973
974                 if(s->event== subs->event && s->pres_uri.len== subs->pres_uri.len &&
975                         s->from_user.len== subs->from_user.len && 
976                         s->from_domain.len==subs->from_domain.len &&
977                         strncmp(s->pres_uri.s, subs->pres_uri.s, subs->pres_uri.len)== 0 &&
978                         strncmp(s->from_user.s, subs->from_user.s, s->from_user.len)== 0 &&
979                         strncmp(s->from_domain.s,subs->from_domain.s,s->from_domain.len)==0)
980                 {
981                         i++;
982                         s->status= subs->status;
983                         s->reason= subs->reason;
984                         s->db_flag= UPDATEDB_FLAG;
985
986                         cs= mem_copy_subs(s, PKG_MEM_TYPE);
987                         if(cs== NULL)
988                         {
989                                 LM_ERR( "copying subs_t stucture\n");
990                 lock_release(&subs_htable[hash_code].lock);
991                 return -1;
992                         }
993                         cs->expires-= (int)time(NULL);
994                         cs->next= (*subs_array);
995                         (*subs_array)= cs;
996                         if(subs->status== TERMINATED_STATUS)
997                         {
998                                 ps->next= s->next;
999                                 shm_free(s->contact.s);
1000                 shm_free(s);
1001                 LM_DBG(" deleted terminated dialog from hash table\n");
1002             }
1003                         else
1004                                 ps= s;
1005
1006                         printf_subs(cs);
1007                 }
1008                 else
1009                         ps= s;
1010         }
1011         
1012     LM_DBG("found %d matching dialogs\n", i);
1013     lock_release(&subs_htable[hash_code].lock);
1014         
1015     return 0;
1016 }