dd9b43f3ea20c55c8227df4ae5d23eb31a47ba6d
[sip-router] / src / modules / presence / presence.c
1 /*
2  * Copyright (C) 2006 Voice Sistem S.R.L.
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 /*!
23  * \defgroup presence Presence :: A generic implementation of the SIP event package (PUBLISH, SUBSCRIBE, NOTIFY)
24  * The Kamailio presence module is a generic module for SIP event packages, which is much more than presence.
25  * It is extensible by developing other modules that use the internal developer API.
26  * Examples:
27  *- \ref presence_mwi
28  *- \ref presence_xml
29  */
30
31 /*!
32  * \file
33  * \brief Kamailio presence module :: Core
34  * \ingroup presence
35  */
36
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <sys/types.h>
42 #include <sys/ipc.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #include <time.h>
46
47 #include "../../lib/srdb1/db.h"
48 #include "../../core/sr_module.h"
49 #include "../../core/dprint.h"
50 #include "../../core/error.h"
51 #include "../../core/ut.h"
52 #include "../../core/parser/parse_to.h"
53 #include "../../core/parser/parse_uri.h"
54 #include "../../core/parser/parse_content.h"
55 #include "../../core/parser/parse_from.h"
56 #include "../../core/mem/mem.h"
57 #include "../../core/mem/shm_mem.h"
58 #include "../../core/usr_avp.h"
59 #include "../../core/rand/kam_rand.h"
60 #include "../../modules/tm/tm_load.h"
61 #include "../../modules/sl/sl.h"
62 #include "../../core/pt.h"
63 #include "../../core/hashes.h"
64 #include "../pua/hash.h"
65 #include "presence.h"
66 #include "publish.h"
67 #include "subscribe.h"
68 #include "event_list.h"
69 #include "bind_presence.h"
70 #include "notify.h"
71 #include "presence_dmq.h"
72 #include "../../core/mod_fix.h"
73 #include "../../core/kemi.h"
74 #include "../../core/timer_proc.h"
75 #include "../../core/rpc.h"
76 #include "../../core/rpc_lookup.h"
77
78 MODULE_VERSION
79
80 #define S_TABLE_VERSION 3
81 #define P_TABLE_VERSION 5
82 #define ACTWATCH_TABLE_VERSION 12
83
84 static int pres_clean_period = 100;
85 static int pres_db_update_period = 100;
86 int pres_local_log_level = L_INFO;
87
88 static char *pres_log_facility_str =
89                 0; /*!< Syslog: log facility that is used */
90 int pres_local_log_facility;
91
92 /* database connection */
93 db1_con_t *pa_db = NULL;
94 db_func_t pa_dbf;
95 str presentity_table = str_init("presentity");
96 str active_watchers_table = str_init("active_watchers");
97 str watchers_table = str_init("watchers");
98
99 int pres_fetch_rows = 500;
100 static int pres_library_mode = 0;
101 str pres_server_address = {0, 0};
102 evlist_t *pres_evlist = NULL;
103 int pres_subs_remove_match = 0;
104 int _pres_subs_mode = 1;
105 static int pres_timer_mode = 1;
106
107 int pres_uri_match = 0;
108 /* sip uri match function pointer */
109 sip_uri_match_f presence_sip_uri_match;
110 static int sip_uri_case_sensitive_match(str *s1, str *s2);
111 static int sip_uri_case_insensitive_match(str *s1, str *s2);
112
113 /* TM bind */
114 struct tm_binds tmb;
115 /* SL API structure */
116 sl_api_t slb;
117
118 /** module functions */
119
120 static int mod_init(void);
121 static int child_init(int);
122 static void destroy(void);
123 int stored_pres_info(struct sip_msg *msg, char *pres_uri, char *s);
124 static int fixup_presence(void **param, int param_no);
125 static int fixup_subscribe(void **param, int param_no);
126 static int update_pw_dialogs(
127                 subs_t *subs, unsigned int hash_code, subs_t **subs_array);
128 static int w_pres_auth_status(struct sip_msg *_msg, char *_sp1, char *_sp2);
129 static int w_pres_refresh_watchers(
130                 struct sip_msg *msg, char *puri, char *pevent, char *ptype);
131 static int w_pres_refresh_watchers5(struct sip_msg *msg, char *puri,
132                 char *pevent, char *ptype, char *furi, char *fname);
133 static int w_pres_update_watchers(
134                 struct sip_msg *msg, char *puri, char *pevent);
135 static int fixup_refresh_watchers(void **param, int param_no);
136 static int fixup_update_watchers(void **param, int param_no);
137 static int presence_init_rpc(void);
138
139 static int w_pres_has_subscribers(struct sip_msg *_msg, char *_sp1, char *_sp2);
140 static int fixup_has_subscribers(void **param, int param_no);
141
142 int pres_counter = 0;
143 int pres_pid = 0;
144 char pres_prefix = 'a';
145 int pres_startup_time = 0;
146 str pres_db_url = {0, 0};
147 int pres_expires_offset = 0;
148 int pres_cseq_offset = 0;
149 uint32_t pres_min_expires = 0;
150 int pres_min_expires_action = 1;
151 uint32_t pres_max_expires = 3600;
152 int shtable_size = 9;
153 shtable_t subs_htable = NULL;
154 int pres_subs_dbmode = WRITE_BACK;
155 int pres_sphere_enable = 0;
156 int pres_timeout_rm_subs = 1;
157 int pres_send_fast_notify = 1;
158 int publ_cache_mode = PS_PCACHE_HYBRID;
159 int pres_waitn_time = 5;
160 int pres_notifier_poll_rate = 10;
161 int pres_notifier_processes = 1;
162 int pres_force_delete = 0;
163 int pres_startup_mode = 1;
164 str pres_xavp_cfg = {0};
165 int pres_retrieve_order = 0;
166 str pres_retrieve_order_by = str_init("priority");
167 int pres_enable_dmq = 0;
168 int pres_delete_same_subs = 0;
169
170 int pres_db_table_lock_type = 1;
171 db_locking_t pres_db_table_lock = DB_LOCKING_WRITE;
172
173 int *pres_notifier_id = NULL;
174
175 int phtable_size = 9;
176 phtable_t *pres_htable = NULL;
177
178 sruid_t pres_sruid;
179
180 /* clang-format off */
181 static cmd_export_t cmds[]=
182 {
183         {"handle_publish",        (cmd_function)w_handle_publish,        0,
184                 fixup_presence, 0, REQUEST_ROUTE},
185         {"handle_publish",        (cmd_function)w_handle_publish,        1,
186                 fixup_presence, 0, REQUEST_ROUTE},
187         {"handle_subscribe",      (cmd_function)handle_subscribe0,       0,
188                 fixup_subscribe, 0, REQUEST_ROUTE},
189         {"handle_subscribe",      (cmd_function)w_handle_subscribe,      1,
190                 fixup_subscribe, 0, REQUEST_ROUTE},
191         {"pres_auth_status",      (cmd_function)w_pres_auth_status,      2,
192                 fixup_spve_spve, fixup_free_spve_spve, REQUEST_ROUTE},
193         {"pres_refresh_watchers", (cmd_function)w_pres_refresh_watchers, 3,
194                 fixup_refresh_watchers, 0, ANY_ROUTE},
195         {"pres_refresh_watchers", (cmd_function)w_pres_refresh_watchers5,5,
196                 fixup_refresh_watchers, 0, ANY_ROUTE},
197         {"pres_update_watchers",  (cmd_function)w_pres_update_watchers,  2,
198                 fixup_update_watchers, 0, ANY_ROUTE},
199         {"pres_has_subscribers",  (cmd_function)w_pres_has_subscribers,  2,
200                 fixup_has_subscribers, 0, ANY_ROUTE},
201         {"bind_presence",         (cmd_function)bind_presence,           1,
202                 0, 0, 0},
203         { 0, 0, 0, 0, 0, 0}
204 };
205 /* clang-format on */
206
207 /* clang-format off */
208 static param_export_t params[]={
209         { "db_url",                 PARAM_STR, &pres_db_url},
210         { "presentity_table",       PARAM_STR, &presentity_table},
211         { "active_watchers_table",  PARAM_STR, &active_watchers_table},
212         { "watchers_table",         PARAM_STR, &watchers_table},
213         { "clean_period",           INT_PARAM, &pres_clean_period },
214         { "db_update_period",       INT_PARAM, &pres_db_update_period },
215         { "waitn_time",             INT_PARAM, &pres_waitn_time },
216         { "notifier_poll_rate",     INT_PARAM, &pres_notifier_poll_rate },
217         { "notifier_processes",     INT_PARAM, &pres_notifier_processes },
218         { "force_delete",           INT_PARAM, &pres_force_delete },
219         { "startup_mode",           INT_PARAM, &pres_startup_mode },
220         { "expires_offset",         INT_PARAM, &pres_expires_offset },
221         { "max_expires",            INT_PARAM, &pres_max_expires },
222         { "min_expires",            INT_PARAM, &pres_min_expires },
223         { "min_expires_action",     INT_PARAM, &pres_min_expires_action },
224         { "server_address",         PARAM_STR, &pres_server_address},
225         { "subs_htable_size",       INT_PARAM, &shtable_size},
226         { "pres_htable_size",       INT_PARAM, &phtable_size},
227         { "subs_db_mode",           INT_PARAM, &pres_subs_dbmode},
228         { "publ_cache",             INT_PARAM, &publ_cache_mode},
229         { "enable_sphere_check",    INT_PARAM, &pres_sphere_enable},
230         { "timeout_rm_subs",        INT_PARAM, &pres_timeout_rm_subs},
231         { "send_fast_notify",       INT_PARAM, &pres_send_fast_notify},
232         { "fetch_rows",             INT_PARAM, &pres_fetch_rows},
233         { "db_table_lock_type",     INT_PARAM, &pres_db_table_lock_type},
234         { "local_log_level",        PARAM_INT, &pres_local_log_level},
235         { "local_log_facility",     PARAM_STR, &pres_log_facility_str},
236         { "subs_remove_match",      PARAM_INT, &pres_subs_remove_match},
237         { "xavp_cfg",               PARAM_STR, &pres_xavp_cfg},
238         { "retrieve_order",         PARAM_INT, &pres_retrieve_order},
239         { "retrieve_order_by",      PARAM_STR, &pres_retrieve_order_by},
240         { "sip_uri_match",          PARAM_INT, &pres_uri_match},
241         { "cseq_offset",            PARAM_INT, &pres_cseq_offset},
242         { "enable_dmq",             PARAM_INT, &pres_enable_dmq},
243         { "pres_subs_mode",         PARAM_INT, &_pres_subs_mode},
244         { "delete_same_subs",       PARAM_INT, &pres_delete_same_subs},
245         { "timer_mode",             PARAM_INT, &pres_timer_mode},
246
247         {0,0,0}
248 };
249 /* clang-format on */
250
251 /* clang-format off */
252 static pv_export_t pres_mod_pvs[] = {
253         { {"subs", (sizeof("subs")-1)}, PVT_OTHER,
254                 pv_get_subscription, 0, pv_parse_subscription_name, 0, 0, 0},
255         { {"notify_reply", (sizeof("notify_reply")-1)}, PVT_OTHER,
256                 pv_get_notify_reply, 0, pv_parse_notify_reply_var_name, 0, 0, 0},
257         { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
258 };
259 /* clang-format on */
260
261 /** module exports */
262 /* clang-format off */
263 struct module_exports exports= {
264         "presence",                     /* module name */
265         DEFAULT_DLFLAGS,        /* dlopen flags */
266         cmds,                           /* exported functions */
267         params,                         /* exported parameters */
268         0,                                      /* RPC method exports */
269         pres_mod_pvs,           /* exported pseudo-variables */
270         0,                                      /* response handling function */
271         mod_init,                       /* module initialization function */
272         child_init,                     /* per-child init function */
273         destroy                         /* module destroy function */
274 };
275 /* clang-format on */
276
277 /**
278  * init module function
279  */
280 static int mod_init(void)
281 {
282         if(pres_uri_match == 1) {
283                 presence_sip_uri_match = sip_uri_case_insensitive_match;
284         } else {
285                 presence_sip_uri_match = sip_uri_case_sensitive_match;
286         }
287
288         if(presence_init_rpc() != 0) {
289                 LM_ERR("failed to register RPC commands\n");
290                 return -1;
291         }
292
293         LM_DBG("db_url=%s (len=%d addr=%p)\n", ZSW(pres_db_url.s), pres_db_url.len,
294                         pres_db_url.s);
295
296         if(pres_db_url.s == NULL || pres_db_url.len == 0) {
297                 if(publ_cache_mode != PS_PCACHE_RECORD) {
298                         LM_DBG("db url is not set - switch to library mode\n");
299                         pres_library_mode = 1;
300                 }
301         }
302
303         pres_evlist = init_evlist();
304         if(!pres_evlist) {
305                 LM_ERR("unsuccessful initialize event list\n");
306                 return -1;
307         }
308
309         if(pres_library_mode == 1) {
310                 LM_DBG("Presence module used for API library purpose only\n");
311                 return 0;
312         }
313
314         if(sruid_init(&pres_sruid, '-', "pres", SRUID_INC) < 0) {
315                 return -1;
316         }
317
318         if(pres_expires_offset < 0) {
319                 pres_expires_offset = 0;
320         }
321
322         if(pres_max_expires <= 0) {
323                 pres_max_expires = 3600;
324         }
325
326         if(pres_min_expires > pres_max_expires) {
327                 pres_min_expires = pres_max_expires;
328         }
329
330         if(pres_min_expires_action < 1 || pres_min_expires_action > 2) {
331                 LM_ERR("min_expires_action must be 1 = RFC 6665/3261 Reply 423, 2 = "
332                            "force min_expires value\n");
333                 return -1;
334         }
335
336         if(pres_server_address.s == NULL || pres_server_address.len==0) {
337                 LM_DBG("server_address parameter not set in configuration file\n");
338         }
339
340         /* bind the SL API */
341         if(sl_load_api(&slb) != 0) {
342                 LM_ERR("cannot bind to SL API\n");
343                 return -1;
344         }
345
346         /* load all TM stuff */
347         if(load_tm_api(&tmb) == -1) {
348                 LM_ERR("Can't load tm functions. Module TM not loaded?\n");
349                 return -1;
350         }
351
352         if(publ_cache_mode==PS_PCACHE_HYBRID || publ_cache_mode==PS_PCACHE_RECORD) {
353                 if(phtable_size < 1)
354                         phtable_size = 256;
355                 else
356                         phtable_size = 1 << phtable_size;
357         }
358
359         if(publ_cache_mode==PS_PCACHE_RECORD) {
360                 if(ps_ptable_init(phtable_size) < 0) {
361                         return -1;
362                 }
363         }
364
365         if(publ_cache_mode != PS_PCACHE_RECORD || pres_subs_dbmode != NO_DB) {
366                 if(pres_db_url.s == NULL) {
367                         LM_ERR("database url not set!\n");
368                         return -1;
369                 }
370
371                 /* binding to database module  */
372                 if(db_bind_mod(&pres_db_url, &pa_dbf)) {
373                         LM_ERR("Database module not found\n");
374                         return -1;
375                 }
376
377                 if(!DB_CAPABILITY(pa_dbf, DB_CAP_ALL)) {
378                         LM_ERR("Database module does not implement all functions"
379                                    " needed by presence module\n");
380                         return -1;
381                 }
382
383                 pa_db = pa_dbf.init(&pres_db_url);
384                 if(!pa_db) {
385                         LM_ERR("Connection to database failed\n");
386                         return -1;
387                 }
388
389                 /*verify table versions */
390                 if((db_check_table_version(
391                                         &pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION)
392                                    < 0)
393                                 || (db_check_table_version(
394                                                         &pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION)
395                                                    < 0)) {
396                         DB_TABLE_VERSION_ERROR(presentity_table);
397                         goto dberror;
398                 }
399
400                 if(pres_subs_dbmode != NO_DB
401                                 && db_check_table_version(&pa_dbf, pa_db, &active_watchers_table,
402                                                    ACTWATCH_TABLE_VERSION)
403                                                    < 0) {
404                         DB_TABLE_VERSION_ERROR(active_watchers_table);
405                         goto dberror;
406                 }
407
408                 if(pres_subs_dbmode != DB_ONLY) {
409                         if(shtable_size < 1)
410                                 shtable_size = 512;
411                         else
412                                 shtable_size = 1 << shtable_size;
413
414                         subs_htable = new_shtable(shtable_size);
415                         if(subs_htable == NULL) {
416                                 LM_ERR(" initializing subscribe hash table\n");
417                                 goto dberror;
418                         }
419                         if(restore_db_subs() < 0) {
420                                 LM_ERR("restoring subscribe info from database\n");
421                                 goto dberror;
422                         }
423                 }
424
425                 if(publ_cache_mode==PS_PCACHE_HYBRID) {
426                         pres_htable = new_phtable();
427                         if(pres_htable == NULL) {
428                                 LM_ERR("initializing presentity hash table\n");
429                                 goto dberror;
430                         }
431
432                         if(pres_htable_restore() < 0) {
433                                 LM_ERR("filling in presentity hash table from database\n");
434                                 goto dberror;
435                         }
436                 }
437         }
438
439
440         pres_startup_time = (int)time(NULL);
441         if(pres_clean_period > 0) {
442                 if(pres_timer_mode==0) {
443                         register_timer(msg_presentity_clean, 0, pres_clean_period);
444                         register_timer(msg_watchers_clean, 0, pres_clean_period);
445                         if(publ_cache_mode==PS_PCACHE_RECORD) {
446                                 register_timer(ps_ptable_timer_clean, 0, pres_clean_period);
447                         }
448                 } else {
449                         sr_wtimer_add(msg_presentity_clean, 0, pres_clean_period);
450                         sr_wtimer_add(msg_watchers_clean, 0, pres_clean_period);
451                         if(publ_cache_mode==PS_PCACHE_RECORD) {
452                                 sr_wtimer_add(ps_ptable_timer_clean, 0, pres_clean_period);
453                         }
454                 }
455         }
456
457         if(pres_db_update_period > 0) {
458                 if(pres_timer_mode==0) {
459                         register_timer(timer_db_update, 0, pres_db_update_period);
460                 } else {
461                         sr_wtimer_add(timer_db_update, 0, pres_db_update_period);
462                 }
463         }
464
465         if(pres_waitn_time <= 0) {
466                 pres_waitn_time = 5;
467         }
468
469         if(pres_notifier_poll_rate <= 0) {
470                 pres_notifier_poll_rate = 10;
471         }
472
473         if(pres_notifier_processes < 0 || pres_subs_dbmode != DB_ONLY) {
474                 pres_notifier_processes = 0;
475         }
476
477         if(pres_notifier_processes > 0) {
478                 if((pres_notifier_id =
479                                                    shm_malloc(sizeof(int) * pres_notifier_processes))
480                                 == NULL) {
481                         LM_ERR("allocating shared memory\n");
482                         goto dberror;
483                 }
484
485                 register_basic_timers(pres_notifier_processes);
486         }
487
488         if(pres_force_delete > 0)
489                 pres_force_delete = 1;
490
491         if(pres_log_facility_str) {
492                 int tmp = str2facility(pres_log_facility_str);
493
494                 if(tmp != -1) {
495                         pres_local_log_facility = tmp;
496                 } else {
497                         LM_ERR("invalid log facility configured\n");
498                         goto dberror;
499                 }
500         } else {
501                 pres_local_log_facility = cfg_get(core, core_cfg, log_facility);
502         }
503
504         if(pres_db_table_lock_type != 1) {
505                 pres_db_table_lock = DB_LOCKING_NONE;
506         }
507
508         if(pa_db) {
509                 pa_dbf.close(pa_db);
510                 pa_db = NULL;
511         }
512
513         goto_on_notify_reply = route_lookup(&event_rt, "presence:notify-reply");
514         if(goto_on_notify_reply >= 0 && event_rt.rlist[goto_on_notify_reply] == 0)
515                 goto_on_notify_reply = -1; /* disable */
516
517         if(pres_enable_dmq > 0 && pres_dmq_initialize() != 0) {
518                 LM_ERR("failed to initialize dmq integration\n");
519                 return -1;
520         }
521
522         return 0;
523
524 dberror:
525         if(pa_db) {
526                 pa_dbf.close(pa_db);
527                 pa_db = NULL;
528         }
529         return -1;
530 }
531
532 /**
533  * Initialize children
534  */
535 static int child_init(int rank)
536 {
537         if(rank == PROC_INIT || rank == PROC_TCP_MAIN) {
538                 return 0;
539         }
540
541         pres_pid = my_pid();
542
543         if(pres_library_mode) {
544                 return 0;
545         }
546
547         if(sruid_init(&pres_sruid, '-', "pres", SRUID_INC) < 0) {
548                 return -1;
549         }
550
551         if(publ_cache_mode == PS_PCACHE_RECORD && pres_subs_dbmode == NO_DB) {
552                 return 0;
553         }
554
555         if(rank == PROC_MAIN) {
556                 int i;
557
558                 for(i = 0; i < pres_notifier_processes; i++) {
559                         char tmp[21];
560                         snprintf(tmp, 21, "PRESENCE NOTIFIER %d", i);
561                         pres_notifier_id[i] = i;
562
563                         if(fork_basic_utimer(PROC_TIMER, tmp, 1, pres_timer_send_notify,
564                                            &pres_notifier_id[i], 1000000 / pres_notifier_poll_rate)
565                                         < 0) {
566                                 LM_ERR("Failed to start PRESENCE NOTIFIER %d\n", i);
567                                 return -1;
568                         }
569                 }
570
571                 return 0;
572         }
573
574         if(pa_dbf.init == 0) {
575                 LM_CRIT("child_init: database not bound\n");
576                 return -1;
577         }
578         /* Do not pool the connections where possible when running notifier
579          * processes. */
580         if(pres_notifier_processes > 0 && pa_dbf.init2)
581                 pa_db = pa_dbf.init2(&pres_db_url, DB_POOLING_NONE);
582         else
583                 pa_db = pa_dbf.init(&pres_db_url);
584         if(!pa_db) {
585                 LM_ERR("child %d: unsuccessful connecting to database\n", rank);
586                 return -1;
587         }
588
589         if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
590                 LM_ERR("child %d:unsuccessful use_table presentity_table\n", rank);
591                 return -1;
592         }
593
594         if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
595                 LM_ERR("child %d:unsuccessful use_table active_watchers_table\n", rank);
596                 return -1;
597         }
598
599         if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
600                 LM_ERR("child %d:unsuccessful use_table watchers_table\n", rank);
601                 return -1;
602         }
603
604         LM_DBG("child %d: Database connection opened successfully\n", rank);
605
606         return 0;
607 }
608
609
610 /*
611  * destroy function
612  */
613 static void destroy(void)
614 {
615         if(subs_htable && pres_subs_dbmode == WRITE_BACK) {
616                 /* open database connection */
617                 pa_db = pa_dbf.init(&pres_db_url);
618                 if(!pa_db) {
619                         LM_ERR("mod_destroy: unsuccessful connecting to database\n");
620                 } else
621                         timer_db_update(0, 0);
622         }
623
624         if(subs_htable) {
625                 destroy_shtable(subs_htable, shtable_size);
626         }
627
628         if(pres_htable) {
629                 destroy_phtable();
630         }
631
632         if(pa_db && pa_dbf.close) {
633                 pa_dbf.close(pa_db);
634         }
635
636         if(pres_notifier_id != NULL) {
637                 shm_free(pres_notifier_id);
638         }
639
640         destroy_evlist();
641
642         ps_ptable_destroy();
643 }
644
645 static int fixup_presence(void **param, int param_no)
646 {
647         if(pres_library_mode) {
648                 LM_ERR("Bad config - you can not call 'handle_publish' function"
649                            " (db_url not set)\n");
650                 return -1;
651         }
652         if(param_no == 0)
653                 return 0;
654
655         return fixup_spve_null(param, 1);
656 }
657
658 static int fixup_subscribe(void **param, int param_no)
659 {
660
661         if(pres_library_mode) {
662                 LM_ERR("Bad config - you can not call 'handle_subscribe' function"
663                            " (db_url not set)\n");
664                 return -1;
665         }
666         if(param_no == 1) {
667                 return fixup_spve_null(param, 1);
668         }
669         return 0;
670 }
671
672 int pres_refresh_watchers(
673                 str *pres, str *event, int type, str *file_uri, str *filename)
674 {
675         pres_ev_t *ev;
676         struct sip_uri uri;
677         str *rules_doc = NULL;
678         int result;
679
680         ev = contains_event(event, NULL);
681         if(ev == NULL) {
682                 LM_ERR("wrong event parameter\n");
683                 return -1;
684         }
685
686         if(type == 0) {
687                 /* if a request to refresh watchers authorization */
688                 if(ev->get_rules_doc == NULL) {
689                         LM_ERR("wrong request for a refresh watchers authorization status"
690                                    "for an event that does not require authorization\n");
691                         goto error;
692                 }
693
694                 if(parse_uri(pres->s, pres->len, &uri) < 0) {
695                         LM_ERR("parsing uri [%.*s]\n", pres->len, pres->s);
696                         goto error;
697                 }
698
699                 result = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
700                 if(result < 0 || rules_doc == NULL || rules_doc->s == NULL) {
701                         LM_ERR("no rules doc found for the user\n");
702                         goto error;
703                 }
704
705                 if(update_watchers_status(pres, ev, rules_doc) < 0) {
706                         LM_ERR("failed to update watchers\n");
707                         goto error;
708                 }
709
710                 pkg_free(rules_doc->s);
711                 pkg_free(rules_doc);
712                 rules_doc = NULL;
713
714         } else {
715                 if(type == 2) {
716                         if(update_hard_presentity(pres, ev, file_uri, filename) < 0) {
717                                 LM_ERR("updating hard presentity\n");
718                                 goto error;
719                         }
720                 }
721
722                 /* if a request to refresh notified info */
723                 if(query_db_notify(pres, ev, NULL) < 0) {
724                         LM_ERR("sending Notify requests\n");
725                         goto error;
726                 }
727         }
728         return 0;
729
730 error:
731         if(rules_doc) {
732                 if(rules_doc->s)
733                         pkg_free(rules_doc->s);
734                 pkg_free(rules_doc);
735         }
736         return -1;
737 }
738
739 int _api_pres_refresh_watchers(str *pres, str *event, int type)
740 {
741         return pres_refresh_watchers(pres, event, type, NULL, NULL);
742 }
743
744 int ki_pres_refresh_watchers(sip_msg_t *msg, str *pres, str *event, int type)
745 {
746         return pres_refresh_watchers(pres, event, type, NULL, NULL);
747 }
748
749 int ki_pres_refresh_watchers_file(sip_msg_t *msg, str *pres, str *event,
750                 int type, str *file_uri, str *filename)
751 {
752         return pres_refresh_watchers(pres, event, type, file_uri, filename);
753 }
754
755 int pres_update_status(subs_t *subs, str reason, db_key_t *query_cols,
756                 db_val_t *query_vals, int n_query_cols, subs_t **subs_array)
757 {
758         db_key_t update_cols[5];
759         db_val_t update_vals[5];
760         int n_update_cols = 0;
761         int u_status_col, u_reason_col, q_wuser_col, q_wdomain_col;
762         int status;
763         query_cols[q_wuser_col = n_query_cols] = &str_watcher_username_col;
764         query_vals[n_query_cols].nul = 0;
765         query_vals[n_query_cols].type = DB1_STR;
766         n_query_cols++;
767
768         query_cols[q_wdomain_col = n_query_cols] = &str_watcher_domain_col;
769         query_vals[n_query_cols].nul = 0;
770         query_vals[n_query_cols].type = DB1_STR;
771         n_query_cols++;
772
773         update_cols[u_status_col = n_update_cols] = &str_status_col;
774         update_vals[u_status_col].nul = 0;
775         update_vals[u_status_col].type = DB1_INT;
776         n_update_cols++;
777
778         update_cols[u_reason_col = n_update_cols] = &str_reason_col;
779         update_vals[u_reason_col].nul = 0;
780         update_vals[u_reason_col].type = DB1_STR;
781         n_update_cols++;
782
783         status = subs->status;
784         if(subs->event->get_auth_status(subs) < 0) {
785                 LM_ERR("getting status from rules document\n");
786                 return -1;
787         }
788         LM_DBG("subs.status= %d\n", subs->status);
789         if(get_status_str(subs->status) == NULL) {
790                 LM_ERR("wrong status: %d\n", subs->status);
791                 return -1;
792         }
793
794         if(subs->status != status || reason.len != subs->reason.len
795                         || (reason.s && subs->reason.s
796                                            && strncmp(reason.s, subs->reason.s, reason.len))) {
797                 /* update in watchers_table */
798                 query_vals[q_wuser_col].val.str_val = subs->watcher_user;
799                 query_vals[q_wdomain_col].val.str_val = subs->watcher_domain;
800
801                 update_vals[u_status_col].val.int_val = subs->status;
802                 update_vals[u_reason_col].val.str_val = subs->reason;
803
804                 if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
805                         LM_ERR("in use_table\n");
806                         return -1;
807                 }
808
809                 if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
810                                    update_vals, n_query_cols, n_update_cols)
811                                 < 0) {
812                         LM_ERR("in sql update\n");
813                         return -1;
814                 }
815                 /* save in the list all affected dialogs */
816                 /* if status switches to terminated -> delete dialog */
817                 if(update_pw_dialogs(subs, subs->db_flag, subs_array) < 0) {
818                         LM_ERR("extracting dialogs from [watcher]=%.*s@%.*s to"
819                                    " [presentity]=%.*s\n",
820                                         subs->watcher_user.len, subs->watcher_user.s,
821                                         subs->watcher_domain.len, subs->watcher_domain.s,
822                                         subs->pres_uri.len, subs->pres_uri.s);
823                         return -1;
824                 }
825         }
826         return 0;
827 }
828
829 int pres_db_delete_status(subs_t *s)
830 {
831         int n_query_cols = 0;
832         db_key_t query_cols[5];
833         db_val_t query_vals[5];
834
835         if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
836                 LM_ERR("sql use table failed\n");
837                 return -1;
838         }
839
840         query_cols[n_query_cols] = &str_event_col;
841         query_vals[n_query_cols].nul = 0;
842         query_vals[n_query_cols].type = DB1_STR;
843         query_vals[n_query_cols].val.str_val = s->event->name;
844         n_query_cols++;
845
846         query_cols[n_query_cols] = &str_presentity_uri_col;
847         query_vals[n_query_cols].nul = 0;
848         query_vals[n_query_cols].type = DB1_STR;
849         query_vals[n_query_cols].val.str_val = s->pres_uri;
850         n_query_cols++;
851
852         query_cols[n_query_cols] = &str_watcher_username_col;
853         query_vals[n_query_cols].nul = 0;
854         query_vals[n_query_cols].type = DB1_STR;
855         query_vals[n_query_cols].val.str_val = s->watcher_user;
856         n_query_cols++;
857
858         query_cols[n_query_cols] = &str_watcher_domain_col;
859         query_vals[n_query_cols].nul = 0;
860         query_vals[n_query_cols].type = DB1_STR;
861         query_vals[n_query_cols].val.str_val = s->watcher_domain;
862         n_query_cols++;
863
864         if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0) {
865                 LM_ERR("sql delete failed\n");
866                 return -1;
867         }
868         return 0;
869 }
870
871 int update_watchers_status(str *pres_uri, pres_ev_t *ev, str *rules_doc)
872 {
873         subs_t subs;
874         db_key_t query_cols[6], result_cols[5];
875         db_val_t query_vals[6];
876         int n_result_cols = 0, n_query_cols = 0;
877         db1_res_t *result = NULL;
878         db_row_t *row;
879         db_val_t *row_vals;
880         int i;
881         str w_user, w_domain, reason = {0, 0};
882         unsigned int status;
883         int status_col, w_user_col, w_domain_col, reason_col;
884         subs_t *subs_array = NULL, *s;
885         unsigned int hash_code;
886         int err_ret = -1;
887         int n = 0;
888
889         typedef struct ws
890         {
891                 int status;
892                 str reason;
893                 str w_user;
894                 str w_domain;
895         } ws_t;
896
897         ws_t *ws_list = NULL;
898
899         LM_DBG("start\n");
900
901         if(ev->content_type.s == NULL) {
902                 ev = contains_event(&ev->name, NULL);
903                 if(ev == NULL) {
904                         LM_ERR("wrong event parameter\n");
905                         return 0;
906                 }
907         }
908
909         memset(&subs, 0, sizeof(subs_t));
910         subs.pres_uri = *pres_uri;
911         subs.event = ev;
912         subs.auth_rules_doc = rules_doc;
913
914         /* update in watchers_table */
915         query_cols[n_query_cols] = &str_presentity_uri_col;
916         query_vals[n_query_cols].nul = 0;
917         query_vals[n_query_cols].type = DB1_STR;
918         query_vals[n_query_cols].val.str_val = *pres_uri;
919         n_query_cols++;
920
921         query_cols[n_query_cols] = &str_event_col;
922         query_vals[n_query_cols].nul = 0;
923         query_vals[n_query_cols].type = DB1_STR;
924         query_vals[n_query_cols].val.str_val = ev->name;
925         n_query_cols++;
926
927         result_cols[status_col = n_result_cols++] = &str_status_col;
928         result_cols[reason_col = n_result_cols++] = &str_reason_col;
929         result_cols[w_user_col = n_result_cols++] = &str_watcher_username_col;
930         result_cols[w_domain_col = n_result_cols++] = &str_watcher_domain_col;
931
932         if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
933                 LM_ERR("in use_table\n");
934                 goto done;
935         }
936
937         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
938                            n_result_cols, 0, &result)
939                         < 0) {
940                 LM_ERR("in sql query\n");
941                 goto done;
942         }
943         if(result == NULL)
944                 return 0;
945
946         if(result->n <= 0) {
947                 err_ret = 0;
948                 goto done;
949         }
950
951         LM_DBG("found %d record-uri in watchers_table\n", result->n);
952         hash_code = core_case_hash(pres_uri, &ev->name, shtable_size);
953         subs.db_flag = hash_code;
954
955         /* must do a copy as sphere_check requires database queries */
956         if(pres_sphere_enable) {
957                 n = result->n;
958                 ws_list = (ws_t *)pkg_malloc(n * sizeof(ws_t));
959                 if(ws_list == NULL) {
960                         LM_ERR("No more private memory\n");
961                         goto done;
962                 }
963                 memset(ws_list, 0, n * sizeof(ws_t));
964
965                 for(i = 0; i < result->n; i++) {
966                         row = &result->rows[i];
967                         row_vals = ROW_VALUES(row);
968
969                         status = row_vals[status_col].val.int_val;
970
971                         reason.s = (char *)row_vals[reason_col].val.string_val;
972                         reason.len = reason.s ? strlen(reason.s) : 0;
973
974                         w_user.s = (char *)row_vals[w_user_col].val.string_val;
975                         w_user.len = strlen(w_user.s);
976
977                         w_domain.s = (char *)row_vals[w_domain_col].val.string_val;
978                         w_domain.len = strlen(w_domain.s);
979
980                         if(reason.len) {
981                                 ws_list[i].reason.s =
982                                                 (char *)pkg_malloc(reason.len * sizeof(char));
983                                 if(ws_list[i].reason.s == NULL) {
984                                         LM_ERR("No more private memory\n");
985                                         goto done;
986                                 }
987                                 memcpy(ws_list[i].reason.s, reason.s, reason.len);
988                                 ws_list[i].reason.len = reason.len;
989                         } else
990                                 ws_list[i].reason.s = NULL;
991
992                         ws_list[i].w_user.s = (char *)pkg_malloc(w_user.len * sizeof(char));
993                         if(ws_list[i].w_user.s == NULL) {
994                                 LM_ERR("No more private memory\n");
995                                 goto done;
996                         }
997                         memcpy(ws_list[i].w_user.s, w_user.s, w_user.len);
998                         ws_list[i].w_user.len = w_user.len;
999
1000                         ws_list[i].w_domain.s =
1001                                         (char *)pkg_malloc(w_domain.len * sizeof(char));
1002                         if(ws_list[i].w_domain.s == NULL) {
1003                                 LM_ERR("No more private memory\n");
1004                                 goto done;
1005                         }
1006                         memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len);
1007                         ws_list[i].w_domain.len = w_domain.len;
1008
1009                         ws_list[i].status = status;
1010                 }
1011
1012                 pa_dbf.free_result(pa_db, result);
1013                 result = NULL;
1014
1015                 for(i = 0; i < n; i++) {
1016                         subs.watcher_user = ws_list[i].w_user;
1017                         subs.watcher_domain = ws_list[i].w_domain;
1018                         subs.status = ws_list[i].status;
1019                         memset(&subs.reason, 0, sizeof(str));
1020
1021                         if(pres_update_status(&subs, reason, query_cols, query_vals,
1022                                            n_query_cols, &subs_array)
1023                                         < 0) {
1024                                 LM_ERR("failed to update watcher status\n");
1025                                 goto done;
1026                         }
1027                 }
1028
1029                 for(i = 0; i < n; i++) {
1030                         pkg_free(ws_list[i].w_user.s);
1031                         pkg_free(ws_list[i].w_domain.s);
1032                         if(ws_list[i].reason.s)
1033                                 pkg_free(ws_list[i].reason.s);
1034                 }
1035                 pkg_free(ws_list);
1036                 ws_list = NULL;
1037
1038                 goto send_notify;
1039         }
1040
1041         for(i = 0; i < result->n; i++) {
1042                 row = &result->rows[i];
1043                 row_vals = ROW_VALUES(row);
1044
1045                 status = row_vals[status_col].val.int_val;
1046
1047                 reason.s = (char *)row_vals[reason_col].val.string_val;
1048                 reason.len = reason.s ? strlen(reason.s) : 0;
1049
1050                 w_user.s = (char *)row_vals[w_user_col].val.string_val;
1051                 w_user.len = strlen(w_user.s);
1052
1053                 w_domain.s = (char *)row_vals[w_domain_col].val.string_val;
1054                 w_domain.len = strlen(w_domain.s);
1055
1056                 subs.watcher_user = w_user;
1057                 subs.watcher_domain = w_domain;
1058                 subs.status = status;
1059                 memset(&subs.reason, 0, sizeof(str));
1060
1061                 if(pres_update_status(&subs, reason, query_cols, query_vals,
1062                                    n_query_cols, &subs_array)
1063                                 < 0) {
1064                         LM_ERR("failed to update watcher status\n");
1065                         goto done;
1066                 }
1067         }
1068
1069         pa_dbf.free_result(pa_db, result);
1070         result = NULL;
1071
1072 send_notify:
1073
1074         if(pres_notifier_processes == 0) {
1075                 s = subs_array;
1076
1077                 while(s) {
1078                         if(notify(s, NULL, NULL, 0, 0) < 0) {
1079                                 LM_ERR("sending Notify request\n");
1080                                 goto done;
1081                         }
1082
1083                         /* delete from database also */
1084                         if(s->status == TERMINATED_STATUS) {
1085                                 if(pres_db_delete_status(s) < 0) {
1086                                         LM_ERR("failed to delete terminated "
1087                                                    "dialog from database\n");
1088                                         goto done;
1089                                 }
1090                         }
1091
1092                         s = s->next;
1093                 }
1094         }
1095
1096         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
1097         return 0;
1098
1099 done:
1100         if(result)
1101                 pa_dbf.free_result(pa_db, result);
1102         free_subs_list(subs_array, PKG_MEM_TYPE, 0);
1103         if(ws_list) {
1104                 for(i = 0; i < n; i++) {
1105                         if(ws_list[i].w_user.s)
1106                                 pkg_free(ws_list[i].w_user.s);
1107                         if(ws_list[i].w_domain.s)
1108                                 pkg_free(ws_list[i].w_domain.s);
1109                         if(ws_list[i].reason.s)
1110                                 pkg_free(ws_list[i].reason.s);
1111                 }
1112                 pkg_free(ws_list);
1113         }
1114         return err_ret;
1115 }
1116
1117 /********************************************************************************/
1118
1119 static int update_pw_dialogs_dbonlymode(subs_t *subs, subs_t **subs_array)
1120 {
1121         db_key_t query_cols[5], db_cols[3];
1122         db_val_t query_vals[5], db_vals[3];
1123         db_key_t result_cols[26];
1124         int n_query_cols = 0, n_result_cols = 0, n_update_cols = 0;
1125         int event_col, pres_uri_col, watcher_user_col, watcher_domain_col;
1126         int r_pres_uri_col, r_to_user_col, r_to_domain_col;
1127         int r_from_user_col, r_from_domain_col, r_callid_col;
1128         int r_to_tag_col, r_from_tag_col, r_sockinfo_col;
1129         int r_event_id_col, r_local_contact_col, r_contact_col;
1130         int r_record_route_col, r_reason_col;
1131         int r_event_col, r_local_cseq_col, r_remote_cseq_col;
1132         int r_status_col, r_version_col;
1133         int r_expires_col, r_watcher_user_col, r_watcher_domain_col;
1134         int r_flags_col, r_user_agent_col;
1135         db1_res_t *result = NULL;
1136         db_val_t *row_vals;
1137         db_row_t *rows;
1138         int nr_rows, loop;
1139         subs_t s, *cs;
1140         str ev_sname;
1141
1142         if(pa_db == NULL) {
1143                 LM_ERR("null database connection\n");
1144                 return (-1);
1145         }
1146
1147         if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
1148                 LM_ERR("use table failed\n");
1149                 return (-1);
1150         }
1151
1152         query_cols[event_col = n_query_cols] = &str_event_col;
1153         query_vals[event_col].nul = 0;
1154         query_vals[event_col].type = DB1_STR;
1155         query_vals[event_col].val.str_val = subs->event->name;
1156         n_query_cols++;
1157
1158         query_cols[pres_uri_col = n_query_cols] = &str_presentity_uri_col;
1159         query_vals[pres_uri_col].nul = 0;
1160         query_vals[pres_uri_col].type = DB1_STR;
1161         query_vals[pres_uri_col].val.str_val = subs->pres_uri;
1162         n_query_cols++;
1163
1164         query_cols[watcher_user_col = n_query_cols] = &str_watcher_username_col;
1165         query_vals[watcher_user_col].nul = 0;
1166         query_vals[watcher_user_col].type = DB1_STR;
1167         query_vals[watcher_user_col].val.str_val = subs->watcher_user;
1168         n_query_cols++;
1169
1170         query_cols[watcher_domain_col = n_query_cols] = &str_watcher_domain_col;
1171         query_vals[watcher_domain_col].nul = 0;
1172         query_vals[watcher_domain_col].type = DB1_STR;
1173         query_vals[watcher_domain_col].val.str_val = subs->watcher_domain;
1174         n_query_cols++;
1175
1176
1177         result_cols[r_to_user_col = n_result_cols++] = &str_to_user_col;
1178         result_cols[r_to_domain_col = n_result_cols++] = &str_to_domain_col;
1179         result_cols[r_from_user_col = n_result_cols++] = &str_from_user_col;
1180         result_cols[r_from_domain_col = n_result_cols++] = &str_from_domain_col;
1181         result_cols[r_watcher_user_col = n_result_cols++] =
1182                         &str_watcher_username_col;
1183         result_cols[r_watcher_domain_col = n_result_cols++] =
1184                         &str_watcher_domain_col;
1185         result_cols[r_callid_col = n_result_cols++] = &str_callid_col;
1186         result_cols[r_to_tag_col = n_result_cols++] = &str_to_tag_col;
1187         result_cols[r_from_tag_col = n_result_cols++] = &str_from_tag_col;
1188         result_cols[r_sockinfo_col = n_result_cols++] = &str_socket_info_col;
1189         result_cols[r_event_id_col = n_result_cols++] = &str_event_id_col;
1190         result_cols[r_local_contact_col = n_result_cols++] = &str_local_contact_col;
1191         result_cols[r_record_route_col = n_result_cols++] = &str_record_route_col;
1192         result_cols[r_reason_col = n_result_cols++] = &str_reason_col;
1193         result_cols[r_local_cseq_col = n_result_cols++] = &str_local_cseq_col;
1194         result_cols[r_version_col = n_result_cols++] = &str_version_col;
1195         result_cols[r_expires_col = n_result_cols++] = &str_expires_col;
1196         result_cols[r_event_col = n_result_cols++] = &str_event_col;
1197         result_cols[r_pres_uri_col = n_result_cols++] = &str_presentity_uri_col;
1198         result_cols[r_contact_col = n_result_cols++] = &str_contact_col;
1199
1200         /* these ones are unused for some reason !!! */
1201         result_cols[r_remote_cseq_col = n_result_cols++] = &str_remote_cseq_col;
1202         result_cols[r_status_col = n_result_cols++] = &str_status_col;
1203         /*********************************************/
1204
1205         result_cols[r_flags_col = n_result_cols++] = &str_flags_col;
1206         result_cols[r_user_agent_col = n_result_cols++] = &str_user_agent_col;
1207
1208         if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
1209                            n_result_cols, 0, &result)
1210                         < 0) {
1211                 LM_ERR("Can't query db\n");
1212                 if(result)
1213                         pa_dbf.free_result(pa_db, result);
1214                 return (-1);
1215         }
1216
1217         if(result == NULL)
1218                 return (-1);
1219
1220         nr_rows = RES_ROW_N(result);
1221
1222         LM_DBG("found %d matching dialogs\n", nr_rows);
1223
1224         if(nr_rows <= 0) {
1225                 pa_dbf.free_result(pa_db, result);
1226                 return 0;
1227         }
1228
1229         rows = RES_ROWS(result);
1230         /* get the results and fill in return data structure */
1231         for(loop = 0; loop < nr_rows; loop++) {
1232                 row_vals = ROW_VALUES(&rows[loop]);
1233
1234                 memset(&s, 0, sizeof(subs_t));
1235                 s.status = subs->status;
1236
1237                 s.reason.s = subs->reason.s;
1238                 s.reason.len = s.reason.s ? strlen(s.reason.s) : 0; //>>>>>>>>>>
1239
1240                 s.pres_uri.s = (char *)row_vals[r_pres_uri_col].val.string_val;
1241                 s.pres_uri.len = s.pres_uri.s ? strlen(s.pres_uri.s) : 0;
1242
1243                 s.to_user.s = (char *)row_vals[r_to_user_col].val.string_val;
1244                 s.to_user.len = s.to_user.s ? strlen(s.to_user.s) : 0;
1245
1246                 s.to_domain.s = (char *)row_vals[r_to_domain_col].val.string_val;
1247                 s.to_domain.len = s.to_domain.s ? strlen(s.to_domain.s) : 0;
1248
1249                 s.from_user.s = (char *)row_vals[r_from_user_col].val.string_val;
1250                 s.from_user.len = s.from_user.s ? strlen(s.from_user.s) : 0;
1251
1252                 s.from_domain.s = (char *)row_vals[r_from_domain_col].val.string_val;
1253                 s.from_domain.len = s.from_domain.s ? strlen(s.from_domain.s) : 0;
1254
1255                 s.watcher_user.s = (char *)row_vals[r_watcher_user_col].val.string_val;
1256                 s.watcher_user.len = s.watcher_user.s ? strlen(s.watcher_user.s) : 0;
1257
1258                 s.watcher_domain.s =
1259                                 (char *)row_vals[r_watcher_domain_col].val.string_val;
1260                 s.watcher_domain.len =
1261                                 s.watcher_domain.s ? strlen(s.watcher_domain.s) : 0;
1262
1263                 s.event_id.s = (char *)row_vals[r_event_id_col].val.string_val;
1264                 s.event_id.len = (s.event_id.s) ? strlen(s.event_id.s) : 0;
1265
1266                 s.to_tag.s = (char *)row_vals[r_to_tag_col].val.string_val;
1267                 s.to_tag.len = s.to_tag.s ? strlen(s.to_tag.s) : 0;
1268
1269                 s.from_tag.s = (char *)row_vals[r_from_tag_col].val.string_val;
1270                 s.from_tag.len = s.from_tag.s ? strlen(s.from_tag.s) : 0;
1271
1272                 s.callid.s = (char *)row_vals[r_callid_col].val.string_val;
1273                 s.callid.len = s.callid.s ? strlen(s.callid.s) : 0;
1274
1275                 s.record_route.s = (char *)row_vals[r_record_route_col].val.string_val;
1276                 s.record_route.len = (s.record_route.s) ? strlen(s.record_route.s) : 0;
1277
1278                 s.contact.s = (char *)row_vals[r_contact_col].val.string_val;
1279                 s.contact.len = s.contact.s ? strlen(s.contact.s) : 0;
1280
1281                 s.sockinfo_str.s = (char *)row_vals[r_sockinfo_col].val.string_val;
1282                 s.sockinfo_str.len = s.sockinfo_str.s ? strlen(s.sockinfo_str.s) : 0;
1283
1284                 s.local_contact.s =
1285                                 (char *)row_vals[r_local_contact_col].val.string_val;
1286                 s.local_contact.len = s.local_contact.s ? strlen(s.local_contact.s) : 0;
1287
1288                 ev_sname.s = (char *)row_vals[r_event_col].val.string_val;
1289                 ev_sname.len = ev_sname.s ? strlen(ev_sname.s) : 0;
1290
1291                 s.event = contains_event(&ev_sname, NULL);
1292
1293                 if(s.event == NULL) {
1294                         LM_ERR("event not found and set to NULL\n");
1295                 }
1296
1297                 s.local_cseq = row_vals[r_local_cseq_col].val.int_val;
1298
1299                 s.expires = row_vals[r_expires_col].val.int_val;
1300
1301                 if(s.expires > (int)time(NULL) + pres_expires_offset)
1302                         s.expires -= (int)time(NULL);
1303                 else
1304                         s.expires = 0;
1305
1306                 s.version = row_vals[r_version_col].val.int_val;
1307
1308                 s.flags = row_vals[r_flags_col].val.int_val;
1309                 s.user_agent.s = (char *)row_vals[r_user_agent_col].val.string_val;
1310                 s.user_agent.len = (s.user_agent.s) ? strlen(s.user_agent.s) : 0;
1311
1312
1313                 cs = mem_copy_subs(&s, PKG_MEM_TYPE);
1314                 if(cs == NULL) {
1315                         LM_ERR("while copying subs_t structure\n");
1316                         /* tidy up and return */
1317                         pa_dbf.free_result(pa_db, result);
1318                         return (-1);
1319                 }
1320                 cs->local_cseq++;
1321                 cs->next = (*subs_array);
1322                 (*subs_array) = cs;
1323
1324                 printf_subs(cs);
1325         }
1326
1327         pa_dbf.free_result(pa_db, result);
1328
1329         if(pres_notifier_processes == 0 && subs->status == TERMINATED_STATUS) {
1330                 /* delete the records */
1331                 if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0) {
1332                         LM_ERR("sql delete failed\n");
1333                         return (-1);
1334                 }
1335
1336                 return (0);
1337         }
1338
1339         /* otherwise we update the records */
1340         db_cols[n_update_cols] = &str_status_col;
1341         db_vals[n_update_cols].type = DB1_INT;
1342         db_vals[n_update_cols].nul = 0;
1343         db_vals[n_update_cols].val.int_val = subs->status;
1344         n_update_cols++;
1345
1346         db_cols[n_update_cols] = &str_reason_col;
1347         db_vals[n_update_cols].type = DB1_STR;
1348         db_vals[n_update_cols].nul = 0;
1349         db_vals[n_update_cols].val.str_val = subs->reason;
1350         n_update_cols++;
1351
1352         db_cols[n_update_cols] = &str_updated_col;
1353         db_vals[n_update_cols].type = DB1_INT;
1354         db_vals[n_update_cols].nul = 0;
1355         if(subs->callid.len == 0 || subs->from_tag.len == 0) {
1356                 db_vals[n_update_cols].val.int_val =
1357                                 (int)((kam_rand() / (KAM_RAND_MAX + 1.0))
1358                                                 * (pres_waitn_time * pres_notifier_poll_rate
1359                                                                   * pres_notifier_processes));
1360         } else {
1361                 db_vals[n_update_cols].val.int_val =
1362                                 core_case_hash(&subs->callid, &subs->from_tag, 0)
1363                                 % (pres_waitn_time * pres_notifier_poll_rate
1364                                                   * pres_notifier_processes);
1365         }
1366         n_update_cols++;
1367
1368         if(pa_dbf.update(pa_db, query_cols, 0, query_vals, db_cols, db_vals,
1369                            n_query_cols, n_update_cols)
1370                         < 0) {
1371                 LM_ERR("DB update failed\n");
1372                 return (-1);
1373         }
1374
1375         return (0);
1376 }
1377
1378 /********************************************************************************/
1379
1380 static int update_pw_dialogs(
1381                 subs_t *subs, unsigned int hash_code, subs_t **subs_array)
1382 {
1383         subs_t *s, *ps, *cs;
1384         int i = 0;
1385
1386         LM_DBG("start\n");
1387
1388         if(pres_subs_dbmode == DB_ONLY) {
1389                 return (update_pw_dialogs_dbonlymode(subs, subs_array));
1390         }
1391
1392         lock_get(&subs_htable[hash_code].lock);
1393
1394         ps = subs_htable[hash_code].entries;
1395
1396         while(ps && ps->next) {
1397                 s = ps->next;
1398
1399                 if(s->event == subs->event && s->pres_uri.len == subs->pres_uri.len
1400                                 && s->watcher_user.len == subs->watcher_user.len
1401                                 && s->watcher_domain.len == subs->watcher_domain.len
1402                                 && presence_sip_uri_match(&s->pres_uri, &subs->pres_uri) == 0
1403                                 && presence_sip_uri_match(&s->watcher_user, &subs->watcher_user)
1404                                                    == 0
1405                                 && presence_sip_uri_match(
1406                                                    &s->watcher_domain, &subs->watcher_domain)
1407                                                    == 0) {
1408                         i++;
1409                         s->status = subs->status;
1410                         s->reason = subs->reason;
1411                         s->db_flag = UPDATEDB_FLAG;
1412
1413                         cs = mem_copy_subs(s, PKG_MEM_TYPE);
1414                         if(cs == NULL) {
1415                                 LM_ERR("copying subs_t structure\n");
1416                                 lock_release(&subs_htable[hash_code].lock);
1417                                 return -1;
1418                         }
1419                         cs->local_cseq++;
1420                         cs->expires -= (int)time(NULL);
1421                         cs->next = (*subs_array);
1422                         (*subs_array) = cs;
1423                         if(subs->status == TERMINATED_STATUS) {
1424                                 ps->next = s->next;
1425                                 shm_free(s->contact.s);
1426                                 shm_free(s);
1427                                 LM_DBG(" deleted terminated dialog from hash table\n");
1428                         } else
1429                                 ps = s;
1430
1431                         printf_subs(cs);
1432                 } else
1433                         ps = s;
1434         }
1435
1436         LM_DBG("found %d matching dialogs\n", i);
1437         lock_release(&subs_htable[hash_code].lock);
1438
1439         return 0;
1440 }
1441
1442 static int w_pres_auth_status(struct sip_msg *_msg, char *_sp1, char *_sp2)
1443 {
1444         str watcher_uri, presentity_uri;
1445
1446         if(fixup_get_svalue(_msg, (gparam_t *)_sp1, &watcher_uri) != 0) {
1447                 LM_ERR("invalid watcher uri parameter");
1448                 return -1;
1449         }
1450
1451         if(fixup_get_svalue(_msg, (gparam_t *)_sp2, &presentity_uri) != 0) {
1452                 LM_ERR("invalid presentity uri parameter");
1453                 return -1;
1454         }
1455
1456         if(watcher_uri.len == 0 || watcher_uri.s == NULL) {
1457                 LM_ERR("missing watcher uri\n");
1458                 return -1;
1459         }
1460
1461         if(presentity_uri.len == 0 || presentity_uri.s == NULL) {
1462                 LM_DBG("missing presentity uri\n");
1463                 return -1;
1464         }
1465
1466         return pres_auth_status(_msg, watcher_uri, presentity_uri);
1467 }
1468
1469 int ki_pres_auth_status(sip_msg_t *msg, str *watcher_uri, str *presentity_uri)
1470 {
1471         if(watcher_uri == NULL || presentity_uri == NULL) {
1472                 LM_ERR("invalid parameters\n");
1473                 return -1;
1474         }
1475         return pres_auth_status(msg, *watcher_uri, *presentity_uri);
1476 }
1477
1478 int pres_auth_status(struct sip_msg *msg, str watcher_uri, str presentity_uri)
1479 {
1480         str event;
1481         struct sip_uri uri;
1482         pres_ev_t *ev;
1483         str *rules_doc = NULL;
1484         subs_t subs;
1485         int res;
1486
1487         event.s = "presence";
1488         event.len = 8;
1489
1490         ev = contains_event(&event, NULL);
1491         if(ev == NULL) {
1492                 LM_ERR("event is not registered\n");
1493                 return -1;
1494         }
1495         if(ev->get_rules_doc == NULL) {
1496                 LM_DBG("event does not require authorization");
1497                 return ACTIVE_STATUS;
1498         }
1499         if(parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
1500                 LM_ERR("failed to parse presentity uri\n");
1501                 return -1;
1502         }
1503         res = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
1504         if((res < 0) || (rules_doc == NULL) || (rules_doc->s == NULL)) {
1505                 LM_DBG("no xcap rules doc found for presentity uri\n");
1506                 return PENDING_STATUS;
1507         }
1508
1509         if(parse_uri(watcher_uri.s, watcher_uri.len, &uri) < 0) {
1510                 LM_ERR("failed to parse watcher uri\n");
1511                 goto err;
1512         }
1513
1514         subs.watcher_user = uri.user;
1515         subs.watcher_domain = uri.host;
1516         subs.pres_uri = presentity_uri;
1517         subs.auth_rules_doc = rules_doc;
1518         if(ev->get_auth_status(&subs) < 0) {
1519                 LM_ERR("getting status from rules document\n");
1520                 goto err;
1521         }
1522         LM_DBG("auth status of watcher <%.*s> on presentity <%.*s> is %d\n",
1523                         watcher_uri.len, watcher_uri.s, presentity_uri.len,
1524                         presentity_uri.s, subs.status);
1525         pkg_free(rules_doc->s);
1526         pkg_free(rules_doc);
1527         if((subs.reason.len == 12)
1528                         && (strncmp(subs.reason.s, "polite-block", 12) == 0))
1529                 return POLITE_BLOCK_STATUS;
1530         return subs.status;
1531
1532 err:
1533         pkg_free(rules_doc->s);
1534         pkg_free(rules_doc);
1535         return -1;
1536 }
1537
1538 /**
1539  * wrapper for pres_refresh_watchers to use in config
1540  */
1541 static int w_pres_refresh_watchers(
1542                 struct sip_msg *msg, char *puri, char *pevent, char *ptype)
1543 {
1544         str pres_uri;
1545         str event;
1546         int refresh_type;
1547
1548         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri) != 0) {
1549                 LM_ERR("invalid uri parameter");
1550                 return -1;
1551         }
1552
1553         if(fixup_get_svalue(msg, (gparam_p)pevent, &event) != 0) {
1554                 LM_ERR("invalid uri parameter");
1555                 return -1;
1556         }
1557
1558         if(fixup_get_ivalue(msg, (gparam_p)ptype, &refresh_type) != 0) {
1559                 LM_ERR("no type value\n");
1560                 return -1;
1561         }
1562
1563         if(refresh_type == 2) {
1564                 LM_ERR("Wrong number of parameters for type 2\n");
1565                 return -1;
1566         }
1567
1568         if(pres_refresh_watchers(&pres_uri, &event, refresh_type, NULL, NULL) < 0)
1569                 return -1;
1570
1571         return 1;
1572 }
1573
1574 static int w_pres_refresh_watchers5(struct sip_msg *msg, char *puri,
1575                 char *pevent, char *ptype, char *furi, char *fname)
1576 {
1577         str pres_uri, event, file_uri, filename;
1578         int refresh_type;
1579
1580         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri) != 0) {
1581                 LM_ERR("invalid uri parameter");
1582                 return -1;
1583         }
1584
1585         if(fixup_get_svalue(msg, (gparam_p)pevent, &event) != 0) {
1586                 LM_ERR("invalid event parameter");
1587                 return -1;
1588         }
1589
1590         if(fixup_get_ivalue(msg, (gparam_p)ptype, &refresh_type) != 0) {
1591                 LM_ERR("no type value\n");
1592                 return -1;
1593         }
1594
1595         if(fixup_get_svalue(msg, (gparam_p)furi, &file_uri) != 0) {
1596                 LM_ERR("invalid file uri parameter");
1597                 return -1;
1598         }
1599
1600         if(fixup_get_svalue(msg, (gparam_p)fname, &filename) != 0) {
1601                 LM_ERR("invalid filename parameter");
1602                 return -1;
1603         }
1604
1605         if(refresh_type != 2) {
1606                 LM_ERR("Wrong number of parameters for type %d\n", refresh_type);
1607                 return -1;
1608         }
1609
1610         if(pres_refresh_watchers(
1611                            &pres_uri, &event, refresh_type, &file_uri, &filename)
1612                         < 0)
1613                 return -1;
1614
1615         return 1;
1616 }
1617
1618 /**
1619  * fixup for w_pres_refresh_watchers
1620  */
1621 static int fixup_refresh_watchers(void **param, int param_no)
1622 {
1623         if(param_no == 1) {
1624                 return fixup_spve_null(param, 1);
1625         } else if(param_no == 2) {
1626                 return fixup_spve_null(param, 1);
1627         } else if(param_no == 3) {
1628                 return fixup_igp_null(param, 1);
1629         } else if(param_no == 4) {
1630                 return fixup_spve_null(param, 1);
1631         } else if(param_no == 5) {
1632                 return fixup_spve_null(param, 1);
1633         }
1634
1635         return 0;
1636 }
1637
1638
1639 /**
1640  * wrapper for update_watchers_status to use via kemi
1641  */
1642 static int ki_pres_update_watchers(
1643                 struct sip_msg *msg, str *pres_uri, str *event)
1644 {
1645         pres_ev_t *ev;
1646         struct sip_uri uri;
1647         str *rules_doc = NULL;
1648         int ret;
1649
1650         ev = contains_event(event, NULL);
1651         if(ev == NULL) {
1652                 LM_ERR("event %.*s is not registered\n", event->len, event->s);
1653                 return -1;
1654         }
1655         if(ev->get_rules_doc == NULL) {
1656                 LM_DBG("event  %.*s does not provide rules doc API\n", event->len,
1657                                 event->s);
1658                 return -1;
1659         }
1660         if(parse_uri(pres_uri->s, pres_uri->len, &uri) < 0) {
1661                 LM_ERR("failed to parse presentity uri [%.*s]\n", pres_uri->len,
1662                                 pres_uri->s);
1663                 return -1;
1664         }
1665         ret = ev->get_rules_doc(&uri.user, &uri.host, &rules_doc);
1666         if((ret < 0) || (rules_doc == NULL) || (rules_doc->s == NULL)) {
1667                 LM_DBG("no xcap rules doc found for presentity uri [%.*s]\n",
1668                                 pres_uri->len, pres_uri->s);
1669                 if(rules_doc != NULL)
1670                         pkg_free(rules_doc);
1671                 return -1;
1672         }
1673         ret = 1;
1674         if(update_watchers_status(pres_uri, ev, rules_doc) < 0) {
1675                 LM_ERR("updating watchers in presence\n");
1676                 ret = -1;
1677         }
1678
1679         pkg_free(rules_doc->s);
1680         pkg_free(rules_doc);
1681
1682         return ret;
1683 }
1684
1685 /**
1686  * wrapper for update_watchers_status to use in config
1687  */
1688 static int w_pres_update_watchers(struct sip_msg *msg, char *puri, char *pevent)
1689 {
1690         str pres_uri;
1691         str event;
1692
1693         if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri) != 0) {
1694                 LM_ERR("invalid uri parameter");
1695                 return -1;
1696         }
1697
1698         if(fixup_get_svalue(msg, (gparam_p)pevent, &event) != 0) {
1699                 LM_ERR("invalid uri parameter");
1700                 return -1;
1701         }
1702         return ki_pres_update_watchers(msg, &pres_uri, &event);
1703 }
1704 /**
1705  * fixup for w_pres_update_watchers
1706  */
1707 static int fixup_update_watchers(void **param, int param_no)
1708 {
1709         if(param_no == 1) {
1710                 return fixup_spve_null(param, 1);
1711         } else if(param_no == 2) {
1712                 return fixup_spve_null(param, 1);
1713         }
1714         return 0;
1715 }
1716
1717 /*! \brief
1718  *  rpc cmd: presence.refreshWatchers
1719  *                      \<presentity_uri>
1720  *                      \<event>
1721  *          \<refresh_type> // can be:  = 0 -> watchers autentification type or
1722  *                                                                        != 0 -> publish type //
1723  *              * */
1724 void rpc_presence_refresh_watchers(rpc_t *rpc, void *ctx)
1725 {
1726         str pres_uri = {0, 0};
1727         str event = {0, 0};
1728         str file_uri = {0, 0};
1729         str filename = {0, 0};
1730         unsigned int refresh_type;
1731         int pn;
1732
1733         LM_DBG("initiation refresh of watchers\n");
1734
1735         pn = rpc->scan(ctx, "SSu*SS", &pres_uri, &event, &refresh_type, &file_uri,
1736                         &filename);
1737         if(pn < 3) {
1738                 rpc->fault(ctx, 500, "Not enough parameters");
1739                 return;
1740         }
1741
1742         if(pres_uri.s == NULL || pres_uri.len == 0) {
1743                 LM_ERR("empty uri\n");
1744                 rpc->fault(ctx, 500, "Empty presentity URI");
1745                 return;
1746         }
1747
1748         if(event.s == NULL || event.len == 0) {
1749                 LM_ERR("empty event parameter\n");
1750                 rpc->fault(ctx, 500, "Empty event parameter");
1751                 return;
1752         }
1753         LM_DBG("event '%.*s'\n", event.len, event.s);
1754
1755         if(refresh_type == 2) {
1756                 if(pn < 5) {
1757                         LM_ERR("empty file uri or name parameters\n");
1758                         rpc->fault(ctx, 500, "No file uri or name parameters");
1759                         return;
1760                 }
1761                 if(file_uri.s == NULL || file_uri.len == 0) {
1762                         LM_ERR("empty file uri parameter\n");
1763                         rpc->fault(ctx, 500, "Empty file uri parameter");
1764                         return;
1765                 }
1766
1767                 if(filename.s == NULL || filename.len == 0) {
1768                         LM_ERR("empty file name parameter\n");
1769                         rpc->fault(ctx, 500, "Empty file name parameter");
1770                         return;
1771                 }
1772         }
1773
1774         if(pres_refresh_watchers(&pres_uri, &event, refresh_type,
1775                            file_uri.len ? &file_uri : NULL, filename.len ? &filename : NULL)
1776                         < 0) {
1777                 rpc->fault(ctx, 500, "Execution failed");
1778                 return;
1779         }
1780 }
1781
1782 static const char *rpc_presence_refresh_watchers_doc[2] = {
1783                 "Trigger refresh of watchers", 0};
1784
1785 /*! \brief
1786  *  rpc cmd: presence.updateWatchers
1787  *                      \<presentity_uri>
1788  *                      \<event>
1789  *              * */
1790 void rpc_presence_update_watchers(rpc_t *rpc, void *ctx)
1791 {
1792         str pres_uri = {0, 0};
1793         str event = {0, 0};
1794         int pn;
1795
1796         LM_DBG("init update of watchers\n");
1797
1798         pn = rpc->scan(ctx, "SS", &pres_uri, &event);
1799         if(pn < 2) {
1800                 rpc->fault(ctx, 500, "Not enough parameters");
1801                 return;
1802         }
1803
1804         if(pres_uri.s == NULL || pres_uri.len == 0) {
1805                 LM_ERR("empty uri\n");
1806                 rpc->fault(ctx, 500, "Empty presentity URI");
1807                 return;
1808         }
1809
1810         if(event.s == NULL || event.len == 0) {
1811                 LM_ERR("empty event parameter\n");
1812                 rpc->fault(ctx, 500, "Empty event parameter");
1813                 return;
1814         }
1815         LM_DBG("uri '%.*s' - event '%.*s'\n", pres_uri.len, pres_uri.s,
1816                         event.len, event.s);
1817
1818         if(ki_pres_update_watchers(NULL, &pres_uri, &event)<0) {
1819                 rpc->fault(ctx, 500, "Processing error");
1820                 return;
1821         }
1822 }
1823
1824 static const char *rpc_presence_update_watchers_doc[2] = {
1825                 "Trigger update of watchers", 0};
1826
1827
1828 void rpc_presence_cleanup(rpc_t *rpc, void *c)
1829 {
1830         LM_DBG("rpc_presence_cleanup:start\n");
1831
1832         (void)msg_watchers_clean(0, 0);
1833         (void)msg_presentity_clean(0, 0);
1834         (void)timer_db_update(0, 0);
1835
1836         rpc->rpl_printf(c, "Reload OK");
1837         return;
1838 }
1839
1840 static const char *rpc_presence_cleanup_doc[2] = {
1841                 "Manually triggers the cleanup functions for the active_watchers, "
1842                 "presentity, and watchers tables.",
1843                 0};
1844
1845 rpc_export_t presence_rpc[] = {
1846                 {"presence.cleanup", rpc_presence_cleanup, rpc_presence_cleanup_doc, 0},
1847                 {"presence.refreshWatchers", rpc_presence_refresh_watchers,
1848                                 rpc_presence_refresh_watchers_doc, 0},
1849                 {"presence.updateWatchers", rpc_presence_update_watchers,
1850                                 rpc_presence_update_watchers_doc, 0},
1851                 {0, 0, 0, 0}};
1852
1853 static int presence_init_rpc(void)
1854 {
1855         if(rpc_register_array(presence_rpc) != 0) {
1856                 LM_ERR("failed to register RPC commands\n");
1857                 return -1;
1858         }
1859         return 0;
1860 }
1861
1862 static int sip_uri_case_sensitive_match(str *s1, str *s2)
1863 {
1864         if(!s1) {
1865                 LM_ERR("null pointer (s1) in sip_uri_match\n");
1866                 return -1;
1867         }
1868         if(!s2) {
1869                 LM_ERR("null pointer (s2) in sip_uri_match\n");
1870                 return -1;
1871         }
1872         return strncmp(s1->s, s2->s, s2->len);
1873 }
1874
1875 static int sip_uri_case_insensitive_match(str *s1, str *s2)
1876 {
1877         if(!s1) {
1878                 LM_ERR("null pointer (s1) in sip_uri_match\n");
1879                 return -1;
1880         }
1881         if(!s2) {
1882                 LM_ERR("null pointer (s2) in sip_uri_match\n");
1883                 return -1;
1884         }
1885         return strncasecmp(s1->s, s2->s, s2->len);
1886 }
1887
1888 static int fixup_has_subscribers(void **param, int param_no)
1889 {
1890         if(param_no == 1) {
1891                 return fixup_spve_null(param, 1);
1892         } else if(param_no == 2) {
1893                 return fixup_spve_null(param, 1);
1894         }
1895
1896         return 0;
1897 }
1898
1899 static int ki_pres_has_subscribers(sip_msg_t *msg, str *pres_uri, str *wevent)
1900 {
1901         pres_ev_t *ev;
1902
1903         ev = contains_event(wevent, NULL);
1904         if(ev == NULL) {
1905                 LM_ERR("event is not registered\n");
1906                 return -1;
1907         }
1908
1909         return get_subscribers_count(msg, *pres_uri, *wevent) > 0 ? 1 : -1;
1910 }
1911
1912 static int w_pres_has_subscribers(sip_msg_t *msg, char *_pres_uri, char *_event)
1913 {
1914         str presentity_uri, watched_event;
1915
1916         if(fixup_get_svalue(msg, (gparam_p)_pres_uri, &presentity_uri) != 0) {
1917                 LM_ERR("invalid presentity_uri parameter");
1918                 return -1;
1919         }
1920         if(fixup_get_svalue(msg, (gparam_p)_event, &watched_event) != 0) {
1921                 LM_ERR("invalid watched_event parameter");
1922                 return -1;
1923         }
1924
1925         return ki_pres_has_subscribers(msg, &presentity_uri, &watched_event);
1926 }
1927
1928 /**
1929  *
1930  */
1931 /* clang-format off */
1932 static sr_kemi_t sr_kemi_presence_exports[] = {
1933         { str_init("presence"), str_init("handle_publish"),
1934                 SR_KEMIP_INT, ki_handle_publish,
1935                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1936                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1937         },
1938         { str_init("presence"), str_init("handle_publish_uri"),
1939                 SR_KEMIP_INT, ki_handle_publish_uri,
1940                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1941                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1942         },
1943         { str_init("presence"), str_init("handle_subscribe"),
1944                 SR_KEMIP_INT, handle_subscribe0,
1945                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1946                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1947         },
1948         { str_init("presence"), str_init("handle_subscribe_uri"),
1949                 SR_KEMIP_INT, handle_subscribe_uri,
1950                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
1951                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1952         },
1953         { str_init("presence"), str_init("pres_refresh_watchers"),
1954                 SR_KEMIP_INT, ki_pres_refresh_watchers,
1955                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
1956                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1957         },
1958         { str_init("presence"), str_init("pres_refresh_watchers_file"),
1959                 SR_KEMIP_INT, ki_pres_refresh_watchers_file,
1960                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_INT,
1961                         SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE }
1962         },
1963         { str_init("presence"), str_init("pres_update_watchers"),
1964                 SR_KEMIP_INT, ki_pres_update_watchers,
1965                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
1966                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1967         },
1968         { str_init("presence"), str_init("pres_has_subscribers"),
1969                 SR_KEMIP_INT, ki_pres_has_subscribers,
1970                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
1971                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1972         },
1973         { str_init("presence"), str_init("pres_auth_status"),
1974                 SR_KEMIP_INT, ki_pres_auth_status,
1975                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
1976                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1977         },
1978
1979         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1980 };
1981 /* clang-format on */
1982
1983 /**
1984  *
1985  */
1986 int mod_register(char *path, int *dlflags, void *p1, void *p2)
1987 {
1988         sr_kemi_modules_add(sr_kemi_presence_exports);
1989         return 0;
1990 }