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