xcap_client: removed unused api function get_elem()
[sip-router] / src / modules / xcap_client / xcap_functions.c
1 /*
2  * xcap_client module - XCAP client for Kamailio
3  *
4  * Copyright (C) 2007 Voice Sistem S.R.L.
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <sys/types.h>
28 #include <sys/ipc.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <time.h>
32 #include <curl/curl.h>
33 #include "../../core/mem/mem.h"
34 #include "../../lib/srdb1/db.h"
35 #include "xcap_functions.h"
36 #include "xcap_client.h"
37 #include "../presence/hash.h"
38
39
40 #define ETAG_HDR          "Etag: "
41 #define ETAG_HDR_LEN      strlen("Etag: ")
42
43 size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream);
44 char* get_xcap_path(xcap_get_req_t req);
45
46 int bind_xcap(xcap_api_t* api)
47 {
48         if (!api)
49         {
50                 LM_ERR("Invalid parameter value\n");
51                 return -1;
52         }
53         api->int_node_sel= xcapInitNodeSel;
54         api->add_step= xcapNodeSelAddStep;
55         api->add_terminal= xcapNodeSelAddTerminal;
56         api->free_node_sel= xcapFreeNodeSel;
57         api->register_xcb= register_xcapcb;
58         api->getNewDoc= xcapGetNewDoc;
59
60         return 0;
61 }
62
63 void xcapFreeNodeSel(xcap_node_sel_t* node)
64 {
65         step_t* s, *p;
66         ns_list_t* n, *m;
67
68         s= node->steps;
69         while(s)
70         {
71                 p= s;
72                 s= s->next;
73                 pkg_free(p->val.s);
74                 pkg_free(p);
75         }
76
77         n= node->ns_list;
78         while(n)
79         {
80                 m= n;
81                 n= n->next;
82                 pkg_free(m->value.s);
83                 pkg_free(m);
84         }
85
86         pkg_free(node);
87
88 }
89
90 xcap_node_sel_t* xcapInitNodeSel(void)
91 {
92         xcap_node_sel_t* nsel= NULL;
93
94         nsel= (xcap_node_sel_t*)pkg_malloc(sizeof(xcap_node_sel_t));
95         if(nsel== NULL)
96         {
97                 ERR_MEM(PKG_MEM_STR);
98         }
99         memset(nsel, 0, sizeof(xcap_node_sel_t));
100         nsel->steps= (step_t*)pkg_malloc(sizeof(step_t));
101         if(nsel->steps== NULL)
102         {
103                 ERR_MEM(PKG_MEM_STR);
104         }
105         memset(nsel->steps, 0, sizeof(step_t));
106         nsel->last_step= nsel->steps;
107
108         nsel->ns_list= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
109         if(nsel->ns_list== NULL)
110         {
111                 ERR_MEM(PKG_MEM_STR);
112         }
113         memset(nsel->ns_list, 0, sizeof(ns_list_t));
114         nsel->last_ns= nsel->ns_list;
115
116         return nsel;
117
118 error:
119         if(nsel)
120         {
121                 if(nsel->steps)
122                         pkg_free(nsel->steps);
123                 if(nsel->ns_list)
124                         pkg_free(nsel->ns_list);
125                 pkg_free(nsel);
126         }
127
128         return NULL;
129 }
130
131 xcap_node_sel_t* xcapNodeSelAddStep(xcap_node_sel_t* curr_sel, str* name,
132                 str* namespace, int pos, attr_test_t*  attr_test, str* extra_sel)
133 {
134         int size= 0;
135         str new_step= {NULL, 0};
136         step_t* s= NULL;
137         char ns_card= 'a';
138         ns_list_t* ns= NULL;
139
140         if(name)
141                 size+= name->len;
142         else
143                 size+= 1;
144
145         if(namespace)
146                 size+= 2;
147         if(pos> 0)
148                 size+= 7;
149         if(attr_test)
150                 size+= 2+ attr_test->name.len+ attr_test->value.len;
151         if(extra_sel)
152                 size+= 2+ extra_sel->len;
153
154         new_step.s= (char*)pkg_malloc(size* sizeof(char));
155         if(new_step.s== NULL)
156         {
157                 ERR_MEM(PKG_MEM_STR);
158         }
159         if(name)
160         {
161                 if(namespace)
162                 {
163                         ns_card= curr_sel->ns_no+ 'a';
164                         curr_sel->ns_no++;
165
166                         if(ns_card> 'z')
167                         {
168                                 LM_ERR("Insuficient name cards for namespaces\n");
169                                 goto error;
170                         }
171                         new_step.len= sprintf(new_step.s, "%c:", ns_card);
172                 }
173                 memcpy(new_step.s+new_step.len, name->s, name->len);
174                 new_step.len+= name->len;
175         }
176         else
177                 memcpy(new_step.s+new_step.len, "*", 1);
178
179         if(attr_test)
180         {
181                 new_step.len+= sprintf(new_step.s+ new_step.len, "[%.*s=%.*s]", attr_test->name.len,
182                                 attr_test->name.s, attr_test->value.len, attr_test->value.s);
183         }
184         if(pos> 0)
185                 new_step.len+= sprintf(new_step.s+ new_step.len, "[%d]", pos);
186
187         if(extra_sel)
188         {
189                 memcpy(new_step.s+ new_step.len, extra_sel->s, extra_sel->len);
190                 new_step.len= extra_sel->len;
191         }
192
193         s= (step_t*)pkg_malloc(sizeof(step_t));
194         if(s== NULL)
195         {
196                 ERR_MEM(PKG_MEM_STR);
197         }
198         s->val= new_step;
199         s->next= NULL;
200
201         curr_sel->last_step->next= s;
202         curr_sel->last_step= s;
203
204         /* add the namespace binding if present */
205         if(namespace)
206         {
207                 ns= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
208                 if(ns== NULL)
209                 {
210                         ERR_MEM(PKG_MEM_STR);
211                 }
212                 ns->name= ns_card;
213                 ns->value.s= (char*)pkg_malloc(namespace->len* sizeof(char));
214                 if(ns->value.s== NULL)
215                 {
216                         ERR_MEM(PKG_MEM_STR);
217                 }
218                 memcpy(ns->value.s, namespace->s, namespace->len);
219                 ns->value.len= namespace->len;
220
221                 curr_sel->last_ns->next= ns;
222                 curr_sel->last_ns= ns;
223         }
224
225         curr_sel->size+= 1+ new_step.len;
226         if(namespace->len)
227         {
228                 curr_sel->size+= namespace->len+ 3;
229         }
230
231         return curr_sel;
232
233 error:
234         if(new_step.s)
235                 pkg_free(new_step.s);
236         if(s)
237                 pkg_free(s);
238         if(ns)
239         {
240                 if(ns->value.s)
241                         pkg_free(ns->value.s);
242                 pkg_free(ns);
243         }
244
245         return NULL;
246 }
247
248 xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel,
249                 char* attr_sel, char* namespace_sel, char* extra_sel )
250 {
251
252         return NULL;
253 }
254
255 char* get_node_selector(xcap_node_sel_t* node_sel)
256 {
257         char* buf= NULL;
258         step_t* s;
259         int len= 0;
260         ns_list_t* ns_elem;
261
262         buf= (char*)pkg_malloc((node_sel->size+ 10)* sizeof(char));
263         if(buf== NULL)
264         {
265                 ERR_MEM(PKG_MEM_STR);
266         }
267
268         s= node_sel->steps->next;
269
270         while(1)
271         {
272                 memcpy(buf+ len, s->val.s, s->val.len);
273                 len+= s->val.len;
274                 s= s->next;
275                 if(s)
276                         buf[len++]= '/';
277                 else
278                         break;
279         }
280         ns_elem= node_sel->ns_list;
281
282         if(ns_elem)
283                 buf[len++]= '?';
284
285         while(ns_elem)
286         {
287                 len+= sprintf(buf+ len, "xmlns(%c=%.*s)", ns_elem->name,
288                                 ns_elem->value.len, ns_elem->value.s);
289                 ns_elem= ns_elem->next;
290         }
291
292         buf[len]= '\0';
293
294         return buf;
295
296 error:
297         return NULL;
298 }
299
300 char* xcapGetNewDoc(xcap_get_req_t req, str user, str domain)
301 {
302         char* etag= NULL;
303         char* doc= NULL;
304         db_key_t query_cols[9];
305         db_val_t query_vals[9];
306         int n_query_cols = 0;
307         char* path= NULL;
308
309         path= get_xcap_path(req);
310         if(path== NULL)
311         {
312                 LM_ERR("while constructing xcap path\n");
313                 return NULL;
314         }
315         /* send HTTP request */
316         doc= send_http_get(path, req.port, NULL, 0, &etag);
317         if(doc== NULL)
318         {
319                 LM_DBG("the searched document was not found\n");
320                 goto done;
321         }
322
323         if(etag== NULL)
324         {
325                 LM_ERR("no etag found\n");
326                 pkg_free(doc);
327                 doc= NULL;
328                 goto done;
329         }
330         /* insert in xcap table*/
331         query_cols[n_query_cols] = &str_username_col;
332         query_vals[n_query_cols].type = DB1_STR;
333         query_vals[n_query_cols].nul = 0;
334         query_vals[n_query_cols].val.str_val = user;
335         n_query_cols++;
336
337         query_cols[n_query_cols] = &str_domain_col;
338         query_vals[n_query_cols].type = DB1_STR;
339         query_vals[n_query_cols].nul = 0;
340         query_vals[n_query_cols].val.str_val = domain;
341         n_query_cols++;
342
343         query_cols[n_query_cols] = &str_doc_type_col;
344         query_vals[n_query_cols].type = DB1_INT;
345         query_vals[n_query_cols].nul = 0;
346         query_vals[n_query_cols].val.int_val= req.doc_sel.doc_type;
347         n_query_cols++;
348
349         query_cols[n_query_cols] = &str_doc_col;
350         query_vals[n_query_cols].type = DB1_STRING;
351         query_vals[n_query_cols].nul = 0;
352         query_vals[n_query_cols].val.string_val= doc;
353         n_query_cols++;
354
355         query_cols[n_query_cols] = &str_etag_col;
356         query_vals[n_query_cols].type = DB1_STRING;
357         query_vals[n_query_cols].nul = 0;
358         query_vals[n_query_cols].val.string_val= etag;
359         n_query_cols++;
360
361         query_cols[n_query_cols] = &str_source_col;
362         query_vals[n_query_cols].type = DB1_INT;
363         query_vals[n_query_cols].nul = 0;
364         query_vals[n_query_cols].val.int_val= XCAP_CL_MOD;
365         n_query_cols++;
366
367         query_cols[n_query_cols] = &str_doc_uri_col;
368         query_vals[n_query_cols].type = DB1_STRING;
369         query_vals[n_query_cols].nul = 0;
370         query_vals[n_query_cols].val.string_val= path;
371         n_query_cols++;
372
373         query_cols[n_query_cols] = &str_port_col;
374         query_vals[n_query_cols].type = DB1_INT;
375         query_vals[n_query_cols].nul = 0;
376         query_vals[n_query_cols].val.int_val= req.port;
377         n_query_cols++;
378
379         if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0)
380         {
381                 LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s);
382                 goto done;
383         }
384
385         if(xcap_dbf.insert(xcap_db, query_cols, query_vals, n_query_cols)< 0)
386         {
387                 LM_ERR("in sql insert\n");
388                 goto done;
389         }
390
391 done:
392         pkg_free(path);
393         return doc;
394 }
395
396 char* get_xcap_path(xcap_get_req_t req)
397 {
398         int len= 0, size;
399         char* path= NULL;
400         char* node_selector= NULL;
401
402         len= (strlen(req.xcap_root)+ 1+ req.doc_sel.auid.len+ 5+
403                         req.doc_sel.xid.len+ req.doc_sel.filename.len+ 50)* sizeof(char);
404
405         if(req.node_sel)
406                 len+= req.node_sel->size;
407
408         path= (char*)pkg_malloc(len);
409         if(path== NULL)
410         {
411                 ERR_MEM(PKG_MEM_STR);
412         }
413
414         if(req.node_sel)
415         {
416                 node_selector= get_node_selector(req.node_sel);
417                 if(node_selector== NULL)
418                 {
419                         LM_ERR("while constructing node selector\n");
420                         goto error;
421                 }
422         }
423
424         size= sprintf(path, "%s/%.*s/", req.xcap_root, req.doc_sel.auid.len,
425                         req.doc_sel.auid.s);
426
427         if(req.doc_sel.type==USERS_TYPE)
428                 size+= sprintf(path+ size, "%s/%.*s/", "users", req.doc_sel.xid.len,
429                                 req.doc_sel.xid.s);
430         else
431                 size+= sprintf(path+ size, "%s/", "global");
432         size+= sprintf(path+ size, "%.*s", req.doc_sel.filename.len,
433                         req.doc_sel.filename.s);
434
435         if(node_selector)
436         {
437                 size+= sprintf(path+ size, "/~~%s", node_selector);
438         }
439
440         if(size> len)
441         {
442                 LM_ERR("buffer size overflow\n");
443                 goto error;
444         }
445         pkg_free(node_selector);
446
447         return path;
448
449 error:
450         if(path)
451                 pkg_free(path);
452         if(node_selector)
453                 pkg_free(node_selector);
454         return NULL;
455 }
456
457 size_t get_xcap_etag( void *ptr, size_t size, size_t nmemb, void *stream)
458 {
459         int len= 0;
460         char* etag= NULL;
461
462         if(strncasecmp(ptr, ETAG_HDR, ETAG_HDR_LEN)== 0)
463         {
464                 len= size* nmemb- ETAG_HDR_LEN;
465                 etag= (char*)pkg_malloc((len+ 1)* sizeof(char));
466                 if(etag== NULL)
467                 {
468                         ERR_MEM(PKG_MEM_STR);
469                 }
470                 memcpy(etag, ptr+ETAG_HDR_LEN, len);
471                 etag[len]= '\0';
472                 *((char**)stream)= etag;
473         }
474         return len;
475
476 error:
477         return -1;
478 }
479
480 char* send_http_get(char* path, unsigned int xcap_port, char* match_etag,
481                 int match_type, char** etag)
482 {
483         int len;
484         char* stream= NULL;
485         CURLcode ret_code;
486         CURL* curl_handle= NULL;
487         static char buf[128];
488         char* match_header= NULL;
489         *etag= NULL;
490
491         if(match_etag)
492         {
493                 char* hdr_name= NULL;
494
495                 memset(buf, 0, 128* sizeof(char));
496                 match_header= buf;
497
498                 hdr_name= (match_type==IF_MATCH)?"If-Match":"If-None-Match";
499
500                 len=sprintf(match_header, "%s: %s\n", hdr_name, match_etag);
501
502                 match_header[len]= '\0';
503         }
504
505         curl_handle = curl_easy_init();
506
507         curl_easy_setopt(curl_handle, CURLOPT_URL, path);
508
509         curl_easy_setopt(curl_handle, CURLOPT_PORT, xcap_port);
510
511         curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
512
513         curl_easy_setopt(curl_handle,  CURLOPT_STDERR, stdout);
514
515         curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_function);
516
517         curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream);
518
519         curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_xcap_etag);
520
521         curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, &etag);
522
523         if(match_header)
524                 curl_easy_setopt(curl_handle, CURLOPT_HEADER, (long)match_header);
525
526         /* non-2xx => error */
527         curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
528
529         ret_code= curl_easy_perform(curl_handle );
530
531         if( ret_code== CURLE_WRITE_ERROR)
532         {
533                 LM_ERR("while performing curl option\n");
534                 if(stream)
535                         pkg_free(stream);
536                 stream= NULL;
537                 return NULL;
538         }
539
540         curl_global_cleanup();
541         return stream;
542 }
543
544 size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream)
545 {
546         /* allocate memory and copy */
547         char* data;
548
549         data= (char*)pkg_malloc(size* nmemb);
550         if(data== NULL)
551         {
552                 ERR_MEM(PKG_MEM_STR);
553         }
554
555         memcpy(data, (char*)ptr, size* nmemb);
556
557         *((char**) stream)= data;
558
559         return size* nmemb;
560
561 error:
562         return CURLE_WRITE_ERROR;
563 }