2 * Copyright (C) 2006 Voice Sistem S.R.L.
4 * This file is part of Kamailio, a free SIP server.
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
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.
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
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.
33 * \brief Kamailio presence module :: Core
41 #include <sys/types.h>
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"
67 #include "subscribe.h"
68 #include "event_list.h"
69 #include "bind_presence.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"
80 #define S_TABLE_VERSION 3
81 #define P_TABLE_VERSION 5
82 #define ACTWATCH_TABLE_VERSION 12
84 static int pres_clean_period = 100;
85 static int pres_db_update_period = 100;
86 int pres_local_log_level = L_INFO;
88 static char *pres_log_facility_str =
89 0; /*!< Syslog: log facility that is used */
90 int pres_local_log_facility;
92 /* database connection */
93 db1_con_t *pa_db = NULL;
95 str presentity_table = str_init("presentity");
96 str active_watchers_table = str_init("active_watchers");
97 str watchers_table = str_init("watchers");
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;
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);
115 /* SL API structure */
118 /** module functions */
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);
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);
142 int pres_counter = 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;
170 int pres_db_table_lock_type = 1;
171 db_locking_t pres_db_table_lock = DB_LOCKING_WRITE;
173 int *pres_notifier_id = NULL;
175 int phtable_size = 9;
176 phtable_t *pres_htable = NULL;
180 /* clang-format off */
181 static cmd_export_t cmds[]=
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,
205 /* clang-format on */
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},
249 /* clang-format on */
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 }
259 /* clang-format on */
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 */
275 /* clang-format on */
278 * init module function
280 static int mod_init(void)
282 if(pres_uri_match == 1) {
283 presence_sip_uri_match = sip_uri_case_insensitive_match;
285 presence_sip_uri_match = sip_uri_case_sensitive_match;
288 if(presence_init_rpc() != 0) {
289 LM_ERR("failed to register RPC commands\n");
293 LM_DBG("db_url=%s (len=%d addr=%p)\n", ZSW(pres_db_url.s), pres_db_url.len,
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;
301 pres_evlist = init_evlist();
303 LM_ERR("unsuccessful initialize event list\n");
307 if(pres_library_mode == 1) {
308 LM_DBG("Presence module used for API library purpose only\n");
312 if(sruid_init(&pres_sruid, '-', "pres", SRUID_INC) < 0) {
316 if(pres_expires_offset < 0) {
317 pres_expires_offset = 0;
320 if(pres_max_expires <= 0) {
321 pres_max_expires = 3600;
324 if(pres_min_expires > pres_max_expires) {
325 pres_min_expires = pres_max_expires;
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");
334 if(pres_server_address.s == NULL || pres_server_address.len==0) {
335 LM_DBG("server_address parameter not set in configuration file\n");
338 /* bind the SL API */
339 if(sl_load_api(&slb) != 0) {
340 LM_ERR("cannot bind to SL API\n");
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");
350 if(pres_db_url.s == NULL) {
351 LM_ERR("database url not set!\n");
355 /* binding to database module */
356 if(db_bind_mod(&pres_db_url, &pa_dbf)) {
357 LM_ERR("Database module not found\n");
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");
367 pa_db = pa_dbf.init(&pres_db_url);
369 LM_ERR("Connection to database failed\n");
373 /*verify table versions */
374 if((db_check_table_version(
375 &pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION)
377 || (db_check_table_version(
378 &pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION)
380 DB_TABLE_VERSION_ERROR(presentity_table);
384 if(pres_subs_dbmode != NO_DB
385 && db_check_table_version(&pa_dbf, pa_db, &active_watchers_table,
386 ACTWATCH_TABLE_VERSION)
388 DB_TABLE_VERSION_ERROR(active_watchers_table);
392 if(pres_subs_dbmode != DB_ONLY) {
396 shtable_size = 1 << shtable_size;
398 subs_htable = new_shtable(shtable_size);
399 if(subs_htable == NULL) {
400 LM_ERR(" initializing subscribe hash table\n");
403 if(restore_db_subs() < 0) {
404 LM_ERR("restoring subscribe info from database\n");
409 if(publ_cache_mode==PS_PCACHE_HYBRID || publ_cache_mode==PS_PCACHE_RECORD) {
413 phtable_size = 1 << phtable_size;
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");
423 if(pres_htable_restore() < 0) {
424 LM_ERR("filling in presentity hash table from database\n");
427 } else if(publ_cache_mode==PS_PCACHE_RECORD) {
428 if(ps_ptable_init(phtable_size) < 0) {
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);
439 sr_wtimer_add(msg_presentity_clean, 0, pres_clean_period);
440 sr_wtimer_add(msg_watchers_clean, 0, pres_clean_period);
444 if(pres_db_update_period > 0) {
445 if(pres_timer_mode==0) {
446 register_timer(timer_db_update, 0, pres_db_update_period);
448 sr_wtimer_add(timer_db_update, 0, pres_db_update_period);
452 if(pres_waitn_time <= 0) {
456 if(pres_notifier_poll_rate <= 0) {
457 pres_notifier_poll_rate = 10;
460 if(pres_notifier_processes < 0 || pres_subs_dbmode != DB_ONLY) {
461 pres_notifier_processes = 0;
464 if(pres_notifier_processes > 0) {
465 if((pres_notifier_id =
466 shm_malloc(sizeof(int) * pres_notifier_processes))
468 LM_ERR("allocating shared memory\n");
472 register_basic_timers(pres_notifier_processes);
475 if(pres_force_delete > 0)
476 pres_force_delete = 1;
478 if(pres_log_facility_str) {
479 int tmp = str2facility(pres_log_facility_str);
482 pres_local_log_facility = tmp;
484 LM_ERR("invalid log facility configured\n");
488 pres_local_log_facility = cfg_get(core, core_cfg, log_facility);
491 if(pres_db_table_lock_type != 1) {
492 pres_db_table_lock = DB_LOCKING_NONE;
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 */
502 if(pres_enable_dmq > 0 && pres_dmq_initialize() != 0) {
503 LM_ERR("failed to initialize dmq integration\n");
516 * Initialize children
518 static int child_init(int rank)
520 if(rank == PROC_INIT || rank == PROC_TCP_MAIN) {
526 if(pres_library_mode) {
530 if(sruid_init(&pres_sruid, '-', "pres", SRUID_INC) < 0) {
534 if(rank == PROC_MAIN) {
537 for(i = 0; i < pres_notifier_processes; i++) {
539 snprintf(tmp, 21, "PRESENCE NOTIFIER %d", i);
540 pres_notifier_id[i] = i;
542 if(fork_basic_utimer(PROC_TIMER, tmp, 1, pres_timer_send_notify,
543 &pres_notifier_id[i], 1000000 / pres_notifier_poll_rate)
545 LM_ERR("Failed to start PRESENCE NOTIFIER %d\n", i);
553 if(pa_dbf.init == 0) {
554 LM_CRIT("child_init: database not bound\n");
557 /* Do not pool the connections where possible when running notifier
559 if(pres_notifier_processes > 0 && pa_dbf.init2)
560 pa_db = pa_dbf.init2(&pres_db_url, DB_POOLING_NONE);
562 pa_db = pa_dbf.init(&pres_db_url);
564 LM_ERR("child %d: unsuccessful connecting to database\n", rank);
568 if(pa_dbf.use_table(pa_db, &presentity_table) < 0) {
569 LM_ERR("child %d:unsuccessful use_table presentity_table\n", rank);
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);
578 if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
579 LM_ERR("child %d:unsuccessful use_table watchers_table\n", rank);
583 LM_DBG("child %d: Database connection opened successfully\n", rank);
592 static void destroy(void)
594 if(subs_htable && pres_subs_dbmode == WRITE_BACK) {
595 /* open database connection */
596 pa_db = pa_dbf.init(&pres_db_url);
598 LM_ERR("mod_destroy: unsuccessful connecting to database\n");
600 timer_db_update(0, 0);
604 destroy_shtable(subs_htable, shtable_size);
611 if(pa_db && pa_dbf.close) {
615 if(pres_notifier_id != NULL) {
616 shm_free(pres_notifier_id);
624 static int fixup_presence(void **param, int param_no)
626 if(pres_library_mode) {
627 LM_ERR("Bad config - you can not call 'handle_publish' function"
628 " (db_url not set)\n");
634 return fixup_spve_null(param, 1);
637 static int fixup_subscribe(void **param, int param_no)
640 if(pres_library_mode) {
641 LM_ERR("Bad config - you can not call 'handle_subscribe' function"
642 " (db_url not set)\n");
646 return fixup_spve_null(param, 1);
651 int pres_refresh_watchers(
652 str *pres, str *event, int type, str *file_uri, str *filename)
656 str *rules_doc = NULL;
659 ev = contains_event(event, NULL);
661 LM_ERR("wrong event parameter\n");
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");
673 if(parse_uri(pres->s, pres->len, &uri) < 0) {
674 LM_ERR("parsing uri [%.*s]\n", pres->len, pres->s);
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");
684 if(update_watchers_status(pres, ev, rules_doc) < 0) {
685 LM_ERR("failed to update watchers\n");
689 pkg_free(rules_doc->s);
695 if(update_hard_presentity(pres, ev, file_uri, filename) < 0) {
696 LM_ERR("updating hard presentity\n");
701 /* if a request to refresh notified info */
702 if(query_db_notify(pres, ev, NULL) < 0) {
703 LM_ERR("sending Notify requests\n");
712 pkg_free(rules_doc->s);
718 int _api_pres_refresh_watchers(str *pres, str *event, int type)
720 return pres_refresh_watchers(pres, event, type, NULL, NULL);
723 int ki_pres_refresh_watchers(sip_msg_t *msg, str *pres, str *event, int type)
725 return pres_refresh_watchers(pres, event, type, NULL, NULL);
728 int ki_pres_refresh_watchers_file(sip_msg_t *msg, str *pres, str *event,
729 int type, str *file_uri, str *filename)
731 return pres_refresh_watchers(pres, event, type, file_uri, filename);
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)
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;
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;
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;
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;
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;
762 status = subs->status;
763 if(subs->event->get_auth_status(subs) < 0) {
764 LM_ERR("getting status from rules document\n");
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);
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;
780 update_vals[u_status_col].val.int_val = subs->status;
781 update_vals[u_reason_col].val.str_val = subs->reason;
783 if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
784 LM_ERR("in use_table\n");
788 if(pa_dbf.update(pa_db, query_cols, 0, query_vals, update_cols,
789 update_vals, n_query_cols, n_update_cols)
791 LM_ERR("in sql update\n");
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);
808 int pres_db_delete_status(subs_t *s)
810 int n_query_cols = 0;
811 db_key_t query_cols[5];
812 db_val_t query_vals[5];
814 if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
815 LM_ERR("sql use table failed\n");
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;
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;
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;
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;
843 if(pa_dbf.delete(pa_db, query_cols, 0, query_vals, n_query_cols) < 0) {
844 LM_ERR("sql delete failed\n");
850 int update_watchers_status(str *pres_uri, pres_ev_t *ev, str *rules_doc)
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;
860 str w_user, w_domain, reason = {0, 0};
862 int status_col, w_user_col, w_domain_col, reason_col;
863 subs_t *subs_array = NULL, *s;
864 unsigned int hash_code;
876 ws_t *ws_list = NULL;
880 if(ev->content_type.s == NULL) {
881 ev = contains_event(&ev->name, NULL);
883 LM_ERR("wrong event parameter\n");
888 memset(&subs, 0, sizeof(subs_t));
889 subs.pres_uri = *pres_uri;
891 subs.auth_rules_doc = rules_doc;
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;
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;
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;
911 if(pa_dbf.use_table(pa_db, &watchers_table) < 0) {
912 LM_ERR("in use_table\n");
916 if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
917 n_result_cols, 0, &result)
919 LM_ERR("in sql query\n");
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;
934 /* must do a copy as sphere_check requires database queries */
935 if(pres_sphere_enable) {
937 ws_list = (ws_t *)pkg_malloc(n * sizeof(ws_t));
938 if(ws_list == NULL) {
939 LM_ERR("No more private memory\n");
942 memset(ws_list, 0, n * sizeof(ws_t));
944 for(i = 0; i < result->n; i++) {
945 row = &result->rows[i];
946 row_vals = ROW_VALUES(row);
948 status = row_vals[status_col].val.int_val;
950 reason.s = (char *)row_vals[reason_col].val.string_val;
951 reason.len = reason.s ? strlen(reason.s) : 0;
953 w_user.s = (char *)row_vals[w_user_col].val.string_val;
954 w_user.len = strlen(w_user.s);
956 w_domain.s = (char *)row_vals[w_domain_col].val.string_val;
957 w_domain.len = strlen(w_domain.s);
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");
966 memcpy(ws_list[i].reason.s, reason.s, reason.len);
967 ws_list[i].reason.len = reason.len;
969 ws_list[i].reason.s = NULL;
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");
976 memcpy(ws_list[i].w_user.s, w_user.s, w_user.len);
977 ws_list[i].w_user.len = w_user.len;
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");
985 memcpy(ws_list[i].w_domain.s, w_domain.s, w_domain.len);
986 ws_list[i].w_domain.len = w_domain.len;
988 ws_list[i].status = status;
991 pa_dbf.free_result(pa_db, result);
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));
1000 if(pres_update_status(&subs, reason, query_cols, query_vals,
1001 n_query_cols, &subs_array)
1003 LM_ERR("failed to update watcher status\n");
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);
1020 for(i = 0; i < result->n; i++) {
1021 row = &result->rows[i];
1022 row_vals = ROW_VALUES(row);
1024 status = row_vals[status_col].val.int_val;
1026 reason.s = (char *)row_vals[reason_col].val.string_val;
1027 reason.len = reason.s ? strlen(reason.s) : 0;
1029 w_user.s = (char *)row_vals[w_user_col].val.string_val;
1030 w_user.len = strlen(w_user.s);
1032 w_domain.s = (char *)row_vals[w_domain_col].val.string_val;
1033 w_domain.len = strlen(w_domain.s);
1035 subs.watcher_user = w_user;
1036 subs.watcher_domain = w_domain;
1037 subs.status = status;
1038 memset(&subs.reason, 0, sizeof(str));
1040 if(pres_update_status(&subs, reason, query_cols, query_vals,
1041 n_query_cols, &subs_array)
1043 LM_ERR("failed to update watcher status\n");
1048 pa_dbf.free_result(pa_db, result);
1053 if(pres_notifier_processes == 0) {
1057 if(notify(s, NULL, NULL, 0, 0) < 0) {
1058 LM_ERR("sending Notify request\n");
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");
1075 free_subs_list(subs_array, PKG_MEM_TYPE, 0);
1080 pa_dbf.free_result(pa_db, result);
1081 free_subs_list(subs_array, PKG_MEM_TYPE, 0);
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);
1096 /********************************************************************************/
1098 static int update_pw_dialogs_dbonlymode(subs_t *subs, subs_t **subs_array)
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;
1122 LM_ERR("null database connection\n");
1126 if(pa_dbf.use_table(pa_db, &active_watchers_table) < 0) {
1127 LM_ERR("use table failed\n");
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;
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;
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;
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;
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;
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 /*********************************************/
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;
1187 if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols,
1188 n_result_cols, 0, &result)
1190 LM_ERR("Can't query db\n");
1192 pa_dbf.free_result(pa_db, result);
1199 nr_rows = RES_ROW_N(result);
1201 LM_DBG("found %d matching dialogs\n", nr_rows);
1204 pa_dbf.free_result(pa_db, result);
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]);
1213 memset(&s, 0, sizeof(subs_t));
1214 s.status = subs->status;
1216 s.reason.s = subs->reason.s;
1217 s.reason.len = s.reason.s ? strlen(s.reason.s) : 0; //>>>>>>>>>>
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1270 s.event = contains_event(&ev_sname, NULL);
1272 if(s.event == NULL) {
1273 LM_ERR("event not found and set to NULL\n");
1276 s.local_cseq = row_vals[r_local_cseq_col].val.int_val;
1278 s.expires = row_vals[r_expires_col].val.int_val;
1280 if(s.expires > (int)time(NULL) + pres_expires_offset)
1281 s.expires -= (int)time(NULL);
1285 s.version = row_vals[r_version_col].val.int_val;
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;
1292 cs = mem_copy_subs(&s, PKG_MEM_TYPE);
1294 LM_ERR("while copying subs_t structure\n");
1295 /* tidy up and return */
1296 pa_dbf.free_result(pa_db, result);
1300 cs->next = (*subs_array);
1306 pa_dbf.free_result(pa_db, result);
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");
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;
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;
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));
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);
1347 if(pa_dbf.update(pa_db, query_cols, 0, query_vals, db_cols, db_vals,
1348 n_query_cols, n_update_cols)
1350 LM_ERR("DB update failed\n");
1357 /********************************************************************************/
1359 static int update_pw_dialogs(
1360 subs_t *subs, unsigned int hash_code, subs_t **subs_array)
1362 subs_t *s, *ps, *cs;
1367 if(pres_subs_dbmode == DB_ONLY) {
1368 return (update_pw_dialogs_dbonlymode(subs, subs_array));
1371 lock_get(&subs_htable[hash_code].lock);
1373 ps = subs_htable[hash_code].entries;
1375 while(ps && ps->next) {
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)
1384 && presence_sip_uri_match(
1385 &s->watcher_domain, &subs->watcher_domain)
1388 s->status = subs->status;
1389 s->reason = subs->reason;
1390 s->db_flag = UPDATEDB_FLAG;
1392 cs = mem_copy_subs(s, PKG_MEM_TYPE);
1394 LM_ERR("copying subs_t structure\n");
1395 lock_release(&subs_htable[hash_code].lock);
1399 cs->expires -= (int)time(NULL);
1400 cs->next = (*subs_array);
1402 if(subs->status == TERMINATED_STATUS) {
1404 shm_free(s->contact.s);
1406 LM_DBG(" deleted terminated dialog from hash table\n");
1415 LM_DBG("found %d matching dialogs\n", i);
1416 lock_release(&subs_htable[hash_code].lock);
1421 static int w_pres_auth_status(struct sip_msg *_msg, char *_sp1, char *_sp2)
1423 str watcher_uri, presentity_uri;
1425 if(fixup_get_svalue(_msg, (gparam_t *)_sp1, &watcher_uri) != 0) {
1426 LM_ERR("invalid watcher uri parameter");
1430 if(fixup_get_svalue(_msg, (gparam_t *)_sp2, &presentity_uri) != 0) {
1431 LM_ERR("invalid presentity uri parameter");
1435 if(watcher_uri.len == 0 || watcher_uri.s == NULL) {
1436 LM_ERR("missing watcher uri\n");
1440 if(presentity_uri.len == 0 || presentity_uri.s == NULL) {
1441 LM_DBG("missing presentity uri\n");
1445 return pres_auth_status(_msg, watcher_uri, presentity_uri);
1448 int ki_pres_auth_status(sip_msg_t *msg, str *watcher_uri, str *presentity_uri)
1450 if(watcher_uri == NULL || presentity_uri == NULL) {
1451 LM_ERR("invalid parameters\n");
1454 return pres_auth_status(msg, *watcher_uri, *presentity_uri);
1457 int pres_auth_status(struct sip_msg *msg, str watcher_uri, str presentity_uri)
1462 str *rules_doc = NULL;
1466 event.s = "presence";
1469 ev = contains_event(&event, NULL);
1471 LM_ERR("event is not registered\n");
1474 if(ev->get_rules_doc == NULL) {
1475 LM_DBG("event does not require authorization");
1476 return ACTIVE_STATUS;
1478 if(parse_uri(presentity_uri.s, presentity_uri.len, &uri) < 0) {
1479 LM_ERR("failed to parse presentity uri\n");
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;
1488 if(parse_uri(watcher_uri.s, watcher_uri.len, &uri) < 0) {
1489 LM_ERR("failed to parse watcher uri\n");
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");
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;
1512 pkg_free(rules_doc->s);
1513 pkg_free(rules_doc);
1518 * wrapper for pres_refresh_watchers to use in config
1520 static int w_pres_refresh_watchers(
1521 struct sip_msg *msg, char *puri, char *pevent, char *ptype)
1527 if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri) != 0) {
1528 LM_ERR("invalid uri parameter");
1532 if(fixup_get_svalue(msg, (gparam_p)pevent, &event) != 0) {
1533 LM_ERR("invalid uri parameter");
1537 if(fixup_get_ivalue(msg, (gparam_p)ptype, &refresh_type) != 0) {
1538 LM_ERR("no type value\n");
1542 if(refresh_type == 2) {
1543 LM_ERR("Wrong number of parameters for type 2\n");
1547 if(pres_refresh_watchers(&pres_uri, &event, refresh_type, NULL, NULL) < 0)
1553 static int w_pres_refresh_watchers5(struct sip_msg *msg, char *puri,
1554 char *pevent, char *ptype, char *furi, char *fname)
1556 str pres_uri, event, file_uri, filename;
1559 if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri) != 0) {
1560 LM_ERR("invalid uri parameter");
1564 if(fixup_get_svalue(msg, (gparam_p)pevent, &event) != 0) {
1565 LM_ERR("invalid event parameter");
1569 if(fixup_get_ivalue(msg, (gparam_p)ptype, &refresh_type) != 0) {
1570 LM_ERR("no type value\n");
1574 if(fixup_get_svalue(msg, (gparam_p)furi, &file_uri) != 0) {
1575 LM_ERR("invalid file uri parameter");
1579 if(fixup_get_svalue(msg, (gparam_p)fname, &filename) != 0) {
1580 LM_ERR("invalid filename parameter");
1584 if(refresh_type != 2) {
1585 LM_ERR("Wrong number of parameters for type %d\n", refresh_type);
1589 if(pres_refresh_watchers(
1590 &pres_uri, &event, refresh_type, &file_uri, &filename)
1598 * fixup for w_pres_refresh_watchers
1600 static int fixup_refresh_watchers(void **param, int param_no)
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);
1619 * wrapper for update_watchers_status to use via kemi
1621 static int ki_pres_update_watchers(
1622 struct sip_msg *msg, str *pres_uri, str *event)
1626 str *rules_doc = NULL;
1629 ev = contains_event(event, NULL);
1631 LM_ERR("event %.*s is not registered\n", event->len, event->s);
1634 if(ev->get_rules_doc == NULL) {
1635 LM_DBG("event %.*s does not provide rules doc API\n", event->len,
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,
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);
1653 if(update_watchers_status(pres_uri, ev, rules_doc) < 0) {
1654 LM_ERR("updating watchers in presence\n");
1658 pkg_free(rules_doc->s);
1659 pkg_free(rules_doc);
1665 * wrapper for update_watchers_status to use in config
1667 static int w_pres_update_watchers(struct sip_msg *msg, char *puri, char *pevent)
1672 if(fixup_get_svalue(msg, (gparam_p)puri, &pres_uri) != 0) {
1673 LM_ERR("invalid uri parameter");
1677 if(fixup_get_svalue(msg, (gparam_p)pevent, &event) != 0) {
1678 LM_ERR("invalid uri parameter");
1681 return ki_pres_update_watchers(msg, &pres_uri, &event);
1684 * fixup for w_pres_update_watchers
1686 static int fixup_update_watchers(void **param, int param_no)
1689 return fixup_spve_null(param, 1);
1690 } else if(param_no == 2) {
1691 return fixup_spve_null(param, 1);
1697 * rpc cmd: presence.refreshWatchers
1700 * \<refresh_type> // can be: = 0 -> watchers autentification type or
1701 * != 0 -> publish type //
1703 void rpc_presence_refresh_watchers(rpc_t *rpc, void *ctx)
1705 str pres_uri = {0, 0};
1707 str file_uri = {0, 0};
1708 str filename = {0, 0};
1709 unsigned int refresh_type;
1712 LM_DBG("initiation refresh of watchers\n");
1714 pn = rpc->scan(ctx, "SSu*SS", &pres_uri, &event, &refresh_type, &file_uri,
1717 rpc->fault(ctx, 500, "Not enough parameters");
1721 if(pres_uri.s == NULL || pres_uri.len == 0) {
1722 LM_ERR("empty uri\n");
1723 rpc->fault(ctx, 500, "Empty presentity URI");
1727 if(event.s == NULL || event.len == 0) {
1728 LM_ERR("empty event parameter\n");
1729 rpc->fault(ctx, 500, "Empty event parameter");
1732 LM_DBG("event '%.*s'\n", event.len, event.s);
1734 if(refresh_type == 2) {
1736 LM_ERR("empty file uri or name parameters\n");
1737 rpc->fault(ctx, 500, "No file uri or name parameters");
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");
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");
1753 if(pres_refresh_watchers(&pres_uri, &event, refresh_type,
1754 file_uri.len ? &file_uri : NULL, filename.len ? &filename : NULL)
1756 rpc->fault(ctx, 500, "Execution failed");
1761 static const char *rpc_presence_refresh_watchers_doc[2] = {
1762 "Trigger refresh of watchers", 0};
1765 * rpc cmd: presence.updateWatchers
1769 void rpc_presence_update_watchers(rpc_t *rpc, void *ctx)
1771 str pres_uri = {0, 0};
1775 LM_DBG("init update of watchers\n");
1777 pn = rpc->scan(ctx, "SS", &pres_uri, &event);
1779 rpc->fault(ctx, 500, "Not enough parameters");
1783 if(pres_uri.s == NULL || pres_uri.len == 0) {
1784 LM_ERR("empty uri\n");
1785 rpc->fault(ctx, 500, "Empty presentity URI");
1789 if(event.s == NULL || event.len == 0) {
1790 LM_ERR("empty event parameter\n");
1791 rpc->fault(ctx, 500, "Empty event parameter");
1794 LM_DBG("uri '%.*s' - event '%.*s'\n", pres_uri.len, pres_uri.s,
1795 event.len, event.s);
1797 if(ki_pres_update_watchers(NULL, &pres_uri, &event)<0) {
1798 rpc->fault(ctx, 500, "Processing error");
1803 static const char *rpc_presence_update_watchers_doc[2] = {
1804 "Trigger update of watchers", 0};
1807 void rpc_presence_cleanup(rpc_t *rpc, void *c)
1809 LM_DBG("rpc_presence_cleanup:start\n");
1811 (void)msg_watchers_clean(0, 0);
1812 (void)msg_presentity_clean(0, 0);
1813 (void)timer_db_update(0, 0);
1815 rpc->rpl_printf(c, "Reload OK");
1819 static const char *rpc_presence_cleanup_doc[2] = {
1820 "Manually triggers the cleanup functions for the active_watchers, "
1821 "presentity, and watchers tables.",
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},
1832 static int presence_init_rpc(void)
1834 if(rpc_register_array(presence_rpc) != 0) {
1835 LM_ERR("failed to register RPC commands\n");
1841 static int sip_uri_case_sensitive_match(str *s1, str *s2)
1844 LM_ERR("null pointer (s1) in sip_uri_match\n");
1848 LM_ERR("null pointer (s2) in sip_uri_match\n");
1851 return strncmp(s1->s, s2->s, s2->len);
1854 static int sip_uri_case_insensitive_match(str *s1, str *s2)
1857 LM_ERR("null pointer (s1) in sip_uri_match\n");
1861 LM_ERR("null pointer (s2) in sip_uri_match\n");
1864 return strncasecmp(s1->s, s2->s, s2->len);
1867 static int fixup_has_subscribers(void **param, int param_no)
1870 return fixup_spve_null(param, 1);
1871 } else if(param_no == 2) {
1872 return fixup_spve_null(param, 1);
1878 static int ki_pres_has_subscribers(sip_msg_t *msg, str *pres_uri, str *wevent)
1882 ev = contains_event(wevent, NULL);
1884 LM_ERR("event is not registered\n");
1888 return get_subscribers_count(msg, *pres_uri, *wevent) > 0 ? 1 : -1;
1891 static int w_pres_has_subscribers(sip_msg_t *msg, char *_pres_uri, char *_event)
1893 str presentity_uri, watched_event;
1895 if(fixup_get_svalue(msg, (gparam_p)_pres_uri, &presentity_uri) != 0) {
1896 LM_ERR("invalid presentity_uri parameter");
1899 if(fixup_get_svalue(msg, (gparam_p)_event, &watched_event) != 0) {
1900 LM_ERR("invalid watched_event parameter");
1904 return ki_pres_has_subscribers(msg, &presentity_uri, &watched_event);
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
1958 { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1960 /* clang-format on */
1965 int mod_register(char *path, int *dlflags, void *p1, void *p2)
1967 sr_kemi_modules_add(sr_kemi_presence_exports);