everything: shotgun attempt to put PROTO_WS and PROTO_WSS across core and in modules...
[sip-router] / modules_k / presence / subscribe.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 serves.
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 Vamanu)
27  */
28
29 /*! \file
30  * \brief Kamailio presence module :: Support for SUBSCRIBE handling
31  * \ingroup presence 
32  */
33
34
35 #include "../../ut.h"
36 #include "../../usr_avp.h"
37 #include "../../data_lump_rpl.h"
38 #include "../../parser/parse_expires.h"
39 #include "../../parser/parse_event.h"
40 #include "../../parser/contact/parse_contact.h"
41 #include "../../hashes.h"
42 #include "presence.h"
43 #include "subscribe.h"
44 #include "utils_func.h"
45 #include "notify.h"
46 #include "../pua/hash.h"
47 #include "../../mod_fix.h"
48
49 int get_stored_info(struct sip_msg* msg, subs_t* subs, int* error_ret,
50                 str* reply_str);
51 int get_database_info(struct sip_msg* msg, subs_t* subs, int* error_ret,
52                 str* reply_str);
53 int get_db_subs_auth(subs_t* subs, int* found);
54 int insert_db_subs_auth(subs_t* subs);
55
56 static str su_200_rpl  = str_init("OK");
57 static str pu_481_rpl  = str_init("Subscription does not exist");
58 static str pu_400_rpl  = str_init("Bad request");
59 static str pu_500_rpl  = str_init("Server Internal Error");
60 static str pu_489_rpl  = str_init("Bad Event");
61
62 int send_2XX_reply(struct sip_msg * msg, int reply_code, int lexpire,
63                 str* local_contact)
64 {
65         str hdr_append = {0, 0};
66         str tmp;
67         char *t = NULL;
68         
69         tmp.s = int2str((unsigned long)lexpire, &tmp.len);
70         hdr_append.len = 9 + tmp.len + CRLF_LEN
71                 + 10 + local_contact->len + 16 + CRLF_LEN;
72         hdr_append.s = (char *)pkg_malloc(sizeof(char)*(hdr_append.len+1));
73         if(hdr_append.s == NULL)
74         {
75                 ERR_MEM(PKG_MEM_STR);
76         }
77         strncpy(hdr_append.s, "Expires: ", 9);
78         strncpy(hdr_append.s+9, tmp.s, tmp.len);
79         tmp.s = hdr_append.s+9+tmp.len;
80         strncpy(tmp.s, CRLF, CRLF_LEN);
81         tmp.s += CRLF_LEN;
82         strncpy(tmp.s, "Contact: <", 10);
83         tmp.s += 10;
84         strncpy(tmp.s, local_contact->s, local_contact->len);
85         tmp.s[local_contact->len] = '\0';
86         t = strstr(tmp.s, ";transport=");
87         tmp.s += local_contact->len;
88         if(t==NULL)
89         {
90                 switch (msg->rcv.proto)
91                 {
92                         case PROTO_TCP:
93                                 strncpy(tmp.s, ";transport=tcp", 14);
94                                 tmp.s += 14;
95                                 hdr_append.len -= 1;
96                         break;
97                         case PROTO_TLS:
98                                 strncpy(tmp.s, ";transport=tls", 14);
99                                 tmp.s += 14;
100                                 hdr_append.len -= 1;
101                         break;
102                         case PROTO_SCTP:
103                                 strncpy(tmp.s, ";transport=sctp", 15);
104                                 tmp.s += 15;
105                         break;
106                         case PROTO_WS:
107                         case PROTO_WSS:
108                                 strncpy(tmp.s, ";transport=ws", 13);
109                                 tmp.s += 13;
110                                 hdr_append.len -= 2;
111                         break;
112                         default:
113                                 hdr_append.len -= 15;
114                 }
115         } else {
116                 hdr_append.len -= 15;
117         }
118         *tmp.s = '>';
119         strncpy(tmp.s+1, CRLF, CRLF_LEN);
120
121         hdr_append.s[hdr_append.len]= '\0';
122         
123         if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 )
124         {
125                 LM_ERR("unable to add lump_rl\n");
126                 goto error;
127         }
128
129         if(slb.freply(msg, reply_code, &su_200_rpl) < 0)
130         {
131                 LM_ERR("sending reply\n");
132                 goto error;
133         }
134         
135         pkg_free(hdr_append.s);
136         return 0;
137
138 error:
139
140         if(hdr_append.s!=NULL)
141                 pkg_free(hdr_append.s);
142         return -1;
143 }
144
145
146 int delete_db_subs(str* to_tag, str* from_tag, str* callid)
147 {
148         db_key_t query_cols[3];
149         db_val_t query_vals[3];
150         int n_query_cols= 0;
151
152         query_cols[n_query_cols] = &str_callid_col;
153         query_vals[n_query_cols].type = DB1_STR;
154         query_vals[n_query_cols].nul = 0;
155         query_vals[n_query_cols].val.str_val = *callid;
156         n_query_cols++;
157
158         query_cols[n_query_cols] = &str_to_tag_col;
159         query_vals[n_query_cols].type = DB1_STR;
160         query_vals[n_query_cols].nul = 0;
161         query_vals[n_query_cols].val.str_val = *to_tag;
162         n_query_cols++;
163
164         query_cols[n_query_cols] = &str_from_tag_col;
165         query_vals[n_query_cols].type = DB1_STR;
166         query_vals[n_query_cols].nul = 0;
167         query_vals[n_query_cols].val.str_val = *from_tag;
168         n_query_cols++;
169
170         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
171         {
172                 LM_ERR("in use table sql operation\n");
173                 return -1;
174         }
175
176         if(pa_dbf.delete(pa_db, query_cols, 0, query_vals,
177                                 n_query_cols)< 0 )
178         {
179                 LM_ERR("sql delete failed\n");
180                 return -1;
181         }
182
183         return 0;
184 }
185
186 int insert_subs_db(subs_t* s, int type)
187 {
188         db_key_t query_cols[24];
189         db_val_t query_vals[24];
190         int n_query_cols = 0;
191         int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col,
192                 callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col, 
193                 local_cseq_col, remote_cseq_col, expires_col, record_route_col, 
194                 contact_col, local_contact_col, version_col,socket_info_col,reason_col,
195                 watcher_user_col, watcher_domain_col, updated_col, updated_winfo_col;
196                 
197         if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
198         {
199                 LM_ERR("sql use table failed\n");
200                 return -1;
201         }
202         
203         query_cols[pres_uri_col= n_query_cols] =&str_presentity_uri_col;
204         query_vals[pres_uri_col].type = DB1_STR;
205         query_vals[pres_uri_col].nul = 0;
206         n_query_cols++;
207         
208         query_cols[callid_col= n_query_cols] =&str_callid_col;
209         query_vals[callid_col].type = DB1_STR;
210         query_vals[callid_col].nul = 0;
211         n_query_cols++;
212
213         query_cols[totag_col= n_query_cols] =&str_to_tag_col;
214         query_vals[totag_col].type = DB1_STR;
215         query_vals[totag_col].nul = 0;
216         n_query_cols++;
217
218         query_cols[fromtag_col= n_query_cols] =&str_from_tag_col;
219         query_vals[fromtag_col].type = DB1_STR;
220         query_vals[fromtag_col].nul = 0;
221         n_query_cols++;
222
223         query_cols[to_user_col= n_query_cols] =&str_to_user_col;
224         query_vals[to_user_col].type = DB1_STR;
225         query_vals[to_user_col].nul = 0;
226         n_query_cols++;
227
228         query_cols[to_domain_col= n_query_cols] =&str_to_domain_col;
229         query_vals[to_domain_col].type = DB1_STR;
230         query_vals[to_domain_col].nul = 0;
231         n_query_cols++;
232         
233         query_cols[from_user_col= n_query_cols] =&str_from_user_col;
234         query_vals[from_user_col].type = DB1_STR;
235         query_vals[from_user_col].nul = 0;
236         n_query_cols++;
237
238         query_cols[from_domain_col= n_query_cols] =&str_from_domain_col;
239         query_vals[from_domain_col].type = DB1_STR;
240         query_vals[from_domain_col].nul = 0;
241         n_query_cols++;
242
243         query_cols[watcher_user_col= n_query_cols] =&str_watcher_username_col;
244         query_vals[watcher_user_col].type = DB1_STR;
245         query_vals[watcher_user_col].nul = 0;
246         n_query_cols++;
247
248         query_cols[watcher_domain_col= n_query_cols] =&str_watcher_domain_col;
249         query_vals[watcher_domain_col].type = DB1_STR;
250         query_vals[watcher_domain_col].nul = 0;
251         n_query_cols++;
252
253         query_cols[event_col= n_query_cols] =&str_event_col;
254         query_vals[event_col].type = DB1_STR;
255         query_vals[event_col].nul = 0;
256         n_query_cols++; 
257
258         query_cols[event_id_col= n_query_cols] =&str_event_id_col;
259         query_vals[event_id_col].type = DB1_STR;
260         query_vals[event_id_col].nul = 0;
261         n_query_cols++;
262
263         query_cols[local_cseq_col= n_query_cols]=&str_local_cseq_col;
264         query_vals[local_cseq_col].type = DB1_INT;
265         query_vals[local_cseq_col].nul = 0;
266         n_query_cols++;
267
268         query_cols[remote_cseq_col= n_query_cols]=&str_remote_cseq_col;
269         query_vals[remote_cseq_col].type = DB1_INT;
270         query_vals[remote_cseq_col].nul = 0;
271         n_query_cols++;
272
273         query_cols[expires_col= n_query_cols] =&str_expires_col;
274         query_vals[expires_col].type = DB1_INT;
275         query_vals[expires_col].nul = 0;
276         n_query_cols++;
277
278         query_cols[status_col= n_query_cols] =&str_status_col;
279         query_vals[status_col].type = DB1_INT;
280         query_vals[status_col].nul = 0;
281         n_query_cols++;
282
283         query_cols[reason_col= n_query_cols] =&str_reason_col;
284         query_vals[reason_col].type = DB1_STR;
285         query_vals[reason_col].nul = 0;
286         n_query_cols++;
287
288         query_cols[record_route_col= n_query_cols] =&str_record_route_col;
289         query_vals[record_route_col].type = DB1_STR;
290         query_vals[record_route_col].nul = 0;
291         n_query_cols++;
292         
293         query_cols[contact_col= n_query_cols] =&str_contact_col;
294         query_vals[contact_col].type = DB1_STR;
295         query_vals[contact_col].nul = 0;
296         n_query_cols++;
297
298         query_cols[local_contact_col= n_query_cols] =&str_local_contact_col;
299         query_vals[local_contact_col].type = DB1_STR;
300         query_vals[local_contact_col].nul = 0;
301         n_query_cols++;
302
303         query_cols[socket_info_col= n_query_cols] =&str_socket_info_col;
304         query_vals[socket_info_col].type = DB1_STR;
305         query_vals[socket_info_col].nul = 0;
306         n_query_cols++;
307
308         query_cols[version_col= n_query_cols]=&str_version_col;
309         query_vals[version_col].type = DB1_INT;
310         query_vals[version_col].nul = 0;
311         n_query_cols++;
312
313         query_cols[updated_col= n_query_cols]=&str_updated_col;
314         query_vals[updated_col].type = DB1_INT;
315         query_vals[updated_col].nul = 0;
316         n_query_cols++;
317
318         query_cols[updated_winfo_col= n_query_cols]=&str_updated_winfo_col;
319         query_vals[updated_winfo_col].type = DB1_INT;
320         query_vals[updated_winfo_col].nul = 0;
321         n_query_cols++;
322
323         query_vals[pres_uri_col].val.str_val= s->pres_uri;
324         query_vals[callid_col].val.str_val= s->callid;
325         query_vals[totag_col].val.str_val= s->to_tag;
326         query_vals[fromtag_col].val.str_val= s->from_tag;
327         query_vals[to_user_col].val.str_val = s->to_user;
328         query_vals[to_domain_col].val.str_val = s->to_domain;
329         query_vals[from_user_col].val.str_val = s->from_user;
330         query_vals[from_domain_col].val.str_val = s->from_domain;
331         query_vals[watcher_user_col].val.str_val = s->watcher_user;
332         query_vals[watcher_domain_col].val.str_val = s->watcher_domain;
333         query_vals[event_col].val.str_val = s->event->name;
334         query_vals[event_id_col].val.str_val = s->event_id;
335         query_vals[local_cseq_col].val.int_val= s->local_cseq;
336         query_vals[remote_cseq_col].val.int_val= s->remote_cseq;
337         query_vals[expires_col].val.int_val = s->expires + (int)time(NULL);
338         query_vals[record_route_col].val.str_val = s->record_route;
339         query_vals[contact_col].val.str_val = s->contact;
340         query_vals[local_contact_col].val.str_val = s->local_contact;
341         query_vals[version_col].val.int_val= s->version;
342         query_vals[status_col].val.int_val= s->status;
343         query_vals[reason_col].val.str_val= s->reason;
344         query_vals[socket_info_col].val.str_val= s->sockinfo_str;
345         query_vals[updated_col].val.int_val = s->updated;
346         query_vals[updated_winfo_col].val.int_val = s->updated_winfo;
347
348         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)
349         {
350                 LM_ERR("in use table sql operation\n"); 
351                 return -1;
352         }
353
354         LM_DBG("inserting subscription in active_watchers table\n");
355         if(pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0)
356         {
357                 LM_ERR("unsuccessful sql insert\n");
358                 return -1;
359         }
360         return 0;
361 }
362
363 int update_subs_db(subs_t* subs, int type)
364 {
365         db_key_t query_cols[3], update_keys[8];
366         db_val_t query_vals[3], update_vals[8];
367         int n_update_cols= 0;
368         int n_query_cols = 0;
369
370         query_cols[n_query_cols] = &str_callid_col;
371         query_vals[n_query_cols].type = DB1_STR;
372         query_vals[n_query_cols].nul = 0;
373         query_vals[n_query_cols].val.str_val = subs->callid;
374         n_query_cols++;
375
376         query_cols[n_query_cols] = &str_to_tag_col;
377         query_vals[n_query_cols].type = DB1_STR;
378         query_vals[n_query_cols].nul = 0;
379         query_vals[n_query_cols].val.str_val = subs->to_tag;
380         n_query_cols++;
381
382         query_cols[n_query_cols] = &str_from_tag_col;
383         query_vals[n_query_cols].type = DB1_STR;
384         query_vals[n_query_cols].nul = 0;
385         query_vals[n_query_cols].val.str_val = subs->from_tag;
386         n_query_cols++;
387
388         if(type & REMOTE_TYPE)
389         {
390                 update_keys[n_update_cols] = &str_expires_col;
391                 update_vals[n_update_cols].type = DB1_INT;
392                 update_vals[n_update_cols].nul = 0;
393                 update_vals[n_update_cols].val.int_val = subs->expires + (int)time(NULL);
394                 n_update_cols++;
395         
396                 update_keys[n_update_cols] = &str_remote_cseq_col;
397                 update_vals[n_update_cols].type = DB1_INT;
398                 update_vals[n_update_cols].nul = 0;
399                 update_vals[n_update_cols].val.int_val = subs->remote_cseq; 
400                 n_update_cols++;
401
402                 update_keys[n_update_cols] = &str_updated_col;
403                 update_vals[n_update_cols].type = DB1_INT;
404                 update_vals[n_update_cols].nul = 0;
405                 update_vals[n_update_cols].val.int_val = subs->updated;
406                 n_update_cols++;
407
408                 update_keys[n_update_cols] = &str_updated_winfo_col;
409                 update_vals[n_update_cols].type = DB1_INT;
410                 update_vals[n_update_cols].nul = 0;
411                 update_vals[n_update_cols].val.int_val = subs->updated_winfo;
412                 n_update_cols++;
413         }
414         if(type & LOCAL_TYPE)
415         {
416                 update_keys[n_update_cols] = &str_local_cseq_col;
417                 update_vals[n_update_cols].type = DB1_INT;
418                 update_vals[n_update_cols].nul = 0;
419                 update_vals[n_update_cols].val.int_val = subs->local_cseq;
420                 n_update_cols++;
421         
422                 update_keys[n_update_cols] = &str_version_col;
423                 update_vals[n_update_cols].type = DB1_INT;
424                 update_vals[n_update_cols].nul = 0;
425                 update_vals[n_update_cols].val.int_val = subs->version;
426                 n_update_cols++;
427         }
428
429         update_keys[n_update_cols] = &str_status_col;
430         update_vals[n_update_cols].type = DB1_INT;
431         update_vals[n_update_cols].nul = 0;
432         update_vals[n_update_cols].val.int_val = subs->status;
433         n_update_cols++;
434
435         update_keys[n_update_cols] = &str_reason_col;
436         update_vals[n_update_cols].type = DB1_STR;
437         update_vals[n_update_cols].nul = 0;
438         update_vals[n_update_cols].val.str_val = subs->reason;
439         n_update_cols++;
440
441         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0)
442         {
443                 LM_ERR("in use table sql operation\n"); 
444                 return -1;
445         }
446                 
447         if( pa_dbf.update( pa_db,query_cols, 0, query_vals,
448                                 update_keys, update_vals, n_query_cols,n_update_cols)<0) 
449         {
450                 LM_ERR("updating presence information\n");
451                 return -1;
452         }
453         return 0;
454 }
455
456 void delete_subs(str* pres_uri, str* ev_name, str* to_tag,
457                 str* from_tag, str* callid)
458 {
459         /* delete record from hash table also if not in dbonly mode */
460         if(subs_dbmode != DB_ONLY)
461         {
462                 unsigned int hash_code= core_hash(pres_uri, ev_name, shtable_size);
463                 if(delete_shtable(subs_htable, hash_code, *to_tag) < 0)
464                         LM_ERR("Failed to delete subscription from memory\n");
465         }
466
467         if(subs_dbmode != NO_DB && delete_db_subs(to_tag, from_tag, callid)< 0)
468                 LM_ERR("Failed to delete subscription from database\n");
469 }
470
471 int update_subscription_notifier(struct sip_msg* msg, subs_t* subs,
472                 int to_tag_gen, int* sent_reply)
473 {
474         int num_peers = 0;
475
476         *sent_reply= 0;
477
478         /* Set the notifier/update fields for the subscription */
479         subs->updated = core_hash(&subs->callid, &subs->from_tag,
480                                 (pres_waitn_time * pres_notifier_poll_rate
481                                         * pres_notifier_processes) - 1);
482         if (subs->event->type & WINFO_TYPE)
483                 subs->updated_winfo = UPDATED_TYPE;
484         else if (subs->event->wipeer)
485         {
486                 if ((num_peers = set_wipeer_subs_updated(&subs->pres_uri,
487                                                 subs->event->wipeer,
488                                                 subs->expires == 0)) < 0)
489                 {
490                         LM_ERR("failed to update database record(s)\n");
491                         goto error;
492                 }
493
494                 if (num_peers > 0)
495                         subs->updated_winfo = UPDATED_TYPE;
496         }
497         if (subs->expires == 0)
498         {
499                 subs->status = TERMINATED_STATUS;
500                 subs->reason.s = "timeout";
501                 subs->reason.len = 7;
502         }
503
504         printf_subs(subs);
505
506         if (to_tag_gen == 0)
507         {
508                 if (update_subs_db(subs, REMOTE_TYPE) < 0)
509                 {
510                         LM_ERR("updating subscription in database table\n");
511                         goto error;
512                 }
513         }
514         else
515         {
516                 subs->version = 1;
517                 if (insert_subs_db(subs, REMOTE_TYPE) < 0)
518                 {
519                         LM_ERR("failed to insert new record in database\n");
520                         goto error;
521                 }
522         }
523
524         if(send_2XX_reply(msg, subs->event->type & PUBL_TYPE ? 202 : 200,
525                                 subs->expires, &subs->local_contact) < 0)
526         {
527                 LM_ERR("sending %d response\n",
528                         subs->event->type & PUBL_TYPE ? 202 : 200);
529                 goto error;
530         }
531         *sent_reply= 1;
532
533         return 1;
534
535 error:
536         return -1;
537 }
538
539 int update_subscription(struct sip_msg* msg, subs_t* subs, int to_tag_gen,
540                 int* sent_reply)
541 {
542         unsigned int hash_code;
543
544         LM_DBG("update subscription\n");
545         printf_subs(subs);
546
547         *sent_reply= 0;
548
549         if( to_tag_gen ==0) /*if a SUBSCRIBE within a dialog */
550         {
551                 if(subs->expires == 0)
552                 {
553                         LM_DBG("expires =0 -> deleting record\n");
554
555                         delete_subs(&subs->pres_uri, &subs->event->name, &subs->to_tag,
556                                         &subs->from_tag, &subs->callid);
557
558                         if(subs->event->type & PUBL_TYPE)
559                         {
560                                 if( send_2XX_reply(msg, 202, subs->expires,
561                                                         &subs->local_contact) <0)
562                                 {
563                                         LM_ERR("sending 202 OK\n");
564                                         goto error;
565                                 }
566                                 *sent_reply= 1;
567                                 if(subs->event->wipeer)
568                                 {
569                                         if(query_db_notify(&subs->pres_uri,
570                                                                 subs->event->wipeer, NULL)< 0)
571                                         {
572                                                 LM_ERR("Could not send notify for winfo\n");
573                                                 goto error;
574                                         }
575                                 }
576
577                         }
578                         else /* if unsubscribe for winfo */
579                         {
580                                 if( send_2XX_reply(msg, 200, subs->expires,
581                                                         &subs->local_contact) <0)
582                                 {
583                                         LM_ERR("sending 200 OK reply\n");
584                                         goto error;
585                                 }
586                                 *sent_reply= 1;
587                         }
588                 
589                         if(notify(subs, NULL, NULL, 0)< 0)
590                         {
591                                 LM_ERR("Could not send notify\n");
592                                 goto error;
593                         }
594                         return 1;
595                 }
596                 /* if subscriptions are stored in memory, update them */
597                 if(subs_dbmode != DB_ONLY)
598                 {
599                         hash_code= core_hash(&subs->pres_uri, &subs->event->name, shtable_size);
600                         if(update_shtable(subs_htable, hash_code, subs, REMOTE_TYPE)< 0)
601                         {
602                                 LM_ERR("failed to update subscription in memory\n");
603                                 goto error;
604                         }
605                 }
606                 /* for modes that update the subscription synchronously in database, write in db */
607                 if(subs_dbmode == DB_ONLY ||  subs_dbmode== WRITE_THROUGH)
608                 {
609                         /* update in database table */
610                         if(update_subs_db(subs, REMOTE_TYPE|LOCAL_TYPE)< 0)
611                         {
612                                 LM_ERR("updating subscription in database table\n");
613                                 goto error;
614                         }
615                 }
616         }
617         else
618         {
619                 LM_DBG("subscription not in dialog\n");
620                 if(subs->expires!= 0)
621                 {
622                         if(subs_dbmode != DB_ONLY)
623                         {
624                                 LM_DBG("inserting in shtable\n");
625                                 subs->db_flag = (subs_dbmode==WRITE_THROUGH)?WTHROUGHDB_FLAG:INSERTDB_FLAG;
626                                 hash_code= core_hash(&subs->pres_uri, &subs->event->name, shtable_size);
627                                 subs->version = 0;
628                                 if(insert_shtable(subs_htable,hash_code,subs)< 0)
629                                 {
630                                         LM_ERR("failed to insert new record in subs htable\n");
631                                         goto error;
632                                 }
633                         }
634
635                         if(subs_dbmode == DB_ONLY || subs_dbmode == WRITE_THROUGH)
636                         {
637                                 subs->version = 1;
638                                 if(insert_subs_db(subs, REMOTE_TYPE) < 0)
639                                 {
640                                         LM_ERR("failed to insert new record in database\n");
641                                         goto error;
642                                 }
643                         }
644                         /* TODO if req_auth, the subscription was in the watcher table first, we must delete it */
645                 }
646                 /*otherwise there is a subscription outside a dialog with expires= 0 
647                  * no update in database, but should try to send Notify */
648                 else
649                 {
650                         LM_DBG("subscription request with expiry=0 not in dialog\n");
651                 }
652         }
653
654         /* reply_and_notify  */
655
656         if(subs->event->type & PUBL_TYPE)
657         {       
658                 if(send_2XX_reply(msg, 202, subs->expires,
659                                         &subs->local_contact)<0)
660                 {
661                         LM_ERR("sending 202 OK reply\n");
662                         goto error;
663                 }
664                 *sent_reply= 1;
665
666                 if(subs->expires!= 0 && subs->event->wipeer)
667                 {
668                         LM_DBG("send Notify with winfo\n");
669                         if(query_db_notify(&subs->pres_uri, subs->event->wipeer, subs)< 0)
670                         {
671                                 LM_ERR("Could not send notify winfo\n");
672                                 goto error;
673                         }
674                         if(subs->send_on_cback== 0)
675                         {
676                                 if(notify(subs, NULL, NULL, 0)< 0)
677                                 {
678                                         LM_ERR("Could not send notify\n");
679                                         goto error;
680                                 }
681                         }
682                 }
683                 else
684                 {
685                         if(notify(subs, NULL, NULL, 0)< 0)
686                         {
687                                 LM_ERR("Could not send notify\n");
688                                 goto error;
689                         }
690                 }       
691                         
692         }
693         else 
694         {
695                 if( send_2XX_reply(msg, 200, subs->expires,
696                                         &subs->local_contact)<0)
697                 {
698                         LM_ERR("sending 200 OK reply\n");
699                         goto error;
700                 }               
701                 *sent_reply= 1;
702                 
703                 if(send_fast_notify && (notify(subs, NULL, NULL, 0 )< 0))
704                 {
705                         LM_ERR("sending notify request\n");
706                         goto error;
707                 }
708         }
709         return 0;
710         
711 error:
712
713         LM_ERR("occured\n");
714         return -1;
715
716 }
717
718 void msg_watchers_clean(unsigned int ticks,void *param)
719 {
720         db_key_t db_keys[2];
721         db_val_t db_vals[2];
722         db_op_t  db_ops[2] ;
723
724         LM_DBG("cleaning pending subscriptions\n");
725
726         db_keys[0] = &str_inserted_time_col;
727         db_ops[0] = OP_LT;
728         db_vals[0].type = DB1_INT;
729         db_vals[0].nul = 0;
730         db_vals[0].val.int_val = (int)time(NULL)- 24*3600 ;
731
732         db_keys[1] = &str_status_col;
733         db_ops [1] = OP_EQ;
734         db_vals[1].type = DB1_INT;
735         db_vals[1].nul = 0;
736         db_vals[1].val.int_val = PENDING_STATUS;
737
738         if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
739         {
740                 LM_ERR("unsuccessful use table sql operation\n");
741                 return ;
742         }
743
744         if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 2) < 0)
745                 LM_ERR("cleaning pending subscriptions\n");
746 }
747
748 int handle_subscribe0(struct sip_msg* msg)
749 {
750         struct to_body *pfrom;
751
752         if (parse_from_uri(msg) < 0)
753         {
754                 LM_ERR("failed to find From header\n");
755                 if (slb.freply(msg, 400, &pu_400_rpl) < 0)
756                 {
757                         LM_ERR("while sending 400 reply\n");
758                         return -1;
759                 }
760                 return 0;
761         }
762         pfrom = (struct to_body *) msg->from->parsed;
763
764         return handle_subscribe(msg, pfrom->parsed_uri.user,
765                                 pfrom->parsed_uri.host);
766 }
767
768 int w_handle_subscribe(struct sip_msg* msg, char* watcher_uri)
769 {
770         str wuri;
771         struct sip_uri parsed_wuri;
772
773         if (fixup_get_svalue(msg, (gparam_p)watcher_uri, &wuri) != 0)
774         {
775                 LM_ERR("invalid uri parameter\n");
776                 return -1;
777         }
778
779         if (parse_uri(wuri.s, wuri.len, &parsed_wuri) < 0)
780         {
781                 LM_ERR("failed to parse watcher URI\n");
782                 return -1;
783         }
784
785         return handle_subscribe(msg, parsed_wuri.user, parsed_wuri.host);
786 }
787
788 int handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_domain)
789 {
790         int  to_tag_gen = 0;
791         subs_t subs;
792         pres_ev_t* event= NULL;
793         event_t* parsed_event= NULL;
794         param_t* ev_param= NULL;
795         int found;
796         str reason= {0, 0};
797         struct sip_uri uri;
798         int reply_code;
799         str reply_str;
800         int sent_reply= 0;
801
802         /* ??? rename to avoid collisions with other symbols */
803         counter++;
804
805         memset(&subs, 0, sizeof(subs_t));
806         
807         reply_code= 500;
808         reply_str= pu_500_rpl;
809
810         if(parse_headers(msg,HDR_EOH_F, 0) == -1)
811         {
812                 LM_ERR("parsing headers\n");
813                 reply_code= 400;
814                 reply_str= pu_400_rpl;
815                 goto error;
816         }
817         
818         /* inspecting the Event header field */
819         if(msg->event && msg->event->body.len > 0)
820         {
821                 if (!msg->event->parsed && (parse_event(msg->event) < 0))
822                 {
823                         reply_code= 400;
824                         reply_str= pu_400_rpl;
825                         goto error;
826                 }
827         }
828         else
829                 goto bad_event;
830
831         /* search event in the list */
832         parsed_event= (event_t*)msg->event->parsed;
833         event= search_event(parsed_event);
834         if(event== NULL)
835         {
836                 goto bad_event;
837         }
838         subs.event= event;
839         
840         /* extract the id if any*/
841         ev_param= parsed_event->params.list;
842         while(ev_param)
843         {
844                 if(ev_param->name.len== 2 && strncmp(ev_param->name.s, "id", 2)== 0)
845                 {
846                         subs.event_id= ev_param->body;
847                         break;
848                 }
849                 ev_param= ev_param->next;
850         }
851         
852         if(extract_sdialog_info(&subs, msg, max_expires, &to_tag_gen,
853                                 server_address, watcher_user, watcher_domain)< 0)
854         {
855                 LM_ERR("failed to extract dialog information\n");
856                 goto error;
857         }
858
859         /* getting presentity uri from Request-URI if initial subscribe - or else from database*/
860         if(to_tag_gen)
861         {
862                 if (!EVENT_DIALOG_SLA(parsed_event))
863                 {
864                         if( parse_sip_msg_uri(msg)< 0)
865                         {
866                                 LM_ERR("failed to parse R-URI\n");
867                                 return -1;
868                         }
869                         if(uandd_to_uri(msg->parsed_uri.user, msg->parsed_uri.host,
870                                         &subs.pres_uri)< 0)
871                         {
872                                 LM_ERR("failed to construct uri from user and domain\n");
873                                 goto error;
874                         }
875                 }
876         }
877         else
878         {
879                 if(get_stored_info(msg, &subs, &reply_code, &reply_str )< 0)
880                 {
881                         LM_INFO("getting stored info\n");
882                         goto error;
883                 }
884                 reason= subs.reason;
885         }
886         /* mark that the received event is a SUBSCRIBE message */
887         subs.recv_event = PRES_SUBSCRIBE_RECV;
888
889         /* call event specific subscription handling */
890         if(event->evs_subs_handl)
891         {
892                 if(event->evs_subs_handl(msg)< 0)
893                 {
894                         LM_ERR("in event specific subscription handling\n");
895                         goto error;
896                 }
897         }
898
899
900         /* if dialog initiation Subscribe - get subscription state */
901         if(to_tag_gen)
902         {
903                 subs.updated = NO_UPDATE_TYPE;
904                 subs.updated_winfo = NO_UPDATE_TYPE;
905
906                 if(!event->req_auth) 
907                         subs.status = ACTIVE_STATUS;
908                 else
909                 {
910                         /* query in watchers_table */
911                         if(get_db_subs_auth(&subs, &found)< 0)
912                         {
913                                 LM_ERR("getting subscription status from watchers table\n");
914                                 goto error;
915                         }
916                         if(found== 0)
917                         {
918                                 /*default 'pending' status */
919                                 subs.status= PENDING_STATUS;
920                                 subs.reason.s= NULL;
921                                 subs.reason.len= 0;
922                                 /* here a query to xcap server must be done -> new process maybe */
923                         
924                                 if(parse_uri(subs.pres_uri.s, subs.pres_uri.len, &uri)< 0)
925                                 {
926                                         LM_ERR("parsing uri\n");
927                                         goto error;
928
929                                 }
930                                 if(subs.event->get_rules_doc(&uri.user, &uri.host, &subs.auth_rules_doc)< 0)
931                                 {
932                                         LM_ERR("getting rules doc\n");
933                                         goto error;
934                                 }
935                                 
936                                 if(subs.event->get_auth_status(&subs)< 0)
937                                 {
938                                         LM_ERR("in event specific function is_watcher_allowed\n");
939                                         goto error;
940                                 }
941                                 if(get_status_str(subs.status) == NULL)
942                                 {
943                                         LM_ERR("wrong status= %d\n", subs.status);
944                                         goto error;
945                                 }
946
947                                 if(insert_db_subs_auth(&subs)< 0)
948                                 {
949                                         LM_ERR("while inserting record in watchers table\n");
950                                         goto error;
951                                 }
952                         }
953                         else
954                         {
955                                 reason= subs.reason;
956                         }
957                 }
958         }
959
960         /* check if correct status */
961         if(get_status_str(subs.status)== NULL)
962         {
963                 LM_ERR("wrong status\n");
964                 goto error;
965         }
966         LM_DBG("subscription status= %s - %s\n", get_status_str(subs.status), 
967             found==0?"inserted":"found in watcher table");
968         
969         if (pres_notifier_processes > 0)
970         {
971                 if (update_subscription_notifier(msg, &subs, to_tag_gen,
972                                                         &sent_reply) < 0)
973                 {
974                         LM_ERR("in update_subscription_notifier\n");
975                         goto error;
976                 }
977         }
978         else if (update_subscription(msg, &subs, to_tag_gen, &sent_reply) <0)
979         {       
980                 LM_ERR("in update_subscription\n");
981                 goto error;
982         }
983         if(subs.auth_rules_doc)
984         {
985                 pkg_free(subs.auth_rules_doc->s);
986                 pkg_free(subs.auth_rules_doc);
987         }
988         if(reason.s)
989                 pkg_free(reason.s);
990         
991         if(subs.pres_uri.s)
992                 pkg_free(subs.pres_uri.s);
993         
994         if((!server_address.s) || (server_address.len== 0))
995         {
996                 pkg_free(subs.local_contact.s);
997         }
998         if(subs.record_route.s)
999                 pkg_free(subs.record_route.s);
1000
1001         return 1;
1002
1003 bad_event:
1004
1005         if (parsed_event && parsed_event->name.s)
1006             LM_ERR("Unsupported event header field value %.*s\n",
1007                    parsed_event->name.len,parsed_event->name.s);
1008         else
1009             LM_ERR("Missing event header field value\n");
1010         
1011         reply_code= BAD_EVENT_CODE;
1012         reply_str= pu_489_rpl;
1013
1014 error:
1015         
1016         if(sent_reply== 0)
1017         {
1018                 if(send_error_reply(msg, reply_code, reply_str)< 0)
1019                 {
1020                         LM_ERR("failed to send reply on error case\n");
1021                 }
1022         }
1023
1024         if(subs.pres_uri.s)     
1025                 pkg_free(subs.pres_uri.s);
1026         
1027         if(subs.auth_rules_doc)
1028         {
1029                 if(subs.auth_rules_doc->s)
1030                         pkg_free(subs.auth_rules_doc->s);
1031                 pkg_free(subs.auth_rules_doc);
1032         }
1033         if(reason.s)
1034                 pkg_free(reason.s);
1035
1036         if(((!server_address.s) ||(server_address.len== 0))&& subs.local_contact.s)
1037         {
1038                 pkg_free(subs.local_contact.s);
1039         }
1040         if(subs.record_route.s)
1041                 pkg_free(subs.record_route.s);
1042
1043         return -1;
1044
1045 }
1046
1047
1048 int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int mexp,
1049                 int* to_tag_gen, str scontact, str watcher_user,
1050                 str watcher_domain)
1051 {
1052         str rec_route= {0, 0};
1053         int rt  = 0;
1054         contact_body_t *b;
1055         struct to_body *pto, TO = {0}, *pfrom = NULL;
1056         int lexpire;
1057         str rtag_value;
1058         struct sip_uri uri;
1059
1060         /* examine the expire header field */
1061         if(msg->expires && msg->expires->body.len > 0)
1062         {
1063                 if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
1064                 {
1065                         LM_ERR("cannot parse Expires header\n");
1066                         goto error;
1067                 }
1068                 lexpire = ((exp_body_t*)msg->expires->parsed)->val;
1069                 LM_DBG("'Expires' header found, value= %d\n", lexpire);
1070
1071         }
1072         else 
1073         {
1074                 LM_DBG("'expires' not found; default=%d\n",subs->event->default_expires);
1075                 lexpire = subs->event->default_expires;
1076         }
1077         if(lexpire > mexp)
1078                 lexpire = mexp;
1079
1080         subs->expires = lexpire;
1081
1082         if( msg->to==NULL || msg->to->body.s==NULL)
1083         {
1084                 LM_ERR("cannot parse TO header\n");
1085                 goto error;
1086         }
1087         /* examine the to header */
1088         if(msg->to->parsed != NULL)
1089         {
1090                 pto = (struct to_body*)msg->to->parsed;
1091                 LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",pto->uri.len,pto->uri.s);
1092         }
1093         else
1094         {
1095                 parse_to(msg->to->body.s,msg->to->body.s + msg->to->body.len + 1, &TO);
1096                 if( TO.uri.len <= 0 )
1097                 {
1098                         LM_DBG("'To' header NOT parsed\n");
1099                         goto error;
1100                 }
1101                 pto = &TO;
1102         }
1103
1104         if( pto->parsed_uri.user.s && pto->parsed_uri.host.s &&
1105                 pto->parsed_uri.user.len && pto->parsed_uri.host.len)
1106         {
1107                 subs->to_user = pto->parsed_uri.user;
1108                 subs->to_domain = pto->parsed_uri.host;
1109         }
1110         else
1111         {
1112                 if(parse_uri(pto->uri.s, pto->uri.len, &uri)< 0)
1113                 {
1114                         LM_ERR("while parsing uri\n");
1115                         goto error;
1116                 }
1117                 subs->to_user = uri.user;
1118                 subs->to_domain = uri.host;
1119         }
1120
1121         /* examine the from header */
1122         if (!msg->from || !msg->from->body.s)
1123         {
1124                 LM_DBG("cannot find 'from' header!\n");
1125                 goto error;
1126         }
1127         if (msg->from->parsed == NULL)
1128         {
1129                 LM_DBG("'From' header not parsed\n");
1130                 /* parsing from header */
1131                 if ( parse_from_header( msg )<0 ) 
1132                 {
1133                         LM_DBG("cannot parse From header\n");
1134                         goto error;
1135                 }
1136         }
1137         pfrom = (struct to_body*)msg->from->parsed;
1138         
1139         if( pfrom->parsed_uri.user.s && pfrom->parsed_uri.host.s && 
1140                 pfrom->parsed_uri.user.len && pfrom->parsed_uri.host.len)
1141         {
1142                 subs->from_user = pfrom->parsed_uri.user;
1143                 subs->from_domain = pfrom->parsed_uri.host;
1144         }
1145         else
1146         {
1147                 if(parse_uri(pfrom->uri.s, pfrom->uri.len, &uri)< 0)
1148                 {
1149                         LM_ERR("while parsing uri\n");
1150                         goto error;
1151                 }
1152                 subs->from_user = uri.user;
1153                 subs->from_domain = uri.host;
1154         }
1155
1156         subs->watcher_user = watcher_user;
1157         subs->watcher_domain = watcher_domain;
1158
1159         /* get to_tag if the message does not have a to_tag*/
1160         if (pto->tag_value.s==NULL || pto->tag_value.len==0 )
1161         {  
1162                 LM_DBG("generating to_tag\n");
1163                 *to_tag_gen = 1;
1164                 rtag_value.len = 0;
1165                 if(slb.get_reply_totag(msg, &rtag_value)<0 || rtag_value.len <= 0)
1166                 {
1167                         LM_ERR("while creating to_tag\n");
1168                         goto error;
1169                 }
1170         }
1171         else
1172         {
1173                 *to_tag_gen = 0;
1174                 rtag_value=pto->tag_value;
1175         }
1176         subs->to_tag = rtag_value;
1177
1178         if( msg->callid==NULL || msg->callid->body.s==NULL)
1179         {
1180                 LM_ERR("cannot parse callid header\n");
1181                 goto error;
1182         }
1183         subs->callid = msg->callid->body;
1184
1185         if( msg->cseq==NULL || msg->cseq->body.s==NULL)
1186         {
1187                 LM_ERR("cannot parse cseq header\n");
1188                 goto error;
1189         }
1190         if (str2int( &(get_cseq(msg)->number), &subs->remote_cseq)!=0 )
1191         {
1192                 LM_ERR("cannot parse cseq number\n");
1193                 goto error;
1194         }
1195         if( msg->contact==NULL || msg->contact->body.s==NULL)
1196         {
1197                 LM_ERR("cannot parse contact header\n");
1198                 goto error;
1199         }
1200         if( parse_contact(msg->contact) <0 )
1201         {
1202                 LM_ERR(" cannot parse contact"
1203                                 " header\n");
1204                 goto error;
1205         }
1206         b= (contact_body_t* )msg->contact->parsed;
1207
1208         if(b == NULL)
1209         {
1210                 LM_ERR("cannot parse contact header\n");
1211                 goto error;
1212         }
1213         if(b->star || b->contacts==NULL)
1214         {
1215                 LM_ERR("Wrong contact header\n");
1216                 goto error;
1217         }
1218
1219         subs->contact = b->contacts->uri;
1220         
1221         LM_DBG("subs->contact= %.*s - len = %d\n",subs->contact.len,
1222                         subs->contact.s, subs->contact.len);    
1223
1224         if (EVENT_DIALOG_SLA(subs->event->evp))
1225         {
1226                 /* user_contact@from_domain */
1227                 if(parse_uri(subs->contact.s, subs->contact.len, &uri)< 0)
1228                 {
1229                         LM_ERR("failed to parse contact uri\n");
1230                         goto error;
1231                 }
1232                 if(uandd_to_uri(uri.user, subs->from_domain, &subs->pres_uri)< 0)
1233                 {
1234                         LM_ERR("failed to construct uri\n");
1235                         goto error;
1236                 }
1237                 LM_DBG("&&&&&&&&&&&&&&& dialog pres_uri= %.*s\n",
1238                                 subs->pres_uri.len, subs->pres_uri.s);
1239         }
1240
1241         /*process record route and add it to a string*/
1242         if(*to_tag_gen && msg->record_route!=NULL)
1243         {
1244                 rt = print_rr_body(msg->record_route, &rec_route, 0, 0);
1245                 if(rt != 0)
1246                 {
1247                         LM_ERR("processing the record route [%d]\n", rt);       
1248                         rec_route.s=NULL;
1249                         rec_route.len=0;
1250                 //      goto error;
1251                 }
1252         }
1253         subs->record_route = rec_route;
1254                         
1255         subs->sockinfo_str= msg->rcv.bind_address->sock_str;
1256
1257         if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
1258         {
1259                 LM_ERR("no from tag value present\n");
1260                 goto error;
1261         }
1262         subs->from_tag = pfrom->tag_value;
1263
1264         subs->version = 1;
1265
1266         if((!scontact.s) || (scontact.len== 0))
1267         {
1268                 if(ps_fill_local_contact(msg, &subs->local_contact)<0)
1269                 {
1270                         LM_ERR("cannot get local contact address\n");
1271                         goto error;
1272                 }
1273         }
1274         else
1275                 subs->local_contact= scontact;
1276
1277         free_to_params(&TO);
1278         return 0;
1279         
1280 error:
1281         free_to_params(&TO);
1282         return -1;
1283 }
1284
1285
1286 int get_stored_info(struct sip_msg* msg, subs_t* subs, int* reply_code,
1287                 str* reply_str)
1288 {
1289         str pres_uri= {0, 0}, reason={0, 0};
1290         subs_t* s;
1291         int i;
1292         unsigned int hash_code;
1293
1294         if(subs_dbmode == DB_ONLY)
1295                 return get_database_info(msg, subs, reply_code, reply_str);
1296
1297         /* first try to_user== pres_user and to_domain== pres_domain */
1298         if(subs->pres_uri.s == NULL)
1299         {
1300                 uandd_to_uri(subs->to_user, subs->to_domain, &pres_uri);
1301                 if(pres_uri.s== NULL)
1302                 {
1303                         LM_ERR("creating uri from user and domain\n");
1304                         return -1;
1305                 }
1306         }
1307         else
1308                 pres_uri = subs->pres_uri;
1309
1310         hash_code= core_hash(&pres_uri, &subs->event->name, shtable_size);
1311         lock_get(&subs_htable[hash_code].lock);
1312         s= search_shtable(subs_htable, subs->callid, subs->to_tag,
1313                 subs->from_tag, hash_code);
1314         if(s)
1315                 goto found_rec;
1316
1317         lock_release(&subs_htable[hash_code].lock);
1318
1319         if(subs->pres_uri.s)
1320                 goto not_found;
1321
1322         pkg_free(pres_uri.s);
1323         pres_uri.s= NULL;
1324
1325         LM_DBG("record not found using R-URI search iteratively\n");
1326         /* take one row at a time */
1327         for(i= 0; i< shtable_size; i++)
1328         {
1329                 lock_get(&subs_htable[i].lock);
1330                 s= search_shtable(subs_htable, subs->callid,subs->to_tag,subs->from_tag, i);
1331                 if (s)
1332                 {
1333                         pres_uri.s= (char*)pkg_malloc(s->pres_uri.len* sizeof(char));
1334                         if(pres_uri.s== NULL)
1335                         {
1336                                 lock_release(&subs_htable[i].lock);
1337                                 ERR_MEM(PKG_MEM_STR);
1338                         }
1339                         memcpy(pres_uri.s, s->pres_uri.s, s->pres_uri.len);
1340                         pres_uri.len= s->pres_uri.len;
1341
1342                         hash_code = i;
1343                         break;
1344                 }
1345                 lock_release(&subs_htable[i].lock);
1346         }
1347
1348         if(!s)
1349                 goto not_found;
1350
1351 found_rec:
1352
1353         LM_DBG("Record found in hash_table\n");
1354
1355         if(subs->pres_uri.s == NULL)
1356                 subs->pres_uri= pres_uri;
1357
1358         subs->version = s->version + 1;
1359         subs->status= s->status;
1360         if(s->reason.s && s->reason.len)
1361         {
1362                 reason.s= (char*)pkg_malloc(s->reason.len* sizeof(char));
1363                 if(reason.s== NULL)
1364                 {
1365                         lock_release(&subs_htable[hash_code].lock);
1366                         ERR_MEM(PKG_MEM_STR);
1367                 }
1368                 memcpy(reason.s, s->reason.s, s->reason.len);
1369                 reason.len= s->reason.len;
1370                 subs->reason= reason;
1371         }
1372         if(s->record_route.s && s->record_route.len)
1373         {
1374                 subs->record_route.s= (char*)pkg_malloc
1375                         (s->record_route.len* sizeof(char));
1376                 if(subs->record_route.s== NULL)
1377                 {
1378                         lock_release(&subs_htable[hash_code].lock);
1379                         ERR_MEM(PKG_MEM_STR);
1380                 }
1381                 memcpy(subs->record_route.s, s->record_route.s, s->record_route.len);
1382                 subs->record_route.len= s->record_route.len;
1383         }
1384
1385         subs->local_cseq= s->local_cseq +1;
1386
1387         if(subs->remote_cseq<= s->remote_cseq)
1388         {
1389                 LM_ERR("wrong sequence number;received: %d - stored: %d\n",
1390                                 subs->remote_cseq, s->remote_cseq);
1391                 
1392                 *reply_code= 400;
1393                 *reply_str= pu_400_rpl;
1394
1395                 lock_release(&subs_htable[hash_code].lock);
1396                 goto error;
1397         }
1398         lock_release(&subs_htable[hash_code].lock);
1399
1400         return 0;
1401
1402 not_found:
1403
1404         LM_INFO("record not found in hash_table\n");
1405         *reply_code= 481;
1406         *reply_str= pu_481_rpl;
1407
1408         return -1;
1409
1410 error:
1411         if(subs->reason.s)
1412                 pkg_free(subs->reason.s);
1413         subs->reason.s= NULL;
1414         if(subs->record_route.s)
1415                 pkg_free(subs->record_route.s);
1416         subs->record_route.s= NULL;
1417         return -1;
1418 }
1419
1420 int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* reply_str)
1421 {
1422         db_key_t query_cols[3];
1423         db_val_t query_vals[3];
1424         db_key_t result_cols[9];
1425         db1_res_t *result= NULL;
1426         db_row_t *row ; 
1427         db_val_t *row_vals ;
1428         int n_query_cols = 0;
1429         int n_result_cols = 0;
1430         int remote_cseq_col= 0, local_cseq_col= 0, status_col, reason_col;
1431         int record_route_col, version_col, pres_uri_col;
1432         int updated_col, updated_winfo_col;
1433         unsigned int remote_cseq;
1434         str pres_uri, record_route;
1435         str reason;
1436
1437         query_cols[n_query_cols] = &str_callid_col;
1438         query_vals[n_query_cols].type = DB1_STR;
1439         query_vals[n_query_cols].nul = 0;
1440         query_vals[n_query_cols].val.str_val = subs->callid;
1441         n_query_cols++;
1442
1443         query_cols[n_query_cols] = &str_to_tag_col;
1444         query_vals[n_query_cols].type = DB1_STR;
1445         query_vals[n_query_cols].nul = 0;
1446         query_vals[n_query_cols].val.str_val = subs->to_tag;
1447         n_query_cols++;
1448
1449         query_cols[n_query_cols] = &str_from_tag_col;
1450         query_vals[n_query_cols].type = DB1_STR;
1451         query_vals[n_query_cols].nul = 0;
1452         query_vals[n_query_cols].val.str_val = subs->from_tag;
1453         n_query_cols++;
1454
1455         result_cols[pres_uri_col=n_result_cols++] = &str_presentity_uri_col;
1456         result_cols[remote_cseq_col=n_result_cols++] = &str_remote_cseq_col;
1457         result_cols[local_cseq_col=n_result_cols++] = &str_local_cseq_col;
1458         result_cols[status_col=n_result_cols++] = &str_status_col;
1459         result_cols[reason_col=n_result_cols++] = &str_reason_col;
1460         result_cols[record_route_col=n_result_cols++] = &str_record_route_col;
1461         result_cols[version_col=n_result_cols++] = &str_version_col;
1462         result_cols[updated_col=n_result_cols++] = &str_updated_col;
1463         result_cols[updated_winfo_col=n_result_cols++] = &str_updated_winfo_col;
1464         
1465         if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
1466         {
1467                 LM_ERR("unsuccessful use_table sql operation\n");
1468                 return -1;
1469         }
1470         
1471         if (pa_dbf.query (pa_db, query_cols, 0, query_vals,
1472                  result_cols, n_query_cols, n_result_cols, 0,  &result) < 0) 
1473         {
1474                 LM_ERR("querying subscription dialog\n");
1475                 if(result)
1476                         pa_dbf.free_result(pa_db, result);
1477                 return -1;
1478         }
1479         if(result== NULL)
1480                 return -1;
1481
1482         if(result && result->n <=0)
1483         {
1484                 LM_INFO("No matching subscription dialog found in database\n");
1485                 
1486                 pa_dbf.free_result(pa_db, result);
1487                 *reply_code= 481;
1488                 *reply_str= pu_481_rpl;
1489
1490                 return -1;
1491         }
1492
1493         row = &result->rows[0];
1494         row_vals = ROW_VALUES(row);
1495         remote_cseq= row_vals[remote_cseq_col].val.int_val;
1496         
1497         if(subs->remote_cseq<= remote_cseq)
1498         {
1499                 LM_ERR("wrong sequence number received: %d - stored: %d\n",
1500                                 subs->remote_cseq, remote_cseq);
1501                 *reply_code= 400;
1502                 *reply_str= pu_400_rpl;
1503                 pa_dbf.free_result(pa_db, result);
1504                 return -1;
1505         }
1506         
1507         subs->status= row_vals[status_col].val.int_val;
1508         reason.s= (char*)row_vals[reason_col].val.string_val;
1509         if(reason.s)
1510         {
1511                 reason.len= strlen(reason.s);
1512                 subs->reason.s= (char*)pkg_malloc(reason.len* sizeof(char));
1513                 if(subs->reason.s== NULL)
1514                 {
1515                         ERR_MEM(PKG_MEM_STR);
1516                 }
1517                 memcpy(subs->reason.s, reason.s, reason.len);
1518                 subs->reason.len= reason.len;
1519         }
1520
1521         subs->local_cseq= row_vals[local_cseq_col].val.int_val + 1;
1522         subs->version= row_vals[version_col].val.int_val + 1;
1523
1524         if(!EVENT_DIALOG_SLA(subs->event->evp))
1525         {
1526                 pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val;
1527                 pres_uri.len= strlen(pres_uri.s);
1528                 subs->pres_uri.s= (char*)pkg_malloc(pres_uri.len* sizeof(char));
1529                 if(subs->pres_uri.s== NULL)
1530                 {       
1531                         if(subs->reason.s)
1532                                 pkg_free(subs->reason.s);
1533                         ERR_MEM(PKG_MEM_STR);
1534                 }
1535                 memcpy(subs->pres_uri.s, pres_uri.s, pres_uri.len);
1536                 subs->pres_uri.len= pres_uri.len;
1537         }
1538
1539         record_route.s= (char*)row_vals[record_route_col].val.string_val;
1540         if(record_route.s)
1541         {
1542                 record_route.len= strlen(record_route.s);
1543                 subs->record_route.s= (char*)pkg_malloc(record_route.len*sizeof(char));
1544                 if(subs->record_route.s== NULL)
1545                 {
1546                         ERR_MEM(PKG_MEM_STR);
1547                 }
1548                 memcpy(subs->record_route.s, record_route.s, record_route.len);
1549                 subs->record_route.len= record_route.len;
1550         }
1551
1552         subs->updated= row_vals[updated_col].val.int_val;
1553         subs->updated_winfo= row_vals[updated_winfo_col].val.int_val;
1554
1555         pa_dbf.free_result(pa_db, result);
1556         result= NULL;
1557
1558         return 0;
1559 error:
1560         if(result)
1561                 pa_dbf.free_result(pa_db, result);
1562
1563         return -1;
1564
1565 }
1566
1567
1568 int handle_expired_subs(subs_t* s)
1569 {
1570         /* send Notify with state=terminated;reason=timeout */
1571         
1572         s->status= TERMINATED_STATUS;
1573         s->reason.s= "timeout";
1574         s->reason.len= 7;
1575         s->expires= 0;
1576         s->local_cseq++;
1577
1578         if(send_notify_request(s, NULL, NULL, 1)< 0)
1579         {
1580                 LM_ERR("send Notify not successful\n");
1581                 return -1;
1582         }
1583         
1584         return 0;
1585
1586 }
1587
1588 void update_db_subs_timer_notifier(void)
1589 {
1590         db_key_t query_cols[1], result_cols[3];
1591         db_val_t query_vals[1], *values;
1592         db_op_t query_ops[1];
1593         db_row_t *rows;
1594         db1_res_t *result = NULL;
1595         int n_query_cols = 0, n_result_cols = 0;
1596         int r_callid_col = 0, r_to_tag_col = 0, r_from_tag_col = 0;
1597         int i;
1598         subs_t subs;
1599
1600         if(pa_db == NULL)
1601         {
1602                 LM_ERR("null database connection\n");
1603                 goto error;
1604         }
1605
1606         if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
1607         {
1608                 LM_ERR("use table failed\n");
1609                 goto error;
1610         }
1611
1612         query_cols[n_query_cols]= &str_expires_col;
1613         query_vals[n_query_cols].type = DB1_INT;
1614         query_vals[n_query_cols].nul = 0;
1615         query_vals[n_query_cols].val.int_val= (int)time(NULL) - expires_offset;
1616         query_ops[n_query_cols]= OP_LT;
1617         n_query_cols++;
1618
1619         result_cols[r_callid_col=n_result_cols++] = &str_callid_col;
1620         result_cols[r_to_tag_col=n_result_cols++] = &str_to_tag_col;
1621         result_cols[r_from_tag_col=n_result_cols++] = &str_from_tag_col;
1622
1623         if(db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, query_cols,
1624                           query_ops, query_vals, result_cols,
1625                           n_query_cols, n_result_cols, 0, &result )< 0)
1626         {
1627                 LM_ERR("Can't query db\n");
1628                 goto error;
1629         }
1630
1631         if(result == NULL)
1632         {
1633                 LM_ERR("bad result\n");
1634                 goto error;
1635         }
1636
1637         do {
1638                 rows = RES_ROWS(result);
1639         
1640                 for (i = 0; i <RES_ROW_N(result); i++)
1641                 {
1642                         values = ROW_VALUES(&rows[i]);
1643
1644                         subs.callid.s = (char *) VAL_STRING(&values[r_callid_col]);
1645                         subs.callid.len = strlen(subs.callid.s);
1646                         subs.to_tag.s = (char *) VAL_STRING(&values[r_to_tag_col]);
1647                         subs.to_tag.len = strlen(subs.to_tag.s);
1648                         subs.from_tag.s = (char *) VAL_STRING(&values[r_from_tag_col]);
1649                         subs.from_tag.len = strlen(subs.from_tag.s);
1650
1651                         set_updated(&subs);
1652                 }
1653         } while (db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result) == 1
1654                         && RES_ROW_N(result) > 0);
1655
1656 error:
1657         if (result) pa_dbf.free_result(pa_db, result);
1658 }
1659
1660 void update_db_subs_timer_dbonly(void)
1661 {
1662         db_op_t qops[1];
1663         db_key_t qcols[1];
1664         db_val_t qvals[1];
1665         db_key_t result_cols[18];
1666         int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col,
1667                 callid_col, totag_col, fromtag_col, event_col, event_id_col,
1668                 local_cseq_col, expires_col, rr_col, sockinfo_col,
1669                 contact_col, lcontact_col, watcher_user_col, watcher_domain_col;
1670         int n_result_cols = 0;
1671         db1_res_t *result= NULL;
1672         db_row_t *row = NULL;
1673         db_val_t *row_vals= NULL;
1674         int i;
1675         subs_t s, *s_new, *s_array = NULL, *s_del;
1676         str ev_name;
1677         pres_ev_t* event;
1678
1679         LM_DBG("update_db_subs_timer_dbonly: start\n");
1680
1681         qcols[0]= &str_expires_col;
1682         qvals[0].type = DB1_INT;
1683         qvals[0].nul = 0;
1684         qvals[0].val.int_val= (int)time(NULL) - expires_offset;
1685         qops[0]= OP_LT;
1686
1687         /* query the expired subscriptions */
1688         result_cols[pres_uri_col=n_result_cols++]   =&str_presentity_uri_col;
1689         result_cols[expires_col=n_result_cols++]    =&str_expires_col;
1690         result_cols[event_col=n_result_cols++]      =&str_event_col;
1691         result_cols[event_id_col=n_result_cols++]   =&str_event_id_col;
1692         result_cols[to_user_col=n_result_cols++]    =&str_to_user_col;
1693         result_cols[to_domain_col=n_result_cols++]  =&str_to_domain_col;
1694         result_cols[from_user_col=n_result_cols++]  =&str_from_user_col;
1695         result_cols[from_domain_col=n_result_cols++]=&str_from_domain_col;
1696         result_cols[watcher_user_col=n_result_cols++]  =&str_watcher_username_col;
1697         result_cols[watcher_domain_col=n_result_cols++]=&str_watcher_domain_col;
1698         result_cols[callid_col=n_result_cols++]     =&str_callid_col;
1699         result_cols[totag_col=n_result_cols++]      =&str_to_tag_col;
1700         result_cols[fromtag_col=n_result_cols++]    =&str_from_tag_col;
1701         result_cols[local_cseq_col= n_result_cols++]=&str_local_cseq_col;
1702         result_cols[rr_col= n_result_cols++]        =&str_record_route_col;
1703         result_cols[sockinfo_col= n_result_cols++]  =&str_socket_info_col;
1704         result_cols[contact_col= n_result_cols++]   =&str_contact_col;
1705         result_cols[lcontact_col= n_result_cols++]  =&str_local_contact_col;
1706
1707         if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
1708         {
1709                 LM_ERR("sql use table failed\n");
1710                 return;
1711         }
1712
1713         if (pa_dbf.query(pa_db, qcols, qops, qvals, result_cols,
1714                                 1, n_result_cols, 0, &result) < 0) {
1715                 LM_ERR("failed to query database for expired subscriptions\n");
1716                 if(result)
1717                         pa_dbf.free_result(pa_db, result);
1718                 return;
1719         }
1720
1721         if(result== NULL)
1722                 return;
1723
1724         if(result->n <=0 ) {
1725                 pa_dbf.free_result(pa_db, result);
1726                 return;
1727         }
1728         LM_DBG("found %d dialogs\n", result->n);
1729         
1730         for(i=0; i<result->n; i++)
1731         {
1732                 row = &result->rows[i];
1733                 row_vals = ROW_VALUES(row);
1734
1735                 memset(&s, 0, sizeof(subs_t));
1736
1737                 s.pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val;
1738                 s.pres_uri.len = strlen(s.pres_uri.s);
1739
1740                 s.to_user.s= (char*)row_vals[to_user_col].val.string_val;
1741                 s.to_user.len= strlen(s.to_user.s);
1742
1743                 s.to_domain.s= (char*)row_vals[to_domain_col].val.string_val;
1744                 s.to_domain.len= strlen(s.to_domain.s);
1745
1746                 s.from_user.s= (char*)row_vals[from_user_col].val.string_val;
1747                 s.from_user.len= strlen(s.from_user.s);
1748
1749                 s.from_domain.s= (char*)row_vals[from_domain_col].val.string_val;
1750                 s.from_domain.len= strlen(s.from_domain.s);
1751
1752                 s.watcher_user.s= (char*)row_vals[watcher_user_col].val.string_val;
1753                 s.watcher_user.len= strlen(s.watcher_user.s);
1754
1755                 s.watcher_domain.s= (char*)row_vals[watcher_domain_col].val.string_val;
1756                 s.watcher_domain.len= strlen(s.watcher_domain.s);
1757
1758                 s.event_id.s=(char*)row_vals[event_id_col].val.string_val;
1759                 s.event_id.len= (s.event_id.s)?strlen(s.event_id.s):0;
1760
1761                 s.to_tag.s= (char*)row_vals[totag_col].val.string_val;
1762                 s.to_tag.len= strlen(s.to_tag.s);
1763
1764                 s.from_tag.s= (char*)row_vals[fromtag_col].val.string_val; 
1765                 s.from_tag.len= strlen(s.from_tag.s);
1766
1767                 s.callid.s= (char*)row_vals[callid_col].val.string_val;
1768                 s.callid.len= strlen(s.callid.s);
1769
1770                 s.record_route.s=  (char*)row_vals[rr_col].val.string_val;
1771                 s.record_route.len= (s.record_route.s)?strlen(s.record_route.s):0;
1772
1773                 s.contact.s= (char*)row_vals[contact_col].val.string_val;
1774                 s.contact.len= strlen(s.contact.s);
1775
1776                 s.sockinfo_str.s = (char*)row_vals[sockinfo_col].val.string_val;
1777                 s.sockinfo_str.len = s.sockinfo_str.s?strlen(s.sockinfo_str.s):0;
1778
1779                 s.local_contact.s = (char*)row_vals[lcontact_col].val.string_val;
1780                 s.local_contact.len = s.local_contact.s?strlen(s.local_contact.s):0;
1781
1782                 ev_name.s= (char*)row_vals[event_col].val.string_val;
1783                 ev_name.len= strlen(ev_name.s);
1784
1785                 event= contains_event(&ev_name, 0);
1786                 if(event== NULL) {
1787                         LM_ERR("Wrong event in database %.*s\n", ev_name.len, ev_name.s);
1788                         continue;
1789                 }
1790                 s.event= event;
1791
1792                 s.local_cseq = row_vals[local_cseq_col].val.int_val +1;
1793                 s.expires = 0;
1794
1795                 s_new= mem_copy_subs(&s, PKG_MEM_TYPE);
1796                 if(s_new== NULL)
1797                 {
1798                         LM_ERR("while copying subs_t structure\n");
1799                         continue;
1800                 }
1801                 s_new->next= s_array;
1802                 s_array= s_new;
1803                 printf_subs(s_new);
1804         }
1805         pa_dbf.free_result(pa_db, result);
1806
1807         s_new = s_array;
1808         while(s_new) {
1809                 handle_expired_subs(s_new);
1810                 s_del = s_new;
1811                 s_new = s_new->next;
1812                 pkg_free(s_del);
1813         }
1814
1815         /* delete the expired subscriptions */
1816         if(pa_dbf.delete(pa_db, qcols, qops, qvals, 1) < 0)
1817         {
1818                 LM_ERR("deleting expired information from database\n");
1819         }
1820 }
1821
1822 void update_db_subs_timer_dbnone(int no_lock)
1823 {
1824         int i;
1825         int now = (int)time(NULL);
1826         subs_t* s= NULL, *prev_s= NULL, *del_s;
1827
1828         LM_DBG("update_db_subs_timer_dbnone: start\n");
1829
1830         for(i=0; i<shtable_size; i++) {
1831                 if(!no_lock)
1832                         lock_get(&subs_htable[i].lock);
1833
1834                 prev_s= subs_htable[i].entries;
1835                 s= prev_s->next;
1836
1837                 while(s) {
1838                         printf_subs(s);
1839                         if(s->expires < now - expires_offset) {
1840                                 LM_DBG("Found expired record\n");
1841                                 if(!no_lock) {
1842                                         if(handle_expired_subs(s)< 0) {
1843                                                 LM_ERR("in function handle_expired_record\n");
1844                                         }
1845                                 }
1846                                 del_s= s;
1847                                 s= s->next;
1848                                 prev_s->next= s;
1849
1850                                 if (del_s->contact.s)
1851                                         shm_free(del_s->contact.s);
1852                                 shm_free(del_s);
1853                                 continue;
1854                         }
1855                         prev_s= s;
1856                         s= s->next;
1857                 }
1858                 if(!no_lock)
1859                         lock_release(&subs_htable[i].lock);
1860         }
1861 }
1862
1863
1864
1865 void update_db_subs_timer(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
1866         int htable_size, int no_lock, handle_expired_func_t handle_expired_func)
1867 {
1868         db_key_t query_cols[24], update_cols[6];
1869         db_val_t query_vals[24], update_vals[6];
1870         db_op_t update_ops[1];
1871         subs_t* del_s;
1872         int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col,
1873                 callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col,
1874                 local_cseq_col, remote_cseq_col, expires_col, record_route_col,
1875                 contact_col, local_contact_col, version_col,socket_info_col,reason_col,
1876                 watcher_user_col, watcher_domain_col, updated_col, updated_winfo_col;
1877         int u_expires_col, u_local_cseq_col, u_remote_cseq_col, u_version_col,
1878                 u_reason_col, u_status_col;
1879         int i;
1880         subs_t* s= NULL, *prev_s= NULL;
1881         int n_query_cols= 0, n_update_cols= 0;
1882         int n_query_update;
1883         int now = (int)time(NULL);
1884
1885         LM_DBG("update_db_subs_timer: start\n");
1886
1887         query_cols[pres_uri_col= n_query_cols] =&str_presentity_uri_col;
1888         query_vals[pres_uri_col].type = DB1_STR;
1889         query_vals[pres_uri_col].nul = 0;
1890         n_query_cols++;
1891
1892         query_cols[callid_col= n_query_cols] =&str_callid_col;
1893         query_vals[callid_col].type = DB1_STR;
1894         query_vals[callid_col].nul = 0;
1895         n_query_cols++;
1896
1897         query_cols[totag_col= n_query_cols] =&str_to_tag_col;
1898         query_vals[totag_col].type = DB1_STR;
1899         query_vals[totag_col].nul = 0;
1900         n_query_cols++;
1901
1902         query_cols[fromtag_col= n_query_cols] =&str_from_tag_col;
1903         query_vals[fromtag_col].type = DB1_STR;
1904         query_vals[fromtag_col].nul = 0;
1905         n_query_cols++;
1906
1907         n_query_update= n_query_cols;
1908
1909         query_cols[to_user_col= n_query_cols] =&str_to_user_col;
1910         query_vals[to_user_col].type = DB1_STR;
1911         query_vals[to_user_col].nul = 0;
1912         n_query_cols++;
1913
1914         query_cols[to_domain_col= n_query_cols] =&str_to_domain_col;
1915         query_vals[to_domain_col].type = DB1_STR;
1916         query_vals[to_domain_col].nul = 0;
1917         n_query_cols++;
1918
1919         query_cols[from_user_col= n_query_cols] =&str_from_user_col;
1920         query_vals[from_user_col].type = DB1_STR;
1921         query_vals[from_user_col].nul = 0;
1922         n_query_cols++;
1923
1924         query_cols[from_domain_col= n_query_cols] =&str_from_domain_col;
1925         query_vals[from_domain_col].type = DB1_STR;
1926         query_vals[from_domain_col].nul = 0;
1927         n_query_cols++;
1928
1929         query_cols[watcher_user_col= n_query_cols] =&str_watcher_username_col;
1930         query_vals[watcher_user_col].type = DB1_STR;
1931         query_vals[watcher_user_col].nul = 0;
1932         n_query_cols++;
1933
1934         query_cols[watcher_domain_col= n_query_cols] =&str_watcher_domain_col;
1935         query_vals[watcher_domain_col].type = DB1_STR;
1936         query_vals[watcher_domain_col].nul = 0;
1937         n_query_cols++;
1938
1939         query_cols[event_col= n_query_cols] =&str_event_col;
1940         query_vals[event_col].type = DB1_STR;
1941         query_vals[event_col].nul = 0;
1942         n_query_cols++;
1943
1944         query_cols[event_id_col= n_query_cols] =&str_event_id_col;
1945         query_vals[event_id_col].type = DB1_STR;
1946         query_vals[event_id_col].nul = 0;
1947         n_query_cols++;
1948
1949         query_cols[local_cseq_col= n_query_cols]=&str_local_cseq_col;
1950         query_vals[local_cseq_col].type = DB1_INT;
1951         query_vals[local_cseq_col].nul = 0;
1952         n_query_cols++;
1953
1954         query_cols[remote_cseq_col= n_query_cols]=&str_remote_cseq_col;
1955         query_vals[remote_cseq_col].type = DB1_INT;
1956         query_vals[remote_cseq_col].nul = 0;
1957         n_query_cols++;
1958
1959         query_cols[expires_col= n_query_cols] =&str_expires_col;
1960         query_vals[expires_col].type = DB1_INT;
1961         query_vals[expires_col].nul = 0;
1962         n_query_cols++;
1963
1964         query_cols[status_col= n_query_cols] =&str_status_col;
1965         query_vals[status_col].type = DB1_INT;
1966         query_vals[status_col].nul = 0;
1967         n_query_cols++;
1968
1969         query_cols[reason_col= n_query_cols] =&str_reason_col;
1970         query_vals[reason_col].type = DB1_STR;
1971         query_vals[reason_col].nul = 0;
1972         n_query_cols++;
1973
1974         query_cols[record_route_col= n_query_cols] =&str_record_route_col;
1975         query_vals[record_route_col].type = DB1_STR;
1976         query_vals[record_route_col].nul = 0;
1977         n_query_cols++;
1978         
1979         query_cols[contact_col= n_query_cols] =&str_contact_col;
1980         query_vals[contact_col].type = DB1_STR;
1981         query_vals[contact_col].nul = 0;
1982         n_query_cols++;
1983
1984         query_cols[local_contact_col= n_query_cols] =&str_local_contact_col;
1985         query_vals[local_contact_col].type = DB1_STR;
1986         query_vals[local_contact_col].nul = 0;
1987         n_query_cols++;
1988
1989         query_cols[socket_info_col= n_query_cols] =&str_socket_info_col;
1990         query_vals[socket_info_col].type = DB1_STR;
1991         query_vals[socket_info_col].nul = 0;
1992         n_query_cols++;
1993
1994         query_cols[version_col= n_query_cols]=&str_version_col;
1995         query_vals[version_col].type = DB1_INT;
1996         query_vals[version_col].nul = 0;
1997         n_query_cols++;
1998
1999         query_cols[updated_col= n_query_cols]=&str_updated_col;
2000         query_vals[updated_col].type = DB1_INT;
2001         query_vals[updated_col].nul = 0;
2002         n_query_cols++;
2003
2004         query_cols[updated_winfo_col= n_query_cols]=&str_updated_winfo_col;
2005         query_vals[updated_winfo_col].type = DB1_INT;
2006         query_vals[updated_winfo_col].nul = 0;
2007         n_query_cols++;
2008
2009         /* cols and values used for update */
2010         update_cols[u_expires_col= n_update_cols]= &str_expires_col;
2011         update_vals[u_expires_col].type = DB1_INT;
2012         update_vals[u_expires_col].nul = 0;
2013         n_update_cols++;
2014
2015         update_cols[u_status_col= n_update_cols]= &str_status_col;
2016         update_vals[u_status_col].type = DB1_INT;
2017         update_vals[u_status_col].nul = 0;
2018         n_update_cols++;
2019
2020         update_cols[u_reason_col= n_update_cols]= &str_reason_col;
2021         update_vals[u_reason_col].type = DB1_STR;
2022         update_vals[u_reason_col].nul = 0;
2023         n_update_cols++;
2024
2025         update_cols[u_remote_cseq_col= n_update_cols]= &str_remote_cseq_col;
2026         update_vals[u_remote_cseq_col].type = DB1_INT;
2027         update_vals[u_remote_cseq_col].nul = 0;
2028         n_update_cols++;
2029
2030         update_cols[u_local_cseq_col= n_update_cols]= &str_local_cseq_col;
2031         update_vals[u_local_cseq_col].type = DB1_INT;
2032         update_vals[u_local_cseq_col].nul = 0;
2033         n_update_cols++;
2034
2035         update_cols[u_version_col= n_update_cols]= &str_version_col;
2036         update_vals[u_version_col].type = DB1_INT;
2037         update_vals[u_version_col].nul = 0;
2038         n_update_cols++;
2039
2040         for(i=0; i<htable_size; i++) 
2041         {
2042                 if(!no_lock)
2043                         lock_get(&hash_table[i].lock);
2044
2045                 prev_s= hash_table[i].entries;
2046                 s= prev_s->next;
2047
2048                 while(s)
2049                 {
2050                         printf_subs(s);
2051                         if(s->expires < now- expires_offset)
2052                         {
2053                                 LM_DBG("Found expired record\n");
2054                                 if(!no_lock)
2055                                 {
2056                                         if(handle_expired_func(s)< 0)
2057                                                 LM_ERR("in function handle_expired_record\n");
2058                                 }
2059                                 del_s= s;
2060                                 s= s->next;
2061                                 prev_s->next= s;
2062                                 
2063                                 /* need for a struct free/destroy? */
2064                                 if (del_s->contact.s)
2065                                         shm_free(del_s->contact.s);
2066                                 shm_free(del_s);
2067                                 continue;
2068                         }
2069                         switch(s->db_flag)
2070                         {
2071                                 case NO_UPDATEDB_FLAG:
2072                                 case WTHROUGHDB_FLAG:
2073                                         LM_DBG("%s\n", (s->db_flag==NO_UPDATEDB_FLAG)?
2074                                                         "NO_UPDATEDB_FLAG":"WTHROUGHDB_FLAG");
2075                                         break;
2076
2077                                 case UPDATEDB_FLAG:
2078                                         LM_DBG("UPDATEDB_FLAG\n");
2079
2080                                         query_vals[pres_uri_col].val.str_val= s->pres_uri;
2081                                         query_vals[callid_col].val.str_val= s->callid;
2082                                         query_vals[totag_col].val.str_val= s->to_tag;
2083                                         query_vals[fromtag_col].val.str_val= s->from_tag;
2084                                 
2085                                         update_vals[u_expires_col].val.int_val= s->expires;
2086                                         update_vals[u_local_cseq_col].val.int_val= s->local_cseq;
2087                                         update_vals[u_remote_cseq_col].val.int_val= s->remote_cseq;
2088                                         update_vals[u_version_col].val.int_val= s->version;
2089                                         update_vals[u_status_col].val.int_val= s->status;
2090                                         update_vals[u_reason_col].val.str_val= s->reason;
2091
2092                                         if(dbf.update(db, query_cols, 0, query_vals, update_cols, 
2093                                                                 update_vals, n_query_update, n_update_cols)< 0)
2094                                         {
2095                                                 LM_ERR("updating in database\n");
2096                                         } else {
2097                                                 s->db_flag= NO_UPDATEDB_FLAG;
2098                                         }
2099                                         break;
2100
2101                                 case  INSERTDB_FLAG:
2102                                         LM_DBG("INSERTDB_FLAG\n");
2103
2104                                         query_vals[pres_uri_col].val.str_val= s->pres_uri;
2105                                         query_vals[callid_col].val.str_val= s->callid;
2106                                         query_vals[totag_col].val.str_val= s->to_tag;
2107                                         query_vals[fromtag_col].val.str_val= s->from_tag;
2108                                         query_vals[to_user_col].val.str_val = s->to_user;
2109                                         query_vals[to_domain_col].val.str_val = s->to_domain;
2110                                         query_vals[from_user_col].val.str_val = s->from_user;
2111                                         query_vals[from_domain_col].val.str_val = s->from_domain;
2112                                         query_vals[watcher_user_col].val.str_val = s->watcher_user;
2113                                         query_vals[watcher_domain_col].val.str_val = s->watcher_domain;
2114                                         query_vals[event_col].val.str_val = s->event->name;
2115                                         query_vals[event_id_col].val.str_val = s->event_id;
2116                                         query_vals[local_cseq_col].val.int_val= s->local_cseq;
2117                                         query_vals[remote_cseq_col].val.int_val= s->remote_cseq;
2118                                         query_vals[expires_col].val.int_val = s->expires;
2119                                         query_vals[record_route_col].val.str_val = s->record_route;
2120                                         query_vals[contact_col].val.str_val = s->contact;
2121                                         query_vals[local_contact_col].val.str_val = s->local_contact;
2122                                         query_vals[version_col].val.int_val= s->version;
2123                                         query_vals[status_col].val.int_val= s->status;
2124                                         query_vals[reason_col].val.str_val= s->reason;
2125                                         query_vals[socket_info_col].val.str_val= s->sockinfo_str;
2126                                         query_vals[updated_col].val.int_val = -1;
2127                                         query_vals[updated_winfo_col].val.int_val = -1;
2128
2129                                         if(dbf.insert(db,query_cols,query_vals,n_query_cols )<0)
2130                                         {
2131                                                 LM_ERR("unsuccessful sql insert\n");
2132                                         } else {
2133                                                 s->db_flag= NO_UPDATEDB_FLAG;
2134                                         }
2135                                         break;
2136                         } /* switch */
2137                         prev_s= s;
2138                         s= s->next;
2139                 }
2140                 if(!no_lock)
2141                         lock_release(&hash_table[i].lock);
2142         }
2143
2144         update_vals[0].val.int_val= (int)time(NULL) - expires_offset;
2145         update_ops[0]= OP_LT;
2146         if(dbf.delete(db, update_cols, update_ops, update_vals, 1) < 0)
2147         {
2148                 LM_ERR("deleting expired information from database\n");
2149         }
2150 }
2151
2152 /**
2153  * timer_db_update function does the following tasks:
2154  *      1. checks for expires subscriptions and does the corresponding processing
2155  *              - if db_mode != DB_ONLY : checks by traversing the hash table
2156  *              - if db_mode == DB_ONLY : checks by querying database
2157  *      2. if db_mode == WRITE_BACK : updates the subscriptions in database
2158 */
2159 void timer_db_update(unsigned int ticks,void *param)
2160 {
2161         int no_lock=0;
2162         LM_DBG("db_update timer\n");
2163         if(ticks== 0 && param == NULL)
2164                 no_lock= 1;
2165
2166
2167         switch (subs_dbmode) {
2168         case DB_ONLY:
2169                 if (pres_notifier_processes > 0)
2170                         update_db_subs_timer_notifier();
2171                 else
2172                         update_db_subs_timer_dbonly();
2173         break;
2174         case NO_DB:
2175                 update_db_subs_timer_dbnone(no_lock);
2176         break;
2177         default:
2178                 if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
2179                 {
2180                         LM_ERR("sql use table failed\n");
2181                         return;
2182                 }
2183                 update_db_subs_timer(pa_db, pa_dbf, subs_htable, shtable_size,
2184                                                 no_lock, handle_expired_subs);
2185         }
2186 }
2187
2188
2189 int restore_db_subs(void)
2190 {
2191         db_key_t result_cols[22]; 
2192         db1_res_t *result= NULL;
2193         db_row_t *rows = NULL;  
2194         db_val_t *row_vals= NULL;
2195         int i;
2196         int n_result_cols= 0;
2197         int pres_uri_col, expires_col, from_user_col, from_domain_col,to_user_col; 
2198         int callid_col,totag_col,fromtag_col,to_domain_col,sockinfo_col,reason_col;
2199         int event_col,contact_col,record_route_col, event_id_col, status_col;
2200         int remote_cseq_col, local_cseq_col, local_contact_col, version_col;
2201         int watcher_user_col, watcher_domain_col;
2202         subs_t s;
2203         str ev_sname;
2204         pres_ev_t* event= NULL;
2205         event_t parsed_event;
2206         unsigned int expires;
2207         unsigned int hash_code;
2208         int nr_rows;
2209
2210         result_cols[pres_uri_col=n_result_cols++]       =&str_presentity_uri_col;
2211         result_cols[expires_col=n_result_cols++]        =&str_expires_col;
2212         result_cols[event_col=n_result_cols++]          =&str_event_col;
2213         result_cols[event_id_col=n_result_cols++]       =&str_event_id_col;
2214         result_cols[to_user_col=n_result_cols++]        =&str_to_user_col;
2215         result_cols[to_domain_col=n_result_cols++]      =&str_to_domain_col;
2216         result_cols[from_user_col=n_result_cols++]      =&str_from_user_col;
2217         result_cols[from_domain_col=n_result_cols++]    =&str_from_domain_col;
2218         result_cols[watcher_user_col=n_result_cols++]   =&str_watcher_username_col;
2219         result_cols[watcher_domain_col=n_result_cols++] =&str_watcher_domain_col;
2220         result_cols[callid_col=n_result_cols++]         =&str_callid_col;
2221         result_cols[totag_col=n_result_cols++]          =&str_to_tag_col;
2222         result_cols[fromtag_col=n_result_cols++]        =&str_from_tag_col;
2223         result_cols[local_cseq_col= n_result_cols++]    =&str_local_cseq_col;
2224         result_cols[remote_cseq_col= n_result_cols++]   =&str_remote_cseq_col;
2225         result_cols[record_route_col= n_result_cols++]  =&str_record_route_col;
2226         result_cols[sockinfo_col= n_result_cols++]      =&str_socket_info_col;
2227         result_cols[contact_col= n_result_cols++]       =&str_contact_col;
2228         result_cols[local_contact_col= n_result_cols++] =&str_local_contact_col;
2229         result_cols[version_col= n_result_cols++]       =&str_version_col;
2230         result_cols[status_col= n_result_cols++]        =&str_status_col;
2231         result_cols[reason_col= n_result_cols++]        =&str_reason_col;
2232         
2233         if(!pa_db)
2234         {
2235                 LM_ERR("null database connection\n");
2236                 return -1;
2237         }
2238
2239         if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
2240         {
2241                 LM_ERR("in use table\n");
2242                 return -1;
2243         }
2244
2245         /* select the whole table and all the columns */
2246         if (db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, 0, 0, 0, result_cols,
2247                                 0, n_result_cols, 0, &result) < 0)
2248         {
2249                 LM_ERR("querying presentity\n");
2250                 goto error;
2251         }
2252
2253         if (result == NULL)
2254         {
2255                 LM_ERR("bad result\n");
2256                 goto error;
2257         }
2258
2259         do {
2260                 nr_rows = RES_ROW_N(result);
2261                 LM_DBG("loading information from database %i records\n", nr_rows);
2262
2263                 rows = RES_ROWS(result);
2264
2265                 /* for every row */
2266                 for(i=0; i<nr_rows; i++)
2267                 {
2268
2269                         row_vals = ROW_VALUES(rows +i);
2270                         memset(&s, 0, sizeof(subs_t));
2271
2272                         expires= row_vals[expires_col].val.int_val;
2273                 
2274                         if(expires< (int)time(NULL))
2275                             continue;
2276         
2277                         s.pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val;
2278                         s.pres_uri.len= strlen(s.pres_uri.s);
2279                 
2280                         s.to_user.s=(char*)row_vals[to_user_col].val.string_val;
2281                         s.to_user.len= strlen(s.to_user.s);
2282                         
2283                         s.to_domain.s=(char*)row_vals[to_domain_col].val.string_val;
2284                         s.to_domain.len= strlen(s.to_domain.s);
2285                         
2286                         s.from_user.s=(char*)row_vals[from_user_col].val.string_val;
2287                         s.from_user.len= strlen(s.from_user.s);
2288                         
2289                         s.from_domain.s=(char*)row_vals[from_domain_col].val.string_val;
2290                         s.from_domain.len= strlen(s.from_domain.s);
2291
2292                         s.watcher_user.s=(char*)row_vals[watcher_user_col].val.string_val;
2293                         s.watcher_user.len= strlen(s.watcher_user.s);
2294                         
2295                         s.watcher_domain.s=(char*)row_vals[watcher_domain_col].val.string_val;
2296                         s.watcher_domain.len= strlen(s.watcher_domain.s);
2297                         
2298                         s.to_tag.s=(char*)row_vals[totag_col].val.string_val;
2299                         s.to_tag.len= strlen(s.to_tag.s);
2300
2301                         s.from_tag.s=(char*)row_vals[fromtag_col].val.string_val;
2302                         s.from_tag.len= strlen(s.from_tag.s);
2303
2304                         s.callid.s=(char*)row_vals[callid_col].val.string_val;
2305                         s.callid.len= strlen(s.callid.s);
2306
2307                         ev_sname.s= (char*)row_vals[event_col].val.string_val;
2308                         ev_sname.len= strlen(ev_sname.s);
2309                 
2310                         event= contains_event(&ev_sname, &parsed_event);
2311                         if(event== NULL)
2312                             {
2313                                 LM_DBG("insert a new event structure in the list waiting"
2314                                        " to be filled in\n");
2315                                 
2316                                 /*insert a new event structure in the list waiting to be filled in*/
2317                                 event= (pres_ev_t*)shm_malloc(sizeof(pres_ev_t));
2318                                 if(event== NULL)
2319                                     {
2320                                         free_event_params(parsed_event.params.list, PKG_MEM_TYPE);
2321                                         ERR_MEM(SHM_MEM_STR);
2322                                     }
2323                                 memset(event, 0, sizeof(pres_ev_t));
2324                                 event->name.s= (char*)shm_malloc(ev_sname.len* sizeof(char));
2325                                 if(event->name.s== NULL)
2326                                     {
2327                                         free_event_params(parsed_event.params.list, PKG_MEM_TYPE);
2328                                         ERR_MEM(SHM_MEM_STR);
2329                                     }
2330                                 memcpy(event->name.s,ev_sname.s, ev_sname.len);
2331                                 event->name.len= ev_sname.len;
2332                                 
2333                                 event->evp= shm_copy_event(&parsed_event);
2334                                 if(event->evp== NULL)
2335                                     {
2336                                         LM_ERR("ERROR copying event_t structure\n");
2337                                         free_event_params(parsed_event.params.list, PKG_MEM_TYPE);
2338                                         goto error;
2339                                     }
2340                                 event->next= EvList->events;
2341                                 EvList->events= event;
2342                             }
2343                         
2344                         free_event_params(parsed_event.params.list, PKG_MEM_TYPE);
2345                         
2346                         s.event= event;
2347
2348                         s.event_id.s=(char*)row_vals[event_id_col].val.string_val;
2349                         if(s.event_id.s)
2350                             s.event_id.len= strlen(s.event_id.s);
2351                         
2352                         s.remote_cseq= row_vals[remote_cseq_col].val.int_val;
2353                         s.local_cseq= row_vals[local_cseq_col].val.int_val;
2354                         s.version= row_vals[version_col].val.int_val;
2355                 
2356                         s.expires= expires- (int)time(NULL);
2357                         s.status= row_vals[status_col].val.int_val;
2358
2359                         s.reason.s= (char*)row_vals[reason_col].val.string_val;
2360                         if(s.reason.s)
2361                             s.reason.len= strlen(s.reason.s);
2362
2363                         s.contact.s=(char*)row_vals[contact_col].val.string_val;
2364                         s.contact.len= strlen(s.contact.s);
2365                         
2366                         s.local_contact.s=(char*)row_vals[local_contact_col].val.string_val;
2367                         s.local_contact.len= strlen(s.local_contact.s);
2368                         
2369                         s.record_route.s=(char*)row_vals[record_route_col].val.string_val;
2370                         if(s.record_route.s)
2371                             s.record_route.len= strlen(s.record_route.s);
2372         
2373                         s.sockinfo_str.s=(char*)row_vals[sockinfo_col].val.string_val;
2374                         s.sockinfo_str.len= strlen(s.sockinfo_str.s);
2375                         s.db_flag = (subs_dbmode==WRITE_THROUGH)?WTHROUGHDB_FLAG:NO_UPDATEDB_FLAG;
2376                         hash_code= core_hash(&s.pres_uri, &s.event->name, shtable_size);
2377                         if(insert_shtable(subs_htable, hash_code, &s)< 0)
2378                         {
2379                                 LM_ERR("adding new record in hash table\n");
2380                                 goto error;
2381                         }
2382                 }
2383
2384         } while((db_fetch_next(&pa_dbf, pres_fetch_rows, pa_db, &result)==1)
2385                         && (RES_ROW_N(result)>0));
2386
2387         pa_dbf.free_result(pa_db, result);
2388
2389         /* delete all records  only if in memory mode */
2390         if(subs_dbmode == NO_DB) {
2391                 if(pa_dbf.delete(pa_db, 0,0,0,0)< 0)
2392                 {
2393                         LM_ERR("deleting all records from database table\n");
2394                         return -1;
2395                 }
2396         }
2397         return 0;
2398
2399 error:
2400         if(result)
2401                 pa_dbf.free_result(pa_db, result);
2402         return -1;
2403
2404 }
2405
2406 int get_db_subs_auth(subs_t* subs, int* found)
2407 {
2408         db_key_t db_keys[5];
2409         db_val_t db_vals[5];
2410         int n_query_cols= 0; 
2411         db_key_t result_cols[3];
2412         db1_res_t *result = NULL;
2413         db_row_t *row ; 
2414         db_val_t *row_vals ;
2415
2416         db_keys[n_query_cols] =&str_presentity_uri_col;
2417         db_vals[n_query_cols].type = DB1_STR;
2418         db_vals[n_query_cols].nul = 0;
2419         db_vals[n_query_cols].val.str_val= subs->pres_uri;
2420         n_query_cols++;
2421
2422         db_keys[n_query_cols] =&str_watcher_username_col;
2423         db_vals[n_query_cols].type = DB1_STR;
2424         db_vals[n_query_cols].nul = 0;
2425         db_vals[n_query_cols].val.str_val = subs->watcher_user;
2426         n_query_cols++;
2427
2428         db_keys[n_query_cols] =&str_watcher_domain_col;
2429         db_vals[n_query_cols].type = DB1_STR;
2430         db_vals[n_query_cols].nul = 0;
2431         db_vals[n_query_cols].val.str_val = subs->watcher_domain;
2432         n_query_cols++;
2433         
2434         db_keys[n_query_cols] =&str_event_col;
2435         db_vals[n_query_cols].type = DB1_STR;
2436         db_vals[n_query_cols].nul = 0;
2437         db_vals[n_query_cols].val.str_val = subs->event->name;
2438         n_query_cols++;
2439
2440         result_cols[0] = &str_status_col;
2441         result_cols[1] = &str_reason_col;
2442         
2443         if(pa_dbf.use_table(pa_db, &watchers_table)< 0)
2444         {
2445                 LM_ERR("in use table\n");
2446                 return -1;
2447         }       
2448
2449         if(pa_dbf.query(pa_db, db_keys, 0, db_vals, result_cols,
2450                                         n_query_cols, 2, 0, &result )< 0)
2451         {
2452                 LM_ERR("while querying watchers table\n");
2453                 if(result)
2454                         pa_dbf.free_result(pa_db, result);
2455                 return -1;
2456         }
2457         if(result== NULL)
2458                 return -1;
2459         
2460         if(result->n<= 0)
2461         {
2462                 *found= 0;
2463                 pa_dbf.free_result(pa_db, result);
2464                 return 0;
2465         }
2466
2467         *found= 1;
2468         row = &result->rows[0];
2469         row_vals = ROW_VALUES(row);
2470         subs->status= row_vals[0].val.int_val;
2471
2472         if(row_vals[1].val.string_val)
2473         {
2474
2475                 subs->reason.len= strlen(row_vals[1].val.string_val);
2476                 if(subs->reason.len== 0)
2477                         subs->reason.s= NULL;
2478                 else
2479                 {
2480                         subs->reason.s= (char*)pkg_malloc(subs->reason.len*sizeof(char));
2481                         if(subs->reason.s== NULL)
2482                         {
2483                                 pa_dbf.free_result(pa_db, result);
2484                                 ERR_MEM(PKG_MEM_STR);
2485                         }               
2486                         memcpy(subs->reason.s, row_vals[1].val.string_val, subs->reason.len);
2487                 }
2488         }
2489         
2490         pa_dbf.free_result(pa_db, result);
2491         return 0;
2492 error:
2493         return -1;
2494 }       
2495
2496 int insert_db_subs_auth(subs_t* subs)
2497 {
2498         db_key_t db_keys[10];
2499         db_val_t db_vals[10];
2500         int n_query_cols= 0; 
2501
2502         db_keys[n_query_cols] =&str_presentity_uri_col;
2503         db_vals[n_query_cols].type = DB1_STR;
2504         db_vals[n_query_cols].nul = 0;
2505         db_vals[n_query_cols].val.str_val= subs->pres_uri;
2506         n_query_cols++;
2507
2508         db_keys[n_query_cols] =&str_watcher_username_col;
2509         db_vals[n_query_cols].type = DB1_STR;
2510         db_vals[n_query_cols].nul = 0;
2511         db_vals[n_query_cols].val.str_val = subs->watcher_user;
2512         n_query_cols++;
2513
2514         db_keys[n_query_cols] =&str_watcher_domain_col;
2515         db_vals[n_query_cols].type = DB1_STR;
2516         db_vals[n_query_cols].nul = 0;
2517         db_vals[n_query_cols].val.str_val = subs->watcher_domain;
2518         n_query_cols++;
2519         
2520         db_keys[n_query_cols] =&str_event_col;
2521         db_vals[n_query_cols].type = DB1_STR;
2522         db_vals[n_query_cols].nul = 0;
2523         db_vals[n_query_cols].val.str_val = subs->event->name;
2524         n_query_cols++;
2525
2526         db_keys[n_query_cols] =&str_status_col;
2527         db_vals[n_query_cols].type = DB1_INT;
2528         db_vals[n_query_cols].nul = 0;
2529         db_vals[n_query_cols].val.int_val = subs->status;
2530         n_query_cols++;
2531                                                                 
2532         db_keys[n_query_cols] = &str_inserted_time_col;
2533         db_vals[n_query_cols].type = DB1_INT;
2534         db_vals[n_query_cols].nul = 0;
2535         db_vals[n_query_cols].val.int_val= (int)time(NULL);
2536         n_query_cols++;
2537
2538         db_keys[n_query_cols] =&str_reason_col;
2539         db_vals[n_query_cols].type = DB1_STR;
2540         db_vals[n_query_cols].nul = 0;
2541         if(subs->reason.s && subs->reason.len)
2542                 db_vals[n_query_cols].val.str_val = subs->reason;
2543         else
2544         {
2545                 db_vals[n_query_cols].val.str_val.s = ""; 
2546                 db_vals[n_query_cols].val.str_val.len = 0; 
2547         }
2548         n_query_cols++; 
2549         
2550         if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
2551         {
2552                 LM_ERR("in use_table\n");
2553                 return -1;
2554         }
2555
2556         if (pa_dbf.replace != NULL)
2557         {
2558                 if(pa_dbf.replace(pa_db, db_keys, db_vals, n_query_cols,
2559                                         2, 0) < 0)
2560                 {
2561                         LM_ERR("in sql replace\n");
2562                         return -1;
2563                 }
2564         }
2565         else
2566         {
2567                 /* If you use insert() instead of replace() be prepared for some
2568                    DB error messages.  There is a lot of time between the 
2569                    query() that indicated there was no matching entry in the DB
2570                    and this insert(), so on a multi-user system it is entirely
2571                    possible (even likely) that a record will be added after the
2572                    query() but before this insert(). */
2573                 if(pa_dbf.insert(pa_db, db_keys, db_vals, n_query_cols )< 0)
2574                 {       
2575                         LM_ERR("in sql insert\n");
2576                         return -1;
2577                 }
2578         }
2579
2580         return 0;
2581 }