presence_xml: use common prefix for global variables
[sip-router] / src / modules / presence_xml / presence_xml.c
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  */
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
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
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
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
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
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
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
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
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
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
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
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
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  */
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 }