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