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  * \file
24  * \brief Kamailio Presence_XML :: Core
25  * \ingroup presence_xml
26  */
27 
28 /*!
29  * \defgroup presence_xml Presence_xml :: This module implements a range
30  *   of XML-based SIP event packages for presence
31  */
32 
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <libxml/parser.h>
38 #include <time.h>
39 
40 #include "../../core/sr_module.h"
41 #include "../../core/dprint.h"
42 #include "../../core/str.h"
43 #include "../../core/ut.h"
44 #include "../../core/parser/msg_parser.h"
45 #include "../../core/parser/parse_uri.h"
46 #include "../../core/mem/mem.h"
47 #include "../presence/bind_presence.h"
48 #include "../presence/hash.h"
49 #include "../presence/notify.h"
50 #include "../xcap_client/xcap_functions.h"
51 #include "../../modules/sl/sl.h"
52 #include "../../core/mod_fix.h"
53 #include "../../core/kemi.h"
54 #include "pidf.h"
55 #include "add_events.h"
56 #include "presence_xml.h"
57 #include "pres_check.h"
58 #include "api.h"
59 
60 MODULE_VERSION
61 
62 #define S_TABLE_VERSION 4
63 
64 /** module functions */
65 
66 static int mod_init(void);
67 static int child_init(int);
68 static void destroy(void);
69 static int pxml_add_xcap_server(modparam_t type, void *val);
70 static int shm_copy_xcap_list(void);
71 static void free_xs_list(xcap_serv_t *xs_list, int mem_type);
72 static int xcap_doc_updated(int doc_type, str xid, char *doc);
73 
74 static int fixup_presxml_check(void **param, int param_no);
75 static int w_presxml_check_basic(
76 		sip_msg_t *msg, char *presentity_uri, char *status);
77 static int w_presxml_check_activities(
78 		sip_msg_t *msg, char *presentity_uri, char *activities);
79 
80 /** module variables ***/
81 presence_api_t psapi = {0};
82 
83 /* Module parameter variables */
84 str pxml_xcap_table = str_init("xcap");
85 static str pxml_db_url = str_init(DEFAULT_DB_URL);
86 int pxml_force_active = 0;
87 int pxml_force_dummy_presence = 0;
88 int pxml_integrated_xcap_server = 0;
89 xcap_serv_t *xs_list = NULL;
90 int pxml_disable_presence = 0;
91 int pxml_disable_winfo = 0;
92 int pxml_disable_bla = 1;
93 int pxml_disable_xcapdiff = 0;
94 static int pxml_passive_mode = 0;
95 str xcapauth_userdel_reason = str_init("probation");
96 
97 int pxml_force_single_body = 0;
98 str pxml_single_body_priorities = str_init("Available|Ringing|On the Phone");
99 str pxml_single_body_lookup_element = str_init("note");
100 
101 /** SL API structure */
102 sl_api_t slb;
103 
104 /* database connection */
105 db1_con_t *pxml_db = NULL;
106 db_func_t pxml_dbf;
107 
108 /* functions imported from xcap_client module */
109 
110 xcapGetNewDoc_t xcap_GetNewDoc;
111 
112 /* clang-format off */
113 static cmd_export_t cmds[]={
114 	{ "pres_check_basic",		(cmd_function)w_presxml_check_basic, 2,
115 		fixup_presxml_check, 0, ANY_ROUTE},
116 	{ "pres_check_activities",	(cmd_function)w_presxml_check_activities, 2,
117 		fixup_presxml_check, 0, ANY_ROUTE},
118 	{ "bind_presence_xml",		(cmd_function)bind_presence_xml, 1,
119 		0, 0, 0},
120 	{ 0, 0, 0, 0, 0, 0}
121 };
122 /* clang-format on */
123 
124 /* clang-format off */
125 static param_export_t params[]={
126 	{ "db_url",		PARAM_STR, &pxml_db_url},
127 	{ "xcap_table",		PARAM_STR, &pxml_xcap_table},
128 	{ "force_active",	INT_PARAM, &pxml_force_active },
129 	{ "integrated_xcap_server", INT_PARAM, &pxml_integrated_xcap_server},
130 	{ "xcap_server",     	PARAM_STRING|USE_FUNC_PARAM,(void*)pxml_add_xcap_server},
131 	{ "disable_presence",	INT_PARAM, &pxml_disable_presence },
132 	{ "disable_winfo",		INT_PARAM, &pxml_disable_winfo },
133 	{ "disable_bla",		INT_PARAM, &pxml_disable_bla },
134 	{ "disable_xcapdiff",	INT_PARAM, &pxml_disable_xcapdiff },
135 	{ "passive_mode",		INT_PARAM, &pxml_passive_mode },
136 	{ "xcapauth_userdel_reason", PARAM_STR, &xcapauth_userdel_reason},
137 	{ "force_dummy_presence",       INT_PARAM, &pxml_force_dummy_presence },
138 	{ "force_presence_single_body", INT_PARAM, &pxml_force_single_body },
139 	{ "presence_single_body_priorities",  PARAM_STR, &pxml_single_body_priorities },
140 	{ "presence_single_body_lookup_element", PARAM_STR, &pxml_single_body_lookup_element },
141 	{ 0, 0, 0}
142 };
143 /* clang-format on */
144 
145 /** module exports */
146 /* clang-format off */
147 struct module_exports exports= {
148 	"presence_xml",		/* module name */
149 	DEFAULT_DLFLAGS,	/* dlopen flags */
150 	cmds,				/* exported functions */
151 	params,				/* exported parameters */
152 	0,					/* RPC method exports */
153 	0,					/* exported pseudo-variables */
154 	0,					/* response handling function */
155 	mod_init,			/* module initialization function */
156 	child_init,			/* per-child init function */
157 	destroy				/* module destroy function */
158 };
159 /* clang-format on */
160 
161 /**
162  * init module function
163  */
mod_init(void)164 static int mod_init(void)
165 {
166 	if(pxml_passive_mode == 1) {
167 		return 0;
168 	}
169 
170 	LM_DBG("db_url=%s (len=%d addr=%p)\n", ZSW(pxml_db_url.s),
171 			pxml_db_url.len, pxml_db_url.s);
172 
173 	/* bind the SL API */
174 	if(sl_load_api(&slb) != 0) {
175 		LM_ERR("cannot bind to SL API\n");
176 		return -1;
177 	}
178 
179 	if(presence_load_api(&psapi) != 0) {
180 		LM_ERR("cannot bind to presence api\n");
181 		return -1;
182 	}
183 
184 	if(psapi.add_event == NULL || psapi.update_watchers_status == NULL) {
185 		LM_ERR("requited presence api not available\n");
186 		return -1;
187 	}
188 	if(xml_add_events() < 0) {
189 		LM_ERR("adding xml events\n");
190 		return -1;
191 	}
192 
193 	if(pxml_force_active == 0) {
194 		/* binding to mysql module  */
195 		if(db_bind_mod(&pxml_db_url, &pxml_dbf)) {
196 			LM_ERR("Database module not found\n");
197 			return -1;
198 		}
199 
200 		if(!DB_CAPABILITY(pxml_dbf, DB_CAP_ALL)) {
201 			LM_ERR("Database module does not implement all functions"
202 				   " needed by the module\n");
203 			return -1;
204 		}
205 
206 		pxml_db = pxml_dbf.init(&pxml_db_url);
207 		if(!pxml_db) {
208 			LM_ERR("while connecting to database\n");
209 			return -1;
210 		}
211 
212 		if(db_check_table_version(
213 				   &pxml_dbf, pxml_db, &pxml_xcap_table, S_TABLE_VERSION)
214 				< 0) {
215 			DB_TABLE_VERSION_ERROR(pxml_xcap_table);
216 			goto dberror;
217 		}
218 		if(!pxml_integrated_xcap_server) {
219 			xcap_api_t xcap_api;
220 			bind_xcap_t bind_xcap;
221 
222 			/* bind xcap */
223 			bind_xcap = (bind_xcap_t)find_export("bind_xcap", 1, 0);
224 			if(!bind_xcap) {
225 				LM_ERR("Can't bind xcap_client\n");
226 				goto dberror;
227 			}
228 
229 			if(bind_xcap(&xcap_api) < 0) {
230 				LM_ERR("Can't bind xcap_api\n");
231 				goto dberror;
232 			}
233 			xcap_GetNewDoc = xcap_api.getNewDoc;
234 			if(xcap_GetNewDoc == NULL) {
235 				LM_ERR("can't import getNewDoc from xcap_client module\n");
236 				goto dberror;
237 			}
238 
239 			if(xcap_api.register_xcb(PRES_RULES, xcap_doc_updated) < 0) {
240 				LM_ERR("registering xcap callback function\n");
241 				goto dberror;
242 			}
243 		}
244 	}
245 
246 	if(shm_copy_xcap_list() < 0) {
247 		LM_ERR("copying xcap server list in share memory\n");
248 		return -1;
249 	}
250 
251 	if(pxml_db)
252 		pxml_dbf.close(pxml_db);
253 	pxml_db = NULL;
254 
255 	return 0;
256 
257 dberror:
258 	pxml_dbf.close(pxml_db);
259 	pxml_db = NULL;
260 	return -1;
261 }
262 
child_init(int rank)263 static int child_init(int rank)
264 {
265 	LM_DBG("[%d]  pid [%d]\n", rank, getpid());
266 
267 	if(pxml_passive_mode == 1) {
268 		return 0;
269 	}
270 
271 	if(rank == PROC_INIT || rank == PROC_MAIN || rank == PROC_TCP_MAIN)
272 		return 0; /* do nothing for the main process */
273 
274 	if(pxml_force_active == 0) {
275 		if(pxml_db)
276 			return 0;
277 		pxml_db = pxml_dbf.init(&pxml_db_url);
278 		if(pxml_db == NULL) {
279 			LM_ERR("while connecting database\n");
280 			return -1;
281 		}
282 		if(pxml_dbf.use_table(pxml_db, &pxml_xcap_table) < 0) {
283 			LM_ERR("in use_table SQL operation\n");
284 			return -1;
285 		}
286 	}
287 
288 	LM_DBG("child %d: Database connection opened successfully\n", rank);
289 
290 	return 0;
291 }
292 
destroy(void)293 static void destroy(void)
294 {
295 	LM_DBG("start\n");
296 	if(pxml_db && pxml_dbf.close)
297 		pxml_dbf.close(pxml_db);
298 
299 	free_xs_list(xs_list, SHM_MEM_TYPE);
300 
301 	return;
302 }
303 
pxml_add_xcap_server(modparam_t type,void * val)304 static int pxml_add_xcap_server(modparam_t type, void *val)
305 {
306 	xcap_serv_t *xs;
307 	int size;
308 	char *serv_addr = (char *)val;
309 	char *sep = NULL;
310 	unsigned int port = 80;
311 	str serv_addr_str;
312 
313 	serv_addr_str.s = serv_addr;
314 	serv_addr_str.len = strlen(serv_addr);
315 
316 	sep = strchr(serv_addr, ':');
317 	if(sep) {
318 		char *sep2 = NULL;
319 		str port_str;
320 
321 		sep2 = strchr(sep + 1, ':');
322 		if(sep2)
323 			sep = sep2;
324 
325 
326 		port_str.s = sep + 1;
327 		port_str.len = serv_addr_str.len - (port_str.s - serv_addr);
328 
329 		if(str2int(&port_str, &port) < 0) {
330 			LM_ERR("while converting string to int\n");
331 			goto error;
332 		}
333 		if(port < 1 || port > 65535) {
334 			LM_ERR("wrong port number\n");
335 			goto error;
336 		}
337 		*sep = '\0';
338 		serv_addr_str.len = sep - serv_addr;
339 	}
340 
341 	size = sizeof(xcap_serv_t) + (serv_addr_str.len + 1) * sizeof(char);
342 	xs = (xcap_serv_t *)pkg_malloc(size);
343 	if(xs == NULL) {
344 		ERR_MEM(PKG_MEM_STR);
345 	}
346 	memset(xs, 0, size);
347 	size = sizeof(xcap_serv_t);
348 
349 	xs->addr = (char *)xs + size;
350 	strcpy(xs->addr, serv_addr);
351 
352 	xs->port = port;
353 	/* check for duplicates */
354 	xs->next = xs_list;
355 	xs_list = xs;
356 	return 0;
357 
358 error:
359 	free_xs_list(xs_list, PKG_MEM_TYPE);
360 	return -1;
361 }
362 
shm_copy_xcap_list(void)363 static int shm_copy_xcap_list(void)
364 {
365 	xcap_serv_t *xs, *shm_xs, *prev_xs;
366 	int size;
367 
368 	xs = xs_list;
369 	if(xs == NULL) {
370 		if(pxml_force_active == 0 && !pxml_integrated_xcap_server) {
371 			LM_ERR("no xcap_server parameter set\n");
372 			return -1;
373 		}
374 		return 0;
375 	}
376 	xs_list = NULL;
377 	size = sizeof(xcap_serv_t);
378 
379 	while(xs) {
380 		size += (strlen(xs->addr) + 1) * sizeof(char);
381 		shm_xs = (xcap_serv_t *)shm_malloc(size);
382 		if(shm_xs == NULL) {
383 			ERR_MEM(SHARE_MEM);
384 		}
385 		memset(shm_xs, 0, size);
386 		size = sizeof(xcap_serv_t);
387 
388 		shm_xs->addr = (char *)shm_xs + size;
389 		strcpy(shm_xs->addr, xs->addr);
390 		shm_xs->port = xs->port;
391 		shm_xs->next = xs_list;
392 		xs_list = shm_xs;
393 
394 		prev_xs = xs;
395 		xs = xs->next;
396 
397 		pkg_free(prev_xs);
398 	}
399 	return 0;
400 
401 error:
402 	free_xs_list(xs_list, SHM_MEM_TYPE);
403 	return -1;
404 }
405 
free_xs_list(xcap_serv_t * xsl,int mem_type)406 static void free_xs_list(xcap_serv_t *xsl, int mem_type)
407 {
408 	xcap_serv_t *xs, *prev_xs;
409 
410 	xs = xsl;
411 
412 	while(xs) {
413 		prev_xs = xs;
414 		xs = xs->next;
415 		if(mem_type & SHM_MEM_TYPE)
416 			shm_free(prev_xs);
417 		else
418 			pkg_free(prev_xs);
419 	}
420 	xsl = NULL;
421 }
422 
xcap_doc_updated(int doc_type,str xid,char * doc)423 static int xcap_doc_updated(int doc_type, str xid, char *doc)
424 {
425 	pres_ev_t ev;
426 	str rules_doc;
427 
428 	/* call updating watchers */
429 	ev.name.s = "presence";
430 	ev.name.len = PRES_LEN;
431 
432 	rules_doc.s = doc;
433 	rules_doc.len = strlen(doc);
434 
435 	if(psapi.update_watchers_status(&xid, &ev, &rules_doc) < 0) {
436 		LM_ERR("updating watchers in presence\n");
437 		return -1;
438 	}
439 	return 0;
440 }
441 
bind_presence_xml(struct presence_xml_binds * pxb)442 int bind_presence_xml(struct presence_xml_binds *pxb)
443 {
444 	if(pxb == NULL) {
445 		LM_WARN("bind_presence_xml: Cannot load presence_xml API into a NULL "
446 				"pointer\n");
447 		return -1;
448 	}
449 
450 	pxb->pres_check_basic = presxml_check_basic;
451 	pxb->pres_check_activities = presxml_check_activities;
452 	return 0;
453 }
454 
fixup_presxml_check(void ** param,int param_no)455 static int fixup_presxml_check(void **param, int param_no)
456 {
457 	if(param_no == 1) {
458 		return fixup_spve_null(param, 1);
459 	} else if(param_no == 2) {
460 		return fixup_spve_null(param, 1);
461 	}
462 	return 0;
463 }
464 
w_presxml_check_basic(sip_msg_t * msg,char * presentity_uri,char * status)465 static int w_presxml_check_basic(
466 		sip_msg_t *msg, char *presentity_uri, char *status)
467 {
468 	str uri, basic;
469 
470 	if(fixup_get_svalue(msg, (gparam_p)presentity_uri, &uri) != 0) {
471 		LM_ERR("invalid presentity uri parameter\n");
472 		return -1;
473 	}
474 
475 	if(fixup_get_svalue(msg, (gparam_p)status, &basic) != 0) {
476 		LM_ERR("invalid status parameter\n");
477 		return -1;
478 	}
479 
480 	return presxml_check_basic(msg, uri, basic);
481 }
482 
ki_presxml_check_basic(sip_msg_t * msg,str * pres_uri,str * status)483 static int ki_presxml_check_basic(sip_msg_t *msg, str *pres_uri, str *status)
484 {
485 	if(pres_uri == NULL || status == NULL) {
486 		return -1;
487 	}
488 	return presxml_check_basic(msg, *pres_uri, *status);
489 }
490 
w_presxml_check_activities(sip_msg_t * msg,char * presentity_uri,char * activity)491 static int w_presxml_check_activities(
492 		sip_msg_t *msg, char *presentity_uri, char *activity)
493 {
494 	str uri, act;
495 
496 	if(fixup_get_svalue(msg, (gparam_p)presentity_uri, &uri) != 0) {
497 		LM_ERR("invalid presentity uri parameter\n");
498 		return -1;
499 	}
500 
501 	if(fixup_get_svalue(msg, (gparam_p)activity, &act) != 0) {
502 		LM_ERR("invalid activity parameter\n");
503 		return -1;
504 	}
505 
506 	return presxml_check_activities(msg, uri, act);
507 }
508 
ki_presxml_check_activities(sip_msg_t * msg,str * pres_uri,str * activity)509 static int ki_presxml_check_activities(
510 		sip_msg_t *msg, str *pres_uri, str *activity)
511 {
512 	if(pres_uri == NULL || activity == NULL) {
513 		return -1;
514 	}
515 	return presxml_check_activities(msg, *pres_uri, *activity);
516 }
517 
518 /**
519  *
520  */
521 /* clang-format off */
522 static sr_kemi_t sr_kemi_presence_xml_exports[] = {
523 	{ str_init("presence_xml"), str_init("pres_check_basic"),
524 		SR_KEMIP_INT, ki_presxml_check_basic,
525 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
526 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
527 	},
528 	{ str_init("presence_xml"), str_init("pres_check_activities"),
529 		SR_KEMIP_INT, ki_presxml_check_activities,
530 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
531 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
532 	},
533 
534 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
535 };
536 /* clang-format on */
537 
538 /**
539  *
540  */
mod_register(char * path,int * dlflags,void * p1,void * p2)541 int mod_register(char *path, int *dlflags, void *p1, void *p2)
542 {
543 	sr_kemi_modules_add(sr_kemi_presence_xml_exports);
544 	return 0;
545 }
546