2 * xcap_client module - XCAP client for Kamailio
4 * Copyright (C) 2007 Voice Sistem S.R.L.
6 * This file is part of Kamailio, a free SIP server.
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
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.
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
27 #include <sys/types.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"
40 #define ETAG_HDR "Etag: "
41 #define ETAG_HDR_LEN strlen("Etag: ")
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);
46 int bind_xcap(xcap_api_t* api)
50 LM_ERR("Invalid parameter value\n");
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;
63 void xcapFreeNodeSel(xcap_node_sel_t* node)
90 xcap_node_sel_t* xcapInitNodeSel(void)
92 xcap_node_sel_t* nsel= NULL;
94 nsel= (xcap_node_sel_t*)pkg_malloc(sizeof(xcap_node_sel_t));
99 memset(nsel, 0, sizeof(xcap_node_sel_t));
100 nsel->steps= (step_t*)pkg_malloc(sizeof(step_t));
101 if(nsel->steps== NULL)
103 ERR_MEM(PKG_MEM_STR);
105 memset(nsel->steps, 0, sizeof(step_t));
106 nsel->last_step= nsel->steps;
108 nsel->ns_list= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
109 if(nsel->ns_list== NULL)
111 ERR_MEM(PKG_MEM_STR);
113 memset(nsel->ns_list, 0, sizeof(ns_list_t));
114 nsel->last_ns= nsel->ns_list;
122 pkg_free(nsel->steps);
124 pkg_free(nsel->ns_list);
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)
135 str new_step= {NULL, 0};
150 size+= 2+ attr_test->name.len+ attr_test->value.len;
152 size+= 2+ extra_sel->len;
154 new_step.s= (char*)pkg_malloc(size* sizeof(char));
155 if(new_step.s== NULL)
157 ERR_MEM(PKG_MEM_STR);
163 ns_card= curr_sel->ns_no+ 'a';
168 LM_ERR("Insuficient name cards for namespaces\n");
171 new_step.len= sprintf(new_step.s, "%c:", ns_card);
173 memcpy(new_step.s+new_step.len, name->s, name->len);
174 new_step.len+= name->len;
177 memcpy(new_step.s+new_step.len, "*", 1);
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);
185 new_step.len+= sprintf(new_step.s+ new_step.len, "[%d]", pos);
189 memcpy(new_step.s+ new_step.len, extra_sel->s, extra_sel->len);
190 new_step.len= extra_sel->len;
193 s= (step_t*)pkg_malloc(sizeof(step_t));
196 ERR_MEM(PKG_MEM_STR);
201 curr_sel->last_step->next= s;
202 curr_sel->last_step= s;
204 /* add the namespace binding if present */
207 ns= (ns_list_t*)pkg_malloc(sizeof(ns_list_t));
210 ERR_MEM(PKG_MEM_STR);
213 ns->value.s= (char*)pkg_malloc(namespace->len* sizeof(char));
214 if(ns->value.s== NULL)
216 ERR_MEM(PKG_MEM_STR);
218 memcpy(ns->value.s, namespace->s, namespace->len);
219 ns->value.len= namespace->len;
221 curr_sel->last_ns->next= ns;
222 curr_sel->last_ns= ns;
225 curr_sel->size+= 1+ new_step.len;
228 curr_sel->size+= namespace->len+ 3;
235 pkg_free(new_step.s);
241 pkg_free(ns->value.s);
248 xcap_node_sel_t* xcapNodeSelAddTerminal(xcap_node_sel_t* curr_sel,
249 char* attr_sel, char* namespace_sel, char* extra_sel )
255 char* get_node_selector(xcap_node_sel_t* node_sel)
262 buf= (char*)pkg_malloc((node_sel->size+ 10)* sizeof(char));
265 ERR_MEM(PKG_MEM_STR);
268 s= node_sel->steps->next;
272 memcpy(buf+ len, s->val.s, s->val.len);
280 ns_elem= node_sel->ns_list;
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;
300 char* xcapGetNewDoc(xcap_get_req_t req, str user, str domain)
304 db_key_t query_cols[9];
305 db_val_t query_vals[9];
306 int n_query_cols = 0;
309 path= get_xcap_path(req);
312 LM_ERR("while constructing xcap path\n");
315 /* send HTTP request */
316 doc= send_http_get(path, req.port, NULL, 0, &etag);
319 LM_DBG("the searched document was not found\n");
325 LM_ERR("no etag found\n");
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;
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;
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;
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;
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;
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;
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;
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;
379 if (xcap_dbf.use_table(xcap_db, &xcap_db_table) < 0)
381 LM_ERR("in use_table-[table]= %.*s\n", xcap_db_table.len, xcap_db_table.s);
385 if(xcap_dbf.insert(xcap_db, query_cols, query_vals, n_query_cols)< 0)
387 LM_ERR("in sql insert\n");
396 char* get_xcap_path(xcap_get_req_t req)
400 char* node_selector= NULL;
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);
406 len+= req.node_sel->size;
408 path= (char*)pkg_malloc(len);
411 ERR_MEM(PKG_MEM_STR);
416 node_selector= get_node_selector(req.node_sel);
417 if(node_selector== NULL)
419 LM_ERR("while constructing node selector\n");
424 size= sprintf(path, "%s/%.*s/", req.xcap_root, req.doc_sel.auid.len,
427 if(req.doc_sel.type==USERS_TYPE)
428 size+= sprintf(path+ size, "%s/%.*s/", "users", req.doc_sel.xid.len,
431 size+= sprintf(path+ size, "%s/", "global");
432 size+= sprintf(path+ size, "%.*s", req.doc_sel.filename.len,
433 req.doc_sel.filename.s);
437 size+= sprintf(path+ size, "/~~%s", node_selector);
442 LM_ERR("buffer size overflow\n");
445 pkg_free(node_selector);
453 pkg_free(node_selector);
457 size_t get_xcap_etag( void *ptr, size_t size, size_t nmemb, void *stream)
462 if(strncasecmp(ptr, ETAG_HDR, ETAG_HDR_LEN)== 0)
464 len= size* nmemb- ETAG_HDR_LEN;
465 etag= (char*)pkg_malloc((len+ 1)* sizeof(char));
468 ERR_MEM(PKG_MEM_STR);
470 memcpy(etag, ptr+ETAG_HDR_LEN, len);
472 *((char**)stream)= etag;
480 char* send_http_get(char* path, unsigned int xcap_port, char* match_etag,
481 int match_type, char** etag)
486 CURL* curl_handle= NULL;
487 static char buf[128];
488 char* match_header= NULL;
493 char* hdr_name= NULL;
495 memset(buf, 0, 128* sizeof(char));
498 hdr_name= (match_type==IF_MATCH)?"If-Match":"If-None-Match";
500 len=sprintf(match_header, "%s: %s\n", hdr_name, match_etag);
502 match_header[len]= '\0';
505 curl_handle = curl_easy_init();
507 curl_easy_setopt(curl_handle, CURLOPT_URL, path);
509 curl_easy_setopt(curl_handle, CURLOPT_PORT, xcap_port);
511 curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1);
513 curl_easy_setopt(curl_handle, CURLOPT_STDERR, stdout);
515 curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_function);
517 curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, &stream);
519 curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, get_xcap_etag);
521 curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, &etag);
524 curl_easy_setopt(curl_handle, CURLOPT_HEADER, (long)match_header);
526 /* non-2xx => error */
527 curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1);
529 ret_code= curl_easy_perform(curl_handle );
531 if( ret_code== CURLE_WRITE_ERROR)
533 LM_ERR("while performing curl option\n");
540 curl_global_cleanup();
544 size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream)
546 /* allocate memory and copy */
549 data= (char*)pkg_malloc(size* nmemb);
552 ERR_MEM(PKG_MEM_STR);
555 memcpy(data, (char*)ptr, size* nmemb);
557 *((char**) stream)= data;
562 return CURLE_WRITE_ERROR;