1 /*
2 * lost module utility functions
3 *
4 * Copyright (C) 2020 Wolfgang Kampichler
5 * DEC112, FREQUENTIS AG
6 *
7 * This file is part of Kamailio, a free SIP server.
8 *
9 * Kamailio is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version
13 *
14 * Kamailio is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 *
23 */
24
25 /*!
26 * \file
27 * \brief Kamailio lost :: utilities
28 * \ingroup lost
29 * Module: \ref lost
30 */
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include <time.h>
37
38 #include "../../core/parser/msg_parser.h"
39 #include "../../core/parser/parse_content.h"
40 #include "../../core/parser/parse_uri.h"
41 #include "../../core/parser/parse_from.h"
42 #include "../../core/parser/parse_ppi_pai.h"
43 #include "../../core/dprint.h"
44 #include "../../core/mem/mem.h"
45 #include "../../core/mem/shm_mem.h"
46 #include "../../core/rand/kam_rand.h"
47
48 #include "pidf.h"
49 #include "utilities.h"
50
51 /*
52 * lost_trim_content(dest, lgth)
53 * removes whitespace that my occur in a content of an xml element
54 */
lost_trim_content(char * str,int * lgth)55 char *lost_trim_content(char *str, int *lgth)
56 {
57 char *end;
58
59 while(isspace(*str))
60 str++;
61
62 if(*str == 0)
63 return NULL;
64
65 end = str + strlen(str) - 1;
66
67 while(end > str && isspace(*end))
68 end--;
69
70 *(end + 1) = '\0';
71
72 *lgth = (end + 1) - str;
73
74 return str;
75 }
76
77 /*
78 * lost_rand_str(dest, length)
79 * creates a random string used as temporary id in a findService request
80 */
lost_rand_str(char * dest,size_t lgth)81 void lost_rand_str(char *dest, size_t lgth)
82 {
83 size_t index;
84 char charset[] = "0123456789"
85 "abcdefghijklmnopqrstuvwxyz"
86 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
87 while(lgth-- > 0) {
88 index = (double)kam_rand() / RAND_MAX * (sizeof charset - 1);
89 *dest++ = charset[index];
90 }
91 *dest = '\0';
92 }
93
94 /*
95 * lost_new_loc(urn)
96 * creates a new location object in private memory and returns a pointer
97 */
lost_new_loc(str rurn)98 p_loc_t lost_new_loc(str rurn)
99 {
100 s_loc_t *ptr = NULL;
101
102 char *id = NULL;
103 char *urn = NULL;
104
105 ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));
106 if(ptr == NULL) {
107 goto err;
108 }
109
110 id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);
111 if(id == NULL) {
112 pkg_free(ptr);
113 goto err;
114 }
115
116 urn = (char *)pkg_malloc(rurn.len + 1);
117 if(urn == NULL) {
118 pkg_free(id);
119 pkg_free(ptr);
120 goto err;
121 }
122
123 memset(urn, 0, rurn.len + 1);
124 memcpy(urn, rurn.s, rurn.len);
125 urn[rurn.len] = '\0';
126
127 lost_rand_str(id, RANDSTRSIZE);
128
129 ptr->identity = id;
130 ptr->urn = urn;
131 ptr->longitude = NULL;
132 ptr->latitude = NULL;
133 ptr->geodetic = NULL;
134 ptr->xpath = NULL;
135 ptr->profile = NULL;
136 ptr->radius = 0;
137 ptr->recursive = LOST_RECURSION_TRUE; /* set recursion to true */
138 ptr->boundary = 0; /* set boundary to reference */
139
140 return ptr;
141
142 err:
143 LM_ERR("no more private memory\n");
144 return NULL;
145 }
146
147 /*
148 * lost_new_held(uri, type, time, exact)
149 * creates a new held object in private memory and returns a pointer
150 */
lost_new_held(str s_uri,str s_type,int time,int exact)151 p_held_t lost_new_held(str s_uri, str s_type, int time, int exact)
152 {
153 s_held_t *ptr = NULL;
154
155 char *uri = NULL;
156 char *type = NULL;
157
158 ptr = (s_held_t *)pkg_malloc(sizeof(s_held_t));
159 if(ptr == NULL) {
160 goto err;
161 }
162
163 uri = (char *)pkg_malloc(s_uri.len + 1);
164 if(uri == NULL) {
165 pkg_free(ptr);
166 goto err;
167 }
168
169 type = (char *)pkg_malloc(s_type.len + 1);
170 if(type == NULL) {
171 pkg_free(uri);
172 pkg_free(ptr);
173 goto err;
174 }
175
176 memset(uri, 0, s_uri.len + 1);
177 memcpy(uri, s_uri.s, s_uri.len);
178 uri[s_uri.len] = '\0';
179
180 memset(type, 0, s_type.len + 1);
181 memcpy(type, s_type.s, s_type.len);
182 type[s_type.len] = '\0';
183
184 ptr->identity = uri;
185 ptr->type = type;
186 ptr->time = time;
187 ptr->exact = exact;
188
189 return ptr;
190
191 err:
192 LM_ERR("no more private memory\n");
193 return NULL;
194 }
195
196 /*
197 * lost_free_loc(ptr)
198 * frees a location object
199 */
lost_free_loc(p_loc_t ptr)200 void lost_free_loc(p_loc_t ptr)
201 {
202 pkg_free(ptr->identity);
203 pkg_free(ptr->urn);
204 if(ptr->xpath)
205 pkg_free(ptr->xpath);
206 if(ptr->geodetic)
207 pkg_free(ptr->geodetic);
208 if(ptr->longitude)
209 pkg_free(ptr->longitude);
210 if(ptr->latitude)
211 pkg_free(ptr->latitude);
212 if(ptr->profile)
213 pkg_free(ptr->profile);
214
215 pkg_free(ptr);
216 ptr = NULL;
217 }
218
219 /*
220 * lost_free_loc(ptr)
221 * frees a held location request object
222 */
lost_free_held(p_held_t ptr)223 void lost_free_held(p_held_t ptr)
224 {
225 pkg_free(ptr->identity);
226 pkg_free(ptr->type);
227
228 pkg_free(ptr);
229 ptr = NULL;
230 }
231
232 /*
233 * lost_free_string(ptr)
234 * frees and resets a string
235 */
lost_free_string(str * string)236 void lost_free_string(str *string)
237 {
238 str ptr = *string;
239
240 if(ptr.s) {
241 pkg_free(ptr.s);
242 ptr.s = NULL;
243 ptr.len = 0;
244 }
245 }
246
247 /*
248 * lost_get_content(node, name, lgth)
249 * gets a nodes "name" content and returns string allocated in private memory
250 */
lost_get_content(xmlNodePtr node,const char * name,int * lgth)251 char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)
252 {
253 xmlNodePtr cur = node;
254 char *content = NULL;
255 char *cnt = NULL;
256 int len;
257
258 *lgth = 0;
259
260 content = xmlNodeGetNodeContentByName(cur, name, NULL);
261 if(content == NULL) {
262 LM_ERR("could not get XML node content\n");
263 return cnt;
264 } else {
265 len = strlen(content);
266 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
267 if(cnt == NULL) {
268 LM_ERR("no more private memory\n");
269 xmlFree(content);
270 return cnt;
271 }
272 memset(cnt, 0, len + 1);
273 memcpy(cnt, content, len);
274 cnt[len] = '\0';
275 }
276
277 xmlFree(content);
278 *lgth = strlen(cnt);
279
280 return cnt;
281 }
282
283 /*
284 * lost_get_property(node, name, lgth)
285 * gets a nodes property "name" and returns string allocated in private memory
286 */
lost_get_property(xmlNodePtr node,const char * name,int * lgth)287 char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)
288 {
289 xmlNodePtr cur = node;
290 char *content;
291 char *cnt = NULL;
292 int len;
293
294 *lgth = 0;
295
296 content = xmlNodeGetAttrContentByName(cur, name);
297 if(content == NULL) {
298 LM_ERR("could not get XML node content\n");
299 return cnt;
300 } else {
301 len = strlen(content);
302 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
303 if(cnt == NULL) {
304 LM_ERR("no more private memory\n");
305 xmlFree(content);
306 return cnt;
307 }
308 memset(cnt, 0, len + 1);
309 memcpy(cnt, content, len);
310 cnt[len] = '\0';
311 }
312
313 xmlFree(content);
314 *lgth = strlen(cnt);
315
316 return cnt;
317 }
318
319 /*
320 * lost_get_childname(name, lgth)
321 * gets a nodes child name and returns string allocated in private memory
322 */
lost_get_childname(xmlNodePtr node,const char * name,int * lgth)323 char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)
324 {
325 xmlNodePtr cur = node;
326 xmlNodePtr parent = NULL;
327 xmlNodePtr child = NULL;
328 char *cnt = NULL;
329 int len;
330
331 *lgth = 0;
332
333 parent = xmlNodeGetNodeByName(cur, name, NULL);
334 if(parent == NULL) {
335 LM_ERR("xmlNodeGetNodeByName() failed\n");
336 return cnt;
337 }
338
339 child = parent->children;
340 if(child == NULL) {
341 LM_ERR("%s has no children '%s'\n", parent->name, name);
342 return cnt;
343 }
344
345 len = strlen((char *)child->name);
346 cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
347 if(cnt == NULL) {
348 LM_ERR("no more private memory\n");
349 return cnt;
350 }
351
352 memset(cnt, 0, len + 1);
353 memcpy(cnt, child->name, len);
354 cnt[len] = '\0';
355
356 *lgth = strlen(cnt);
357
358 return cnt;
359 }
360
361 /*
362 * lost_get_geolocation_header(msg, lgth)
363 * gets the Geolocation header value and returns string allocated in
364 * private memory
365 */
lost_get_geolocation_header(struct sip_msg * msg,int * lgth)366 char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)
367 {
368 struct hdr_field *hf;
369 char *res = NULL;
370
371 *lgth = 0;
372
373 if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
374 LM_ERR("failed to parse geolocation header\n");
375 return res;
376 }
377
378 for(hf = msg->headers; hf; hf = hf->next) {
379 if((hf->type == HDR_OTHER_T)
380 && (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {
381 /* possible hit */
382 if(strncasecmp(hf->name.s, LOST_GEOLOC_HEADER,
383 LOST_GEOLOC_HEADER_SIZE) == 0) {
384
385 res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));
386 if(res == NULL) {
387 LM_ERR("no more private memory\n");
388 return res;
389 } else {
390 memset(res, 0, hf->body.len + 1);
391 memcpy(res, hf->body.s, hf->body.len + 1);
392 res[hf->body.len] = '\0';
393
394 *lgth = strlen(res);
395 }
396 } else {
397 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
398 hf->body.len);
399 }
400 break;
401 }
402 }
403
404 return res;
405 }
406
407 /*
408 * lost_get_pai_header(msg, lgth)
409 * gets the P-A-I header value and returns string allocated in
410 * private memory
411 */
lost_get_pai_header(struct sip_msg * msg,int * lgth)412 char *lost_get_pai_header(struct sip_msg *msg, int *lgth)
413 {
414 struct hdr_field *hf;
415 to_body_t *pai_body;
416 char *res = NULL;
417
418 *lgth = 0;
419
420 if(parse_headers(msg, HDR_PAI_F, 0) == -1) {
421 LM_ERR("could not parse P-A-I header\n");
422 return res;
423 }
424
425 for(hf = msg->headers; hf; hf = hf->next) {
426 if((hf->type == HDR_PAI_T)
427 && (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {
428 /* possible hit */
429 if(strncasecmp(hf->name.s, LOST_PAI_HEADER,
430 LOST_PAI_HEADER_SIZE) == 0) {
431
432 LM_DBG("P-A-I body: [%.*s]\n", hf->body.len, hf->body.s);
433
434 /* first, get some memory */
435 pai_body = pkg_malloc(sizeof(to_body_t));
436 if(pai_body == NULL) {
437 LM_ERR("no more private memory\n");
438 return res;
439 }
440 /* parse P-A-I body */
441 memset(pai_body, 0, sizeof(to_body_t));
442 parse_to(hf->body.s, hf->body.s + hf->body.len + 1, pai_body);
443 if(pai_body->error == PARSE_ERROR) {
444 LM_ERR("bad P-A-I header\n");
445 pkg_free(pai_body);
446 return res;
447 }
448 if(pai_body->error == PARSE_OK) {
449 res = (char *)pkg_malloc(
450 (pai_body->uri.len + 1) * sizeof(char));
451 if(res == NULL) {
452 LM_ERR("no more private memory\n");
453 pkg_free(pai_body);
454 return res;
455 } else {
456 memset(res, 0, pai_body->uri.len + 1);
457 memcpy(res, pai_body->uri.s, pai_body->uri.len + 1);
458 res[pai_body->uri.len] = '\0';
459 pkg_free(pai_body);
460
461 *lgth = strlen(res);
462 }
463 }
464 } else {
465 LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
466 hf->body.len);
467 }
468 break;
469 }
470 }
471
472 return res;
473 }
474
475 /*
476 * lost_get_from_header(msg, lgth)
477 * gets the From header value and returns string allocated in
478 * private memory
479 */
lost_get_from_header(struct sip_msg * msg,int * lgth)480 char *lost_get_from_header(struct sip_msg *msg, int *lgth)
481 {
482 to_body_t *f_body;
483 char *res = NULL;
484
485 *lgth = 0;
486
487 if(parse_headers(msg, HDR_FROM_F, 0) == -1) {
488 LM_ERR("failed to parse From header\n");
489 return res;
490 }
491
492 if(msg->from == NULL || get_from(msg) == NULL) {
493 LM_ERR("From header not found\n");
494 return res;
495 }
496 f_body = get_from(msg);
497
498 LM_DBG("From body: [%.*s]\n", f_body->body.len, f_body->body.s);
499
500 res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));
501 if(res == NULL) {
502 LM_ERR("no more private memory\n");
503 return res;
504 } else {
505 memset(res, 0, f_body->uri.len + 1);
506 memcpy(res, f_body->uri.s, f_body->uri.len + 1);
507 res[f_body->uri.len] = '\0';
508
509 *lgth = strlen(res);
510 }
511
512 return res;
513 }
514
515 /*
516 * lost_parse_geo(node, loc)
517 * parses locationResponse (pos|circle) and writes
518 * results to location object
519 */
lost_parse_geo(xmlNodePtr node,p_loc_t loc)520 int lost_parse_geo(xmlNodePtr node, p_loc_t loc)
521 {
522 xmlNodePtr cur = NULL;
523
524 char bufLat[BUFSIZE];
525 char bufLon[BUFSIZE];
526 char *content = NULL;
527
528 char s_profile[] = LOST_PRO_GEO2D;
529
530 int iRadius = 0;
531 int len = 0;
532
533 cur = node;
534 /* find <pos> element */
535 content = xmlNodeGetNodeContentByName(cur, "pos", NULL);
536
537 if(content == NULL) {
538 LM_WARN("could not find pos element\n");
539 return -1;
540 }
541
542 sscanf(content, "%s %s", bufLat, bufLon);
543 xmlFree(content);
544
545 len = strlen((char *)bufLat);
546 loc->latitude = (char *)pkg_malloc(len + 1);
547 if(loc->latitude == NULL)
548 goto err;
549
550 snprintf(loc->latitude, len, "%s", (char *)bufLat);
551
552 len = strlen((char *)bufLon);
553 loc->longitude = (char *)pkg_malloc(len + 1);
554 if(loc->longitude == NULL) {
555 pkg_free(loc->latitude);
556 goto err;
557 }
558
559 snprintf(loc->longitude, len, "%s", (char *)bufLon);
560
561 len = strlen((char *)bufLat) + strlen((char *)bufLon) + 1;
562 loc->geodetic = (char *)pkg_malloc(len + 1);
563 if(loc->longitude == NULL) {
564 pkg_free(loc->latitude);
565 pkg_free(loc->longitude);
566 goto err;
567 }
568
569 snprintf(loc->geodetic, len, "%s %s", (char *)bufLat, (char *)bufLon);
570
571 /* find <radius> element */
572 content = xmlNodeGetNodeContentByName(cur, "radius", NULL);
573 if(content != NULL) {
574 sscanf(content, "%d", &iRadius);
575 xmlFree(content);
576 }
577
578 /* write results */
579 loc->radius = iRadius;
580 loc->profile = (char *)pkg_malloc(strlen(s_profile) + 1);
581 strcpy(loc->profile, s_profile);
582
583 return 0;
584
585 err:
586 LM_ERR("no more private memory\n");
587 return -1;
588 }
589 /*
590 * lost_xpath_location(doc, path, loc)
591 * performs xpath expression on locationResponse and writes
592 * results (location-info child element) to location object
593 */
lost_xpath_location(xmlDocPtr doc,char * path,p_loc_t loc)594 int lost_xpath_location(xmlDocPtr doc, char *path, p_loc_t loc)
595 {
596 xmlXPathObjectPtr result = NULL;
597 xmlNodeSetPtr nodes = NULL;
598 xmlNodePtr root = NULL;
599 xmlNodePtr cur = NULL;
600 xmlDocPtr new = NULL;
601 xmlChar *xpath = NULL;
602 xmlChar *xmlbuff = NULL;
603 xmlChar *cname = NULL;
604
605 const unsigned char s_point[] = LOST_PNT;
606 const unsigned char s_circle[] = LOST_CIR;
607 const unsigned char s_civic[] = LOST_CIV;
608
609 char *ptr = NULL;
610 char *tmp = NULL;
611 char *s_profile = NULL;
612
613 int buffersize = 0;
614 int remove = 0;
615 int size = 0;
616 int len = 0;
617 int i = 0;
618 int nok = -1;
619
620 xpath = (xmlChar *)path;
621 /* get location via xpath expression */
622 result = xmlGetNodeSet(doc, xpath, BAD_CAST XPATH_NS);
623
624 if(result == NULL) {
625 LM_DBG("xmlGetNodeSet() returned no result\n");
626 return -1;
627 }
628
629 nodes = result->nodesetval;
630 if(nodes != NULL) {
631 size = nodes->nodeNr;
632 for(i = 0; i < size; ++i) {
633 if(nodes->nodeTab[i] == NULL) {
634 LM_WARN("xpath '%s' failed\n", xpath);
635 xmlXPathFreeObject(result);
636 return -1;
637 }
638 if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
639 cur = nodes->nodeTab[i];
640 /* check if child element is point, circle or civic */
641 while(nok < LOST_XPATH_DPTH) {
642 if(cur->children == NULL) {
643 /* no additional DOM level */
644 break;
645 } else {
646 /* check current DOM level */
647 nok++;
648 cname = BAD_CAST cur->name;
649 if(xmlStrcasecmp(cname, s_point) == 0) {
650 s_profile = LOST_PRO_GEO2D;
651 break;
652 }
653 if(xmlStrcasecmp(cname, s_circle) == 0) {
654 s_profile = LOST_PRO_GEO2D;
655 break;
656 }
657 if(xmlStrcasecmp(cname, s_civic) == 0) {
658 s_profile = LOST_PRO_CIVIC;
659 break;
660 }
661 /* nothing found ... try next DOM level */
662 cur = cur->children;
663 }
664 }
665
666 if(nok == 0) {
667 LM_DBG("xpath '%s' returned valid element (level %d/%d)\n",
668 xpath, nok, LOST_XPATH_DPTH);
669 } else if(nok < LOST_XPATH_DPTH) {
670 /* malformed pidf-lo but still ok */
671 LM_WARN("xpath '%s' returned malformed pidf-lo (level "
672 "%d/%d)\n",
673 xpath, nok, LOST_XPATH_DPTH);
674 } else {
675 /* really bad pidf-lo */
676 LM_WARN("xpath '%s' failed (level %d/%d)\n", xpath, nok,
677 LOST_XPATH_DPTH);
678 xmlXPathFreeObject(result);
679 return -1;
680 }
681
682 if(cur == NULL) {
683 LM_ERR("xpath xmlCopyNode() failed\n");
684 xmlXPathFreeObject(result);
685 return -1;
686 }
687
688 root = xmlCopyNode(cur, 1);
689 if(root == NULL) {
690 LM_ERR("xpath xmlCopyNode() failed\n");
691 xmlXPathFreeObject(result);
692 return -1;
693 }
694
695 new = xmlNewDoc(BAD_CAST "1.0");
696 if(new == NULL) {
697 LM_ERR("xpath xmlNewDoc() failed\n");
698 xmlXPathFreeObject(result);
699 return -1;
700 }
701 xmlDocSetRootElement(new, root);
702 xmlDocDumpFormatMemory(new, &xmlbuff, &buffersize, 0);
703 if(xmlbuff == NULL) {
704 LM_ERR("xpath xmlDocDumpFormatMemory() failed\n");
705 xmlFreeDoc(new);
706 xmlXPathFreeObject(result);
707 return -1;
708 }
709 /* take the first location-info element only */
710 if(i == 0) {
711 /* return the current profile */
712 loc->profile = (char *)pkg_malloc(strlen(s_profile) + 1);
713 if(loc->profile == NULL) {
714 xmlFree(xmlbuff);
715 xmlFreeDoc(new);
716 xmlXPathFreeObject(result);
717 goto err;
718 }
719 memset(loc->profile, 0, strlen(s_profile) + 1);
720 memcpy(loc->profile, s_profile, strlen(s_profile));
721
722 /* remove xml header from location element */
723 remove = strlen("<?xml version='1.0'?>\n");
724 buffersize = buffersize - remove;
725 ptr = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
726 if(ptr == NULL) {
727 xmlFree(xmlbuff);
728 xmlFreeDoc(new);
729 xmlXPathFreeObject(result);
730 goto err;
731 }
732
733 memset(ptr, 0, buffersize);
734 memcpy(ptr, (char *)(xmlbuff + remove), buffersize);
735 ptr[buffersize] = '\0';
736
737 /* trim the result */
738 tmp = lost_trim_content(ptr, &len);
739
740 /* return the location DOM */
741 loc->xpath = (char *)pkg_malloc(len + 1);
742 if(loc->xpath == NULL) {
743 pkg_free(ptr);
744 ptr = NULL;
745 xmlFree(xmlbuff);
746 xmlFreeDoc(new);
747 xmlXPathFreeObject(result);
748 goto err;
749 }
750 memset(loc->xpath, 0, len + 1);
751 memcpy(loc->xpath, tmp, len);
752 /* free memory */
753 pkg_free(ptr);
754 ptr = NULL;
755 } else {
756 LM_WARN("xpath location-info element(%d) ignored\n", i + 1);
757 }
758 xmlFree(xmlbuff);
759 xmlFreeDoc(new);
760 }
761 }
762 } else {
763 LM_WARN("xpath '%s' failed\n", xpath);
764 xmlXPathFreeObject(result);
765 return -1;
766 }
767 xmlXPathFreeObject(result);
768
769 return 0;
770
771 err:
772 LM_ERR("no more private memory\n");
773 return -1;
774 }
775
776 /*
777 * lost_parse_location_info(node, loc)
778 * wrapper to call xpath or simple pos|circle parser (last resort)
779 */
lost_parse_location_info(xmlNodePtr root,p_loc_t loc)780 int lost_parse_location_info(xmlNodePtr root, p_loc_t loc)
781 {
782
783 if(lost_xpath_location(root->doc, LOST_XPATH_GP, loc) == 0) {
784 return 0;
785 }
786
787 LM_WARN("xpath expression failed ... trying pos|circle\n");
788
789 if(lost_parse_geo(root, loc) == 0) {
790 return 0;
791 }
792
793 return -1;
794 }
795
796 /*
797 * lost_held_location_request(id, lgth, responsetime, exact, type)
798 * assembles and returns locationRequest string (allocated in private memory)
799 */
lost_held_location_request(p_held_t held,int * lgth)800 char *lost_held_location_request(p_held_t held, int *lgth)
801 {
802 int buffersize = 0;
803
804 char buf[BUFSIZE];
805 char *doc = NULL;
806
807 xmlChar *xmlbuff = NULL;
808 xmlDocPtr request = NULL;
809
810 xmlNodePtr ptrLocationRequest = NULL;
811 xmlNodePtr ptrLocationType = NULL;
812 xmlNodePtr ptrDevice = NULL;
813
814 xmlKeepBlanksDefault(1);
815 *lgth = 0;
816
817 /*
818 https://tools.ietf.org/html/rfc6155
819 https://tools.ietf.org/html/rfc5985
820
821 <?xml version="1.0" encoding="UTF-8"?>
822 <locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">
823 <locationType exact="true">geodetic locationURI</locationType>
824 <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
825 <uri>sip:user@example.net</uri>
826 </device>
827 </locationRequest>
828 */
829
830 /* create request */
831 request = xmlNewDoc(BAD_CAST "1.0");
832 if(request == NULL) {
833 LM_ERR("locationRequest xmlNewDoc() failed\n");
834 return doc;
835 }
836 /* locationRequest - element */
837 ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");
838 if(ptrLocationRequest == NULL) {
839 LM_ERR("locationRequest xmlNewNode() failed\n");
840 xmlFreeDoc(request);
841 return doc;
842 }
843 xmlDocSetRootElement(request, ptrLocationRequest);
844 /* properties */
845 xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",
846 BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");
847 /* responseTime - element (optional) */
848 if(held->time > 0) {
849 snprintf(buf, BUFSIZE, "%d", held->time);
850 xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST buf);
851 }
852 /* locationType - element (optional) */
853 ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,
854 BAD_CAST "locationType", BAD_CAST held->type);
855 /* properties */
856 xmlNewProp(ptrLocationType, BAD_CAST "exact",
857 (held->exact == HELD_EXACT_TRUE) ? BAD_CAST "true"
858 : BAD_CAST "false");
859 /* device - element */
860 ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);
861 if(ptrDevice == NULL) {
862 LM_ERR("locationRequest xmlNewChild() failed\n");
863 xmlFreeDoc(request);
864 return doc;
865 }
866 /* properties */
867 xmlNewProp(ptrDevice, BAD_CAST "xmlns",
868 BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");
869 /* uri - element */
870 xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST held->identity);
871
872 xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
873 if(xmlbuff == NULL) {
874 LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");
875 xmlFreeDoc(request);
876 return doc;
877 }
878
879 doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
880 if(doc == NULL) {
881 LM_ERR("no more private memory\n");
882 xmlFree(xmlbuff);
883 xmlFreeDoc(request);
884 return doc;
885 }
886
887 memset(doc, 0, buffersize + 1);
888 memcpy(doc, (char *)xmlbuff, buffersize);
889 doc[buffersize] = '\0';
890
891 *lgth = strlen(doc);
892
893 xmlFree(xmlbuff);
894 xmlFreeDoc(request);
895
896 return doc;
897 }
898
899 /*
900 * lost_find_service_request(loc, lgth)
901 * assembles and returns findService request string (allocated in private memory)
902 */
lost_find_service_request(p_loc_t loc,int * lgth)903 char *lost_find_service_request(p_loc_t loc, int *lgth)
904 {
905 int buffersize = 0;
906
907 char buf[BUFSIZE];
908 char *doc = NULL;
909
910 xmlChar *xmlbuff = NULL;
911 xmlDocPtr request = NULL;
912
913 xmlNodePtr ptrFindService = NULL;
914 xmlNodePtr ptrLocation = NULL;
915 xmlNodePtr ptrPoint = NULL;
916 xmlNodePtr ptrCircle = NULL;
917 xmlNodePtr ptrRadius = NULL;
918 xmlNodePtr ptrNode = NULL;
919
920 xmlKeepBlanksDefault(1);
921
922 *lgth = 0;
923
924 /*
925 https://tools.ietf.org/html/rfc5222
926
927 <?xml version="1.0" encoding="UTF-8"?>
928 <findService
929 xmlns="urn:ietf:params:xml:ns:lost1"
930 xmlns:p2="http://www.opengis.net/gml"
931 serviceBoundary="value"
932 recursive="true">
933 <location id="6020688f1ce1896d" profile="geodetic-2d">
934 <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">
935 <p2:pos>37.775 -122.422</p2:pos>
936 </p2:Point>
937 </location>
938 <service>urn:service:sos.police</service>
939 </findService>
940 */
941 /* create request */
942 request = xmlNewDoc(BAD_CAST "1.0");
943 if(request == NULL) {
944 LM_ERR("findService request xmlNewDoc() failed\n");
945 return doc;
946 }
947 /* findService - element */
948 ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");
949 if(ptrFindService == NULL) {
950 LM_ERR("findService xmlNewNode() failed\n");
951 xmlFreeDoc(request);
952 return doc;
953 }
954 xmlDocSetRootElement(request, ptrFindService);
955 /* set properties */
956 xmlNewProp(ptrFindService, BAD_CAST "xmlns",
957 BAD_CAST "urn:ietf:params:xml:ns:lost1");
958 xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",
959 BAD_CAST "http://www.opengis.net/gml");
960 xmlNewProp(ptrFindService, BAD_CAST "serviceBoundary",
961 (loc->boundary == 1) ? BAD_CAST "value" : BAD_CAST "reference");
962 xmlNewProp(ptrFindService, BAD_CAST "recursive",
963 (loc->recursive == 1) ? BAD_CAST "true" : BAD_CAST "false");
964 /* location - element */
965 ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);
966 xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);
967 xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST loc->profile);
968 /* set pos */
969 snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);
970 /* xpath result */
971 if(loc->xpath != NULL) {
972 xmlParseInNodeContext(
973 ptrLocation, loc->xpath, strlen(loc->xpath), 0, &ptrNode);
974 if(ptrNode == NULL) {
975 LM_ERR("locationRequest xmlParseInNodeContext() failed\n");
976 xmlFreeDoc(request);
977 return doc;
978 } else {
979 xmlAddChild(ptrLocation, ptrNode);
980 }
981 }
982 /* Point */
983 else if(loc->radius == 0) {
984 ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);
985 if(ptrPoint == NULL) {
986 LM_ERR("locationRequest xmlNewChild() failed\n");
987 xmlFreeDoc(request);
988 return doc;
989 }
990 xmlNewProp(ptrPoint, BAD_CAST "xmlns",
991 BAD_CAST "http://www.opengis.net/gml");
992 xmlNewProp(ptrPoint, BAD_CAST "srsName",
993 BAD_CAST "urn:ogc:def:crs:EPSG::4326");
994 /* pos */
995 xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);
996 }
997 /* circle - Point */
998 else {
999 ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);
1000 if(ptrCircle == NULL) {
1001 LM_ERR("locationRequest xmlNewChild() failed\n");
1002 xmlFreeDoc(request);
1003 return doc;
1004 }
1005 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",
1006 BAD_CAST "http://www.opengis.net/gml");
1007 xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",
1008 BAD_CAST "http://www.opengis.net/pidflo/1.0");
1009 xmlNewProp(ptrCircle, BAD_CAST "srsName",
1010 BAD_CAST "urn:ogc:def:crs:EPSG::4326");
1011 /* pos */
1012 xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);
1013 /* circle - radius */
1014 snprintf(buf, BUFSIZE, "%d", loc->radius);
1015 ptrRadius = xmlNewChild(
1016 ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);
1017 if(ptrRadius == NULL) {
1018 LM_ERR("locationRequest xmlNewChild() failed\n");
1019 xmlFreeDoc(request);
1020 return doc;
1021 }
1022 xmlNewProp(ptrRadius, BAD_CAST "uom",
1023 BAD_CAST "urn:ogc:def:uom:EPSG::9001");
1024 }
1025 /* service - element */
1026 snprintf(buf, BUFSIZE, "%s", loc->urn);
1027 xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);
1028
1029 xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
1030 if(xmlbuff == NULL) {
1031 LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");
1032 xmlFreeDoc(request);
1033 return doc;
1034 }
1035
1036 doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
1037 if(doc == NULL) {
1038 LM_ERR("no more private memory\n");
1039 xmlFree(xmlbuff);
1040 xmlFreeDoc(request);
1041 return doc;
1042 }
1043
1044 memset(doc, 0, buffersize + 1);
1045 memcpy(doc, (char *)xmlbuff, buffersize);
1046 doc[buffersize] = '\0';
1047
1048 *lgth = strlen(doc);
1049
1050 xmlFree(xmlbuff);
1051 xmlFreeDoc(request);
1052
1053 return doc;
1054 }
1055