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