2 * Copyright (C) 2006 Voice Sistem S.R.L.
4 * This file is part of Kamailio, a free SIP server.
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 * \brief Kamailio Presence_XML :: Core
25 * \ingroup presence_xml
29 * \defgroup presence_xml Presence_xml :: This module implements a range
30 * of XML-based SIP event packages for presence
37 #include <libxml/parser.h>
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"
55 #include "add_events.h"
56 #include "presence_xml.h"
57 #include "pres_check.h"
62 #define S_TABLE_VERSION 4
64 /** module functions */
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);
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);
80 /** module variables ***/
81 presence_api_t psapi = {0};
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");
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");
101 /** SL API structure */
104 /* database connection */
105 db1_con_t *pxml_db = NULL;
108 /* functions imported from xcap_client module */
110 xcapGetNewDoc_t xcap_GetNewDoc;
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,
122 /* clang-format on */
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 },
143 /* clang-format on */
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 */
159 /* clang-format on */
162 * init module function
164 static int mod_init(void)
166 if(pxml_passive_mode == 1) {
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);
173 /* bind the SL API */
174 if(sl_load_api(&slb) != 0) {
175 LM_ERR("cannot bind to SL API\n");
179 if(presence_load_api(&psapi) != 0) {
180 LM_ERR("cannot bind to presence api\n");
184 if(psapi.add_event == NULL || psapi.update_watchers_status == NULL) {
185 LM_ERR("requited presence api not available\n");
188 if(xml_add_events() < 0) {
189 LM_ERR("adding xml events\n");
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");
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");
206 pxml_db = pxml_dbf.init(&pxml_db_url);
208 LM_ERR("while connecting to database\n");
212 if(db_check_table_version(
213 &pxml_dbf, pxml_db, &pxml_xcap_table, S_TABLE_VERSION)
215 DB_TABLE_VERSION_ERROR(pxml_xcap_table);
218 if(!pxml_integrated_xcap_server) {
220 bind_xcap_t bind_xcap;
223 bind_xcap = (bind_xcap_t)find_export("bind_xcap", 1, 0);
225 LM_ERR("Can't bind xcap_client\n");
229 if(bind_xcap(&xcap_api) < 0) {
230 LM_ERR("Can't bind xcap_api\n");
233 xcap_GetNewDoc = xcap_api.getNewDoc;
234 if(xcap_GetNewDoc == NULL) {
235 LM_ERR("can't import getNewDoc from xcap_client module\n");
239 if(xcap_api.register_xcb(PRES_RULES, xcap_doc_updated) < 0) {
240 LM_ERR("registering xcap callback function\n");
246 if(shm_copy_xcap_list() < 0) {
247 LM_ERR("copying xcap server list in share memory\n");
252 pxml_dbf.close(pxml_db);
258 pxml_dbf.close(pxml_db);
263 static int child_init(int rank)
265 LM_DBG("[%d] pid [%d]\n", rank, getpid());
267 if(pxml_passive_mode == 1) {
271 if(rank == PROC_INIT || rank == PROC_MAIN || rank == PROC_TCP_MAIN)
272 return 0; /* do nothing for the main process */
274 if(pxml_force_active == 0) {
277 pxml_db = pxml_dbf.init(&pxml_db_url);
278 if(pxml_db == NULL) {
279 LM_ERR("while connecting database\n");
282 if(pxml_dbf.use_table(pxml_db, &pxml_xcap_table) < 0) {
283 LM_ERR("in use_table SQL operation\n");
288 LM_DBG("child %d: Database connection opened successfully\n", rank);
293 static void destroy(void)
296 if(pxml_db && pxml_dbf.close)
297 pxml_dbf.close(pxml_db);
299 free_xs_list(xs_list, SHM_MEM_TYPE);
304 static int pxml_add_xcap_server(modparam_t type, void *val)
308 char *serv_addr = (char *)val;
310 unsigned int port = 80;
313 serv_addr_str.s = serv_addr;
314 serv_addr_str.len = strlen(serv_addr);
316 sep = strchr(serv_addr, ':');
321 sep2 = strchr(sep + 1, ':');
326 port_str.s = sep + 1;
327 port_str.len = serv_addr_str.len - (port_str.s - serv_addr);
329 if(str2int(&port_str, &port) < 0) {
330 LM_ERR("while converting string to int\n");
333 if(port < 1 || port > 65535) {
334 LM_ERR("wrong port number\n");
338 serv_addr_str.len = sep - serv_addr;
341 size = sizeof(xcap_serv_t) + (serv_addr_str.len + 1) * sizeof(char);
342 xs = (xcap_serv_t *)pkg_malloc(size);
344 ERR_MEM(PKG_MEM_STR);
347 size = sizeof(xcap_serv_t);
349 xs->addr = (char *)xs + size;
350 strcpy(xs->addr, serv_addr);
353 /* check for duplicates */
359 free_xs_list(xs_list, PKG_MEM_TYPE);
363 static int shm_copy_xcap_list(void)
365 xcap_serv_t *xs, *shm_xs, *prev_xs;
370 if(pxml_force_active == 0 && !pxml_integrated_xcap_server) {
371 LM_ERR("no xcap_server parameter set\n");
377 size = sizeof(xcap_serv_t);
380 size += (strlen(xs->addr) + 1) * sizeof(char);
381 shm_xs = (xcap_serv_t *)shm_malloc(size);
385 memset(shm_xs, 0, size);
386 size = sizeof(xcap_serv_t);
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;
402 free_xs_list(xs_list, SHM_MEM_TYPE);
406 static void free_xs_list(xcap_serv_t *xsl, int mem_type)
408 xcap_serv_t *xs, *prev_xs;
415 if(mem_type & SHM_MEM_TYPE)
423 static int xcap_doc_updated(int doc_type, str xid, char *doc)
428 /* call updating watchers */
429 ev.name.s = "presence";
430 ev.name.len = PRES_LEN;
433 rules_doc.len = strlen(doc);
435 if(psapi.update_watchers_status(&xid, &ev, &rules_doc) < 0) {
436 LM_ERR("updating watchers in presence\n");
442 int bind_presence_xml(struct presence_xml_binds *pxb)
445 LM_WARN("bind_presence_xml: Cannot load presence_xml API into a NULL "
450 pxb->pres_check_basic = presxml_check_basic;
451 pxb->pres_check_activities = presxml_check_activities;
455 static int fixup_presxml_check(void **param, int param_no)
458 return fixup_spve_null(param, 1);
459 } else if(param_no == 2) {
460 return fixup_spve_null(param, 1);
465 static int w_presxml_check_basic(
466 sip_msg_t *msg, char *presentity_uri, char *status)
470 if(fixup_get_svalue(msg, (gparam_p)presentity_uri, &uri) != 0) {
471 LM_ERR("invalid presentity uri parameter\n");
475 if(fixup_get_svalue(msg, (gparam_p)status, &basic) != 0) {
476 LM_ERR("invalid status parameter\n");
480 return presxml_check_basic(msg, uri, basic);
483 static int ki_presxml_check_basic(sip_msg_t *msg, str *pres_uri, str *status)
485 if(pres_uri == NULL || status == NULL) {
488 return presxml_check_basic(msg, *pres_uri, *status);
491 static int w_presxml_check_activities(
492 sip_msg_t *msg, char *presentity_uri, char *activity)
496 if(fixup_get_svalue(msg, (gparam_p)presentity_uri, &uri) != 0) {
497 LM_ERR("invalid presentity uri parameter\n");
501 if(fixup_get_svalue(msg, (gparam_p)activity, &act) != 0) {
502 LM_ERR("invalid activity parameter\n");
506 return presxml_check_activities(msg, uri, act);
509 static int ki_presxml_check_activities(
510 sip_msg_t *msg, str *pres_uri, str *activity)
512 if(pres_uri == NULL || activity == NULL) {
515 return presxml_check_activities(msg, *pres_uri, *activity);
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 }
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 }
534 { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
536 /* clang-format on */
541 int mod_register(char *path, int *dlflags, void *p1, void *p2)
543 sr_kemi_modules_add(sr_kemi_presence_xml_exports);