xcap_server.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671
  1. /*
  2. * $Id$
  3. *
  4. * xcap_server module - builtin XCAP server
  5. *
  6. * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
  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. */
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <sys/types.h>
  29. #include <unistd.h>
  30. #include <fcntl.h>
  31. #include <time.h>
  32. #include "../../lib/srdb1/db.h"
  33. #include "../../pt.h"
  34. #include "../../sr_module.h"
  35. #include "../../dprint.h"
  36. #include "../../error.h"
  37. #include "../../ut.h"
  38. #include "../../mem/mem.h"
  39. #include "../../data_lump.h"
  40. #include "../../data_lump_rpl.h"
  41. #include "../../mod_fix.h"
  42. #include "../../parser/parse_uri.h"
  43. #include "../../modules/xcap_client/xcap_callbacks.h"
  44. #include "../../modules/sl/sl.h"
  45. #include "../../lib/kcore/cmpapi.h"
  46. #include "../../ip_addr.h"
  47. #include "xcap_misc.h"
  48. MODULE_VERSION
  49. #define XCAP_TABLE_VERSION 4
  50. static int xcaps_put_db(str* user, str *domain, xcap_uri_t *xuri, str *etag,
  51. str* doc);
  52. static int xcaps_get_db_doc(str* user, str *domain, xcap_uri_t *xuri,
  53. str *doc);
  54. static int xcaps_get_db_etag(str* user, str *domain, xcap_uri_t *xuri,
  55. str *etag);
  56. static int xcaps_del_db(str* user, str *domain, xcap_uri_t *xuri);
  57. static int w_xcaps_put(sip_msg_t* msg, char* puri, char* ppath,
  58. char* pbody);
  59. static int w_xcaps_get(sip_msg_t* msg, char* puri, char* ppath);
  60. static int w_xcaps_del(sip_msg_t* msg, char* puri, char* ppath);
  61. static int fixup_xcaps_put(void** param, int param_no);
  62. static int check_preconditions(sip_msg_t *msg, str etag_hdr);
  63. static int check_match_header(str body, str *etag);
  64. static int mod_init(void);
  65. static int child_init(int rank);
  66. static void destroy(void);
  67. int xcaps_xpath_ns_param(modparam_t type, void *val);
  68. int xcaps_path_get_auid_type(str *path);
  69. int xcaps_generate_etag_hdr(str *etag);
  70. static str xcaps_db_table = str_init("xcap");
  71. static str xcaps_db_url = str_init(DEFAULT_DB_URL);
  72. static int xcaps_init_time = 0;
  73. static int xcaps_etag_counter = 1;
  74. str xcaps_root = str_init("/xcap-root/");
  75. static int xcaps_directory_scheme = -1;
  76. static str xcaps_directory_hostname = {0, 0};
  77. static str xcaps_buf = {0, 8192};
  78. #define XCAPS_HDR_SIZE 128
  79. static char xcaps_hdr_buf[XCAPS_HDR_SIZE];
  80. static str str_id_col = str_init("id");
  81. static str str_source_col = str_init("source");
  82. static str str_doc_col = str_init("doc");
  83. static str str_etag_col = str_init("etag");
  84. static str str_username_col = str_init("username");
  85. static str str_domain_col = str_init("domain");
  86. static str str_doc_type_col = str_init("doc_type");
  87. static str str_doc_uri_col = str_init("doc_uri");
  88. static str str_port_col = str_init("port");
  89. /* database connection */
  90. db1_con_t *xcaps_db = NULL;
  91. db_func_t xcaps_dbf;
  92. /** SL API structure */
  93. sl_api_t slb;
  94. static pv_export_t mod_pvs[] = {
  95. { {"xcapuri", sizeof("xcapuri")-1}, PVT_OTHER, pv_get_xcap_uri,
  96. pv_set_xcap_uri, pv_parse_xcap_uri_name, 0, 0, 0 },
  97. { {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
  98. };
  99. static param_export_t params[] = {
  100. { "db_url", PARAM_STR, &xcaps_db_url },
  101. { "xcap_table", PARAM_STR, &xcaps_db_table },
  102. { "xcap_root", PARAM_STR, &xcaps_root },
  103. { "buf_size", INT_PARAM, &xcaps_buf.len },
  104. { "xml_ns", PARAM_STRING|USE_FUNC_PARAM, (void*)xcaps_xpath_ns_param },
  105. { "directory_scheme", INT_PARAM, &xcaps_directory_scheme },
  106. { "directory_hostname", PARAM_STR, &xcaps_directory_hostname },
  107. { 0, 0, 0 }
  108. };
  109. static cmd_export_t cmds[]={
  110. {"xcaps_put", (cmd_function)w_xcaps_put, 3,
  111. fixup_xcaps_put, 0, REQUEST_ROUTE},
  112. {"xcaps_get", (cmd_function)w_xcaps_get, 2,
  113. fixup_xcaps_put, 0, REQUEST_ROUTE},
  114. {"xcaps_del", (cmd_function)w_xcaps_del, 2,
  115. fixup_xcaps_put, 0, REQUEST_ROUTE},
  116. {0,0,0,0,0,0}
  117. };
  118. /** module exports */
  119. struct module_exports exports= {
  120. "xcap_server", /* module name */
  121. DEFAULT_DLFLAGS, /* dlopen flags */
  122. cmds, /* exported functions */
  123. params, /* exported parameters */
  124. 0, /* exported statistics */
  125. 0, /* exported MI functions */
  126. mod_pvs, /* exported pseudo-variables */
  127. 0, /* extra processes */
  128. mod_init, /* module initialization function */
  129. 0, /* response handling function */
  130. destroy, /* destroy function */
  131. child_init /* per-child init function */
  132. };
  133. /**
  134. * init module function
  135. */
  136. static int mod_init(void)
  137. {
  138. if (xcaps_directory_scheme < -1 || xcaps_directory_scheme > 1)
  139. {
  140. LM_ERR("invalid xcaps_directory_scheme\n");
  141. return -1;
  142. }
  143. if(xcaps_buf.len<=0)
  144. {
  145. LM_ERR("invalid buffer size\n");
  146. return -1;
  147. }
  148. xcaps_buf.s = (char*)pkg_malloc(xcaps_buf.len+1);
  149. if(xcaps_buf.s==NULL)
  150. {
  151. LM_ERR("no pkg\n");
  152. return -1;
  153. }
  154. /* binding to mysql module */
  155. if (db_bind_mod(&xcaps_db_url, &xcaps_dbf))
  156. {
  157. LM_ERR("Database module not found\n");
  158. return -1;
  159. }
  160. if (!DB_CAPABILITY(xcaps_dbf, DB_CAP_ALL)) {
  161. LM_ERR("Database module does not implement all functions"
  162. " needed by the module\n");
  163. return -1;
  164. }
  165. xcaps_db = xcaps_dbf.init(&xcaps_db_url);
  166. if (xcaps_db==NULL)
  167. {
  168. LM_ERR("connecting to database\n");
  169. return -1;
  170. }
  171. if(db_check_table_version(&xcaps_dbf, xcaps_db, &xcaps_db_table,
  172. XCAP_TABLE_VERSION) < 0) {
  173. LM_ERR("error during table version check.\n");
  174. return -1;
  175. }
  176. xcaps_dbf.close(xcaps_db);
  177. xcaps_db = NULL;
  178. /* bind the SL API */
  179. if (sl_load_api(&slb)!=0) {
  180. LM_ERR("cannot bind to SL API\n");
  181. return -1;
  182. }
  183. xcaps_init_time = (int)time(NULL);
  184. return 0;
  185. }
  186. /**
  187. *
  188. */
  189. static int child_init(int rank)
  190. {
  191. if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
  192. return 0; /* do nothing for the main process */
  193. if((xcaps_db = xcaps_dbf.init(&xcaps_db_url))==NULL)
  194. {
  195. LM_ERR("cannot connect to db\n");
  196. return -1;
  197. }
  198. return 0;
  199. }
  200. /**
  201. *
  202. */
  203. static void destroy(void)
  204. {
  205. if(xcaps_db != NULL)
  206. xcaps_dbf.close(xcaps_db);
  207. }
  208. /**
  209. *
  210. */
  211. static int xcaps_send_reply(sip_msg_t *msg, int code, str *reason,
  212. str *hdrs, str *ctype, str *body)
  213. {
  214. str tbuf;
  215. if(hdrs && hdrs->len>0)
  216. {
  217. if (add_lump_rpl(msg, hdrs->s, hdrs->len, LUMP_RPL_HDR) == 0)
  218. {
  219. LM_ERR("failed to insert extra-headers lump\n");
  220. return -1;
  221. }
  222. }
  223. if(ctype && ctype->len>0)
  224. {
  225. /* add content-type */
  226. tbuf.len=sizeof("Content-Type: ") - 1 + ctype->len + CRLF_LEN;
  227. tbuf.s=pkg_malloc(sizeof(char)*(tbuf.len));
  228. if (tbuf.len==0)
  229. {
  230. LM_ERR("out of pkg memory\n");
  231. return -1;
  232. }
  233. memcpy(tbuf.s, "Content-Type: ", sizeof("Content-Type: ") - 1);
  234. memcpy(tbuf.s+sizeof("Content-Type: ") - 1, ctype->s, ctype->len);
  235. memcpy(tbuf.s+sizeof("Content-Type: ") - 1 + ctype->len,
  236. CRLF, CRLF_LEN);
  237. if (add_lump_rpl(msg, tbuf.s, tbuf.len, LUMP_RPL_HDR) == 0)
  238. {
  239. LM_ERR("failed to insert content-type lump\n");
  240. pkg_free(tbuf.s);
  241. return -1;
  242. }
  243. pkg_free(tbuf.s);
  244. }
  245. if(body && body->len>0)
  246. {
  247. if (add_lump_rpl(msg, body->s, body->len, LUMP_RPL_BODY) < 0)
  248. {
  249. LM_ERR("Error while adding reply lump\n");
  250. return -1;
  251. }
  252. }
  253. if (slb.freply(msg, code, reason) < 0)
  254. {
  255. LM_ERR("Error while sending reply\n");
  256. return -1;
  257. }
  258. return 0;
  259. }
  260. /**
  261. *
  262. */
  263. int xcaps_xpath_hack(str *buf, int type)
  264. {
  265. char *match;
  266. char *repl;
  267. char c;
  268. char *p;
  269. char *start;
  270. if(buf==NULL || buf->len <=10)
  271. return 0;
  272. if(type==0)
  273. {
  274. match = " xmlns=";
  275. repl = " x____=";
  276. } else {
  277. match = " x____=";
  278. repl = " xmlns=";
  279. }
  280. start = buf->s;
  281. c = buf->s[buf->len-1];
  282. buf->s[buf->len-1] = '\0';
  283. while((p = strstr(start, match))!=NULL)
  284. {
  285. memcpy(p, repl, 7);
  286. start = p + 7;
  287. }
  288. buf->s[buf->len-1] = c;
  289. return 0;
  290. }
  291. /**
  292. *
  293. */
  294. static int xcaps_put_db(str* user, str *domain, xcap_uri_t *xuri, str *etag,
  295. str* doc)
  296. {
  297. db_key_t qcols[9], rcols[2], ucols[5];
  298. db_val_t qvals[9], uvals[5];
  299. db1_res_t *res = NULL;
  300. int ncols = 0, num_ucols = 0, nrows = 0;
  301. if(xcaps_check_doc_validity(doc)<0)
  302. {
  303. LM_ERR("invalid xml doc to insert in database\n");
  304. goto error;
  305. }
  306. qcols[ncols] = &str_username_col;
  307. qvals[ncols].type = DB1_STR;
  308. qvals[ncols].nul = 0;
  309. qvals[ncols].val.str_val = *user;
  310. ncols++;
  311. qcols[ncols] = &str_domain_col;
  312. qvals[ncols].type = DB1_STR;
  313. qvals[ncols].nul = 0;
  314. qvals[ncols].val.str_val = *domain;
  315. ncols++;
  316. qcols[ncols] = &str_doc_type_col;
  317. qvals[ncols].type = DB1_INT;
  318. qvals[ncols].nul = 0;
  319. qvals[ncols].val.int_val= xuri->type;
  320. ncols++;
  321. qcols[ncols] = &str_doc_uri_col;
  322. qvals[ncols].type = DB1_STR;
  323. qvals[ncols].nul = 0;
  324. qvals[ncols].val.str_val= xuri->adoc;
  325. ncols++;
  326. rcols[0] = &str_id_col;
  327. if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
  328. {
  329. LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
  330. xcaps_db_table.s);
  331. goto error;
  332. }
  333. if (xcaps_dbf.query(xcaps_db, qcols, 0, qvals, rcols, ncols, 1, 0, &res) < 0)
  334. {
  335. LM_ERR("in sql query\n");
  336. goto error;
  337. }
  338. nrows = RES_ROW_N(res);
  339. xcaps_dbf.free_result(xcaps_db, res);
  340. if (nrows == 0)
  341. {
  342. qcols[ncols] = &str_doc_col;
  343. qvals[ncols].type = DB1_BLOB;
  344. qvals[ncols].nul = 0;
  345. qvals[ncols].val.str_val= *doc;
  346. ncols++;
  347. qcols[ncols] = &str_etag_col;
  348. qvals[ncols].type = DB1_STR;
  349. qvals[ncols].nul = 0;
  350. qvals[ncols].val.str_val= *etag;
  351. ncols++;
  352. qcols[ncols] = &str_source_col;
  353. qvals[ncols].type = DB1_INT;
  354. qvals[ncols].nul = 0;
  355. qvals[ncols].val.int_val = 0;
  356. ncols++;
  357. qcols[ncols] = &str_port_col;
  358. qvals[ncols].type = DB1_INT;
  359. qvals[ncols].nul = 0;
  360. qvals[ncols].val.int_val = 0;
  361. ncols++;
  362. if(xcaps_dbf.insert(xcaps_db, qcols, qvals, ncols)< 0)
  363. {
  364. LM_ERR("in sql insert\n");
  365. goto error;
  366. }
  367. }
  368. else if (nrows == 1)
  369. {
  370. ucols[num_ucols] = &str_doc_col;
  371. uvals[num_ucols].type = DB1_BLOB;
  372. uvals[num_ucols].nul = 0;
  373. uvals[num_ucols].val.str_val= *doc;
  374. num_ucols++;
  375. ucols[num_ucols] = &str_etag_col;
  376. uvals[num_ucols].type = DB1_STR;
  377. uvals[num_ucols].nul = 0;
  378. uvals[num_ucols].val.str_val= *etag;
  379. num_ucols++;
  380. ucols[num_ucols] = &str_source_col;
  381. uvals[num_ucols].type = DB1_INT;
  382. uvals[num_ucols].nul = 0;
  383. uvals[num_ucols].val.int_val = 0;
  384. num_ucols++;
  385. ucols[num_ucols] = &str_port_col;
  386. uvals[num_ucols].type = DB1_INT;
  387. uvals[num_ucols].nul = 0;
  388. uvals[num_ucols].val.int_val = 0;
  389. num_ucols++;
  390. if (xcaps_dbf.update(xcaps_db, qcols, 0, qvals, ucols, uvals, ncols, num_ucols) < 0)
  391. {
  392. LM_ERR("in sql update\n");
  393. goto error;
  394. }
  395. }
  396. else
  397. {
  398. LM_ERR("found %d copies of the same document in XCAP Server\n", nrows);
  399. goto error;
  400. }
  401. return 0;
  402. error:
  403. return -1;
  404. }
  405. static str xcaps_str_ok = {"OK", 2};
  406. static str xcaps_str_srverr = {"Server error", 12};
  407. static str xcaps_str_notfound = {"Not found", 9};
  408. static str xcaps_str_precon = {"Precondition Failed", 19};
  409. static str xcaps_str_notmod = {"Not Modified", 12};
  410. static str xcaps_str_notallowed = {"Method Not Allowed", 18};
  411. static str xcaps_str_notimplemented = {"Not Implemented", 15};
  412. static str xcaps_str_appxml = {"application/xml", 15};
  413. static str xcaps_str_apprlxml = {"application/resource-lists+xml", 30};
  414. static str xcaps_str_apprsxml = {"application/rls-services+xml", 28};
  415. #if 0
  416. static str xcaps_str_nocontent = {"No content", 10};
  417. static str xcaps_str_appxcxml = {"application/xcap-caps+xml", 25};
  418. static str xcaps_str_appsexml = {"application/vnd.oma.search+xml", 30};
  419. #endif
  420. static str xcaps_str_appapxml = {"application/auth-policy+xml", 27};
  421. static str xcaps_str_appupxml = {"application/vnd.oma.user-profile+xml", 36};
  422. static str xcaps_str_apppcxml = {"application/vnd.oma.pres-content+xml", 36};
  423. static str xcaps_str_apppdxml = {"application/pidf+xml", 20};
  424. static str xcaps_str_appdrxml = {"application/vnd.oma.xcap-directory+xml", 38};
  425. /**
  426. *
  427. */
  428. static int w_xcaps_put(sip_msg_t* msg, char* puri, char* ppath,
  429. char* pbody)
  430. {
  431. struct sip_uri turi;
  432. str uri;
  433. str path;
  434. str body = {0, 0};
  435. str etag = {0, 0};
  436. str etag_hdr = {0, 0};
  437. str tbuf;
  438. str nbuf = {0, 0};
  439. str allow = {0, 0};
  440. pv_elem_t *xm;
  441. xcap_uri_t xuri;
  442. if(puri==0 || ppath==0 || pbody==0)
  443. {
  444. LM_ERR("invalid parameters\n");
  445. goto error;
  446. }
  447. if(fixup_get_svalue(msg, (gparam_p)puri, &uri)!=0)
  448. {
  449. LM_ERR("unable to get uri\n");
  450. goto error;
  451. }
  452. if(uri.s==NULL || uri.len == 0)
  453. {
  454. LM_ERR("invalid uri parameter\n");
  455. goto error;
  456. }
  457. if(fixup_get_svalue(msg, (gparam_p)ppath, &path)!=0)
  458. {
  459. LM_ERR("unable to get path\n");
  460. goto error;
  461. }
  462. if(path.s==NULL || path.len == 0)
  463. {
  464. LM_ERR("invalid path parameter\n");
  465. return -1;
  466. }
  467. if(parse_uri(uri.s, uri.len, &turi)!=0)
  468. {
  469. LM_ERR("parsing uri parameter\n");
  470. goto error;
  471. }
  472. if(xcap_parse_uri(&path, &xcaps_root, &xuri)<0)
  473. {
  474. LM_ERR("cannot parse xcap uri [%.*s]\n",
  475. path.len, path.s);
  476. goto error;
  477. }
  478. switch(xuri.type)
  479. {
  480. case DIRECTORY:
  481. case XCAP_CAPS:
  482. allow.s = xcaps_hdr_buf;
  483. allow.len = snprintf(allow.s, XCAPS_HDR_SIZE, "Allow: GET\r\n");
  484. xcaps_send_reply(msg, 405, &xcaps_str_notallowed, &allow, NULL, NULL);
  485. break;
  486. case SEARCH:
  487. allow.s = xcaps_hdr_buf;
  488. allow.len = snprintf(allow.s, XCAPS_HDR_SIZE, "Allow: POST\r\n");
  489. xcaps_send_reply(msg, 405, &xcaps_str_notallowed, &allow, NULL, NULL);
  490. break;
  491. default:
  492. xm = (pv_elem_t*)pbody;
  493. body.len = xcaps_buf.len - 1;
  494. if(pv_printf(msg, xm, xcaps_buf.s, &body.len)<0)
  495. {
  496. LM_ERR("unable to get body\n");
  497. goto error;
  498. }
  499. if(body.len <= 0)
  500. {
  501. LM_ERR("invalid body parameter\n");
  502. goto error;
  503. }
  504. body.s = (char*)pkg_malloc(body.len+1);
  505. if(body.s==NULL)
  506. {
  507. LM_ERR("no more pkg\n");
  508. goto error;
  509. }
  510. memcpy(body.s, xcaps_buf.s, body.len);
  511. body.s[body.len] = '\0';
  512. xcaps_get_db_etag(&turi.user, &turi.host, &xuri, &etag);
  513. if(check_preconditions(msg, etag)!=1)
  514. {
  515. xcaps_send_reply(msg, 412, &xcaps_str_precon, NULL, NULL, NULL);
  516. pkg_free(body.s);
  517. return -2;
  518. }
  519. if(xuri.nss!=NULL && xuri.node.len>0)
  520. {
  521. /* partial document upload
  522. * - fetch, update, delete and store
  523. */
  524. if(xcaps_get_db_doc(&turi.user, &turi.host, &xuri, &tbuf) != 0)
  525. {
  526. LM_ERR("could not fetch xcap document\n");
  527. goto error;
  528. }
  529. if(xcaps_xpath_hack(&tbuf, 0)<0)
  530. {
  531. LM_ERR("could not hack xcap document\n");
  532. goto error;
  533. }
  534. if(xcaps_xpath_set(&tbuf, &xuri.node, &body, &nbuf)<0)
  535. {
  536. LM_ERR("could not update xcap document\n");
  537. goto error;
  538. }
  539. if(nbuf.len<=0)
  540. {
  541. LM_ERR("no new content\n");
  542. goto error;
  543. }
  544. pkg_free(body.s);
  545. body = nbuf;
  546. if(xcaps_xpath_hack(&body, 1)<0)
  547. {
  548. LM_ERR("could not hack xcap document\n");
  549. goto error;
  550. }
  551. }
  552. if(xcaps_generate_etag_hdr(&etag_hdr)<0)
  553. {
  554. LM_ERR("could not generate etag\n");
  555. goto error;
  556. }
  557. etag.s = etag_hdr.s + 7; /* 'ETag: "' */
  558. etag.len = etag_hdr.len - 10; /* 'ETag: " "\r\n' */
  559. if(xcaps_put_db(&turi.user, &turi.host,
  560. &xuri, &etag, &body)<0)
  561. {
  562. LM_ERR("could not store document\n");
  563. goto error;
  564. }
  565. xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag_hdr,
  566. NULL, NULL);
  567. if(body.s!=NULL)
  568. pkg_free(body.s);
  569. break;
  570. }
  571. return 1;
  572. error:
  573. xcaps_send_reply(msg, 500, &xcaps_str_srverr, NULL, NULL, NULL);
  574. if(body.s!=NULL)
  575. pkg_free(body.s);
  576. return -1;
  577. }
  578. /**
  579. *
  580. */
  581. static int xcaps_get_db_doc(str* user, str *domain, xcap_uri_t *xuri, str *doc)
  582. {
  583. db_key_t qcols[3];
  584. db_val_t qvals[3];
  585. int ncols = 0;
  586. db_key_t rcols[3];
  587. int nrcols = 0;
  588. db1_res_t* db_res = NULL;
  589. str s;
  590. /* returned cols from table xcap*/
  591. rcols[nrcols] = &str_doc_col;
  592. nrcols++;
  593. /* query cols in xcap table*/
  594. qcols[ncols] = &str_username_col;
  595. qvals[ncols].type = DB1_STR;
  596. qvals[ncols].nul = 0;
  597. qvals[ncols].val.str_val = *user;
  598. ncols++;
  599. qcols[ncols] = &str_domain_col;
  600. qvals[ncols].type = DB1_STR;
  601. qvals[ncols].nul = 0;
  602. qvals[ncols].val.str_val = *domain;
  603. ncols++;
  604. qcols[ncols] = &str_doc_uri_col;
  605. qvals[ncols].type = DB1_STR;
  606. qvals[ncols].nul = 0;
  607. qvals[ncols].val.str_val= xuri->adoc;
  608. ncols++;
  609. if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
  610. {
  611. LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
  612. xcaps_db_table.s);
  613. goto error;
  614. }
  615. if(xcaps_dbf.query(xcaps_db, qcols, NULL, qvals, rcols,
  616. ncols, nrcols, NULL, &db_res)< 0)
  617. {
  618. LM_ERR("in sql query\n");
  619. goto error;
  620. }
  621. if (RES_ROW_N(db_res) <= 0)
  622. {
  623. LM_DBG("no document\n");
  624. goto notfound;
  625. }
  626. /* doc */
  627. switch(RES_ROWS(db_res)[0].values[0].type)
  628. {
  629. case DB1_STRING:
  630. s.s=(char*)RES_ROWS(db_res)[0].values[0].val.string_val;
  631. s.len=strlen(s.s);
  632. break;
  633. case DB1_STR:
  634. s.len=RES_ROWS(db_res)[0].values[0].val.str_val.len;
  635. s.s=(char*)RES_ROWS(db_res)[0].values[0].val.str_val.s;
  636. break;
  637. case DB1_BLOB:
  638. s.len=RES_ROWS(db_res)[0].values[0].val.blob_val.len;
  639. s.s=(char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s;
  640. break;
  641. default:
  642. s.len=0;
  643. s.s=NULL;
  644. }
  645. if(s.len==0)
  646. {
  647. LM_ERR("no xcap doc in db record\n");
  648. goto error;
  649. }
  650. if(s.len>xcaps_buf.len-1)
  651. {
  652. LM_ERR("xcap doc buffer overflow\n");
  653. goto error;
  654. }
  655. doc->len = s.len;
  656. doc->s = xcaps_buf.s;
  657. memcpy(doc->s, s.s, s.len);
  658. doc->s[doc->len] = '\0';
  659. if(xcaps_check_doc_validity(doc)<0)
  660. {
  661. LM_ERR("invalid xml doc retrieved from database\n");
  662. goto error;
  663. }
  664. xcaps_dbf.free_result(xcaps_db, db_res);
  665. return 0;
  666. notfound:
  667. xcaps_dbf.free_result(xcaps_db, db_res);
  668. return 1;
  669. error:
  670. if(db_res!=NULL)
  671. xcaps_dbf.free_result(xcaps_db, db_res);
  672. return -1;
  673. }
  674. /**
  675. * get the etag from database record for (user@domain, xuri)
  676. * - return: -1 error; 0 - found; 1 - not found
  677. *
  678. */
  679. static int xcaps_get_db_etag(str* user, str *domain, xcap_uri_t *xuri, str *etag)
  680. {
  681. db_key_t qcols[3];
  682. db_val_t qvals[3];
  683. int ncols = 0;
  684. db_key_t rcols[3];
  685. int nrcols = 0;
  686. db1_res_t* db_res = NULL;
  687. str s;
  688. /* returned cols from xcap table*/
  689. rcols[nrcols] = &str_etag_col;
  690. nrcols++;
  691. /* query cols in xcap table*/
  692. qcols[ncols] = &str_username_col;
  693. qvals[ncols].type = DB1_STR;
  694. qvals[ncols].nul = 0;
  695. qvals[ncols].val.str_val = *user;
  696. ncols++;
  697. qcols[ncols] = &str_domain_col;
  698. qvals[ncols].type = DB1_STR;
  699. qvals[ncols].nul = 0;
  700. qvals[ncols].val.str_val = *domain;
  701. ncols++;
  702. qcols[ncols] = &str_doc_uri_col;
  703. qvals[ncols].type = DB1_STR;
  704. qvals[ncols].nul = 0;
  705. qvals[ncols].val.str_val= xuri->adoc;
  706. ncols++;
  707. if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
  708. {
  709. LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
  710. xcaps_db_table.s);
  711. goto error;
  712. }
  713. if(xcaps_dbf.query(xcaps_db, qcols, NULL, qvals, rcols,
  714. ncols, nrcols, NULL, &db_res)< 0)
  715. {
  716. LM_ERR("in sql query\n");
  717. goto error;
  718. }
  719. if (RES_ROW_N(db_res) <= 0)
  720. {
  721. LM_DBG("no document\n");
  722. goto notfound;
  723. }
  724. /* etag */
  725. switch(RES_ROWS(db_res)[0].values[0].type)
  726. {
  727. case DB1_STRING:
  728. s.s=(char*)RES_ROWS(db_res)[0].values[0].val.string_val;
  729. s.len=strlen(s.s);
  730. break;
  731. case DB1_STR:
  732. s.len=RES_ROWS(db_res)[0].values[0].val.str_val.len;
  733. s.s=(char*)RES_ROWS(db_res)[0].values[0].val.str_val.s;
  734. break;
  735. case DB1_BLOB:
  736. s.len=RES_ROWS(db_res)[0].values[0].val.blob_val.len;
  737. s.s=(char*)RES_ROWS(db_res)[0].values[0].val.blob_val.s;
  738. break;
  739. default:
  740. s.len=0;
  741. s.s=NULL;
  742. }
  743. if(s.len==0)
  744. {
  745. LM_ERR("no etag in db record\n");
  746. goto error;
  747. }
  748. etag->len = snprintf(xcaps_hdr_buf, XCAPS_HDR_SIZE,
  749. "ETag: \"%.*s\"\r\n", s.len, s.s);
  750. if(etag->len < 0)
  751. {
  752. LM_ERR("error printing etag hdr\n ");
  753. goto error;
  754. }
  755. if(etag->len >= XCAPS_HDR_SIZE)
  756. {
  757. LM_ERR("etag buffer overflow\n");
  758. goto error;
  759. }
  760. etag->s = xcaps_hdr_buf;
  761. etag->s[etag->len] = '\0';
  762. xcaps_dbf.free_result(xcaps_db, db_res);
  763. return 0;
  764. notfound:
  765. xcaps_dbf.free_result(xcaps_db, db_res);
  766. return 1;
  767. error:
  768. if(db_res!=NULL)
  769. xcaps_dbf.free_result(xcaps_db, db_res);
  770. return -1;
  771. }
  772. static int xcaps_get_directory(struct sip_msg *msg, str *user, str *domain, str *directory)
  773. {
  774. db_key_t qcols[2];
  775. db_val_t qvals[2], *values;
  776. db_key_t rcols[3];
  777. db_row_t *rows;
  778. db1_res_t* db_res = NULL;
  779. int n_qcols = 0, n_rcols = 0;
  780. int i, cur_type = 0, cur_pos = 0;
  781. int doc_type_col, doc_uri_col, etag_col;
  782. str auid_string = {0, 0};
  783. struct hdr_field *hdr = msg->headers;
  784. str server_name = {0, 0};
  785. qcols[n_qcols] = &str_username_col;
  786. qvals[n_qcols].type = DB1_STR;
  787. qvals[n_qcols].nul = 0;
  788. qvals[n_qcols].val.str_val = *user;
  789. n_qcols++;
  790. qcols[n_qcols] = &str_domain_col;
  791. qvals[n_qcols].type = DB1_STR;
  792. qvals[n_qcols].nul = 0;
  793. qvals[n_qcols].val.str_val = *domain;
  794. n_qcols++;
  795. rcols[doc_type_col = n_rcols++] = &str_doc_type_col;
  796. rcols[doc_uri_col = n_rcols++] = &str_doc_uri_col;
  797. rcols[etag_col = n_rcols++] = &str_etag_col;
  798. if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
  799. {
  800. LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
  801. xcaps_db_table.s);
  802. goto error;
  803. }
  804. if (xcaps_dbf.query(xcaps_db, qcols, 0, qvals, rcols, n_qcols,
  805. n_rcols, &str_doc_type_col, &db_res) < 0)
  806. {
  807. LM_ERR("in sql query\n");
  808. goto error;
  809. }
  810. if (db_res == NULL)
  811. goto error;
  812. directory->s = xcaps_buf.s;
  813. directory->len = 0;
  814. directory->len += snprintf(directory->s + directory->len,
  815. xcaps_buf.len - directory->len,
  816. "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
  817. "<xcap-directory xmlns=\"urn:oma:xml:xdm:xcap-directory\">\r\n");
  818. rows = RES_ROWS(db_res);
  819. for (i = 0; i < RES_ROW_N(db_res); i++)
  820. {
  821. values = ROW_VALUES(&rows[i]);
  822. if (cur_type != VAL_INT(&values[doc_type_col]))
  823. {
  824. if (cur_type != 0)
  825. {
  826. directory->len += snprintf(directory->s + directory->len,
  827. xcaps_buf.len - directory->len,
  828. "</folder>\r\n");
  829. }
  830. cur_type = VAL_INT(&values[doc_type_col]);
  831. memset(&auid_string, 0, sizeof(str));
  832. while(xcaps_auid_list[cur_pos].auid.s != NULL)
  833. {
  834. if (xcaps_auid_list[cur_pos].type == cur_type)
  835. {
  836. auid_string.s = xcaps_auid_list[cur_pos].auid.s;
  837. auid_string.len = xcaps_auid_list[cur_pos].auid.len;
  838. break;
  839. }
  840. cur_pos++;
  841. }
  842. if (auid_string.s == NULL)
  843. {
  844. goto error;
  845. }
  846. directory->len += snprintf(directory->s + directory->len,
  847. xcaps_buf.len - directory->len,
  848. "<folder auid=\"%.*s\">\r\n",
  849. auid_string.len, auid_string.s);
  850. }
  851. switch(xcaps_directory_scheme)
  852. {
  853. case -1:
  854. directory->len += snprintf(directory->s + directory->len,
  855. xcaps_buf.len - directory->len,
  856. "<entry uri=\"%s://", msg->rcv.proto == PROTO_TLS ? "https" : "http");
  857. break;
  858. case 0:
  859. directory->len += snprintf(directory->s + directory->len,
  860. xcaps_buf.len - directory->len,
  861. "<entry uri=\"http://");
  862. break;
  863. case 1:
  864. directory->len += snprintf(directory->s + directory->len,
  865. xcaps_buf.len - directory->len,
  866. "<entry uri=\"https://");
  867. break;
  868. }
  869. if (xcaps_directory_hostname.len > 0)
  870. {
  871. directory->len += snprintf(directory->s + directory->len,
  872. xcaps_buf.len - directory->len,
  873. "%.*s", xcaps_directory_hostname.len, xcaps_directory_hostname.s);
  874. }
  875. else
  876. {
  877. if (parse_headers(msg, HDR_EOH_F, 0) < 0)
  878. {
  879. LM_ERR("error parsing headers\n");
  880. goto error;
  881. }
  882. while (hdr != NULL)
  883. {
  884. if (cmp_hdrname_strzn(&hdr->name, "Host", 4) == 0)
  885. {
  886. server_name = hdr->body;
  887. break;
  888. }
  889. hdr = hdr->next;
  890. }
  891. if (server_name.len > 0)
  892. {
  893. directory->len += snprintf(directory->s + directory->len,
  894. xcaps_buf.len - directory->len,
  895. "%.*s", server_name.len, server_name.s);
  896. }
  897. else
  898. {
  899. server_name.s = pkg_malloc(IP6_MAX_STR_SIZE + 6);
  900. server_name.len = ip_addr2sbuf(&msg->rcv.dst_ip, server_name.s, IP6_MAX_STR_SIZE);
  901. directory->len += snprintf(directory->s + directory->len,
  902. xcaps_buf.len - directory->len,
  903. "%.*s:%d", server_name.len, server_name.s, msg->rcv.dst_port);
  904. pkg_free(server_name.s);
  905. }
  906. }
  907. directory->len += snprintf(directory->s + directory->len,
  908. xcaps_buf.len - directory->len,
  909. "%s\" etag=\"%s\"/>\r\n",
  910. VAL_STRING(&values[doc_uri_col]),
  911. VAL_STRING(&values[etag_col]));
  912. }
  913. if (cur_type != 0)
  914. {
  915. directory->len += snprintf(directory->s + directory->len, xcaps_buf.len - directory->len,
  916. "</folder>\r\n");
  917. }
  918. directory->len += snprintf(directory->s + directory->len, xcaps_buf.len - directory->len,
  919. "</xcap-directory>");
  920. if (db_res != NULL)
  921. xcaps_dbf.free_result(xcaps_db, db_res);
  922. return 0;
  923. error:
  924. if (db_res != NULL)
  925. xcaps_dbf.free_result(xcaps_db, db_res);
  926. return -1;
  927. }
  928. /**
  929. *
  930. */
  931. static int w_xcaps_get(sip_msg_t* msg, char* puri, char* ppath)
  932. {
  933. struct sip_uri turi;
  934. str uri;
  935. str path;
  936. str etag = {0, 0};
  937. str body = {0, 0};
  938. str new_body = {0, 0};
  939. int ret = 0;
  940. xcap_uri_t xuri;
  941. str *ctype;
  942. str allow;
  943. if(puri==0 || ppath==0)
  944. {
  945. LM_ERR("invalid parameters\n");
  946. return -1;
  947. }
  948. if(fixup_get_svalue(msg, (gparam_p)puri, &uri)!=0)
  949. {
  950. LM_ERR("unable to get uri\n");
  951. return -1;
  952. }
  953. if(uri.s==NULL || uri.len == 0)
  954. {
  955. LM_ERR("invalid uri parameter\n");
  956. return -1;
  957. }
  958. if(fixup_get_svalue(msg, (gparam_p)ppath, &path)!=0)
  959. {
  960. LM_ERR("unable to get path\n");
  961. return -1;
  962. }
  963. if(path.s==NULL || path.len == 0)
  964. {
  965. LM_ERR("invalid path parameter\n");
  966. return -1;
  967. }
  968. if(parse_uri(uri.s, uri.len, &turi)!=0)
  969. {
  970. LM_ERR("parsing uri parameter\n");
  971. goto error;
  972. }
  973. if(xcap_parse_uri(&path, &xcaps_root, &xuri)<0)
  974. {
  975. LM_ERR("cannot parse xcap uri [%.*s]\n",
  976. path.len, path.s);
  977. goto error;
  978. }
  979. switch(xuri.type)
  980. {
  981. case DIRECTORY:
  982. if (strncmp(xuri.file.s, "directory.xml", xuri.file.len) == 0)
  983. {
  984. if (xcaps_get_directory(msg, &turi.user, &turi.host, &body) < 0)
  985. goto error;
  986. xcaps_send_reply(msg, 200, &xcaps_str_ok, NULL, &xcaps_str_appdrxml, &body);
  987. }
  988. else
  989. {
  990. xcaps_send_reply(msg, 404, &xcaps_str_notfound, NULL, NULL, NULL);
  991. }
  992. break;
  993. case XCAP_CAPS:
  994. xcaps_send_reply(msg, 501, &xcaps_str_notimplemented, NULL, NULL, NULL);
  995. break;
  996. case SEARCH:
  997. allow.s = xcaps_hdr_buf;
  998. allow.len = snprintf(allow.s, XCAPS_HDR_SIZE, "Allow: POST\r\n");
  999. xcaps_send_reply(msg, 405, &xcaps_str_notallowed, &allow, NULL, NULL);
  1000. break;
  1001. default:
  1002. if((ret=xcaps_get_db_etag(&turi.user, &turi.host, &xuri, &etag))<0)
  1003. {
  1004. LM_ERR("could not fetch etag for xcap document\n");
  1005. goto error;
  1006. }
  1007. if (ret==1)
  1008. {
  1009. /* doc not found */
  1010. xcaps_send_reply(msg, 404, &xcaps_str_notfound, NULL,
  1011. NULL, NULL);
  1012. return 1;
  1013. }
  1014. if((ret=check_preconditions(msg, etag))==-1)
  1015. {
  1016. xcaps_send_reply(msg, 412, &xcaps_str_precon, NULL,
  1017. NULL, NULL);
  1018. return -2;
  1019. } else if (ret==-2) {
  1020. xcaps_send_reply(msg, 304, &xcaps_str_notmod, NULL,
  1021. NULL, NULL);
  1022. return -2;
  1023. }
  1024. if((ret=xcaps_get_db_doc(&turi.user, &turi.host, &xuri, &body))<0)
  1025. {
  1026. LM_ERR("could not fetch xcap document\n");
  1027. goto error;
  1028. }
  1029. if(ret!=0)
  1030. {
  1031. /* doc not found */
  1032. xcaps_send_reply(msg, 404, &xcaps_str_notfound, NULL,
  1033. NULL, NULL);
  1034. break;
  1035. }
  1036. if(xuri.nss!=NULL && xuri.node.len>0)
  1037. {
  1038. if((new_body.s = pkg_malloc(body.len))==NULL)
  1039. {
  1040. LM_ERR("allocating package memory\n");
  1041. goto error;
  1042. }
  1043. new_body.len = body.len;
  1044. if(xcaps_xpath_hack(&body, 0)<0)
  1045. {
  1046. LM_ERR("could not hack xcap document\n");
  1047. goto error;
  1048. }
  1049. if(xcaps_xpath_get(&body, &xuri.node, &new_body)<0)
  1050. {
  1051. LM_ERR("could not retrieve element from xcap document\n");
  1052. goto error;
  1053. }
  1054. if(new_body.len<=0)
  1055. {
  1056. /* element not found */
  1057. xcaps_send_reply(msg, 404, &xcaps_str_notfound, NULL,
  1058. NULL, NULL);
  1059. pkg_free(new_body.s);
  1060. new_body.s = NULL;
  1061. break;
  1062. }
  1063. if(xcaps_xpath_hack(&new_body, 1)<0)
  1064. {
  1065. LM_ERR("could not hack xcap document\n");
  1066. goto error;
  1067. }
  1068. memcpy(body.s, new_body.s, new_body.len);
  1069. body.len = new_body.len;
  1070. pkg_free(new_body.s);
  1071. new_body.s = NULL;
  1072. }
  1073. /* doc or element found */
  1074. ctype = &xcaps_str_appxml;
  1075. if(xuri.type==RESOURCE_LIST)
  1076. ctype = &xcaps_str_apprlxml;
  1077. else if(xuri.type==PRES_RULES)
  1078. ctype = &xcaps_str_appapxml;
  1079. else if(xuri.type==RLS_SERVICE)
  1080. ctype = &xcaps_str_apprsxml;
  1081. else if(xuri.type==USER_PROFILE)
  1082. ctype = &xcaps_str_appupxml;
  1083. else if(xuri.type==PRES_CONTENT)
  1084. ctype = &xcaps_str_apppcxml;
  1085. else if(xuri.type==PIDF_MANIPULATION)
  1086. ctype = &xcaps_str_apppdxml;
  1087. xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag,
  1088. ctype, &body);
  1089. break;
  1090. }
  1091. return 1;
  1092. error:
  1093. if (new_body.s) pkg_free(new_body.s);
  1094. xcaps_send_reply(msg, 500, &xcaps_str_srverr, NULL,
  1095. NULL, NULL);
  1096. return -1;
  1097. }
  1098. /**
  1099. *
  1100. */
  1101. static int xcaps_del_db(str* user, str *domain, xcap_uri_t *xuri)
  1102. {
  1103. db_key_t qcols[4];
  1104. db_val_t qvals[4];
  1105. int ncols = 0;
  1106. /* delete in xcap table*/
  1107. qcols[ncols] = &str_username_col;
  1108. qvals[ncols].type = DB1_STR;
  1109. qvals[ncols].nul = 0;
  1110. qvals[ncols].val.str_val = *user;
  1111. ncols++;
  1112. qcols[ncols] = &str_domain_col;
  1113. qvals[ncols].type = DB1_STR;
  1114. qvals[ncols].nul = 0;
  1115. qvals[ncols].val.str_val = *domain;
  1116. ncols++;
  1117. qcols[ncols] = &str_doc_uri_col;
  1118. qvals[ncols].type = DB1_STR;
  1119. qvals[ncols].nul = 0;
  1120. qvals[ncols].val.str_val= xuri->adoc;
  1121. ncols++;
  1122. if (xcaps_dbf.use_table(xcaps_db, &xcaps_db_table) < 0)
  1123. {
  1124. LM_ERR("in use_table-[table]= %.*s\n", xcaps_db_table.len,
  1125. xcaps_db_table.s);
  1126. goto error;
  1127. }
  1128. if(xcaps_dbf.delete(xcaps_db, qcols, NULL, qvals, ncols)< 0)
  1129. {
  1130. LM_ERR("in sql delete\n");
  1131. goto error;
  1132. }
  1133. return 0;
  1134. error:
  1135. return -1;
  1136. }
  1137. /**
  1138. *
  1139. */
  1140. static int w_xcaps_del(sip_msg_t* msg, char* puri, char* ppath)
  1141. {
  1142. struct sip_uri turi;
  1143. str uri;
  1144. str path;
  1145. xcap_uri_t xuri;
  1146. str body = {0, 0};
  1147. str etag_hdr = {0, 0};
  1148. str etag = {0, 0};
  1149. str tbuf;
  1150. str allow = {0, 0};
  1151. if(puri==0 || ppath==0)
  1152. {
  1153. LM_ERR("invalid parameters\n");
  1154. return -1;
  1155. }
  1156. if(fixup_get_svalue(msg, (gparam_p)puri, &uri)!=0)
  1157. {
  1158. LM_ERR("unable to get uri\n");
  1159. return -1;
  1160. }
  1161. if(uri.s==NULL || uri.len == 0)
  1162. {
  1163. LM_ERR("invalid uri parameter\n");
  1164. return -1;
  1165. }
  1166. if(fixup_get_svalue(msg, (gparam_p)ppath, &path)!=0)
  1167. {
  1168. LM_ERR("unable to get path\n");
  1169. return -1;
  1170. }
  1171. if(path.s==NULL || path.len == 0)
  1172. {
  1173. LM_ERR("invalid path parameter\n");
  1174. return -1;
  1175. }
  1176. if(parse_uri(uri.s, uri.len, &turi)!=0)
  1177. {
  1178. LM_ERR("parsing uri parameter\n");
  1179. goto error;
  1180. }
  1181. if(xcap_parse_uri(&path, &xcaps_root, &xuri)<0)
  1182. {
  1183. LM_ERR("cannot parse xcap uri [%.*s]\n",
  1184. path.len, path.s);
  1185. goto error;
  1186. }
  1187. switch(xuri.type)
  1188. {
  1189. case DIRECTORY:
  1190. case XCAP_CAPS:
  1191. allow.s = xcaps_hdr_buf;
  1192. allow.len = snprintf(allow.s, XCAPS_HDR_SIZE, "Allow: GET\r\n");
  1193. xcaps_send_reply(msg, 405, &xcaps_str_notallowed, &allow, NULL, NULL);
  1194. break;
  1195. case SEARCH:
  1196. allow.s = xcaps_hdr_buf;
  1197. allow.len = snprintf(allow.s, XCAPS_HDR_SIZE, "Allow: POST\r\n");
  1198. xcaps_send_reply(msg, 405, &xcaps_str_notallowed, &allow, NULL, NULL);
  1199. break;
  1200. default:
  1201. if(xcaps_get_db_etag(&turi.user, &turi.host, &xuri, &etag)!=0)
  1202. {
  1203. LM_ERR("could not fetch etag for xcap document\n");
  1204. goto error;
  1205. }
  1206. if(check_preconditions(msg, etag)!=1)
  1207. {
  1208. xcaps_send_reply(msg, 412, &xcaps_str_precon, NULL,
  1209. NULL, NULL);
  1210. return -2;
  1211. }
  1212. if(xuri.nss==NULL)
  1213. {
  1214. /* delete document */
  1215. if(xcaps_del_db(&turi.user, &turi.host, &xuri)<0)
  1216. {
  1217. LM_ERR("could not delete document\n");
  1218. goto error;
  1219. }
  1220. xcaps_send_reply(msg, 200, &xcaps_str_ok, NULL,
  1221. NULL, NULL);
  1222. } else {
  1223. /* delete element */
  1224. if(xcaps_get_db_doc(&turi.user, &turi.host, &xuri, &tbuf) != 0)
  1225. {
  1226. LM_ERR("could not fetch xcap document\n");
  1227. goto error;
  1228. }
  1229. if(xcaps_xpath_hack(&tbuf, 0)<0)
  1230. {
  1231. LM_ERR("could not hack xcap document\n");
  1232. goto error;
  1233. }
  1234. if(xcaps_xpath_set(&tbuf, &xuri.node, NULL, &body)<0)
  1235. {
  1236. LM_ERR("could not update xcap document\n");
  1237. goto error;
  1238. }
  1239. if(body.len<=0)
  1240. {
  1241. LM_ERR("no new content\n");
  1242. goto error;
  1243. }
  1244. if(xcaps_xpath_hack(&body, 1)<0)
  1245. {
  1246. LM_ERR("could not hack xcap document\n");
  1247. goto error;
  1248. }
  1249. if(xcaps_generate_etag_hdr(&etag_hdr)<0)
  1250. {
  1251. LM_ERR("could not generate etag\n");
  1252. goto error;
  1253. }
  1254. etag.s = etag_hdr.s + 7; /* 'ETag: "' */
  1255. etag.len = etag_hdr.len - 10; /* 'ETag: " "\r\n' */
  1256. if(xcaps_put_db(&turi.user, &turi.host,
  1257. &xuri, &etag, &body)<0)
  1258. {
  1259. LM_ERR("could not store document\n");
  1260. goto error;
  1261. }
  1262. xcaps_send_reply(msg, 200, &xcaps_str_ok, &etag_hdr,
  1263. NULL, NULL);
  1264. if(body.s!=NULL)
  1265. pkg_free(body.s);
  1266. }
  1267. break;
  1268. }
  1269. return 1;
  1270. error:
  1271. xcaps_send_reply(msg, 500, &xcaps_str_srverr, NULL,
  1272. NULL, NULL);
  1273. if(body.s!=NULL)
  1274. pkg_free(body.s);
  1275. return -1;
  1276. }
  1277. /**
  1278. *
  1279. */
  1280. int xcaps_path_get_auid_type(str *path)
  1281. {
  1282. str s;
  1283. char c;
  1284. int ret;
  1285. ret = -1;
  1286. if(path==NULL)
  1287. return -1;
  1288. if(path->len<xcaps_root.len)
  1289. return -1;
  1290. if(strncmp(path->s, xcaps_root.s, xcaps_root.len)!=0)
  1291. {
  1292. LM_ERR("missing xcap-root in [%.*s]\n", path->len, path->s);
  1293. return -1;
  1294. }
  1295. s.s = path->s + xcaps_root.len - 1;
  1296. s.len = path->len - xcaps_root.len + 1;
  1297. c = s.s[s.len];
  1298. s.s[s.len] = '\0';
  1299. if(s.len>12 && strstr(s.s, "/pres-rules/")!=NULL)
  1300. {
  1301. LM_DBG("matched pres-rules\n");
  1302. ret = PRES_RULES;
  1303. goto done;
  1304. }
  1305. if(s.len>35 && strstr(s.s, "/org.openmobilealliance.pres-rules/")!=NULL)
  1306. {
  1307. LM_DBG("matched oma pres-rules\n");
  1308. ret = PRES_RULES;
  1309. goto done;
  1310. }
  1311. if(s.len>14 && strstr(s.s, "/rls-services/")!=NULL)
  1312. {
  1313. LM_DBG("matched rls-services\n");
  1314. ret = RLS_SERVICE;
  1315. goto done;
  1316. }
  1317. if(s.len>19 && strstr(s.s, "pidf-manipulation")!=NULL)
  1318. {
  1319. LM_DBG("matched pidf-manipulation\n");
  1320. ret = PIDF_MANIPULATION;
  1321. goto done;
  1322. }
  1323. if(s.len>16 && strstr(s.s, "/resource-lists/")!=NULL)
  1324. {
  1325. LM_DBG("matched resource-lists\n");
  1326. ret = RESOURCE_LIST;
  1327. goto done;
  1328. }
  1329. if(s.len>11 && strstr(s.s, "/xcap-caps/")!=NULL)
  1330. {
  1331. LM_DBG("matched xcap-caps\n");
  1332. ret = XCAP_CAPS;
  1333. goto done;
  1334. }
  1335. if(s.len> 37 && strstr(s.s, "/org.openmobilealliance.user-profile/")!=NULL)
  1336. {
  1337. LM_DBG("matched oma user-profile\n");
  1338. ret = USER_PROFILE;
  1339. goto done;
  1340. }
  1341. if(s.len> 37 && strstr(s.s, "/org.openmobilealliance.pres-content/")!=NULL)
  1342. {
  1343. LM_DBG("matched oma pres-content\n");
  1344. ret = PRES_CONTENT;
  1345. goto done;
  1346. }
  1347. if(s.len>31 && strstr(s.s, "/org.openmobilealliance.search?")!=NULL)
  1348. {
  1349. LM_DBG("matched oma search\n");
  1350. ret = SEARCH;
  1351. goto done;
  1352. }
  1353. done:
  1354. s.s[s.len] = c;
  1355. return ret;
  1356. }
  1357. /**
  1358. *
  1359. */
  1360. int xcaps_generate_etag_hdr(str *etag)
  1361. {
  1362. etag->len = snprintf(xcaps_hdr_buf, XCAPS_HDR_SIZE,
  1363. "ETag: \"sr-%d-%d-%d\"\r\n", xcaps_init_time, my_pid(),
  1364. xcaps_etag_counter++);
  1365. if(etag->len <0)
  1366. {
  1367. LM_ERR("error printing etag\n ");
  1368. return -1;
  1369. }
  1370. if(etag->len >= XCAPS_HDR_SIZE)
  1371. {
  1372. LM_ERR("etag buffer overflow\n");
  1373. return -1;
  1374. }
  1375. etag->s = xcaps_hdr_buf;
  1376. etag->s[etag->len] = '\0';
  1377. return 0;
  1378. }
  1379. /**
  1380. *
  1381. */
  1382. static int fixup_xcaps_put(void** param, int param_no)
  1383. {
  1384. str s;
  1385. pv_elem_t *xm;
  1386. if (param_no == 1) {
  1387. return fixup_spve_null(param, 1);
  1388. } else if (param_no == 2) {
  1389. return fixup_spve_null(param, 1);
  1390. } else if (param_no == 3) {
  1391. s.s = (char*)(*param); s.len = strlen(s.s);
  1392. if(pv_parse_format(&s, &xm)<0)
  1393. {
  1394. LM_ERR("wrong format[%s]\n", (char*)(*param));
  1395. return E_UNSPEC;
  1396. }
  1397. *param = (void*)xm;
  1398. return 0;
  1399. }
  1400. return 0;
  1401. }
  1402. static int check_preconditions(sip_msg_t *msg, str etag_hdr)
  1403. {
  1404. struct hdr_field* hdr = msg->headers;
  1405. int ifmatch_found=0;
  1406. int matched_matched=0;
  1407. int matched_nonematched=0;
  1408. if (parse_headers(msg, HDR_EOH_F, 0) < 0)
  1409. {
  1410. LM_ERR("error parsing headers\n");
  1411. return 1;
  1412. }
  1413. if (etag_hdr.len > 0)
  1414. {
  1415. str etag;
  1416. /* Keep the surrounding "s in the ETag */
  1417. etag.s = etag_hdr.s + 6; /* 'ETag: ' */
  1418. etag.len = etag_hdr.len - 8; /* 'ETag: " "\r\n' */
  1419. while (hdr!=NULL)
  1420. {
  1421. if(cmp_hdrname_strzn(&hdr->name, "If-Match", 8)==0)
  1422. {
  1423. ifmatch_found = 1;
  1424. if (check_match_header(hdr->body, &etag)>0)
  1425. matched_matched = 1;
  1426. }
  1427. else if (cmp_hdrname_strzn(&hdr->name, "If-None-Match", 13)==0)
  1428. {
  1429. if (check_match_header(hdr->body, &etag)>0)
  1430. matched_nonematched = 1;
  1431. }
  1432. hdr = hdr->next;
  1433. }
  1434. } else {
  1435. while (hdr!=NULL)
  1436. {
  1437. if(cmp_hdrname_strzn(&hdr->name, "If-Match", 8)==0)
  1438. ifmatch_found = 1;
  1439. hdr = hdr->next;
  1440. }
  1441. }
  1442. if (ifmatch_found == 1 && matched_matched == 0)
  1443. return -1;
  1444. else if (matched_nonematched == 1)
  1445. return -2;
  1446. else
  1447. return 1;
  1448. }
  1449. static int check_match_header(str body, str *etag)
  1450. {
  1451. if (etag == NULL)
  1452. return -1;
  1453. if (etag->s == NULL || etag->len == 0)
  1454. return -1;
  1455. do
  1456. {
  1457. char *start_pos, *end_pos, *old_body_pos;
  1458. int cur_etag_len;
  1459. if ((start_pos = strchr(body.s, '"')) == NULL)
  1460. return -1;
  1461. if ((end_pos = strchr(start_pos + 1, '"')) == NULL)
  1462. return -1;
  1463. cur_etag_len = end_pos - start_pos + 1;
  1464. if (strncmp(start_pos, etag->s, cur_etag_len)==0)
  1465. return 1;
  1466. else if (strncmp(start_pos, "\"*\"", cur_etag_len)==0)
  1467. return 1;
  1468. old_body_pos = body.s;
  1469. if ((body.s = strchr(end_pos, ',')) == NULL)
  1470. return -1;
  1471. body.len -= body.s - old_body_pos;
  1472. } while (body.len > 0);
  1473. return -1;
  1474. }