00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <stdlib.h>
00029 #include <sys/types.h>
00030 #include <unistd.h>
00031 #include <fcntl.h>
00032 #include <time.h>
00033
00034 #include "../../lib/srdb1/db.h"
00035 #include "../../pt.h"
00036 #include "../../sr_module.h"
00037 #include "../../dprint.h"
00038 #include "../../error.h"
00039 #include "../../ut.h"
00040 #include "../../mem/mem.h"
00041 #include "../../data_lump.h"
00042 #include "../../data_lump_rpl.h"
00043 #include "../../mod_fix.h"
00044 #include "../../parser/parse_uri.h"
00045 #include "../../modules_k/xcap_client/xcap_callbacks.h"
00046 #include "../../modules/sl/sl.h"
00047 #include "../../lib/kcore/cmpapi.h"
00048
00049 #include "xcap_misc.h"
00050
00051 MODULE_VERSION
00052
00053 #define XCAP_TABLE_VERSION 4
00054
00055
00056 static int xcaps_put_db(str* user, str *domain, xcap_uri_t *xuri, str *etag,
00057 str* doc);
00058 static int xcaps_get_db_doc(str* user, str *domain, xcap_uri_t *xuri,
00059 str *doc);
00060 static int xcaps_get_db_etag(str* user, str *domain, xcap_uri_t *xuri,
00061 str *etag);
00062 static int xcaps_del_db(str* user, str *domain, xcap_uri_t *xuri);
00063
00064 static int w_xcaps_put(sip_msg_t* msg, char* puri, char* ppath,
00065 char* pbody);
00066 static int w_xcaps_get(sip_msg_t* msg, char* puri, char* ppath);
00067 static int w_xcaps_del(sip_msg_t* msg, char* puri, char* ppath);
00068 static int fixup_xcaps_put(void** param, int param_no);
00069 static int check_preconditions(sip_msg_t *msg, str etag_hdr);
00070 static int check_match_header(str body, str *etag);
00071
00072 static int mod_init(void);
00073 static int child_init(int rank);
00074 static void destroy(void);
00075
00076 int xcaps_xpath_ns_param(modparam_t type, void *val);
00077
00078 int xcaps_path_get_auid_type(str *path);
00079 int xcaps_generate_etag_hdr(str *etag);
00080
00081 static str xcaps_db_table = str_init("xcap");
00082 static str xcaps_db_url = str_init(DEFAULT_DB_URL);
00083 static int xcaps_init_time = 0;
00084 static int xcaps_etag_counter = 1;
00085 str xcaps_root = str_init("/xcap-root/");
00086
00087 static str xcaps_buf = {0, 8192};
00088 #define XCAPS_ETAG_SIZE 128
00089 static char xcaps_etag_buf[XCAPS_ETAG_SIZE];
00090
00091 static str str_id_col = str_init("id");
00092 static str str_source_col = str_init("source");
00093 static str str_doc_col = str_init("doc");
00094 static str str_etag_col = str_init("etag");
00095 static str str_username_col = str_init("username");
00096 static str str_domain_col = str_init("domain");
00097 static str str_doc_type_col = str_init("doc_type");
00098 static str str_doc_uri_col = str_init("doc_uri");
00099 static str str_port_col = str_init("port");
00100
00101
00102
00103 db1_con_t *xcaps_db = NULL;
00104 db_func_t xcaps_dbf;
00105
00107 sl_api_t slb;
00108
00109 static pv_export_t mod_pvs[] = {
00110 { {"xcapuri", sizeof("xcapuri")-1}, PVT_OTHER, pv_get_xcap_uri,
00111 pv_set_xcap_uri, pv_parse_xcap_uri_name, 0, 0, 0 },
00112 { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
00113 };
00114
00115 static param_export_t params[] = {
00116 { "db_url", STR_PARAM, &xcaps_db_url.s },
00117 { "xcap_table", STR_PARAM, &xcaps_db_table.s },
00118 { "xcap_root", STR_PARAM, &xcaps_root.s },
00119 { "buf_size", INT_PARAM, &xcaps_buf.len },
00120 { "xml_ns", STR_PARAM|USE_FUNC_PARAM, (void*)xcaps_xpath_ns_param },
00121 { 0, 0, 0 }
00122 };
00123
00124 static cmd_export_t cmds[]={
00125 {"xcaps_put", (cmd_function)w_xcaps_put, 3,
00126 fixup_xcaps_put, 0, REQUEST_ROUTE},
00127 {"xcaps_get", (cmd_function)w_xcaps_get, 2,
00128 fixup_xcaps_put, 0, REQUEST_ROUTE},
00129 {"xcaps_del", (cmd_function)w_xcaps_del, 2,
00130 fixup_xcaps_put, 0, REQUEST_ROUTE},
00131 {0,0,0,0,0,0}
00132 };
00133
00134
00136 struct module_exports exports= {
00137 "xcap_server",
00138 DEFAULT_DLFLAGS,
00139 cmds,
00140 params,
00141 0,
00142 0,
00143 mod_pvs,
00144 0,
00145 mod_init,
00146 0,
00147 destroy,
00148 child_init
00149 };
00150
00154 static int mod_init(void)
00155 {
00156
00157 xcaps_db_url.len = (xcaps_db_url.s) ? strlen(xcaps_db_url.s) : 0;
00158 xcaps_db_table.len = (xcaps_db_table.s) ? strlen(xcaps_db_table.s) : 0;
00159 xcaps_root.len = (xcaps_root.s) ? strlen(xcaps_root.s) : 0;
00160
00161 if(xcaps_buf.len<=0)
00162 {
00163 LM_ERR("invalid buffer size\n");
00164 return -1;
00165 }
00166
00167 xcaps_buf.s = (char*)pkg_malloc(xcaps_buf.len+1);
00168 if(xcaps_buf.s==NULL)
00169 {
00170 LM_ERR("no pkg\n");
00171 return -1;
00172 }
00173
00174
00175 if (db_bind_mod(&xcaps_db_url, &xcaps_dbf))
00176 {
00177 LM_ERR("Database module not found\n");
00178 return -1;
00179 }
00180
00181 if (!DB_CAPABILITY(xcaps_dbf, DB_CAP_ALL)) {
00182 LM_ERR("Database module does not implement all functions"
00183 " needed by the module\n");
00184 return -1;
00185 }
00186
00187 xcaps_db = xcaps_dbf.init(&xcaps_db_url);
00188 if (xcaps_db==NULL)
00189 {
00190 LM_ERR("connecting to database\n");
00191 return -1;
00192 }
00193
00194 if(db_check_table_version(&xcaps_dbf, xcaps_db, &xcaps_db_table,
00195 XCAP_TABLE_VERSION) < 0) {
00196 LM_ERR("error during table version check.\n");
00197 return -1;
00198 }
00199 xcaps_dbf.close(xcaps_db);
00200 xcaps_db = NULL;
00201
00202
00203 if (sl_load_api(&slb)!=0) {
00204 LM_ERR("cannot bind to SL API\n");
00205 return -1;
00206 }
00207
00208 xcaps_init_time = (int)time(NULL);
00209 return 0;
00210 }
00211
00215 static int child_init(int rank)
00216 {
00217 if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00218 return 0;
00219
00220 if((xcaps_db = xcaps_dbf.init(&xcaps_db_url))==NULL)
00221 {
00222 LM_ERR("cannot connect to db\n");
00223 return -1;
00224 }
00225 return 0;
00226 }
00227
00231 static void destroy(void)
00232 {
00233 if(xcaps_db != NULL)
00234 xcaps_dbf.close(xcaps_db);
00235 }
00236
00237
00241 static int xcaps_send_reply(sip_msg_t *msg, int code, str *reason,
00242 str *hdrs, str *ctype, str *body)
00243 {
00244 str tbuf;
00245
00246 if(hdrs->len>0)
00247 {
00248 if (add_lump_rpl(msg, hdrs->s, hdrs->len, LUMP_RPL_HDR) == 0)
00249 {
00250 LM_ERR("failed to insert extra-headers lump\n");
00251 return -1;
00252 }
00253 }
00254
00255 if(ctype->len>0)
00256 {
00257
00258 tbuf.len=sizeof("Content-Type: ") - 1 + ctype->len + CRLF_LEN;
00259 tbuf.s=pkg_malloc(sizeof(char)*(tbuf.len));
00260
00261 if (tbuf.len==0)
00262 {
00263 LM_ERR("out of pkg memory\n");
00264 return -1;
00265 }
00266 memcpy(tbuf.s, "Content-Type: ", sizeof("Content-Type: ") - 1);
00267 memcpy(tbuf.s+sizeof("Content-Type: ") - 1, ctype->s, ctype->len);
00268 memcpy(tbuf.s+sizeof("Content-Type: ") - 1 + ctype->len,
00269 CRLF, CRLF_LEN);
00270 if (add_lump_rpl(msg, tbuf.s, tbuf.len, LUMP_RPL_HDR) == 0)
00271 {
00272 LM_ERR("failed to insert content-type lump\n");
00273 pkg_free(tbuf.s);
00274 return -1;
00275 }
00276 pkg_free(tbuf.s);
00277 }
00278 if(body->len>0)
00279 {
00280 if (add_lump_rpl(msg, body->s, body->len, LUMP_RPL_BODY) < 0)
00281 {
00282 LM_ERR("Error while adding reply lump\n");
00283 return -1;
00284 }
00285 }
00286 if (slb.freply(msg, code, reason) < 0)
00287 {
00288 LM_ERR("Error while sending reply\n");
00289 return -1;
00290 }
00291 return 0;
00292 }
00293
00297 int xcaps_xpath_hack(str *buf, int type)
00298 {
00299 char *match;
00300 char *repl;
00301 char c;
00302 char *p;
00303 char *start;
00304
00305 if(buf==NULL || buf->len <=10)
00306 return 0;
00307
00308 if(type==0)
00309 {
00310 match = " xmlns=";
00311 repl = " x____=";
00312 } else {
00313 match = " x____=";
00314 repl = " xmlns=";
00315 }
00316
00317 start = buf->s;
00318 c = buf->s[buf->len-1];
00319 buf->s[buf->len-1] = '\0';
00320 while((p = strstr(start, match))!=NULL)
00321 {
00322 memcpy(p, repl, 7);
00323 start = p + 7;
00324 }
00325 buf->s[buf->len-1] = c;
00326 return 0;
00327 }
00328
00332 static int xcaps_put_db(str* user, str *domain, xcap_uri_t *xuri, str *etag,
00333 str* doc)
00334 {
00335 db_key_t qcols[9], rcols[2], ucols[5];
00336 db_val_t qvals[9], uvals[5];
00337 db1_res_t *res = NULL;
00338 int ncols = 0, num_ucols = 0, nrows = 0;
00339
00340 if(xcaps_check_doc_validity(doc)<0)
00341 {
00342 LM_ERR("invalid xml doc to insert in database\n");
00343 goto error;
00344 }
00345
00346 qcols[ncols] = &str_username_col;
00347 qvals[ncols].type = DB1_STR;
00348 qvals[ncols].nul = 0;
00349 qvals[ncols].val.str_val = *user;
00350 ncols++;
00351
00352 qcols[ncols] = &str_domain_col;
00353 qvals[ncols].type = DB1_STR;
00354 qvals[ncols].nul = 0;
00355 qvals[ncols].val.str_val = *domain;
00356 ncols++;
00357
00358 qcols[ncols] = &str_doc_type_col;
00359 qvals[ncols].type = DB1_INT;
00360 qvals[ncols].nul = 0;
00361 qvals[ncols].val.int_val= xuri->type;
00362 ncols++;
00363
00364 qcols[ncols] = &str_doc_uri_col;
00365 qvals[ncols].type = DB1_STR;
00366 qvals[ncols].nul = 0;
00367 qvals[ncols].val.str_val= xuri->adoc;
00368 ncols++;
00369
00370 rcols[0] = &str_id_col;
00371
00372 if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
00373 {
00374 LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
00375 xcaps_db_table.s);
00376 goto error;
00377 }
00378
00379 if (xcaps_dbf.query(xcaps_db, qcols, 0, qvals, rcols, ncols, 1, 0, &res) < 0)
00380 {
00381 LM_ERR("in sql query\n");
00382 goto error;
00383 }
00384
00385 nrows = RES_ROW_N(res);
00386 xcaps_dbf.free_result(xcaps_db, res);
00387
00388 if (nrows == 0)
00389 {
00390 qcols[ncols] = &str_doc_col;
00391 qvals[ncols].type = DB1_BLOB;
00392 qvals[ncols].nul = 0;
00393 qvals[ncols].val.str_val= *doc;
00394 ncols++;
00395
00396 qcols[ncols] = &str_etag_col;
00397 qvals[ncols].type = DB1_STR;
00398 qvals[ncols].nul = 0;
00399 qvals[ncols].val.str_val= *etag;
00400 ncols++;
00401
00402 qcols[ncols] = &str_source_col;
00403 qvals[ncols].type = DB1_INT;
00404 qvals[ncols].nul = 0;
00405 qvals[ncols].val.int_val = 0;
00406 ncols++;
00407
00408 qcols[ncols] = &str_port_col;
00409 qvals[ncols].type = DB1_INT;
00410 qvals[ncols].nul = 0;
00411 qvals[ncols].val.int_val = 0;
00412 ncols++;
00413
00414 if(xcaps_dbf.insert(xcaps_db, qcols, qvals, ncols)< 0)
00415 {
00416 LM_ERR("in sql insert\n");
00417 goto error;
00418 }
00419 }
00420 else if (nrows == 1)
00421 {
00422 ucols[num_ucols] = &str_doc_col;
00423 uvals[num_ucols].type = DB1_BLOB;
00424 uvals[num_ucols].nul = 0;
00425 uvals[num_ucols].val.str_val= *doc;
00426 num_ucols++;
00427
00428 ucols[num_ucols] = &str_etag_col;
00429 uvals[num_ucols].type = DB1_STR;
00430 uvals[num_ucols].nul = 0;
00431 uvals[num_ucols].val.str_val= *etag;
00432 num_ucols++;
00433
00434 ucols[num_ucols] = &str_source_col;
00435 uvals[num_ucols].type = DB1_INT;
00436 uvals[num_ucols].nul = 0;
00437 uvals[num_ucols].val.int_val = 0;
00438 num_ucols++;
00439
00440 ucols[num_ucols] = &str_port_col;
00441 uvals[num_ucols].type = DB1_INT;
00442 uvals[num_ucols].nul = 0;
00443 uvals[num_ucols].val.int_val = 0;
00444 num_ucols++;
00445
00446 if (xcaps_dbf.update(xcaps_db, qcols, 0, qvals, ucols, uvals, ncols, num_ucols) < 0)
00447 {
00448 LM_ERR("in sql update\n");
00449 goto error;
00450 }
00451 }
00452 else
00453 {
00454 LM_ERR("found %d copies of the same document in XCAP Server\n", nrows);
00455 goto error;
00456 }
00457
00458 return 0;
00459 error:
00460 return -1;
00461 }
00462
00463 static str xcaps_str_empty = {"", 0};
00464 static str xcaps_str_ok = {"OK", 2};
00465 static str xcaps_str_srverr = {"Server error", 12};
00466 static str xcaps_str_notfound = {"Not found", 9};
00467 static str xcaps_str_precon = {"Precondition Failed", 19};
00468 static str xcaps_str_notmod = {"Not Modified", 12};
00469 static str xcaps_str_appxml = {"application/xml", 15};
00470 static str xcaps_str_apprlxml = {"application/resource-lists+xml", 30};
00471 static str xcaps_str_apprsxml = {"application/rls-services+xml", 28};
00472 #if 0
00473 static str xcaps_str_nocontent = {"No content", 10};
00474 static str xcaps_str_appxcxml = {"application/xcap-caps+xml", 25};
00475 static str xcaps_str_appsexml = {"application/vnd.oma.search+xml", 30};
00476 #endif
00477 static str xcaps_str_appapxml = {"application/auth-policy+xml", 27};
00478 static str xcaps_str_appupxml = {"application/vnd.oma.user-profile+xml", 36};
00479 static str xcaps_str_apppcxml = {"application/vnd.oma.pres-content+xml", 36};
00480 static str xcaps_str_apppdxml = {"application/pidf+xml", 20};
00481
00482
00486 static int w_xcaps_put(sip_msg_t* msg, char* puri, char* ppath,
00487 char* pbody)
00488 {
00489 struct sip_uri turi;
00490 str uri;
00491 str path;
00492 str body = {0, 0};
00493 str etag;
00494 str etag_hdr;
00495 str tbuf;
00496 str nbuf = {0, 0};
00497 pv_elem_t *xm;
00498 xcap_uri_t xuri;
00499
00500 if(puri==0 || ppath==0 || pbody==0)
00501 {
00502 LM_ERR("invalid parameters\n");
00503 goto error;
00504 }
00505
00506 if(fixup_get_svalue(msg, (gparam_p)puri, &uri)!=0)
00507 {
00508 LM_ERR("unable to get uri\n");
00509 goto error;
00510 }
00511 if(uri.s==NULL || uri.len == 0)
00512 {
00513 LM_ERR("invalid uri parameter\n");
00514 goto error;
00515 }
00516
00517 if(fixup_get_svalue(msg, (gparam_p)ppath, &path)!=0)
00518 {
00519 LM_ERR("unable to get path\n");
00520 goto error;
00521 }
00522 if(path.s==NULL || path.len == 0)
00523 {
00524 LM_ERR("invalid path parameter\n");
00525 goto error;
00526 }
00527
00528 xm = (pv_elem_t*)pbody;
00529 body.len = xcaps_buf.len - 1;
00530 if(pv_printf(msg, xm, xcaps_buf.s, &body.len)<0)
00531 {
00532 LM_ERR("unable to get body\n");
00533 goto error;
00534 }
00535 if(body.len <= 0)
00536 {
00537 LM_ERR("invalid body parameter\n");
00538 goto error;
00539 }
00540 body.s = (char*)pkg_malloc(body.len+1);
00541 if(body.s==NULL)
00542 {
00543 LM_ERR("no more pkg\n");
00544 goto error;
00545 }
00546
00547 memcpy(body.s, xcaps_buf.s, body.len);
00548 body.s[body.len] = '\0';
00549
00550 if(parse_uri(uri.s, uri.len, &turi)!=0)
00551 {
00552 LM_ERR("parsing uri parameter\n");
00553 goto error;
00554 }
00555
00556
00557 if(xcap_parse_uri(&path, &xcaps_root, &xuri)<0)
00558 {
00559 LM_ERR("cannot parse xcap uri [%.*s]\n",
00560 path.len, path.s);
00561 goto error;
00562 }
00563
00564 xcaps_get_db_etag(&turi.user, &turi.host, &xuri, &etag);
00565 if(check_preconditions(msg, etag)!=1)
00566 {
00567 xcaps_send_reply(msg, 412, &xcaps_str_precon, &xcaps_str_empty,
00568 &xcaps_str_empty, &xcaps_str_empty);
00569
00570 pkg_free(body.s);
00571 return -2;
00572 }
00573
00574 if(xuri.nss!=NULL && xuri.node.len>0)
00575 {
00576
00577
00578
00579 if(xcaps_get_db_doc(&turi.user, &turi.host, &xuri, &tbuf) != 0)
00580 {
00581 LM_ERR("could not fetch xcap document\n");
00582 goto error;
00583 }
00584 if(xcaps_xpath_hack(&tbuf, 0)<0)
00585 {
00586 LM_ERR("could not hack xcap document\n");
00587 goto error;
00588 }
00589 if(xcaps_xpath_set(&tbuf, &xuri.node, &body, &nbuf)<0)
00590 {
00591 LM_ERR("could not update xcap document\n");
00592 goto error;
00593 }
00594 if(nbuf.len<=0)
00595 {
00596 LM_ERR("no new content\n");
00597 goto error;
00598 }
00599 pkg_free(body.s);
00600 body = nbuf;
00601 if(xcaps_xpath_hack(&body, 1)<0)
00602 {
00603 LM_ERR("could not hack xcap document\n");
00604 goto error;
00605 }
00606 }
00607
00608 if(xcaps_generate_etag_hdr(&etag_hdr)<0)
00609 {
00610 LM_ERR("could not generate etag\n");
00611 goto error;
00612 }
00613 etag.s = etag_hdr.s + 7;
00614 etag.len = etag_hdr.len - 10;
00615 if(xcaps_put_db(&turi.user, &turi.host,
00616 &xuri, &etag, &body)<0)
00617 {
00618 LM_ERR("could not store document\n");
00619 goto error;
00620 }
00621 xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag_hdr,
00622 &xcaps_str_empty, &xcaps_str_empty);
00623 if(body.s!=NULL)
00624 pkg_free(body.s);
00625 return 1;
00626
00627 error:
00628 xcaps_send_reply(msg, 500, &xcaps_str_srverr, &xcaps_str_empty,
00629 &xcaps_str_empty, &xcaps_str_empty);
00630 if(body.s!=NULL)
00631 pkg_free(body.s);
00632 return -1;
00633 }
00634
00638 static int xcaps_get_db_doc(str* user, str *domain, xcap_uri_t *xuri, str *doc)
00639 {
00640 db_key_t qcols[3];
00641 db_val_t qvals[3];
00642 int ncols = 0;
00643 db_key_t rcols[3];
00644 int nrcols = 0;
00645 db1_res_t* db_res = NULL;
00646 str s;
00647
00648
00649 rcols[nrcols] = &str_doc_col;
00650 nrcols++;
00651
00652
00653 qcols[ncols] = &str_username_col;
00654 qvals[ncols].type = DB1_STR;
00655 qvals[ncols].nul = 0;
00656 qvals[ncols].val.str_val = *user;
00657 ncols++;
00658
00659 qcols[ncols] = &str_domain_col;
00660 qvals[ncols].type = DB1_STR;
00661 qvals[ncols].nul = 0;
00662 qvals[ncols].val.str_val = *domain;
00663 ncols++;
00664
00665 qcols[ncols] = &str_doc_uri_col;
00666 qvals[ncols].type = DB1_STR;
00667 qvals[ncols].nul = 0;
00668 qvals[ncols].val.str_val= xuri->adoc;
00669 ncols++;
00670
00671 if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
00672 {
00673 LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
00674 xcaps_db_table.s);
00675 goto error;
00676 }
00677
00678 if(xcaps_dbf.query(xcaps_db, qcols, NULL, qvals, rcols,
00679 ncols, nrcols, NULL, &db_res)< 0)
00680 {
00681 LM_ERR("in sql query\n");
00682 goto error;
00683 }
00684 if (RES_ROW_N(db_res) <= 0)
00685 {
00686 LM_DBG("no document\n");
00687 goto notfound;
00688 }
00689
00690
00691 switch(RES_ROWS(db_res)[0].values[0].type)
00692 {
00693 case DB1_STRING:
00694 s.s=(char*)RES_ROWS(db_res)[0].values[0].val.string_val;
00695 s.len=strlen(s.s);
00696 break;
00697 case DB1_STR:
00698 s.len=RES_ROWS(db_res)[0].values[0].val.str_val.len;
00699 s.s=(char*)RES_ROWS(db_res)[0].values[0].val.str_val.s;
00700 break;
00701 case DB1_BLOB:
00702 s.len=RES_ROWS(db_res)[0].values[0].val.blob_val.len;
00703 s.s=(char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s;
00704 break;
00705 default:
00706 s.len=0;
00707 s.s=NULL;
00708 }
00709 if(s.len==0)
00710 {
00711 LM_ERR("no xcap doc in db record\n");
00712 goto error;
00713 }
00714 if(s.len>xcaps_buf.len-1)
00715 {
00716 LM_ERR("xcap doc buffer overflow\n");
00717 goto error;
00718 }
00719 doc->len = s.len;
00720 doc->s = xcaps_buf.s;
00721 memcpy(doc->s, s.s, s.len);
00722 doc->s[doc->len] = '\0';
00723
00724 if(xcaps_check_doc_validity(doc)<0)
00725 {
00726 LM_ERR("invalid xml doc retrieved from database\n");
00727 goto error;
00728 }
00729
00730 xcaps_dbf.free_result(xcaps_db, db_res);
00731 return 0;
00732
00733 notfound:
00734 xcaps_dbf.free_result(xcaps_db, db_res);
00735 return 1;
00736
00737 error:
00738 if(db_res!=NULL)
00739 xcaps_dbf.free_result(xcaps_db, db_res);
00740 return -1;
00741 }
00742
00748 static int xcaps_get_db_etag(str* user, str *domain, xcap_uri_t *xuri, str *etag)
00749 {
00750 db_key_t qcols[3];
00751 db_val_t qvals[3];
00752 int ncols = 0;
00753 db_key_t rcols[3];
00754 int nrcols = 0;
00755 db1_res_t* db_res = NULL;
00756 str s;
00757
00758
00759 rcols[nrcols] = &str_etag_col;
00760 nrcols++;
00761
00762
00763 qcols[ncols] = &str_username_col;
00764 qvals[ncols].type = DB1_STR;
00765 qvals[ncols].nul = 0;
00766 qvals[ncols].val.str_val = *user;
00767 ncols++;
00768
00769 qcols[ncols] = &str_domain_col;
00770 qvals[ncols].type = DB1_STR;
00771 qvals[ncols].nul = 0;
00772 qvals[ncols].val.str_val = *domain;
00773 ncols++;
00774
00775 qcols[ncols] = &str_doc_uri_col;
00776 qvals[ncols].type = DB1_STR;
00777 qvals[ncols].nul = 0;
00778 qvals[ncols].val.str_val= xuri->adoc;
00779 ncols++;
00780
00781 if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
00782 {
00783 LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
00784 xcaps_db_table.s);
00785 goto error;
00786 }
00787
00788 if(xcaps_dbf.query(xcaps_db, qcols, NULL, qvals, rcols,
00789 ncols, nrcols, NULL, &db_res)< 0)
00790 {
00791 LM_ERR("in sql query\n");
00792 goto error;
00793 }
00794 if (RES_ROW_N(db_res) <= 0)
00795 {
00796 LM_DBG("no document\n");
00797 goto notfound;
00798 }
00799
00800 switch(RES_ROWS(db_res)[0].values[0].type)
00801 {
00802 case DB1_STRING:
00803 s.s=(char*)RES_ROWS(db_res)[0].values[0].val.string_val;
00804 s.len=strlen(s.s);
00805 break;
00806 case DB1_STR:
00807 s.len=RES_ROWS(db_res)[0].values[0].val.str_val.len;
00808 s.s=(char*)RES_ROWS(db_res)[0].values[0].val.str_val.s;
00809 break;
00810 case DB1_BLOB:
00811 s.len=RES_ROWS(db_res)[0].values[0].val.blob_val.len;
00812 s.s=(char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s;
00813 break;
00814 default:
00815 s.len=0;
00816 s.s=NULL;
00817 }
00818 if(s.len==0)
00819 {
00820 LM_ERR("no etag in db record\n");
00821 goto error;
00822 }
00823 etag->len = snprintf(xcaps_etag_buf, XCAPS_ETAG_SIZE,
00824 "ETag: \"%.*s\"\r\n", s.len, s.s);
00825 if(etag->len < 0)
00826 {
00827 LM_ERR("error printing etag hdr\n ");
00828 goto error;
00829 }
00830 if(etag->len >= XCAPS_ETAG_SIZE)
00831 {
00832 LM_ERR("etag buffer overflow\n");
00833 goto error;
00834 }
00835
00836 etag->s = xcaps_etag_buf;
00837 etag->s[etag->len] = '\0';
00838
00839 xcaps_dbf.free_result(xcaps_db, db_res);
00840 return 0;
00841
00842 notfound:
00843 xcaps_dbf.free_result(xcaps_db, db_res);
00844 return 1;
00845
00846 error:
00847 if(db_res!=NULL)
00848 xcaps_dbf.free_result(xcaps_db, db_res);
00849 return -1;
00850 }
00851
00855 static int w_xcaps_get(sip_msg_t* msg, char* puri, char* ppath)
00856 {
00857 struct sip_uri turi;
00858 str uri;
00859 str path;
00860 str etag;
00861 str body;
00862 int ret = 0;
00863 xcap_uri_t xuri;
00864 str *ctype;
00865
00866 if(puri==0 || ppath==0)
00867 {
00868 LM_ERR("invalid parameters\n");
00869 return -1;
00870 }
00871
00872 if(fixup_get_svalue(msg, (gparam_p)puri, &uri)!=0)
00873 {
00874 LM_ERR("unable to get uri\n");
00875 return -1;
00876 }
00877 if(uri.s==NULL || uri.len == 0)
00878 {
00879 LM_ERR("invalid uri parameter\n");
00880 return -1;
00881 }
00882
00883 if(fixup_get_svalue(msg, (gparam_p)ppath, &path)!=0)
00884 {
00885 LM_ERR("unable to get path\n");
00886 return -1;
00887 }
00888 if(path.s==NULL || path.len == 0)
00889 {
00890 LM_ERR("invalid path parameter\n");
00891 return -1;
00892 }
00893
00894 if(parse_uri(uri.s, uri.len, &turi)!=0)
00895 {
00896 LM_ERR("parsing uri parameter\n");
00897 goto error;
00898 }
00899
00900 if(xcap_parse_uri(&path, &xcaps_root, &xuri)<0)
00901 {
00902 LM_ERR("cannot parse xcap uri [%.*s]\n",
00903 path.len, path.s);
00904 goto error;
00905 }
00906
00907 if((ret=xcaps_get_db_etag(&turi.user, &turi.host, &xuri, &etag))<0)
00908 {
00909 LM_ERR("could not fetch etag for xcap document\n");
00910 goto error;
00911 }
00912 if (ret==1)
00913 {
00914
00915 xcaps_send_reply(msg, 404, &xcaps_str_notfound, &xcaps_str_empty,
00916 &xcaps_str_empty, &xcaps_str_empty);
00917 return 1;
00918 }
00919
00920 if((ret=check_preconditions(msg, etag))==-1)
00921 {
00922 xcaps_send_reply(msg, 412, &xcaps_str_precon, &xcaps_str_empty,
00923 &xcaps_str_empty, &xcaps_str_empty);
00924 return -2;
00925 } else if (ret==-2) {
00926 xcaps_send_reply(msg, 304, &xcaps_str_notmod, &xcaps_str_empty,
00927 &xcaps_str_empty, &xcaps_str_empty);
00928 return -2;
00929 }
00930
00931 if((ret=xcaps_get_db_doc(&turi.user, &turi.host, &xuri, &body))<0)
00932 {
00933 LM_ERR("could not fetch xcap document\n");
00934 goto error;
00935 }
00936 if(ret==0)
00937 {
00938
00939 ctype = &xcaps_str_appxml;
00940 if(xuri.type==RESOURCE_LIST)
00941 ctype = &xcaps_str_apprlxml;
00942 else if(xuri.type==PRES_RULES)
00943 ctype = &xcaps_str_appapxml;
00944 else if(xuri.type==RLS_SERVICE)
00945 ctype = &xcaps_str_apprsxml;
00946 else if(xuri.type==USER_PROFILE)
00947 ctype = &xcaps_str_appupxml;
00948 else if(xuri.type==PRES_CONTENT)
00949 ctype = &xcaps_str_apppcxml;
00950 else if(xuri.type==PIDF_MANIPULATION)
00951 ctype = &xcaps_str_apppdxml;
00952 xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag,
00953 ctype, &body);
00954 } else {
00955
00956 xcaps_send_reply(msg, 404, &xcaps_str_notfound, &xcaps_str_empty,
00957 &xcaps_str_empty, &xcaps_str_empty);
00958 }
00959 return 1;
00960
00961 error:
00962 xcaps_send_reply(msg, 500, &xcaps_str_srverr, &xcaps_str_empty,
00963 &xcaps_str_empty, &xcaps_str_empty);
00964 return -1;
00965 }
00966
00967
00971 static int xcaps_del_db(str* user, str *domain, xcap_uri_t *xuri)
00972 {
00973 db_key_t qcols[4];
00974 db_val_t qvals[4];
00975 int ncols = 0;
00976
00977
00978 qcols[ncols] = &str_username_col;
00979 qvals[ncols].type = DB1_STR;
00980 qvals[ncols].nul = 0;
00981 qvals[ncols].val.str_val = *user;
00982 ncols++;
00983
00984 qcols[ncols] = &str_domain_col;
00985 qvals[ncols].type = DB1_STR;
00986 qvals[ncols].nul = 0;
00987 qvals[ncols].val.str_val = *domain;
00988 ncols++;
00989
00990 qcols[ncols] = &str_doc_uri_col;
00991 qvals[ncols].type = DB1_STR;
00992 qvals[ncols].nul = 0;
00993 qvals[ncols].val.str_val= xuri->adoc;
00994 ncols++;
00995
00996 if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
00997 {
00998 LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
00999 xcaps_db_table.s);
01000 goto error;
01001 }
01002
01003 if(xcaps_dbf.delete(xcaps_db, qcols, NULL, qvals, ncols)< 0)
01004 {
01005 LM_ERR("in sql delete\n");
01006 goto error;
01007 }
01008
01009 return 0;
01010 error:
01011 return -1;
01012 }
01013
01014
01018 static int w_xcaps_del(sip_msg_t* msg, char* puri, char* ppath)
01019 {
01020 struct sip_uri turi;
01021 str uri;
01022 str path;
01023 xcap_uri_t xuri;
01024 str body = {0, 0};
01025 str etag_hdr = {0, 0};
01026 str etag = {0, 0};
01027 str tbuf;
01028
01029 if(puri==0 || ppath==0)
01030 {
01031 LM_ERR("invalid parameters\n");
01032 return -1;
01033 }
01034
01035 if(fixup_get_svalue(msg, (gparam_p)puri, &uri)!=0)
01036 {
01037 LM_ERR("unable to get uri\n");
01038 return -1;
01039 }
01040 if(uri.s==NULL || uri.len == 0)
01041 {
01042 LM_ERR("invalid uri parameter\n");
01043 return -1;
01044 }
01045
01046 if(fixup_get_svalue(msg, (gparam_p)ppath, &path)!=0)
01047 {
01048 LM_ERR("unable to get path\n");
01049 return -1;
01050 }
01051 if(path.s==NULL || path.len == 0)
01052 {
01053 LM_ERR("invalid path parameter\n");
01054 return -1;
01055 }
01056
01057 if(parse_uri(uri.s, uri.len, &turi)!=0)
01058 {
01059 LM_ERR("parsing uri parameter\n");
01060 goto error;
01061 }
01062
01063 if(xcap_parse_uri(&path, &xcaps_root, &xuri)<0)
01064 {
01065 LM_ERR("cannot parse xcap uri [%.*s]\n",
01066 path.len, path.s);
01067 goto error;
01068 }
01069
01070 if(xcaps_get_db_etag(&turi.user, &turi.host, &xuri, &etag)!=0)
01071 {
01072 LM_ERR("could not fetch etag for xcap document\n");
01073 goto error;
01074 }
01075
01076 if(check_preconditions(msg, etag)!=1)
01077 {
01078 xcaps_send_reply(msg, 412, &xcaps_str_precon, &xcaps_str_empty,
01079 &xcaps_str_empty, &xcaps_str_empty);
01080 return -2;
01081 }
01082
01083 if(xuri.nss==NULL)
01084 {
01085
01086 if(xcaps_del_db(&turi.user, &turi.host, &xuri)<0)
01087 {
01088 LM_ERR("could not delete document\n");
01089 goto error;
01090 }
01091 xcaps_send_reply(msg, 200, &xcaps_str_ok, &xcaps_str_empty,
01092 &xcaps_str_empty, &xcaps_str_empty);
01093 } else {
01094
01095 if(xcaps_get_db_doc(&turi.user, &turi.host, &xuri, &tbuf) != 0)
01096 {
01097 LM_ERR("could not fetch xcap document\n");
01098 goto error;
01099 }
01100 if(xcaps_xpath_hack(&tbuf, 0)<0)
01101 {
01102 LM_ERR("could not hack xcap document\n");
01103 goto error;
01104 }
01105 if(xcaps_xpath_set(&tbuf, &xuri.node, NULL, &body)<0)
01106 {
01107 LM_ERR("could not update xcap document\n");
01108 goto error;
01109 }
01110 if(body.len<=0)
01111 {
01112 LM_ERR("no new content\n");
01113 goto error;
01114 }
01115 if(xcaps_xpath_hack(&body, 1)<0)
01116 {
01117 LM_ERR("could not hack xcap document\n");
01118 goto error;
01119 }
01120 if(xcaps_generate_etag_hdr(&etag_hdr)<0)
01121 {
01122 LM_ERR("could not generate etag\n");
01123 goto error;
01124 }
01125 etag.s = etag_hdr.s + 7;
01126 etag.len = etag_hdr.len - 10;
01127 if(xcaps_put_db(&turi.user, &turi.host,
01128 &xuri, &etag, &body)<0)
01129 {
01130 LM_ERR("could not store document\n");
01131 goto error;
01132 }
01133 xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag_hdr,
01134 &xcaps_str_empty, &xcaps_str_empty);
01135 if(body.s!=NULL)
01136 pkg_free(body.s);
01137 return 1;
01138 }
01139 return 1;
01140
01141 error:
01142 xcaps_send_reply(msg, 500, &xcaps_str_srverr, &xcaps_str_empty,
01143 &xcaps_str_empty, &xcaps_str_empty);
01144 if(body.s!=NULL)
01145 pkg_free(body.s);
01146 return -1;
01147 }
01148
01152 int xcaps_path_get_auid_type(str *path)
01153 {
01154 str s;
01155 char c;
01156 int ret;
01157
01158 ret = -1;
01159 if(path==NULL)
01160 return -1;
01161 if(path->len<xcaps_root.len)
01162 return -1;
01163
01164 if(strncmp(path->s, xcaps_root.s, xcaps_root.len)!=0)
01165 {
01166 LM_ERR("missing xcap-root in [%.*s]\n", path->len, path->s);
01167 return -1;
01168 }
01169
01170 s.s = path->s + xcaps_root.len - 1;
01171 s.len = path->len - xcaps_root.len + 1;
01172
01173 c = s.s[s.len];
01174 s.s[s.len] = '\0';
01175
01176 if(s.len>12 && strstr(s.s, "/pres-rules/")!=NULL)
01177 {
01178 LM_DBG("matched pres-rules\n");
01179 ret = PRES_RULES;
01180 goto done;
01181 }
01182
01183 if(s.len>35 && strstr(s.s, "/org.openmobilealliance.pres-rules/")!=NULL)
01184 {
01185 LM_DBG("matched oma pres-rules\n");
01186 ret = PRES_RULES;
01187 goto done;
01188 }
01189
01190 if(s.len>14 && strstr(s.s, "/rls-services/")!=NULL)
01191 {
01192 LM_DBG("matched rls-services\n");
01193 ret = RLS_SERVICE;
01194 goto done;
01195 }
01196
01197 if(s.len>19 && strstr(s.s, "pidf-manipulation")!=NULL)
01198 {
01199 LM_DBG("matched pidf-manipulation\n");
01200 ret = PIDF_MANIPULATION;
01201 goto done;
01202 }
01203
01204 if(s.len>16 && strstr(s.s, "/resource-lists/")!=NULL)
01205 {
01206 LM_DBG("matched resource-lists\n");
01207 ret = RESOURCE_LIST;
01208 goto done;
01209 }
01210
01211 if(s.len>11 && strstr(s.s, "/xcap-caps/")!=NULL)
01212 {
01213 LM_DBG("matched xcap-caps\n");
01214 ret = XCAP_CAPS;
01215 goto done;
01216 }
01217
01218 if(s.len> 37 && strstr(s.s, "/org.openmobilealliance.user-profile/")!=NULL)
01219 {
01220 LM_DBG("matched oma user-profile\n");
01221 ret = USER_PROFILE;
01222 goto done;
01223 }
01224
01225 if(s.len> 37 && strstr(s.s, "/org.openmobilealliance.pres-content/")!=NULL)
01226 {
01227 LM_DBG("matched oma pres-content\n");
01228 ret = PRES_CONTENT;
01229 goto done;
01230 }
01231
01232 if(s.len>31 && strstr(s.s, "/org.openmobilealliance.search?")!=NULL)
01233 {
01234 LM_DBG("matched oma search\n");
01235 ret = SEARCH;
01236 goto done;
01237 }
01238
01239 done:
01240 s.s[s.len] = c;
01241 return ret;
01242 }
01243
01247 int xcaps_generate_etag_hdr(str *etag)
01248 {
01249 etag->len = snprintf(xcaps_etag_buf, XCAPS_ETAG_SIZE,
01250 "ETag: \"sr-%d-%d-%d\"\r\n", xcaps_init_time, my_pid(),
01251 xcaps_etag_counter++);
01252 if(etag->len <0)
01253 {
01254 LM_ERR("error printing etag\n ");
01255 return -1;
01256 }
01257 if(etag->len >= XCAPS_ETAG_SIZE)
01258 {
01259 LM_ERR("etag buffer overflow\n");
01260 return -1;
01261 }
01262
01263 etag->s = xcaps_etag_buf;
01264 etag->s[etag->len] = '\0';
01265 return 0;
01266 }
01267
01271 static int fixup_xcaps_put(void** param, int param_no)
01272 {
01273 str s;
01274 pv_elem_t *xm;
01275 if (param_no == 1) {
01276 return fixup_spve_null(param, 1);
01277 } else if (param_no == 2) {
01278 return fixup_spve_null(param, 1);
01279 } else if (param_no == 3) {
01280 s.s = (char*)(*param); s.len = strlen(s.s);
01281 if(pv_parse_format(&s, &xm)<0)
01282 {
01283 LM_ERR("wrong format[%s]\n", (char*)(*param));
01284 return E_UNSPEC;
01285 }
01286 *param = (void*)xm;
01287 return 0;
01288 }
01289 return 0;
01290 }
01291
01292 static int check_preconditions(sip_msg_t *msg, str etag_hdr)
01293 {
01294 struct hdr_field* hdr = msg->headers;
01295 int ifmatch_found=0;
01296 int matched_matched=0;
01297 int matched_nonematched=0;
01298
01299 if (etag_hdr.len > 0)
01300 {
01301 str etag;
01302
01303
01304 etag.s = etag_hdr.s + 6;
01305 etag.len = etag_hdr.len - 8;
01306
01307 while (hdr!=NULL)
01308 {
01309 if(cmp_hdrname_strzn(&hdr->name, "If-Match", 8)==0)
01310 {
01311 ifmatch_found = 1;
01312 if (check_match_header(hdr->body, &etag)>0)
01313 matched_matched = 1;
01314 }
01315 else if (cmp_hdrname_strzn(&hdr->name, "If-None-Match", 13)==0)
01316 {
01317 if (check_match_header(hdr->body, &etag)>0)
01318 matched_nonematched = 1;
01319 }
01320 hdr = hdr->next;
01321 }
01322 } else {
01323 while (hdr!=NULL)
01324 {
01325 if(cmp_hdrname_strzn(&hdr->name, "If-Match", 8)==0)
01326 ifmatch_found = 1;
01327
01328 hdr = hdr->next;
01329 }
01330 }
01331
01332 if (ifmatch_found == 1 && matched_matched == 0)
01333 return -1;
01334 else if (matched_nonematched == 1)
01335 return -2;
01336 else
01337 return 1;
01338 }
01339
01340 static int check_match_header(str body, str *etag)
01341 {
01342 do
01343 {
01344 char *start_pos, *end_pos, *old_body_pos;
01345 int cur_etag_len;
01346
01347 if ((start_pos = strchr(body.s, '"')) == NULL)
01348 return -1;
01349 if ((end_pos = strchr(start_pos + 1, '"')) == NULL)
01350 return -1;
01351 cur_etag_len = end_pos - start_pos + 1;
01352
01353 if (strncmp(start_pos, etag->s, cur_etag_len)==0)
01354 return 1;
01355 else if (strncmp(start_pos, "\"*\"", cur_etag_len)==0)
01356 return 1;
01357
01358 old_body_pos = body.s;
01359 if ((body.s = strchr(end_pos, ',')) == NULL)
01360 return -1;
01361 body.len -= body.s - old_body_pos;
01362 } while (body.len > 0);
01363
01364 return -1;
01365 }