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