all: updated FSF address in GPL text
[sip-router] / modules / ims_registrar_scscf / userdata_parser.c
1 /*
2  * $Id$
3  *
4  * The initial version of this code was written by Dragos Vingarzan
5  * (dragos(dot)vingarzan(at)fokus(dot)fraunhofer(dot)de and the
6  * Fruanhofer Institute. It was and still is maintained in a separate
7  * branch of the original SER. We are therefore migrating it to
8  * Kamailio/SR and look forward to maintaining it from here on out.
9  * 2011/2012 Smile Communications, Pty. Ltd.
10  * ported/maintained/improved by 
11  * Jason Penton (jason(dot)penton(at)smilecoms.com and
12  * Richard Good (richard(dot)good(at)smilecoms.com) as part of an 
13  * effort to add full IMS support to Kamailio/SR using a new and
14  * improved architecture
15  * 
16  * NB: Alot of this code was originally part of OpenIMSCore,
17  * FhG Fokus. 
18  * Copyright (C) 2004-2006 FhG Fokus
19  * Thanks for great work! This is an effort to 
20  * break apart the various CSCF functions into logically separate
21  * components. We hope this will drive wider use. We also feel
22  * that in this way the architecture is more complete and thereby easier
23  * to manage in the Kamailio/SR environment
24  *
25  * This file is part of Kamailio, a free SIP server.
26  *
27  * Kamailio is free software; you can redistribute it and/or modify
28  * it under the terms of the GNU General Public License as published by
29  * the Free Software Foundation; either version 2 of the License, or
30  * (at your option) any later version
31  *
32  * Kamailio is distributed in the hope that it will be useful,
33  * but WITHOUT ANY WARRANTY; without even the implied warranty of
34  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
35  * GNU General Public License for more details.
36  *
37  * You should have received a copy of the GNU General Public License 
38  * along with this program; if not, write to the Free Software 
39  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
40  * 
41  */
42
43 #include "../../parser/parse_uri.h"
44 #include "userdata_parser.h"
45 #include "../../parser/parse_hname2.h"
46
47 int ctxtInit=0;                                                 /**< the XML context            */
48 static xmlDtdPtr dtd;
49 static xmlValidCtxtPtr dtdCtxt;
50 static xmlSchemaValidCtxtPtr xsdCtxt=0; /**< Schema Validating context */
51 static xmlSchemaPtr xsd;
52
53 /**
54  *      Duplicate a string into shm and trim leading&trailing spaces and surrounding quotes.
55  * @param dest - destination
56  * @param src - source
57  */
58 void space_quotes_trim_dup(str *dest,char * src) {
59         int i = 0;
60         //right space trim
61         if (src == NULL) return ;
62         dest->len = strlen(src);
63         i = dest->len - 1;
64         while((src[i] == ' '||src[i]=='\t') && i > 0) {
65                 dest->len--;
66                 i--;
67         }
68         //left space trim
69         i = 0;
70         while((src[i] == ' '||src[i]=='\t') && i<dest->len)
71                 i++;
72
73         while(i<dest->len &&(src[i]=='\"'&&src[dest->len-1]=='\"')){
74                 i++;
75                 if (i<dest->len) dest->len--;
76         }
77
78         dest->len -= i;
79         if (dest->len<=0) return;
80         dest->s = shm_malloc(dest->len);
81         memcpy(dest->s, src+i , dest->len);
82 }
83
84 /**
85  * Converts strings to integer values.
86  * - False -> 0
87  * - True  -> 1
88  * @param x - input value
89  * @returns int value
90  */
91 static inline char ifc_tBool2char(xmlChar *x)
92 {
93         int r=0;        
94         while(x[r]){
95                 switch(x[r]){
96                         case '0': return 0;
97                         case '1': return 1;
98                         case 't': case 'T': return 1;
99                         case 'f': case 'F': return 0;
100                 }
101                 r++;
102         }
103         return 0;
104 }
105
106 /**
107  * Converts strings to integer values.
108  * - SESSION_CONTINUED   -> 0
109  * - SESSION_TERMINATED  -> 1
110  * @param x - input value
111  * @returns int value
112  */
113 static inline char ifc_tDefaultHandling2char(xmlChar *x)
114 {
115         char r; 
116         r = strtol((char*)x, (char **)NULL, 10);
117         if (errno==EINVAL){
118                 while(x[0]){
119                         if (x[0]=='c'||x[0]=='C') return 0;//SESSION_CONTINUED
120                         if (x[0]=='r'||x[0]=='R') return 1;//SESSION_TERMINATED
121                         x++;
122                 }
123                 return 0;
124         } 
125         else return (char)r; 
126 }
127
128 /**
129  * Converts strings to integer values.
130  * - ORIGINATING_SESSION      -> 0
131  * - TERMINATING_REGISTERED   -> 1
132  * - TERMINATING_UNREGISTERED -> 2
133  * @param x - input value
134  * @returns int value
135  */
136 static inline char ifc_tDirectionOfRequest2char(xmlChar *x)
137 {
138         int r;  
139         r = strtol((char*)x, (char **)NULL, 10);
140         if (errno==EINVAL){
141                 while(x[0]){
142                         if (x[0]=='o'||x[0]=='O') return 0;//ORIGINATING_SESSION
143                         if (x[0]=='s'||x[0]=='S') return 1;//TERMINATING_REGISTERED
144                         if (x[0]=='u'||x[0]=='U') return 2;//TERMINATING_UNREGISTERED
145                         x++;
146                 }
147                 return 0;
148         } 
149         else return (char)r; 
150 }
151
152 /**
153  * Converts strings to integer values.
154  * - REGISTERED     -> 0
155  * - UNREGISTERED   -> 1
156  * - error (any)         -> -1
157  * @param x - input value
158  * @returns int value
159  */
160 static inline char ifc_tProfilePartIndicator2char(xmlChar *x)
161 {
162         int r;  
163         if (x==0||x[0]==0) return -1;
164         r = strtol((char*)x, (char **)NULL, 10);
165         if (errno==EINVAL){
166                 while(x[0]){
167                         if (x[0]=='r'||x[0]=='R') return 0;//REGISTERED
168                         if (x[0]=='u'||x[0]=='U') return 1;//UNREGISTERED
169                         x++;
170                 }
171                 return 0;
172         } 
173         else return (char)r; 
174 }
175
176 /**
177  * Duplicate a string into shm and trim leading&trailing spaces.
178  * @param dest - destination
179  * @param src - source
180  */
181 static inline void space_trim_dup(str *dest, char *src)
182 {
183         int i;
184         dest->s=0;
185         dest->len=0;
186         if (!src) return;
187         dest->len = strlen(src);
188         i = dest->len-1;
189         while((src[i]==' '||src[i]=='\t') && i>0) 
190                 i--;
191         i=0;
192         while((src[i]==' '||src[i]=='\t') && i<dest->len)
193                 i++;
194         dest->len -= i;
195         
196         dest->s = shm_malloc(dest->len);
197         if (!dest->s) {
198                 LM_ERR("Out of memory allocating %d bytes\n",dest->len);
199                 dest->len=0;
200                 return;
201         }
202         memcpy(dest->s,src+i,dest->len);
203 }
204
205 /**
206  *      Parse a Application Server.
207  * @param doc - the XML document
208  * @param node - the current node
209  * @param as - structure to fill
210  * @returns 1 on success, 0 on failure
211  */
212 static int parse_application_server(xmlDocPtr doc,xmlNodePtr node,ims_application_server *as)
213 {
214         xmlNodePtr child;
215         xmlChar *x;
216         as->server_name.s=NULL;as->server_name.len=0;
217         as->default_handling=IFC_NO_DEFAULT_HANDLING;
218         as->service_info.s=NULL;as->service_info.len=0;
219
220         for(child=node->children ; child ; child=child->next)
221                 if (child->type==XML_ELEMENT_NODE)
222                         switch (child->name[0]) {
223                                 case 'S':case 's':      {//ServerName / ServiceInfo
224                                         switch (child->name[4]) {
225                                                 case 'E':case 'e':  //ServerName
226                                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
227                                                         space_trim_dup(&(as->server_name),(char*)x);
228                                                         xmlFree((char*)x);
229                                                         break;
230                                                 case 'I':case 'i':  //ServiceInfo
231                                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
232                                                         space_trim_dup(&(as->service_info),(char*)x);
233                                                         xmlFree(x);
234                                                         break;
235                                         }
236                                         break;
237                                 }
238                                 case 'D':case 'd': //DefaultHandling
239                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
240                                         as->default_handling=ifc_tDefaultHandling2char(x);
241                                         xmlFree(x);
242                                         break;
243                         }
244         return 1;
245 }
246
247
248 /**
249  *      Parse SPT for SIP Header.
250  * @param doc - the XML document
251  * @param node - the current node
252  * @param sh - structure to fill
253  * @returns 1 on success, 0 on failure
254  */
255 static int parse_sip_header(xmlDocPtr doc,xmlNodePtr node,ims_sip_header *sh)
256 {
257         xmlNodePtr child;
258         xmlChar *x;
259         char c[256];
260         int len;
261         struct hdr_field hf;
262         sh->header.s=NULL;sh->header.len=0;
263         sh->content.s=NULL;sh->content.len=0;
264
265         for(child=node->children ; child ; child=child->next)
266                 if (child->type==XML_ELEMENT_NODE)
267                         switch (child->name[0]) {
268                                 case 'H':case 'h':      //Header
269                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
270                                         len = strlen((char*)x);         
271                                         memcpy(c,x,len);
272                                         c[len++]=':';
273                                         c[len]=0;
274                                         space_trim_dup(&(sh->header),(char*)x);
275                                         parse_hname2(c,c+(len<4?4:len),&hf);
276                                         sh->type=(short)hf.type;
277                                         //LOG(L_CRIT,"[%.*s(%d)]\n",sh->header.len,sh->header.s,sh->type);
278                                         xmlFree(x);
279                                         break;
280                                 case 'C':case 'c':      //Content
281                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
282                                         space_quotes_trim_dup(&(sh->content),(char*)x);
283                                         xmlFree(x);
284                                         break;
285                         }
286         return 1;
287 }
288
289 /**
290  *      Parse SPT for Session Description.
291  * @param doc - the XML document
292  * @param node - the current node
293  * @param sd - structure to fill
294  * @returns 1 on success, 0 on failure
295  */
296 static int parse_session_desc(xmlDocPtr doc,xmlNodePtr node,ims_session_desc *sd)
297 {
298         xmlNodePtr child;
299         xmlChar *x;
300         sd->line.s=NULL;sd->line.len=0;
301         sd->content.s=NULL;sd->content.len=0;
302
303         for(child=node->children ; child ; child=child->next)
304                 if (child->type==XML_ELEMENT_NODE)
305                         switch (child->name[0]) {
306                                 case 'L':case 'l':      //Line
307                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
308                                         space_trim_dup(&(sd->line),(char*)x);
309                                         xmlFree(x);
310                                         break;
311                                 case 'C':case 'c':      //Content
312                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
313                                         space_quotes_trim_dup(&(sd->content),(char*)x);
314                                         xmlFree(x);
315                                         break;
316                         }
317         return 1;
318 }
319
320 /**
321  *      Parse a Service Point Trigger Extension (RegistrationType).
322  * @param doc - the XML document
323  * @param node - the current node
324  * @param spt - structure to fill
325  * @returns 1 on success, 0 on failure
326  */
327 static int parse_spt_extension(xmlDocPtr doc,xmlNodePtr node,ims_spt *spt)
328 {
329         xmlNodePtr child;
330         xmlChar *x;
331
332         for(child=node->children ; child ; child=child->next) {
333                 if (child->type==XML_ELEMENT_NODE && (child->name[0]=='R' || child->name[0]=='r')) {
334                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
335                         switch(atoi((char*)x)) {
336                                 case 0:
337                                         spt->registration_type |= IFC_INITIAL_REGISTRATION;
338                                         break;
339                                 case 1:
340                                         spt->registration_type |= IFC_RE_REGISTRATION;
341                                         break;
342                                 case 2:
343                                         spt->registration_type |= IFC_DE_REGISTRATION;
344                                         break;
345                         }                                                               
346                         xmlFree(x);
347                 }
348         }
349 //      LOG(L_CRIT,"INFO:"M_NAME":parse_spt_extension: spt->registration_type=%d\n",spt->registration_type);
350         return 1;                       
351 }
352
353 /**
354  *      Parse a Service Point Trigger.
355  * @param doc - the XML document
356  * @param node - the current node
357  * @param spt_to - structure to fill
358  * @param spt_cnt - structure to fill with the spt count
359  * @returns 1 on success, 0 on failure
360  */
361 static int parse_spt(xmlDocPtr doc,xmlNodePtr node,ims_spt *spt_to,unsigned short *spt_cnt)
362 {
363         xmlNodePtr child,saved=0;
364         xmlChar *x;
365
366         ims_spt *spt,*spt2;
367         int group;
368         
369         spt = spt_to + *spt_cnt;
370         
371         spt->condition_negated=0;
372         spt->group=0;
373         spt->type=IFC_UNKNOWN;
374         spt->registration_type=0;
375
376         for(child=node->children ; child ; child=child->next)
377                 if (child->type==XML_ELEMENT_NODE)
378                         switch (child->name[0]) {
379                                 case 'C':case 'c': //ConditionNegated
380                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
381                                         spt->condition_negated=ifc_tBool2char(x);
382                                         xmlFree(x);
383                                         break;
384                                 case 'G':case 'g': //Group
385                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
386                                         spt->group=atoi((char*)x);
387                                         xmlFree(x);
388                                         break;
389                                 case 'R':case 'r': //RequestUri
390                                         spt->type=IFC_REQUEST_URI;
391                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
392                                         space_trim_dup(&(spt->request_uri),(char*)x);
393                                         xmlFree(x);
394                                         break;
395                                 case 'E':case 'e': //Extension
396                                     parse_spt_extension(doc,child,spt);
397                                         break;
398                                 case 'M':case 'm': //method
399                                         spt->type=IFC_METHOD;
400                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
401                                         space_trim_dup(&(spt->method),(char*)x);
402                                         xmlFree(x);
403                                         break;
404                                 case 'S':case 's': {//SIPHeader/SessionCase/SessionDescription
405                                         switch(child->name[7]) {
406                                                 case 'E':case 'e'://SIP_HEADER
407                                                         spt->type=IFC_SIP_HEADER;
408                                                         parse_sip_header(doc,child,&(spt->sip_header));
409                                                         saved = child;
410                                                         break;
411                                                 case 'C':case 'c'://Session Case
412                                                         spt->type=IFC_SESSION_CASE;
413                                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
414                                                         spt->session_case=ifc_tDirectionOfRequest2char(x);
415                                                         xmlFree(x);
416                                                         break;
417                                                 case 'D':case 'd'://Session Description
418                                                         spt->type=IFC_SESSION_DESC;
419                                                         parse_session_desc(doc,child,&(spt->session_desc));
420                                                         saved = child;
421                                                         break;
422                                         }
423
424                                 }
425                                         break;
426                         }
427         *spt_cnt=*spt_cnt+1;
428
429         /* adding the other nodes for multiple groups */                        
430         for(child=node->children ; child ; child=child->next)
431                 if (child->type==XML_ELEMENT_NODE)
432                         switch (child->name[0]) {
433                                 case 'G':case 'g': //Group
434                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
435                                         group=atoi((char*)x);
436                                         xmlFree(x);
437                                         if (group != spt->group){
438                                                 spt2 = spt_to + *spt_cnt;
439                                                 spt2->condition_negated = spt->condition_negated;
440                                                 spt2->group = group;
441                                                 spt2->type = spt->type;
442                                                 switch(spt2->type){
443                                                         case IFC_REQUEST_URI:
444                                                                 spt2->request_uri.len = spt->request_uri.len;
445                                                                 spt2->request_uri.s = shm_malloc(spt2->request_uri.len);
446                                                                 if (!spt2->request_uri.s){
447                                                                         LM_ERR("Out of memory allocating %d bytes\n",spt->request_uri.len);
448                                                                         break;
449                                                                 }
450                                                                 memcpy(spt2->request_uri.s,spt->request_uri.s,spt->request_uri.len);
451                                                                 break;
452                                                         case IFC_METHOD:
453                                                                 spt2->method.len = spt->method.len;
454                                                                 spt2->method.s = shm_malloc(spt2->method.len);
455                                                                 if (!spt2->method.s){
456                                                                         LM_ERR("Out of memory allocating %d bytes\n",spt->method.len);
457                                                                         break;
458                                                                 }
459                                                                 memcpy(spt2->method.s,spt->method.s,spt->method.len);
460                                                                 break;
461                                                         case IFC_SIP_HEADER:
462                                                                 parse_sip_header(doc,saved,&(spt2->sip_header));
463                                                                 break;
464                                                         case IFC_SESSION_CASE:
465                                                                 spt2->session_case = spt->session_case;
466                                                                 break;
467                                                         case IFC_SESSION_DESC:
468                                                                 parse_session_desc(doc,saved,&(spt2->session_desc));
469                                                                 break;                                                          
470                                                 }
471                                                 spt2->registration_type = spt->registration_type;
472                                                 *spt_cnt = *spt_cnt+1;                                          
473                                         }
474                                         break;
475                         }
476         return 1;                       
477 }
478
479
480 /**
481  *      Parse a Trigger Point.
482  * @param doc - the XML document
483  * @param node - the current node
484  * @param tp - structure to fill
485  * @returns 1 on success, 0 on failure
486  * \todo An effective sort for the priority
487  */
488 static int parse_trigger_point(xmlDocPtr doc,xmlNodePtr node,ims_trigger_point *tp)
489 {
490         xmlNodePtr child,child2;
491         xmlChar *x;
492         unsigned short spt_cnt=0;
493         int i,j;
494         ims_spt spttemp;
495         tp->condition_type_cnf=IFC_DNF;//0
496         tp->spt=NULL;
497         tp->spt_cnt=0;
498
499         for(child=node->children ; child ; child=child->next)
500                 if (child->type==XML_ELEMENT_NODE)
501                         switch (child->name[0]) {
502                                 case 'C':case 'c': //ConditionTypeCNF
503                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
504                                         tp->condition_type_cnf=ifc_tBool2char(x);
505                                         xmlFree(x);
506                                         break;
507                                 case 'S':case 's': //SPT - Service Point Trigger
508                                         // COUNT all in another groups
509                                         for(child2=child->children ; child2 ; child2=child2->next)
510                                                 if (child2->type==XML_ELEMENT_NODE)
511                                                         switch (child2->name[0]) {
512                                                                 case 'G':case 'g':
513                                                                         spt_cnt++;
514                                                         }
515                                         break;
516                         }
517         tp->spt = (ims_spt*) shm_malloc(sizeof(ims_spt)*spt_cnt);
518         if (!tp->spt){
519                 LM_ERR("Out of memory allocating %lx bytes\n",sizeof(ims_spt)*spt_cnt);
520                 return 0;
521         }
522         for(child=node->children ; child ; child=child->next)
523                 if (child->type==XML_ELEMENT_NODE)
524                         switch (child->name[0]) {
525                                 case 'S':case 's': //SPT - Service Point Trigger
526                                         parse_spt(doc,child,tp->spt,&(tp->spt_cnt));
527                                         /*i=0;
528                                         while(i<tp->spt_cnt&&tp->spt[i].group<spttemp.group)
529                                                 i++;
530                                         for(j=tp->spt_cnt-1;j>=i;j--)
531                                                 tp->spt[j+1]=tp->spt[j];
532                                         tp->spt[i]=spttemp;
533                                         tp->spt_cnt++;*/
534                         
535                                         break;
536                         }
537         
538         j=1;
539         while(j){
540                 j=0;
541                 for(i=0;i<tp->spt_cnt-1;i++)
542                         if (tp->spt[i].group > tp->spt[i+1].group){
543                                 j=1;
544                                 spttemp = tp->spt[i];
545                                 tp->spt[i]=tp->spt[i+1];
546                                 tp->spt[i+1]=spttemp;
547                         }                       
548         }
549         return 1;
550 }
551
552 /**
553  *      Parse a Filter Criteria.
554  * @param doc - the XML document
555  * @param node - the current node
556  * @param fc - structure to fill
557  * @returns 1 on success, 0 on failure
558  */
559 static int parse_filter_criteria(xmlDocPtr doc,xmlNodePtr node,ims_filter_criteria *fc)
560 {
561         xmlNodePtr child;
562         xmlChar *x;
563         char k;
564         fc->priority=0;
565         fc->trigger_point=NULL;
566         fc->profile_part_indicator=NULL;
567         //fc->apllication_server init mai tarziu
568         for(child=node->children ; child ; child=child->next)
569                 if (child->type==XML_ELEMENT_NODE)
570                         switch (child->name[3]) {
571                                 case 'O':case 'o':      //Priority
572                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
573                                         fc->priority=atoi((char*)x);
574                                         xmlFree(x);
575                                         break;
576                                 case 'G':case 'g':      //TriggerPoint
577                                         fc->trigger_point=(ims_trigger_point*) shm_malloc(sizeof(ims_trigger_point));
578                                         if (!fc->trigger_point){
579                                                 LM_ERR("Out of memory allocating %lx bytes\n",sizeof(ims_trigger_point));
580                                                 break;
581                                         }
582                                         if (!parse_trigger_point(doc,child,fc->trigger_point)){
583                                                 shm_free(fc->trigger_point);
584                                                 fc->trigger_point=0;
585                                                 return 0;
586                                         }
587                                         break;
588                                 case 'L':case 'l':      //ApplicationServer
589                                         parse_application_server(doc,child,&(fc->application_server));
590                                         break;
591                                 case 'F':case 'f':      //ProfilePartIndicator
592                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
593                                         k = ifc_tProfilePartIndicator2char(x);
594                                         if (k<0) break;
595                                         fc->profile_part_indicator=(char*)shm_malloc(sizeof(char));
596                                         if (!fc->profile_part_indicator){
597                                                 LM_ERR("Out of memory allocating %lx bytes\n",sizeof(ims_trigger_point));
598                                                 break;
599                                         }
600                                         *fc->profile_part_indicator=k;
601                                         xmlFree(x);
602                                         break;
603                         }
604         return 1;
605 }
606
607
608
609 /**
610  * Parse the Public Identity.
611  * @param doc - the XML document
612  * @param root - the current node
613  * @param pi - structure to fill
614  * @returns 1 on success, 0 on failure , 2 if its a wildcardpsi
615  */
616 static int parse_public_identity(xmlDocPtr doc, xmlNodePtr root, ims_public_identity *pi)
617 {
618         xmlNodePtr child;
619         xmlNodePtr grandson;
620         xmlChar *x;
621         int return_code=1;
622         
623         for(child=root->children;child;child=child->next)
624                 if (child->type==XML_ELEMENT_NODE)
625                         switch (child->name[0]){
626                                 case 'I': case 'i':
627                                         if (!pi->public_identity.len){
628                                                 x = xmlNodeListGetString(doc,child->xmlChildrenNode,1);
629                                                 space_trim_dup(&(pi->public_identity),(char*)x);
630                                                 xmlFree(x);
631                                         }                                       
632                                         break;
633                                 case 'B': case 'b':
634                                         x = xmlNodeListGetString(doc,child->xmlChildrenNode,1);
635                                         pi->barring = ifc_tBool2char(x);
636                                         xmlFree(x);
637                                         break;
638                                 //lets add something 
639                                 case 'E' : case 'e':
640                                         // that would be Extension
641                                         // here i need to parse Identity Type 
642                                         // if its two then  wildcardedpsi
643                                         // and then extension!!!
644                                         // I have to check how you parse this shit
645
646                                         for(grandson=child->children;grandson;grandson=grandson->next)
647                                         {
648                                                                                                 
649                                                 if (grandson->type==XML_ELEMENT_NODE)
650                                                 {
651                                                         switch (grandson->name[0]) {
652                                                                 case 'I' : case 'i':
653                                                                         //identity type 0 public identity 1 distinct psi 2 wildcard psi
654                                                                         //x = xmlNodeListGetString(doc,grandson->xmlChildrenNode,1);
655                                                                         // i need to compare x with 2, but i have to trim leading 
656                                                                         // space characters or tabs                     
657                                                                         //xmlFree(x);
658                                                                         break;
659                                                                 case 'W' : case 'w':
660                                                                         //wildcardpsi
661                                                                         if(!scscf_support_wildcardPSI) {
662                                                                                 LOG(L_ERR,"Configured without support for Wildcard PSI and got one from HSS\n");
663                                                                                 LOG(L_ERR,"the identity will be stored but never be matched, please include the parameter to support wildcard PSI in the config file\n");
664                                                                         }
665                                                                         
666                                                                         x = xmlNodeListGetString(doc,grandson->xmlChildrenNode,1);
667                                                                         space_trim_dup(&(pi->wildcarded_psi),(char*)x);
668                                                                         
669                                                                         xmlFree(x);
670                                                                         return_code=2;
671                                                                         break;
672                                                                 default :
673                                                                         break;
674                                                         }
675                                                 }
676                                         }
677                                                                                 
678                                         break;                          
679                         }
680
681         return return_code;
682 }
683
684 /**
685  *      Parse a Core Network Service Authorization.
686  * @param doc - the XML document
687  * @param node - the current node
688  * @param cn - structure to fill
689  * @returns 1 on success, 0 on failure
690  */
691 static int parse_cn_service_auth(xmlDocPtr doc,xmlNodePtr node,ims_cn_service_auth *cn)
692 {
693         xmlNodePtr child;
694         xmlChar *x;
695         cn->subscribed_media_profile_id=-1;
696         for(child=node->children ; child ; child=child->next)
697                 if (child->type==XML_ELEMENT_NODE)
698                         switch (child->name[0]) {
699                                 case 'S':case 's':      //BarringIndication
700                                         x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
701                                         cn->subscribed_media_profile_id=atoi((char*)x);
702                                         xmlFree(x);
703                                         return 1;
704                                         break;
705
706                         }
707         return 0;
708 }
709
710 /**
711  *      Parse a Core Network Service Profile.
712  * @param doc - the XML document
713  * @param root - the current node
714  * @param sp - structure to fill
715  * @returns 1 on success, 0 on failure
716  */
717 static int parse_service_profile(xmlDocPtr doc, xmlNodePtr root, ims_service_profile *sp) {
718     xmlNodePtr child;
719     xmlChar *x;
720     unsigned short pi_cnt = 0, ifc_cnt = 0, sh_cnt = 0;
721     int i, j;
722     ims_filter_criteria fctemp;
723     int returncode = 0;
724
725     for (child = root->children; child; child = child->next)
726         if (child->type == XML_ELEMENT_NODE) {
727             LM_DBG("child name is [%s]\n", child->name);
728             switch (child->name[0]) {
729                 case 'P': case 'p':
730                     pi_cnt++;
731                     break;
732                 case 'i':case 'I': //InitialFilterCriteria
733                     ifc_cnt++;
734                     break;
735                 case 'c':case 'C': //CoreNetworkServiceAuthorization
736                     sp->cn_service_auth = (ims_cn_service_auth*) shm_malloc(
737                             sizeof (ims_cn_service_auth));
738                     break;
739                 case 's':case 'S': //SharedIFCSet
740                     sh_cnt++;
741                     break;
742
743             }
744
745         }
746
747     sp->public_identities = shm_malloc(pi_cnt * sizeof (ims_public_identity));
748     if (!sp->public_identities) {
749         LM_ERR("Out of memory allocating %lx bytes\n", pi_cnt * sizeof (ims_public_identity));
750         return 0;
751     }
752     memset(sp->public_identities, 0, pi_cnt * sizeof (ims_public_identity));
753     
754     sp->filter_criteria = (ims_filter_criteria*) shm_malloc(sizeof (ims_filter_criteria) * ifc_cnt);
755     if (!sp->filter_criteria) {
756         LM_ERR("Out of memory allocating %lx bytes\n", ifc_cnt * sizeof (ims_filter_criteria));
757         return 0;
758     }
759     memset(sp->filter_criteria, 0, ifc_cnt * sizeof (ims_filter_criteria));
760     
761     sp->shared_ifc_set = (int*) shm_malloc(sizeof (int) *sh_cnt);
762     if (!sp->shared_ifc_set) {
763         LM_ERR("Out of memory allocating %lx bytes\n", sh_cnt * sizeof (int));
764         return 0;
765     }
766     memset(sp->shared_ifc_set, 0, sh_cnt * sizeof (int));
767     
768     for (child = root->children; child; child = child->next)
769         if (child->type == XML_ELEMENT_NODE)
770             switch (child->name[0]) {
771                 case 'P': case 'p':
772                     returncode = parse_public_identity(doc, child, &(sp->public_identities[sp->public_identities_cnt]));
773                     if (returncode)
774                         sp->public_identities_cnt++;
775                     break;
776                 case 'I':case 'i': //InitialFilterCriteria
777                     if (!parse_filter_criteria(doc, child, &(fctemp)))
778                         break;
779                     i = 0;
780                     while (i < sp->filter_criteria_cnt && sp->filter_criteria[i].priority < fctemp.priority)
781                         i++;
782                     for (j = sp->filter_criteria_cnt - 1; j >= i; j--)
783                         sp->filter_criteria[j + 1] = sp->filter_criteria[j];
784                     sp->filter_criteria[i] = fctemp;
785                     sp->filter_criteria_cnt++;
786                     break;
787                 case 'C':case 'c': //CoreNetworkServiceAuthorization
788                     if (!parse_cn_service_auth(doc, child, sp->cn_service_auth)) {
789                         shm_free(sp->cn_service_auth);
790                         sp->cn_service_auth = 0;
791                     }
792                     break;
793                 case 'S':case 's': //SharedIFCSet
794                     x = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
795                     sp->shared_ifc_set[sp->shared_ifc_set_cnt++] = atoi((char*) x);
796                     xmlFree(x);
797                     break;
798             }
799     if (returncode == 2)
800         return 2; // i need to know if there is a wildcardpsi hiding in the public_identity
801     return 1;
802 }
803
804 /**
805  *      Parse a IMS Subscription.
806  * @param doc - the XML document
807  * @param root - the current node
808  * @returns the ims_subscription* on success or NULL on error
809  */
810 static ims_subscription* parse_ims_subscription(xmlDocPtr doc, xmlNodePtr root)
811 {
812         xmlNodePtr child;
813         xmlChar *x;
814         ims_subscription *s;
815         unsigned short sp_cnt=0;
816         int rc;
817         
818         if (!root) return 0;
819         while(root->type!=XML_ELEMENT_NODE || strcasecmp((char*)root->name,"IMSSubscription")!=0){
820                 root = root->next;
821         }
822         if (!root) {
823                 LM_ERR("No IMSSubscription node found\n");
824                 return 0;
825         }
826         s = (ims_subscription*) shm_malloc(sizeof(ims_subscription));
827         if (!s) {
828                 LM_ERR("Out of memory allocating %lx bytes\n",sizeof(ims_subscription));
829                 return 0;
830         }
831         memset(s,0,sizeof(ims_subscription));
832         for(child=root->children;child;child=child->next)
833                 if (child->type==XML_ELEMENT_NODE)
834                         switch (child->name[0]){
835                                 case 'P':case 'p':  /* Private Identity */
836                                         if (!s->private_identity.len){
837                                                 x = xmlNodeListGetString(doc,child->xmlChildrenNode,1);
838                                                 space_trim_dup(&(s->private_identity),(char*)x);
839                                                 xmlFree(x);
840                                         }
841                                         break;
842                                 case 'S':case 's':      /* Service Profile */
843                                         sp_cnt++;
844                                         break;                                  
845                         }
846         s->service_profiles = (ims_service_profile*) shm_malloc(sp_cnt * sizeof(ims_service_profile));
847         if (!s->service_profiles) {
848                 LM_ERR("Out of memory allocating %lx bytes\n",sp_cnt*sizeof(ims_service_profile));
849                 return s;       
850         }
851         memset(s->service_profiles,0,sp_cnt * sizeof(ims_service_profile));
852         for(child=root->children;child;child=child->next)
853                 if (child->type==XML_ELEMENT_NODE)
854                         if (child->name[0]=='S' || child->name[0]=='s')
855                         {
856                                 rc=parse_service_profile(doc,child,&(s->service_profiles[s->service_profiles_cnt]));
857                                 if (rc==2)
858                                         s->wpsi=1;
859                                 if (rc)
860                                         s->service_profiles_cnt++;
861                         }                               
862         s->lock = lock_alloc();
863         s->lock = lock_init(s->lock);
864         return s;
865 }
866
867
868 /**
869  * Parses the user data XML and copies data into a new ims_subscription structure.
870  * @param xml - the input xml (NB must be null terminated)
871  * @returns the ims_subscription* on success or NULL on error
872  */
873 ims_subscription *parse_user_data(str xml)
874 {
875         xmlDocPtr doc=0;
876         xmlNodePtr root=0;
877         ims_subscription *s = 0;
878         if (!ctxtInit) parser_init(scscf_user_data_dtd,scscf_user_data_xsd);    
879         doc=0;
880         
881         doc = xmlParseDoc((unsigned char *)xml.s);
882         if (!doc){
883                 LM_ERR("This is not a valid XML <%.*s>\n", xml.len,xml.s);
884                 goto error;
885         }
886
887         if (dtdCtxt){
888                 if (xmlValidateDtd(dtdCtxt,doc,dtd)!=1){
889                         LM_ERR("Verification of XML against DTD failed <%.*s>\n", xml.len,xml.s);
890                         goto error;
891                 }
892         }
893         if (xsdCtxt){
894                 if (xmlSchemaValidateDoc(xsdCtxt,doc)!=0){
895                         LM_ERR("Verification of XML against XSD failed <%.*s>\n", xml.len,xml.s);
896                         goto error;
897                 }
898         }
899
900         root = xmlDocGetRootElement(doc);
901         if (!root){
902                 LM_ERR("Empty XML <%.*s>\n",
903                         xml.len,xml.s);
904                 goto error;
905         }
906         s = parse_ims_subscription(doc,root);
907         if (!s){
908                 LM_ERR("Error while loading into  ims subscription structure\n");
909                 goto error;             
910         }
911         xmlFreeDoc(doc);
912         print_user_data(s);
913         return s;
914 error:  
915         if (doc) xmlFreeDoc(doc);
916         return 0;       
917 }
918
919 /**
920  * Initializes the libxml2 parser.
921  * @param dtd_filename - path to the DTD or NULL if none
922  * @param xsd_filename - path to the XSD or NULL if none
923  * @returns 1 on success or 0 on error
924  */
925 int parser_init(char *dtd_filename, char *xsd_filename)
926 {
927         if (dtd_filename){
928                 dtd = xmlParseDTD(NULL,(unsigned char*)dtd_filename);
929                 if (!dtd){
930                         LM_ERR("unsuccesful DTD parsing from file <%s>\n",
931                                 dtd_filename);
932                         return 0;
933                 }
934                 dtdCtxt = xmlNewValidCtxt();
935                 dtdCtxt->userData = (void*)stderr;
936                 dtdCtxt->error = (xmlValidityErrorFunc) fprintf;
937                 dtdCtxt->warning = (xmlValidityWarningFunc) fprintf;
938         }
939         if (xsd_filename){
940                 xmlSchemaParserCtxtPtr ctxt;
941                 ctxt = xmlSchemaNewParserCtxt(xsd_filename);
942                 if (!ctxt) {
943                         LM_ERR("unsuccesful XSD parsing from file <%s>\n",
944                                 xsd_filename);
945                         return 0;
946                 }
947                 xmlSchemaSetParserErrors(ctxt,(xmlValidityErrorFunc) fprintf,(xmlValidityWarningFunc) fprintf,stderr);
948                 xsd = xmlSchemaParse(ctxt);
949                 xmlSchemaFreeParserCtxt(ctxt);          
950                 
951                 xsdCtxt = xmlSchemaNewValidCtxt(xsd);
952                 xmlSchemaSetValidErrors(xsdCtxt,(xmlValidityErrorFunc) fprintf,(xmlValidityWarningFunc) fprintf,stderr);
953         }
954         ctxtInit=1;
955         return 1;
956 }
957
958
959 /**
960  * Print the contents of an ims_subscription structure.
961  * @param log_level - level to log on
962  * @param s - the ims_subscription to be printed
963  */
964 void print_user_data(ims_subscription *s) {
965     int i, j, k;
966
967     LM_DBG("IMSSubscription:\n");
968     if (!s) return;
969     
970     LM_DBG("Private Identity: <%.*s>\n", s->private_identity.len, s->private_identity.s);
971     for (i = 0; i < s->service_profiles_cnt; i++) {
972         LM_DBG("\tService Profile:\n");
973         for (j = 0; j < s->service_profiles[i].public_identities_cnt; j++) {
974             LM_DBG("\t\tPublic Identity: Barring [%d] <%.*s> \n",
975                     s->service_profiles[i].public_identities[j].barring,
976                     s->service_profiles[i].public_identities[j].public_identity.len,
977                     s->service_profiles[i].public_identities[j].public_identity.s);
978         }
979         for (j = 0; j < s->service_profiles[i].filter_criteria_cnt; j++) {
980             LM_DBG("\t\tFilter Criteria: Priority [%d]ProfilePartInd [%d]\n",
981                     s->service_profiles[i].filter_criteria[j].priority,
982                     s->service_profiles[i].filter_criteria[j].profile_part_indicator ?
983                     *(s->service_profiles[i].filter_criteria[j].profile_part_indicator) : -1);
984             if (s->service_profiles[i].filter_criteria[j].trigger_point) {
985                 LM_DBG("\t\t\tTrigger Point: CNF [%c] %s\n",
986                         s->service_profiles[i].filter_criteria[j].trigger_point->condition_type_cnf ? 'X' : ' ',
987                         s->service_profiles[i].filter_criteria[j].trigger_point->condition_type_cnf ? "(_|_)&(_|_)" : "(_&_)|(_&_)"
988                         );
989                 for (k = 0; k < s->service_profiles[i].filter_criteria[j].trigger_point->spt_cnt; k++) {
990                     LM_DBG("\t\t\t\tSPT: Grp[%d] NOT[%c] RegType[%d]\n",
991                             s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].group,
992                             s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].condition_negated ? 'X' : ' ',
993                             s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].registration_type
994                             );
995                     switch (s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].type) {
996                         case 1:
997                             LM_DBG("\t\t\t\t\t Request-URI == <%.*s>\n",
998                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].request_uri.len,
999                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].request_uri.s);
1000                             break;
1001                         case 2:
1002                             LM_DBG("\t\t\t\t\t Method == <%.*s>\n",
1003                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].method.len,
1004                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].method.s);
1005                             break;
1006                         case 3:
1007                             LM_DBG("\t\t\t\t\t Hdr(%.*s(%d)) == <%.*s>\n",
1008                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].sip_header.header.len,
1009                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].sip_header.header.s,
1010                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].sip_header.type,
1011                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].sip_header.content.len,
1012                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].sip_header.content.s);
1013                             break;
1014                         case 4:
1015                             LM_DBG("\t\t\t\t\t SessionCase [%d]\n",
1016                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].session_case);
1017                             break;
1018                         case 5:
1019                             LM_DBG("\t\t\t\t\t SDP(%.*s) == <%.*s>\n",
1020                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].session_desc.line.len,
1021                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].session_desc.line.s,
1022                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].session_desc.content.len,
1023                                     s->service_profiles[i].filter_criteria[j].trigger_point->spt[k].session_desc.content.s);
1024                             break;
1025                     }
1026                 }
1027             }
1028             LM_DBG("\t\t\tAS: <%.*s> Handling [%d] SrvInfo: <%.*s>\n",
1029                     s->service_profiles[i].filter_criteria[j].application_server.server_name.len,
1030                     s->service_profiles[i].filter_criteria[j].application_server.server_name.s,
1031                     s->service_profiles[i].filter_criteria[j].application_server.default_handling,
1032                     s->service_profiles[i].filter_criteria[j].application_server.service_info.len,
1033                     s->service_profiles[i].filter_criteria[j].application_server.service_info.s);
1034         }
1035         if (s->service_profiles[i].cn_service_auth) {
1036             LM_DBG("\t\tCN Serv Auth: Subs Media Profile ID [%d]\n",
1037                     s->service_profiles[i].cn_service_auth->subscribed_media_profile_id);
1038         }
1039         for (j = 0; j < s->service_profiles[i].shared_ifc_set_cnt; j++) {
1040             LM_DBG("\t\tShared IFC Set: [%d]\n",
1041                     s->service_profiles[i].shared_ifc_set[j]);
1042         }
1043     }
1044 }
1045
1046 str cscf_get_realm_from_ruri(struct sip_msg *msg) {
1047         str realm = { 0, 0 };
1048         if (!msg || msg->first_line.type != SIP_REQUEST) {
1049                 LM_ERR("This is not a request!!!\n");
1050                 return realm;
1051         }
1052
1053         if (!msg->parsed_orig_ruri_ok)
1054                 if (parse_orig_ruri(msg) < 0)
1055                         return realm;
1056
1057         realm = msg->parsed_orig_ruri.host;
1058         return realm;
1059 }