all: updated FSF address in GPL text
[sip-router] / modules / rls / notify.c
1 /*
2  * $Id: notify.c 2230 2007-06-06 07:13:20Z anca_vamanu $
3  *
4  * rls module - resource list server
5  *
6  * Copyright (C) 2007 Voice Sistem S.R.L.
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * Kamailio is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  *
24  * History:
25  * --------
26  *  2007-09-11  initial version (anca)
27  */
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <time.h>
33
34 #include "../../ut.h"
35 #include "../../str.h"
36 #include "../../dprint.h"
37 #include "../../trim.h"
38 #include "../../data_lump_rpl.h"
39 #include "../../parser/msg_parser.h"
40 #include "../../parser/parse_event.h"
41 #include "../../parser/parse_expires.h"
42 #include "../../parser/parse_cseq.h"
43 #include "../../parser/contact/parse_contact.h"
44 #include "../../parser/parse_rr.h"
45 #include "../../modules/tm/dlg.h"
46 #include "../presence/utils_func.h"
47 #include "../presence/hash.h"
48 #include "../../hashes.h"
49 #include "rls.h"
50 #include "notify.h"
51 #include "utils.h"
52 #include <libxml/xpath.h>
53 #include <libxml/xpathInternals.h>
54
55 static str *multipart_body = NULL;
56 static int multipart_body_size = 0;
57
58 typedef struct res_param
59 {
60     struct uri_link **next;
61 }res_param_t;
62
63 typedef struct uri_link
64 {
65     char *uri;
66     struct uri_link *next;
67 } uri_link_t;
68
69 int resource_uri_col=0, content_type_col, pres_state_col= 0,
70         auth_state_col= 0, reason_col= 0;
71
72 xmlDocPtr constr_rlmi_doc(db1_res_t* result, str* rl_uri, int version,
73                 xmlNodePtr rl_node, char*** cid_array,
74                 str username, str domain);
75 void constr_multipart_body(const str *const content_type, const str *const body, str *cid, int boundary_len, char *boundary_string);
76
77 dlg_t* rls_notify_dlg(subs_t* subs);
78
79 void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps);
80
81 int parse_xcap_uri(char *uri, str *host, unsigned short *port, str *path);
82 int rls_get_resource_list(str *rl_uri, str *username, str *domain,
83                 xmlNodePtr *rl_node, xmlDocPtr *xmldoc);
84 int add_resource_to_list(char* uri, void* param);
85 int add_resource(char* uri, xmlNodePtr list_node, char * boundary_string, db1_res_t *result, int *len_est);
86
87 char *instance_id = "Scf8UhwQ";
88
89 int send_full_notify(subs_t* subs, xmlNodePtr rl_node, str* rl_uri,
90                 unsigned int hash_code)
91 {
92         xmlDocPtr rlmi_body= NULL;
93         xmlNodePtr list_node= NULL;
94         db_key_t query_cols[1], update_cols[1], result_cols[5];
95         db_val_t query_vals[1], update_vals[1];
96         db1_res_t *result= NULL;
97         int n_result_cols= 0;
98         char* boundary_string;
99         str rlsubs_did= {0, 0};
100         str* rlmi_cont= NULL;
101         uri_link_t *uri_list_head = NULL;
102         int len_est;
103         res_param_t param;
104         int resource_added = 0; /* Flag to indicate that we have added at least one resource */
105         multipart_body=NULL;
106         db_query_f query_fn = rlpres_dbf.query_lock ? rlpres_dbf.query_lock : rlpres_dbf.query;
107
108         LM_DBG("start\n");
109         
110         if(CONSTR_RLSUBS_DID(subs, &rlsubs_did)<0)
111         {
112                 LM_ERR("cannot build rls subs did\n");
113                 goto error;
114         }
115
116         query_cols[0]= &str_rlsubs_did_col;
117         query_vals[0].type = DB1_STR;
118         query_vals[0].nul = 0;
119         query_vals[0].val.str_val= rlsubs_did; 
120
121         result_cols[resource_uri_col= n_result_cols++]= &str_resource_uri_col;
122         result_cols[content_type_col= n_result_cols++]= &str_content_type_col;
123         result_cols[pres_state_col= n_result_cols++]= &str_presence_state_col;
124         result_cols[auth_state_col= n_result_cols++]= &str_auth_state_col;
125         result_cols[reason_col= n_result_cols++]= &str_reason_col;
126
127         update_cols[0]= &str_updated_col;
128         update_vals[0].type = DB1_INT;
129         update_vals[0].nul = 0;
130         update_vals[0].val.int_val= NO_UPDATE_TYPE; 
131         
132         if (rlpres_dbf.use_table(rlpres_db, &rlpres_table) < 0) 
133         {
134                 LM_ERR("in use_table\n");
135                 goto error;
136         }
137
138         if (dbmode == RLS_DB_ONLY && rlpres_dbf.start_transaction)
139         {
140                 if (rlpres_dbf.start_transaction(rlpres_db, DB_LOCKING_WRITE) < 0)
141                 {
142                         LM_ERR("in start_transaction\n");
143                         goto error;
144                 }
145         }
146
147         if(query_fn(rlpres_db, query_cols, 0, query_vals, result_cols,
148                                         1, n_result_cols, NULL, &result )< 0)
149         {
150                 LM_ERR("in sql query\n");
151                 goto error;
152         }
153         if(result == NULL)
154         {
155                 LM_ERR("bad result\n");
156                 goto error;
157         }
158
159         if (result->n > 0)
160         {
161                 if(rlpres_dbf.update(rlpres_db, query_cols, 0, query_vals,
162                                      update_cols, update_vals, 1, 1) < 0)
163                 {
164                         LM_ERR("in sql update\n");
165                         goto error;
166                 }
167         }
168
169         if (dbmode == RLS_DB_ONLY && rlpres_dbf.end_transaction)
170         {
171                 if (rlpres_dbf.end_transaction(rlpres_db) < 0)
172                 {
173                         LM_ERR("in end_transaction\n");
174                         goto error;
175                 }
176         }
177
178         /* Allocate an initial buffer for the multipart body.
179          * This buffer will be reallocated if neccessary */
180         multipart_body= (str*)pkg_malloc(sizeof(str));
181         if(multipart_body== NULL)
182         {
183                 ERR_MEM(PKG_MEM_STR);
184         }
185
186         multipart_body_size = BUF_REALLOC_SIZE;
187         multipart_body->s = (char *)pkg_malloc(multipart_body_size);
188
189         if(multipart_body->s== NULL)
190         {
191                 ERR_MEM(PKG_MEM_STR);
192         }
193     
194         multipart_body->len= 0;
195
196         /* Create an empty rlmi document */
197         len_est = create_empty_rlmi_doc(&rlmi_body, &list_node, rl_uri, subs->version, 1);
198         xmlDocSetRootElement(rlmi_body, list_node);
199
200         /* Find all the uri's to which we are subscribed */
201         param.next = &uri_list_head;
202         if(process_list_and_exec(rl_node, subs->watcher_user, subs->watcher_domain, add_resource_to_list,(void*)(&param))< 0)
203         {
204                 LM_ERR("in process_list_and_exec function\n");
205                 goto error;
206         }
207
208         boundary_string= generate_string(BOUNDARY_STRING_LEN);
209         
210         while (uri_list_head)
211         {
212                 uri_link_t *last = uri_list_head;
213                 if (add_resource(uri_list_head->uri, list_node, boundary_string, result, &len_est) >0)
214                 {
215                         if (resource_added == 0)
216                         {
217                                 /* We have exceeded our length estimate without adding any resource.
218                                    We cannot send this resource, move on. */
219                                 LM_ERR("Failed to add a single resource %d vs %d\n", len_est, rls_max_notify_body_len);
220                                 uri_list_head = uri_list_head->next;
221                                 if (last->uri) pkg_free(last->uri);
222                                 pkg_free(last); 
223                         }
224                         else
225                         {
226                                 LM_DBG("send_full_notify estimate exceeded %d vs %d\n", len_est, rls_max_notify_body_len);
227                                 /* If add_resource returns > 0 the resource did not fit in our size limit */
228                                 rlmi_cont= (str*)pkg_malloc(sizeof(str));
229                                 if(rlmi_cont== NULL)
230                                 {
231                                         ERR_MEM(PKG_MEM_STR);
232                                 }
233                                 /* Where we are worried about length we won't use padding */
234                                 xmlDocDumpFormatMemory(rlmi_body,(xmlChar**)(void*)&rlmi_cont->s,
235                                                         &rlmi_cont->len, 0);
236                                 xmlFreeDoc(rlmi_body);
237
238                                 if(agg_body_sendn_update(rl_uri, boundary_string, rlmi_cont,
239                                                 multipart_body, subs, hash_code)< 0)
240                                 {
241                                         LM_ERR("in function agg_body_sendn_update\n");
242                                         goto error;
243                                 }
244                 
245                                 /* Create a new rlmi body, but not a full_state one this time */
246                                 len_est = create_empty_rlmi_doc(&rlmi_body, &list_node, rl_uri, subs->version, 0);
247                                 xmlDocSetRootElement(rlmi_body, list_node);
248                                 multipart_body->len = 0;
249                                 resource_added = 0;
250                         }
251                 }
252                 else
253                 {
254                         resource_added = 1;
255                         uri_list_head = uri_list_head->next;
256                         if (last->uri) pkg_free(last->uri);
257                         pkg_free(last);
258                 }
259         }
260     
261         rlmi_cont= (str*)pkg_malloc(sizeof(str));
262         if(rlmi_cont== NULL)
263         {
264                 ERR_MEM(PKG_MEM_STR);
265         }
266         xmlDocDumpFormatMemory(rlmi_body,(xmlChar**)(void*)&rlmi_cont->s,
267                         &rlmi_cont->len, (rls_max_notify_body_len == 0));
268         xmlFreeDoc(rlmi_body);
269
270         if(agg_body_sendn_update(rl_uri, boundary_string, rlmi_cont,
271                 multipart_body, subs, hash_code)< 0)
272         {
273                 LM_ERR("in function agg_body_sendn_update\n");
274                 goto error;
275         }
276
277         xmlFree(rlmi_cont->s);
278         pkg_free(rlmi_cont);
279
280         if(multipart_body)                      
281         {
282             if (multipart_body->s)
283                         pkg_free(multipart_body->s);
284                 pkg_free(multipart_body);
285         }
286         multipart_body_size = 0;
287         pkg_free(rlsubs_did.s);
288         rlpres_dbf.free_result(rlpres_db, result);
289         
290         return 0;
291 error:
292         if(rlmi_cont)
293         {
294                 if(rlmi_cont->s)
295                         xmlFree(rlmi_cont->s);
296                 pkg_free(rlmi_cont);
297         }
298         if(multipart_body)
299         {
300                 if(multipart_body->s)
301                         pkg_free(multipart_body->s);
302                 pkg_free(multipart_body);
303         }
304         multipart_body_size = 0;
305         
306         if(result)
307                 rlpres_dbf.free_result(rlpres_db, result);
308         if(rlsubs_did.s)
309                 pkg_free(rlsubs_did.s);
310
311         if (dbmode == RLS_DB_ONLY && rlpres_dbf.abort_transaction)
312         {
313                 if (rlpres_dbf.abort_transaction(rlpres_db) < 0)
314                         LM_ERR("in abort_transaction");
315         }
316         return -1;
317 }
318
319 int agg_body_sendn_update(str* rl_uri, char* boundary_string, str* rlmi_body,
320                 str* multipart_body, subs_t* subs, unsigned int hash_code)
321 {
322         char* cid;
323         int len;
324         str body= {0, 0};
325         int init_len;
326
327         cid= generate_cid(rl_uri->s, rl_uri->len);
328
329         len= 2*strlen(boundary_string)+4+102+strlen(cid)+2+rlmi_body->len+50;
330         if(multipart_body)
331                 len+= multipart_body->len;
332         
333         init_len= len;
334
335         body.s= (char*)pkg_malloc((len+1)* sizeof(char));
336         if(body.s== NULL)
337         {
338                 ERR_MEM(PKG_MEM_STR);
339         }
340         len=  sprintf(body.s, "--%s\r\n", boundary_string);
341         len+= sprintf(body.s+ len , "Content-Transfer-Encoding: binary\r\n");
342         len+= sprintf(body.s+ len , "Content-ID: <%s>\r\n", cid);       
343         len+= sprintf(body.s+ len , 
344                         "Content-Type: application/rlmi+xml;charset=\"UTF-8\"\r\n");
345         len+= sprintf(body.s+ len, "\r\n"); /*blank line*/
346         memcpy(body.s+ len, rlmi_body->s, rlmi_body->len);
347         len+= rlmi_body->len;
348         len+= sprintf(body.s+ len, "\r\n"); /*blank line*/
349
350         if(multipart_body)
351         {
352                 memcpy(body.s+ len, multipart_body->s, multipart_body->len);
353                 len+= multipart_body->len;
354         }
355         len+= sprintf(body.s+ len, "--%s--\r\n", boundary_string);
356
357         if(init_len< len)
358         {
359                 LM_ERR("buffer size overflow init_size= %d\tlen= %d\n",init_len,len);
360                 goto error;
361         }
362         body.s[len]= '\0';
363         body.len= len;
364
365         /* send Notify */
366         if(rls_send_notify(subs, &body, cid, boundary_string)< 0)
367         {
368                 LM_ERR("when sending Notify\n");
369                 goto error;
370         }
371         /* update local_cseq in cache list watchers table */
372         pkg_free(body.s);
373         body.s= NULL;
374
375         if (dbmode==RLS_DB_ONLY)
376         {
377                 if (update_dialog_notify_rlsdb(subs) < 0)
378                 {
379                         LM_ERR( "updating DB\n" );
380                         goto error;
381                 }
382         }
383         else
384         {
385                 if(pres_update_shtable(rls_table, hash_code,subs, LOCAL_TYPE)< 0)
386                 {
387                         LM_ERR("updating in hash table\n");
388                         goto error;
389                 }
390         }
391
392         return 0;
393
394 error:
395         if(body.s)
396                 pkg_free(body.s);
397
398         return -1;
399 }
400
401
402 int add_resource_instance(char* uri, xmlNodePtr resource_node,
403                 db1_res_t* result, char * boundary_string,
404         int *len_est)
405 {
406         xmlNodePtr instance_node= NULL;
407         db_row_t *row;  
408         db_val_t *row_vals;
409         int i, cmp_code;
410         char* auth_state= NULL;
411         int auth_state_flag;
412         int boundary_len = strlen(boundary_string);
413         str cid;
414         str content_type= {0, 0};
415         str body= {0, 0};
416
417         for(i= 0; i< result->n; i++)
418         {
419                 row = &result->rows[i];
420                 row_vals = ROW_VALUES(row);
421                 
422                 cmp_code= strncmp(row_vals[resource_uri_col].val.string_val, uri,
423                                 strlen(uri));
424                 if(cmp_code> 0)
425                         break;
426
427                 if(cmp_code== 0)
428                 {
429                         auth_state_flag= row_vals[auth_state_col].val.int_val;
430                         auth_state= get_auth_string(auth_state_flag );
431                         if(auth_state== NULL)
432                         {
433                                 LM_ERR("bad authorization status flag\n");
434                                 goto error;
435                         }
436                         *len_est += strlen(auth_state) + 38; /* <instance id="12345678" state="[auth_state]" />r/n */
437
438                         if(auth_state_flag & ACTIVE_STATE)
439                         {
440                                 cid.s= generate_cid(uri, strlen(uri));
441                                 cid.len= strlen(cid.s);
442                                 body.s= (char*)row_vals[pres_state_col].val.string_val;
443                                 body.len= strlen(body.s);
444                                 trim(&body);
445
446                                 *len_est += cid.len + 8; /* cid="[cid]" */
447                                 content_type.s = (char*)row_vals[content_type_col].val.string_val;
448                                 content_type.len = strlen(content_type.s);
449                                 *len_est += 4 + boundary_len
450                                                  + 35
451                                                  + 16 + cid.len
452                                                  + 18 + content_type.len
453                                                  + 4 + body.len + 8;
454                         }
455                         else if(auth_state_flag & TERMINATED_STATE)
456                         {
457                                 *len_est += strlen(row_vals[resource_uri_col].val.string_val) + 10; /* reason="[resaon]" */
458                         }
459                         if (rls_max_notify_body_len > 0 && *len_est > rls_max_notify_body_len)
460                         {
461                                 /* We have a limit on body length set, and we were about to exceed it */
462                                 return *len_est;
463                         }
464             
465                         instance_node= xmlNewChild(resource_node, NULL, 
466                                         BAD_CAST "instance", NULL);
467                         if(instance_node== NULL)
468                         {
469                                 LM_ERR("while adding instance child\n");
470                                 goto error;
471                         }
472                 
473                         /* OK, we are happy this will fit */
474                         /* Instance ID should be unique for each instance node
475                            within a resource node.  The same instance ID can be
476                            used in different resource nodes.  Instance ID needs
477                            to remain the same for each resource instance in
478                            future updates.  We can just use a common string
479                            here because you will only get multiple instances
480                            for a resource when the back-end SUBSCRIBE is forked
481                            and pua does not support this.  If/when pua supports
482                            forking of the SUBSCRIBEs it sends this will need to
483                            be fixed properly. */
484                         xmlNewProp(instance_node, BAD_CAST "id",
485                                         BAD_CAST instance_id);
486                         xmlNewProp(instance_node, BAD_CAST "state", BAD_CAST auth_state);
487
488                         if(auth_state_flag & ACTIVE_STATE)
489                         {
490                                 constr_multipart_body (&content_type, &body, &cid, boundary_len, boundary_string);
491                                 xmlNewProp(instance_node, BAD_CAST "cid", BAD_CAST cid.s);
492                         }
493                         else
494                         if(auth_state_flag & TERMINATED_STATE)
495                         {
496                                 xmlNewProp(instance_node, BAD_CAST "reason", 
497                                                 BAD_CAST row_vals[reason_col].val.string_val);  
498                         }
499                 }
500         }
501
502         /* if record not found should not add a instance node */        
503         return 0;
504 error:
505         return -1;
506 }
507
508 int add_resource(char* uri, xmlNodePtr list_node, char * boundary_string, db1_res_t *result, int *len_est)
509 {
510         xmlNodePtr resource_node= NULL;
511     int res;
512
513     if (rls_max_notify_body_len > 0)
514     {
515         *len_est += strlen (uri) + 35; /* <resource uri="[uri]"></resource>/r/n */
516         if (*len_est > rls_max_notify_body_len)
517         {
518             return *len_est;
519         }
520     }
521         resource_node= xmlNewChild(list_node, NULL, BAD_CAST "resource", NULL);
522         if(resource_node== NULL)
523         {
524                 goto error;
525         }
526         xmlNewProp(resource_node, BAD_CAST "uri", BAD_CAST uri);
527
528     res = add_resource_instance(uri, resource_node, result, boundary_string, len_est);
529         if(res < 0)
530         {
531                 LM_ERR("while adding resource instance node\n");
532                 goto error;
533         }
534
535         return res;
536 error:
537         return -1;
538 }
539
540 int add_resource_to_list(char* uri, void* param)
541 {
542     struct uri_link **next = ((res_param_t*)param)->next;
543     *next = pkg_malloc(sizeof(uri_link_t));
544     if (*next == NULL)
545         {
546         LM_ERR("while creating linked list element\n");
547                 goto error;
548         }
549
550     (*next)->next = NULL;
551     (*next)->uri = pkg_malloc(strlen(uri) + 1);
552     if ((*next)->uri == NULL)
553         {
554         LM_ERR("while creating uri store\n");
555         pkg_free(*next);
556         *next = NULL;
557                 goto error;
558         }
559     strcpy((*next)->uri, uri);
560     ((res_param_t*)param)->next = &(*next)->next;
561
562         return 0;
563 error:
564         return -1;
565 }
566
567 int create_empty_rlmi_doc(xmlDocPtr *rlmi_doc, xmlNodePtr *list_node, str *uri, int version, int full_state)
568 {
569     /* length is an pessimitic estimate of the size of an empty document
570        We calculate it once for performance reasons.
571        We add in the uri length each time as this varies, and it is cheap to add */
572     static int length = 0;
573     char* rl_uri= NULL;
574     int len;
575     
576     /* make new rlmi and multipart documents */
577     *rlmi_doc= xmlNewDoc(BAD_CAST "1.0");
578     if(*rlmi_doc== NULL)
579     {
580         LM_ERR("when creating new xml doc\n");
581         return 0;
582     }
583     *list_node= xmlNewNode(NULL, BAD_CAST "list");
584     if(*list_node== NULL)
585         {
586                 LM_ERR("while creating new xml node\n");
587         return 0;
588         }
589     rl_uri= (char*)pkg_malloc((uri->len+ 1)* sizeof(char));
590     if(rl_uri==  NULL)
591         {
592                 ERR_MEM(PKG_MEM_STR);
593         }
594     memcpy(rl_uri, uri->s, uri->len);
595     rl_uri[uri->len]= '\0';
596
597     xmlNewProp(*list_node, BAD_CAST "uri", BAD_CAST rl_uri);
598     xmlNewProp(*list_node, BAD_CAST "xmlns",
599                         BAD_CAST "urn:ietf:params:xml:ns:rlmi");
600     xmlNewProp(*list_node, BAD_CAST "version",
601             BAD_CAST int2str(version, &len));
602     if (full_state)               
603         xmlNewProp(*list_node, BAD_CAST "fullState", BAD_CAST "true");
604     else
605         xmlNewProp(*list_node, BAD_CAST "fullState", BAD_CAST "false");
606         
607     xmlDocSetRootElement(*rlmi_doc, *list_node);
608     pkg_free(rl_uri);  /* xmlNewProp takes a copy, so we can free this now */
609
610     if (length == 0)
611         {
612         /* We haven't found out how big an empty doc is
613            Let's find out now ! */
614         xmlChar* dumped_document;
615         /* Where we are worried about length we won't use padding */
616         xmlDocDumpFormatMemory( *rlmi_doc,&dumped_document, &length, 0);
617         xmlFree(dumped_document);
618         length -= uri->len; /* The uri varies, so we will add it each time */
619         }
620     return length + uri->len;
621 error:
622     return 0;
623 }
624
625
626 void constr_multipart_body(const str *const content_type, const str *const body, str *cid, int boundary_len, char *boundary_string)
627 {
628         char* buf= multipart_body->s;
629         int length= multipart_body->len;
630         int chunk_len;
631         
632         LM_DBG("start\n");
633
634     chunk_len = 4 + boundary_len
635                 + 35
636                 + 16 + cid->len
637                 + 18 + content_type->len
638                 + 4 + body->len + 8;
639                 while(length + chunk_len >= multipart_body_size)
640                 {
641                         multipart_body_size += BUF_REALLOC_SIZE;
642                         multipart_body->s = (char*)pkg_realloc(multipart_body->s, multipart_body_size);
643                         if(multipart_body->s == NULL) 
644                         {
645                                 ERR_MEM("constr_multipart_body");
646                         }
647                 }
648                 buf = multipart_body->s;
649
650                 length+= sprintf(buf+ length, "--%.*s\r\n",
651             boundary_len, boundary_string);
652                 length+= sprintf(buf+ length, "Content-Transfer-Encoding: binary\r\n");
653                 length+= sprintf(buf+ length, "Content-ID: <%.*s>\r\n",
654             cid->len, cid->s);
655                 length+= sprintf(buf+ length, "Content-Type: %.*s\r\n\r\n",
656             content_type->len, content_type->s);
657                 length+= sprintf(buf+length,"%.*s\r\n\r\n",
658             body->len, body->s);
659
660         multipart_body->len = length;
661
662 error:
663
664         return;
665 }
666
667 str* rls_notify_extra_hdr(subs_t* subs, char* start_cid, char* boundary_string)
668 {
669         str* str_hdr= NULL;
670         int len= 0, expires;
671
672         str_hdr= (str*)pkg_malloc(sizeof(str));
673         if(str_hdr== NULL)
674         {
675                 ERR_MEM(PKG_MEM_STR);
676         }
677         memset(str_hdr, 0, sizeof(str));
678
679         str_hdr->s= (char*)pkg_malloc(RLS_HDR_LEN* sizeof(char));
680         if(str_hdr->s== NULL)
681         {
682                 ERR_MEM(PKG_MEM_STR);
683         }
684         memcpy(str_hdr->s ,"Max-Forwards: ", 14);
685         str_hdr->len = 14;
686         len= sprintf(str_hdr->s+str_hdr->len, "%d", MAX_FORWARD);
687         if(len<= 0)
688         {
689                 LM_ERR("while printing in string\n");
690                 goto error;
691         }       
692         str_hdr->len+= len; 
693         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
694         str_hdr->len += CRLF_LEN;
695
696         memcpy(str_hdr->s+str_hdr->len  ,"Event: ", 7);
697         str_hdr->len+= 7;
698         memcpy(str_hdr->s+str_hdr->len, subs->event->name.s,
699                         subs->event->name.len);
700         str_hdr->len+= subs->event->name.len;           
701         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
702         str_hdr->len += CRLF_LEN;
703
704         memcpy(str_hdr->s+str_hdr->len ,"Contact: <", 10);
705         str_hdr->len += 10;
706         memcpy(str_hdr->s+str_hdr->len,subs->local_contact.s,
707                         subs->local_contact.len);
708         str_hdr->len +=  subs->local_contact.len;
709         memcpy(str_hdr->s+str_hdr->len, ">", 1);
710         str_hdr->len += 1;
711         memcpy(str_hdr->s+str_hdr->len, CRLF, CRLF_LEN);
712         str_hdr->len += CRLF_LEN;
713
714         expires= subs->expires;
715
716         if( expires> 0 )
717                 str_hdr->len+= sprintf(str_hdr->s+str_hdr->len,
718                         "Subscription-State: active;expires=%d\r\n", expires);
719         else
720                 str_hdr->len+= sprintf(str_hdr->s+str_hdr->len,
721                         "Subscription-State: terminated;reason=timeout\r\n");
722
723         str_hdr->len+= sprintf(str_hdr->s+str_hdr->len, "Require: eventlist\r\n");
724
725         if(start_cid && boundary_string)
726         {
727                 str_hdr->len+= sprintf(str_hdr->s+str_hdr->len,
728                         "Content-Type: multipart/related;type=\"application/rlmi+xml\"");
729                 str_hdr->len+= sprintf(str_hdr->s+str_hdr->len,
730                                 ";start=\"<%s>\";boundary=\"%s\"\r\n",
731                                 start_cid, boundary_string);
732         }               
733         if(str_hdr->len> RLS_HDR_LEN)
734         {
735                 LM_ERR("buffer size overflow\n");
736                 goto error;
737         }
738         str_hdr->s[str_hdr->len] = '\0';
739
740         return str_hdr;
741
742 error:
743         if(str_hdr)
744         {
745                 if(str_hdr->s)
746                         pkg_free(str_hdr->s);
747                 pkg_free(str_hdr);
748         }
749         return NULL;
750
751 }
752
753 void rls_free_td(dlg_t* td)
754 {
755         if(td)
756         {
757                 if(td->loc_uri.s)
758                         pkg_free(td->loc_uri.s);
759         
760                 if(td->rem_uri.s)
761                         pkg_free(td->rem_uri.s);
762
763                 if(td->route_set)
764                         free_rr(&td->route_set); 
765
766                 pkg_free(td);
767         }       
768 }
769
770 int rls_send_notify(subs_t* subs, str* body, char* start_cid,
771                 char* boundary_string)
772 {
773         dlg_t* td= NULL;
774         str met= {"NOTIFY", 6};
775         str* str_hdr= NULL;
776         dialog_id_t* cb_param= NULL;
777         int size;
778         int rt;
779         uac_req_t uac_r;
780
781         LM_DBG("start\n");
782         td= rls_notify_dlg(subs);
783         if(td ==NULL)
784         {
785                 LM_ERR("while building dlg_t structure\n");
786                 goto error;     
787         }
788         
789         LM_DBG("constructed dlg_t struct\n");
790         size= sizeof(dialog_id_t)+(subs->to_tag.len+ subs->callid.len+ 
791                         subs->from_tag.len) *sizeof(char);
792         
793         cb_param = (dialog_id_t*)shm_malloc(size);
794         if(cb_param== NULL)
795         {
796                 ERR_MEM(SHARE_MEM);
797         }
798         size= sizeof(dialog_id_t);
799         
800         cb_param->callid.s= (char*)cb_param + size;
801         memcpy(cb_param->callid.s, subs->callid.s, subs->callid.len);
802         cb_param->callid.len= subs->callid.len;
803         size+= subs->callid.len;
804
805         cb_param->to_tag.s= (char*)cb_param + size;
806         memcpy(cb_param->to_tag.s, subs->to_tag.s, subs->to_tag.len);
807         cb_param->to_tag.len= subs->to_tag.len;
808         size+= subs->to_tag.len;
809
810         cb_param->from_tag.s= (char*)cb_param + size;
811         memcpy(cb_param->from_tag.s, subs->from_tag.s, subs->from_tag.len);
812         cb_param->from_tag.len= subs->from_tag.len;
813         
814         LM_DBG("constructed cb_param\n");
815
816         str_hdr= rls_notify_extra_hdr(subs, start_cid, boundary_string);
817         if(str_hdr== NULL || str_hdr->s== NULL)
818         {
819                 LM_ERR("while building extra headers\n");
820                 goto error;
821         }
822         LM_DBG("str_hdr= %.*s\n", str_hdr->len, str_hdr->s);
823
824         set_uac_req(&uac_r, &met, str_hdr, body, td, TMCB_LOCAL_COMPLETED,
825                         rls_notify_callback, (void*)cb_param);
826
827         rt = tmb.t_request_within(&uac_r);
828         if(rt < 0)
829         {
830                 LM_ERR("in function tmb.t_request_within\n");
831                 goto error;     
832         }
833
834         pkg_free(str_hdr->s);
835         pkg_free(str_hdr);
836         rls_free_td(td);
837         return 0;
838
839 error:
840         if(td)
841                 rls_free_td(td);
842         if(cb_param)
843                 shm_free(cb_param);
844         if(str_hdr)
845         {
846                 if(str_hdr->s)
847                         pkg_free(str_hdr->s);
848                 pkg_free(str_hdr);
849         }
850         return -1;
851
852 }
853
854 dlg_t* rls_notify_dlg(subs_t* subs)
855 {
856         dlg_t* td=NULL;
857
858         td= (dlg_t*)pkg_malloc(sizeof(dlg_t));
859         if(td== NULL)
860         {
861                 ERR_MEM(PKG_MEM_STR);
862         }
863
864         memset(td, 0, sizeof(dlg_t));
865         td->loc_seq.value = subs->local_cseq;
866         td->loc_seq.is_set = 1;
867
868         td->id.call_id = subs->callid;
869         td->id.rem_tag = subs->from_tag;
870         td->id.loc_tag =subs->to_tag;
871         if(uandd_to_uri(subs->to_user, subs->to_domain, &td->loc_uri)< 0)
872         {
873                 LM_ERR("while constructing uri from user and domain\n");
874                 goto error;
875         }
876         
877         if(uandd_to_uri(subs->from_user, subs->from_domain, &td->rem_uri)< 0)
878         {
879                 LM_ERR("while constructing uri from user and domain\n");
880                 goto error;
881         }
882
883         if(subs->contact.len ==0 || subs->contact.s == NULL )
884         {
885                 LM_DBG("BAD BAD contact NULL\n");
886                 td->rem_target = td->rem_uri;
887         }
888         else
889                 td->rem_target = subs->contact;
890
891         if(subs->record_route.s && subs->record_route.len)
892         {
893                 if(parse_rr_body(subs->record_route.s, subs->record_route.len,
894                         &td->route_set)< 0)
895                 {
896                         LM_ERR("in function parse_rr_body\n");
897                         goto error;
898                 }
899         }       
900         td->state= DLG_CONFIRMED ;
901
902         if (subs->sockinfo_str.len) {
903                 int port, proto;
904         str host;
905                 char* tmp;
906                 if ((tmp = as_asciiz(&subs->sockinfo_str)) == NULL) {
907                         LM_ERR("no pkg mem left\n");
908                         goto error;
909                 }
910                 if (parse_phostport (tmp,&host.s,
911                                 &host.len,&port, &proto )) {
912                         LM_ERR("bad sockinfo string\n");
913                         pkg_free(tmp);
914                         goto error;
915                 }
916                 pkg_free(tmp);
917                 td->send_sock = grep_sock_info (
918                         &host, (unsigned short) port, (unsigned short) proto);
919         }
920         
921         return td;
922
923 error:
924         if(td) rls_free_td(td); 
925
926         return NULL;
927
928 }
929 void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps)
930 {
931         if(ps->param==NULL || *ps->param==NULL || 
932                         ((dialog_id_t*)(*ps->param)) == NULL)
933         {
934                 LM_DBG("message id not received\n");
935                 return;
936         }
937         
938         LM_DBG("completed with status %d [to_tag:"
939                         "%.*s]\n",ps->code,
940                         ((dialog_id_t*)(*ps->param))->to_tag.len, 
941                         ((dialog_id_t*)(*ps->param))->to_tag.s);
942
943         if(ps->code >= 300)
944         {
945                 db_key_t db_keys[2];
946                 db_val_t db_vals[2];
947                 unsigned int hash_code;
948                 subs_t subs;
949
950                 memset(&subs, 0, sizeof(subs_t));
951
952                 subs.to_tag= ((dialog_id_t*)(*ps->param))->to_tag;
953                 subs.from_tag= ((dialog_id_t*)(*ps->param))->from_tag;
954                 subs.callid= ((dialog_id_t*)(*ps->param))->callid;
955
956                 if (dbmode != RLS_DB_ONLY)
957                 {
958                         /* delete from cache table */
959                         hash_code= core_hash(&subs.callid, &subs.to_tag , hash_size);
960
961                         if(pres_delete_shtable(rls_table,hash_code, &subs)< 0)
962                         {
963                                 LM_ERR("record not found in hash table\n");
964                         }
965         
966                         /* delete from database table */
967                         if (rls_dbf.use_table(rls_db, &rlsubs_table) < 0) 
968                         {
969                                 LM_ERR("in use_table\n");
970                                 goto done;
971                         }
972                 
973                         db_keys[0] =&str_to_tag_col;
974                         db_vals[0].type = DB1_STR;
975                         db_vals[0].nul = 0;
976                         db_vals[0].val.str_val = subs.to_tag;
977
978                         db_keys[1] =&str_callid_col;
979                         db_vals[1].type = DB1_STR;
980                         db_vals[1].nul = 0;
981                         db_vals[1].val.str_val = subs.callid;
982
983
984                         if (rls_dbf.delete(rls_db, db_keys, 0, db_vals, 2) < 0) 
985                                 LM_ERR("cleaning expired messages\n");  
986                 }
987                 else
988                 {
989                         if (delete_rlsdb(&subs.callid, &subs.to_tag, NULL) < 0 )
990                         {
991                                 LM_ERR( "unable to delete record from DB\n" );
992                         }
993                 }
994         }       
995
996 done:   
997         if(*ps->param !=NULL  )
998                 shm_free(*ps->param);
999         return ;
1000
1001 }
1002
1003 int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
1004                 list_func_t function, void* param)
1005 {
1006         xmlNodePtr node;
1007         str uri;
1008         int res = 0;
1009
1010         for(node= list_node->children; node; node= node->next)
1011         {
1012                 if(xmlStrcasecmp(node->name,(unsigned char*)"resource-list")==0)
1013                 {
1014                         str hostname, rl_uri;
1015                         unsigned short port = 0;
1016                         xmlNodePtr rl_node = NULL;
1017                         xmlDocPtr rl_doc = NULL;
1018                         str unescaped_uri;
1019                         char buf[MAX_URI_SIZE];
1020                         
1021
1022                         uri.s = XMLNodeGetNodeContentByName(node, "resource-list", NULL);
1023                         if (uri.s == NULL)
1024                         {
1025                                 LM_ERR("when extracting URI from node\n");
1026                                 return -1;
1027                         }
1028                         uri.len = strlen(uri.s);
1029                         if (uri.len > MAX_URI_SIZE-1) {
1030                             LM_ERR("XCAP URI is too long\n");
1031                             xmlFree(uri.s);
1032                             return -1;
1033                         }
1034                         LM_DBG("got resource-list uri <%.*s>\n", uri.len, uri.s);
1035
1036                         unescaped_uri.s = buf;
1037                         unescaped_uri.len = 0;
1038                         if (un_escape(&uri, &unescaped_uri) < 0) {
1039                             LM_ERR("Error un-escaping XCAP URI\n");
1040                             xmlFree(uri.s);
1041                             return -1;
1042                         }
1043                         unescaped_uri.s[unescaped_uri.len] = 0;
1044                         LM_DBG("got unescaped uri <%s>\n", unescaped_uri.s);
1045
1046                         if(parse_xcap_uri(unescaped_uri.s, &hostname, &port, &rl_uri)>0)
1047                         {
1048                                 if (rls_integrated_xcap_server == 1
1049                                         && (hostname.len == 0
1050                                                 || check_self(&hostname, 0, PROTO_NONE) == 1))
1051                                 {
1052                                         LM_DBG("fetching local <resource-list - %.*s>\n", uri.len, uri.s);
1053                                         if (rls_get_resource_list(&rl_uri, &username, &domain, &rl_node, &rl_doc)>0)
1054                                         {
1055                                                 LM_DBG("calling myself for rl_node\n");
1056                                                 res = process_list_and_exec(rl_node, username, domain, function, param);
1057                                                 xmlFree(uri.s);
1058                                                 xmlFreeDoc(rl_doc);
1059                                         }
1060                                         else
1061                                         {
1062                                                 LM_ERR("<resource-list - %.*s> not found\n", uri.len, uri.s);
1063                                                 xmlFree(uri.s);
1064                                                 return -1;
1065                                         }
1066                                         
1067                                 }
1068                                 else
1069                                 {
1070                                         LM_ERR("<resource-list - %.*s> is not local - unsupported at this time\n", uri.len, uri.s);
1071                                         xmlFree(uri.s);
1072                                         return -1;
1073                                 }
1074                         }
1075                         else
1076                         {
1077                                 LM_ERR("unable to parse URI for <resource-list - %.*s>\n", uri.len, uri.s);
1078                                 xmlFree(uri.s);
1079                                 return -1;
1080                         }
1081                 }
1082                 else
1083                 if(xmlStrcasecmp(node->name,(unsigned char*)"entry")== 0)
1084                 {
1085                         uri.s = XMLNodeGetAttrContentByName(node, "uri");
1086                         if(uri.s== NULL)
1087                         {
1088                                 LM_ERR("when extracting entry uri attribute\n");
1089                                 return -1;
1090                         }
1091                         LM_DBG("uri= %s\n", uri.s);
1092                         if(function(uri.s, param)< 0)
1093                         {
1094                                 LM_ERR("in function given as a parameter\n");
1095                                 xmlFree(uri.s);
1096                                 return -1;
1097                         }
1098                         xmlFree(uri.s);
1099                 }
1100                 else
1101                 if(xmlStrcasecmp(node->name,(unsigned char*)"list")== 0)
1102                         res = process_list_and_exec(node, username, domain, function, param);
1103         }
1104         return res;
1105 }
1106
1107 char* generate_string(int length)
1108 {
1109         static char buf[128];
1110         int r,i;
1111
1112         if(length>= 128)
1113         {
1114                 LM_ERR("requested length exceeds buffer size\n");
1115                 return NULL;
1116         }
1117                 
1118         for(i=0; i<length; i++) 
1119         {
1120                 r= rand() % ('z'- 'A') + 'A';
1121                 if(r>'Z' && r< 'a')
1122                 r= '0'+ (r- 'Z');
1123
1124                 sprintf(buf+i, "%c", r);
1125         }
1126         buf[length]= '\0';
1127
1128         return buf;
1129 }
1130
1131 char* generate_cid(char* uri, int uri_len)
1132 {
1133         static char cid[512];
1134         int len;
1135
1136         len= sprintf(cid, "%d.%.*s.%d", (int)time(NULL), uri_len, uri, rand());
1137         cid[len]= '\0';
1138         
1139         return cid;
1140 }
1141
1142 char* get_auth_string(int flag)
1143 {
1144         switch(flag)
1145         {
1146                 case ACTIVE_STATE:     return "active";
1147                 case PENDING_STATE:    return "pending";
1148                 case TERMINATED_STATE: return "terminated";
1149         }
1150         return NULL;
1151 }
1152
1153 #define HTTP_PREFIX             "http://"
1154 #define HTTP_PREFIX_LEN         7
1155 #define HTTP_PORT_DEFAULT       80
1156 #define HTTPS_PREFIX            "https://"
1157 #define HTTPS_PREFIX_LEN        8
1158 #define HTTPS_PORT_DEFAULT      443
1159 #define LOCAL_PREFIX            "/"
1160 #define LOCAL_PREFIX_LEN        1
1161 #define CHAR_PORT_LEN           5
1162
1163 int parse_xcap_uri(char *uri, str *host, unsigned short *port, str *path)
1164 {
1165         host->s = NULL;
1166         host->len = 0;
1167         *port = 0;
1168         path->s = NULL;
1169         path->len = 0;          
1170         
1171         if(strncmp(uri, HTTP_PREFIX, HTTP_PREFIX_LEN) == 0)
1172         {
1173                 host->s = &uri[HTTP_PREFIX_LEN];
1174                 *port = HTTP_PORT_DEFAULT;
1175                 LM_DBG("resource list is on http server\n");
1176         }
1177         else
1178         if(strncmp(uri, HTTPS_PREFIX, HTTPS_PREFIX_LEN) == 0)
1179         {
1180                 host->s = &uri[HTTPS_PREFIX_LEN];
1181                 *port = HTTPS_PORT_DEFAULT;
1182                 LM_DBG("resource list is on https server\n");
1183         }
1184         else
1185         if(strncmp(uri, LOCAL_PREFIX, LOCAL_PREFIX_LEN) == 0)
1186         {
1187                 path->s = &uri[0];
1188                 LM_DBG("resource list is local\n");
1189         }
1190         else
1191         {
1192                 LM_ERR("resource list is unidentifiable\n");
1193                 return -1;
1194         }
1195
1196         if (host->s != NULL)
1197         {
1198                 while(host->s[host->len] != '\0' && host->s[host->len] != ':' && host->s[host->len] != '/') host->len++;
1199
1200                 if (host->s[host->len] == ':')
1201                 {
1202                         char char_port[CHAR_PORT_LEN + 1];
1203                         unsigned cur_pos = host->len + 1;
1204                         memset(char_port, '\0', CHAR_PORT_LEN + 1);
1205
1206                         while(host->s[cur_pos] != '\0' && host->s[cur_pos] != '/') cur_pos++;
1207                         strncpy(char_port, &host->s[host->len + 1], MIN(cur_pos - host->len - 1, CHAR_PORT_LEN));
1208                         *port = atoi(char_port);
1209
1210                         path->s = &host->s[cur_pos];
1211                 }
1212                 else
1213                 {
1214                         path->s = &host->s[host->len];
1215                 }
1216         }
1217
1218         while(path->s[path->len] != '\0') path->len++;
1219
1220         return 1;
1221 }
1222
1223 #define MAX_PATH_LEN    127
1224 int rls_get_resource_list(str *rl_uri, str *username, str *domain,
1225                 xmlNodePtr *rl_node, xmlDocPtr *xmldoc)
1226 {
1227         db_key_t query_cols[4];
1228         db_val_t query_vals[4];
1229         int n_query_cols = 0;
1230         db_key_t result_cols[1];
1231         int n_result_cols = 0;
1232         db1_res_t *result = 0;
1233         db_row_t *row;
1234         db_val_t *row_vals;
1235         int xcap_col;
1236         str body;
1237         int checked = 0;
1238         str root, path = {0, 0};
1239         char path_str[MAX_PATH_LEN + 1];
1240         xmlXPathContextPtr xpathCtx = NULL;
1241         xmlXPathObjectPtr xpathObj = NULL;
1242
1243
1244         if (rl_uri==NULL || username==NULL || domain==NULL)
1245         {
1246                 LM_ERR("invalid parameters\n");
1247                 return -1;
1248         }
1249
1250         LM_DBG("rl_uri: %.*s", rl_uri->len, rl_uri->s);
1251
1252         root.s = rl_uri->s;
1253         root.len = rl_uri->len;
1254         while (checked < rl_uri->len)
1255         {
1256                 if (checked < rl_uri->len - 3 && strncmp(rl_uri->s + checked, "/~~", 3) == 0)
1257                 {
1258                         root.len = checked;
1259                         checked += 3;
1260                         break;
1261                 }
1262                 checked++;
1263         }
1264         LM_DBG("doc: %.*s", root.len, root.s);
1265
1266         memset (path_str, '\0', MAX_PATH_LEN + 1);
1267         path.s = path_str;
1268         path.len = 0;
1269         while (checked < rl_uri->len && path.len <= MAX_PATH_LEN)
1270         {
1271                 if (rl_uri->s[checked] == '/')
1272                 {
1273                         strcat(path.s, "/xmlns:");
1274                         path.len += 7;
1275                         checked++;
1276                 }
1277                 else
1278                 {
1279                         path.s[path.len++] = rl_uri->s[checked];
1280                         checked++;
1281                 }
1282         }
1283         LM_DBG("path: %.*s", path.len, path.s);
1284
1285         query_cols[n_query_cols] = &str_username_col;
1286         query_vals[n_query_cols].type = DB1_STR;
1287         query_vals[n_query_cols].nul = 0;
1288         query_vals[n_query_cols].val.str_val = *username;
1289         n_query_cols++;
1290
1291         query_cols[n_query_cols] = &str_domain_col;
1292         query_vals[n_query_cols].type = DB1_STR;
1293         query_vals[n_query_cols].nul = 0;
1294         query_vals[n_query_cols].val.str_val = *domain;
1295         n_query_cols++;
1296
1297         query_cols[n_query_cols] = &str_doc_type_col;
1298         query_vals[n_query_cols].type = DB1_INT;
1299         query_vals[n_query_cols].nul = 0;
1300         query_vals[n_query_cols].val.int_val = RESOURCE_LIST;
1301         n_query_cols++;
1302
1303         query_cols[n_query_cols] = &str_doc_uri_col;
1304         query_vals[n_query_cols].type = DB1_STR;
1305         query_vals[n_query_cols].nul = 0;
1306         query_vals[n_query_cols].val.str_val = root;
1307         n_query_cols++;
1308
1309         if(rls_xcap_dbf.use_table(rls_xcap_db, &rls_xcap_table) < 0)
1310         {
1311                 LM_ERR("in use_table-[table]=%.*s\n",
1312                         rls_xcap_table.len, rls_xcap_table.s);
1313                 return -1;
1314         }
1315
1316         result_cols[xcap_col= n_result_cols++] = &str_doc_col;
1317
1318         if(rls_xcap_dbf.query(rls_xcap_db, query_cols, 0, query_vals, result_cols,
1319                                 n_query_cols, n_result_cols, 0, &result)<0)
1320         {
1321                 LM_ERR("failed querying table xcap for document: %.*s\n",
1322                                 root.len, root.s);
1323                 if(result)
1324                         rls_xcap_dbf.free_result(rls_xcap_db, result);
1325                 return -1;
1326         }
1327
1328         if(result == NULL)
1329         {
1330                 LM_ERR("bad result\n");
1331                 return -1;
1332         }
1333
1334         if(result->n<=0)
1335         {
1336                 LM_DBG("No rl document found\n");
1337                 rls_xcap_dbf.free_result(rls_xcap_db, result);
1338                 return -1;
1339         }
1340
1341         row = &result->rows[0];
1342         row_vals = ROW_VALUES(row);
1343
1344         body.s = (char*)row_vals[xcap_col].val.string_val;
1345         if(body.s==NULL)
1346         {
1347                 LM_ERR("xcap doc is null\n");
1348                 goto error;
1349         }
1350         body.len = strlen(body.s);
1351         if(body.len==0)
1352         {
1353                 LM_ERR("xcap doc is empty\n");
1354                 goto error;
1355         }
1356
1357         LM_DBG("rl document:\n%.*s", body.len, body.s);
1358         *xmldoc = xmlParseMemory(body.s, body.len);
1359         if(*xmldoc==NULL)
1360         {
1361                 LM_ERR("while parsing XML memory. len = %d\n", body.len);
1362                 goto error;
1363         }
1364
1365         if (path.len == 0)
1366         {
1367                 /* No path specified - use all resource-lists. */
1368                 *rl_node = XMLDocGetNodeByName(*xmldoc,"resource-lists", NULL);
1369                 if(*rl_node==NULL)
1370                 {
1371                         LM_ERR("no resource-lists node in XML document\n");
1372                         goto error;
1373                 }
1374         }
1375         else if (path.s != NULL)
1376         {
1377                 xpathCtx = xmlXPathNewContext(*xmldoc);
1378                 if (xpathCtx == NULL)
1379                 {
1380                         LM_ERR("unable to create new XPath context");
1381                         goto error;
1382                 }
1383
1384                 if (xmlXPathRegisterNs(xpathCtx, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:resource-lists") != 0)
1385                 {
1386                         LM_ERR("unable to register xmlns\n");
1387                         goto error;
1388                 }
1389
1390                 xpathObj = xmlXPathEvalExpression(BAD_CAST path.s, xpathCtx);
1391                 if (xpathObj == NULL)
1392                 {
1393                         LM_ERR("unable to evaluate path\n");
1394                         goto error;
1395                 }
1396
1397                 if (xpathObj->nodesetval == NULL || xpathObj->nodesetval->nodeNr <= 0)
1398                 {
1399                         LM_ERR("no nodes found\n");
1400                         goto error;
1401                 }
1402                 if (xpathObj->nodesetval->nodeTab[0] != NULL && xpathObj->nodesetval->nodeTab[0]->type != XML_ELEMENT_NODE)
1403                 {
1404                         LM_ERR("no nodes of the correct type found\n");
1405                         goto error;
1406
1407                 }
1408
1409                 *rl_node = xpathObj->nodesetval->nodeTab[0];
1410
1411                 xmlXPathFreeObject(xpathObj);
1412                 xmlXPathFreeContext(xpathCtx);
1413         }
1414         
1415         rls_xcap_dbf.free_result(rls_xcap_db, result);
1416         return 1;
1417
1418 error:
1419         if(result!=NULL)
1420                 rls_xcap_dbf.free_result(rls_xcap_db, result);
1421         if(xpathObj!=NULL)
1422                 xmlXPathFreeObject(xpathObj);
1423         
1424         if(xpathCtx!=NULL)
1425                 xmlXPathFreeContext(xpathCtx);
1426         if(xmldoc!=NULL)
1427                 xmlFreeDoc(*xmldoc);
1428
1429         return -1;
1430 }