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