소스 검색

lost: end of line normalization to linux line ending format

Henning Westerholt 6 년 전
부모
커밋
73207ad103
7개의 변경된 파일1961개의 추가작업 그리고 1961개의 파일을 삭제
  1. 611 611
      src/modules/lost/functions.c
  2. 40 40
      src/modules/lost/functions.h
  3. 339 339
      src/modules/lost/lost.c
  4. 137 137
      src/modules/lost/pidf.c
  5. 50 50
      src/modules/lost/pidf.h
  6. 708 708
      src/modules/lost/utilities.c
  7. 76 76
      src/modules/lost/utilities.h

+ 611 - 611
src/modules/lost/functions.c

@@ -1,611 +1,611 @@
-/*
- * lost module functions
- *
- * Copyright (C) 2019 Wolfgang Kampichler
- * DEC112, FREQUENTIS AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*!
- * \file
- * \brief Kamailio lost :: functions
- * \ingroup lost
- * Module: \ref lost
- */
-/*****************/
-
-#include "../../modules/http_client/curl_api.h"
-
-#include "../../core/mod_fix.h"
-#include "../../core/pvar.h"
-#include "../../core/route_struct.h"
-#include "../../core/ut.h"
-#include "../../core/trim.h"
-#include "../../core/mem/mem.h"
-#include "../../core/parser/msg_parser.h"
-#include "../../core/parser/parse_body.h"
-#include "../../core/lvalue.h"
-
-#include "pidf.h"
-#include "utilities.h"
-
-#define LOST_SUCCESS 200
-#define LOST_CLIENT_ERROR 400
-#define LOST_SERVER_ERROR 500
-
-extern httpc_api_t httpapi;
-
-char mtheld[] = "application/held+xml;charset=utf-8";
-char mtlost[] = "application/lost+xml;charset=utf-8";
-
-char uri_element[] = "uri";
-char name_element[] = "displayName";
-char errors_element[] = "errors";
-
-/*
- * lost_function_held(msg, con, pidf, url, err, id)
- * assembles and runs HELD locationRequest, parses results
- */
-int lost_function_held(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
-		char *_err, char *_id)
-{
-	pv_spec_t *pspidf;
-	pv_spec_t *psurl;
-	pv_spec_t *pserr;
-
-	pv_value_t pvpidf;
-	pv_value_t pvurl;
-	pv_value_t pverr;
-
-	xmlDocPtr doc = NULL;
-	xmlNodePtr root = NULL;
-
-	str did = {NULL, 0};
-	str que = {NULL, 0};
-	str con = {NULL, 0};
-	str geo = {NULL, 0};
-	str err = {NULL, 0};
-	str res = {NULL, 0};
-	str idhdr = {NULL, 0};
-
-	int curlres = 0;
-
-	if(_con == NULL || _pidf == NULL || _url == NULL || _err == NULL) {
-		LM_ERR("invalid parameter\n");
-		goto err;
-	}
-	/* connection from parameter */
-	if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) {
-		LM_ERR("cannot get connection string\n");
-		goto err;
-	}
-	/* id from parameter */
-	if(_id) {
-		if(fixup_get_svalue(_m, (gparam_p)_id, &did) != 0) {
-			LM_ERR("cannot get device id\n");
-			goto err;
-		}
-		if(!did.s) {
-			LM_ERR("no device found\n");
-			goto err;
-		}
-	} else {
-
-		LM_DBG("parsing P-A-I header\n");
-
-		/* id from P-A-I header */
-		idhdr.s = lost_get_pai_header(_m, &idhdr.len);
-		if(idhdr.len == 0) {
-			LM_WARN("P-A-I header not found, trying From header ...\n");
-
-			LM_DBG("parsing From header\n");
-			
-			/* id from From header */
-			idhdr.s = lost_get_from_header(_m, &idhdr.len);
-			if(idhdr.len == 0) {
-				LM_ERR("no device id found\n");
-				goto err;
-			}
-		}
-		did.s = idhdr.s;
-		did.len = idhdr.len;
-	}
-	LM_INFO("### HELD id [%.*s]\n", did.len, did.s);
-
-	/* check if connection exists */
-	if(httpapi.http_connection_exists(&con) == 0) {
-		LM_ERR("connection: [%s] does not exist\n", con.s);
-		goto err;
-	}
-
-	/* assemble locationRequest */
-	que.s = lost_held_location_request(did.s, &que.len);
-	/* free memory */
-	lost_free_string(&idhdr);
-	did.s = NULL;
-	did.len = 0;
-	if(!que.s) {
-		LM_ERR("held request document error\n");
-		goto err;
-	}
-
-	LM_DBG("held location request: [%s]\n", que.s);
-
-	/* send locationRequest to location server - HTTP POST */
-	curlres = httpapi.http_connect(_m, &con, NULL, &res, mtheld, &que);
-	/* only HTTP 2xx responses are accepted */ 
-	if(curlres >= 300 || curlres < 100) {
-		LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres);
-		res.s = NULL;
-		res.len = 0;
-		goto err;
-	}
-
-	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres);
-
-	/* free memory */
-	lost_free_string(&que);
-	/* read and parse the returned xml */
-	doc = xmlReadMemory(res.s, res.len, 0, NULL,
-			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
-	if(!doc) {
-		LM_WARN("invalid xml document: [%.*s]\n", res.len, res.s);
-		doc = xmlRecoverMemory(res.s, res.len);
-		if(!doc) {
-			LM_ERR("xml document recovery failed on: [%.*s]\n", res.len,
-					res.s);
-			goto err;
-		}
-
-		LM_DBG("xml document recovered\n");
-	}
-	root = xmlDocGetRootElement(doc);
-	if(!root) {
-		LM_ERR("empty xml document\n");
-		goto err;
-	}
-	/* check the root element, shall be locationResponse, or errors */
-	if(!xmlStrcmp(root->name, (const xmlChar *)"locationResponse")) {
-
-		LM_DBG("HELD location response [%.*s]\n", res.len, res.s);
-
-		/* get the locationUri element */
-		geo.s = lost_get_content(root, (char *)"locationURI", &geo.len);
-		if(!geo.s) {
-			LM_ERR("no locationURI element found\n");
-			goto err;
-		}
-	} else if(!xmlStrcmp(root->name, (const xmlChar *)"error")) {
-
-		LM_DBG("HELD error response [%.*s]\n", res.len, res.s);
-
-		/* get the error patterm */
-		err.s = lost_get_property(root, (char *)"code", &err.len);
-		if(!err.s) {
-			LM_ERR("error - code property not found: [%.*s]\n", res.len,
-					res.s);
-			goto err;
-		}
-		LM_WARN("locationRequest error response: [%.*s]\n", err.len, err.s);
-	} else {
-		LM_ERR("root element is not valid: [%.*s]\n", res.len, res.s);
-		goto err;
-	}
-	xmlFreeDoc(doc);
-
-	/* set writeable pvars */
-	pvpidf.rs = res;
-	pvpidf.rs.s = res.s;
-	pvpidf.rs.len = res.len;
-
-	pvpidf.flags = PV_VAL_STR;
-	pspidf = (pv_spec_t *)_pidf;
-	pspidf->setf(_m, &pspidf->pvp, (int)EQ_T, &pvpidf);
-
-	pvurl.rs = geo;
-	pvurl.rs.s = geo.s;
-	pvurl.rs.len = geo.len;
-
-	pvurl.flags = PV_VAL_STR;
-	psurl = (pv_spec_t *)_url;
-	psurl->setf(_m, &psurl->pvp, (int)EQ_T, &pvurl);
-
-	pverr.rs = err;
-	pverr.rs.s = err.s;
-	pverr.rs.len = err.len;
-
-	pverr.flags = PV_VAL_STR;
-	pserr = (pv_spec_t *)_err;
-	pserr->setf(_m, &pserr->pvp, (int)EQ_T, &pverr);
-
-	return (err.len > 0) ? LOST_SERVER_ERROR : LOST_SUCCESS;
-
-err:
-	if(doc)
-		xmlFreeDoc(doc);
-	
-	lost_free_string(&idhdr);
-	lost_free_string(&que);
-
-	return LOST_CLIENT_ERROR;
-}
-
-/*
- * lost_function(msg, con, pidf, uri, name, err, pidf, urn)
- * assembles and runs LOST findService request, parses results
- */
-int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
-		char *_err, char *_pidf, char *_urn)
-{
-	pv_spec_t *psname;
-	pv_spec_t *psuri;
-	pv_spec_t *pserr;
-
-	pv_value_t pvname;
-	pv_value_t pvuri;
-	pv_value_t pverr;
-
-	p_loc_t loc = NULL;
-
-	xmlDocPtr doc = NULL;
-	xmlNodePtr root = NULL;
-
-	str uri = {NULL, 0};
-	str urn = {NULL, 0};
-	str err = {NULL, 0};
-	str res = {NULL, 0};
-	str con = {NULL, 0};
-	str ret = {NULL, 0};
-	str geo = {NULL, 0};
-	str geohdr = {NULL, 0};
-	str name = {NULL, 0};
-	str pidf = {NULL, 0};
-	str pidfhdr = {NULL, 0};
-
-	struct msg_start *fl;
-	char *search = NULL;
-	int curlres = 0;
-	
-	if(_con == NULL || _uri == NULL || _name == NULL || _err == NULL) {
-		LM_ERR("invalid parameter\n");
-		goto err;
-	}
-	if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) {
-		LM_ERR("cannot get connection string\n");
-		goto err;
-	}
-	/* urn from parameter */
-	if(_urn) {
-		if(fixup_get_svalue(_m, (gparam_p)_urn, &urn) != 0) {
-			LM_ERR("cannot get service urn\n");
-			goto err;
-		}
-	}
-	/* urn from request line */
-	if(urn.len == 0) {
-		LM_WARN("no sevice urn parameter, trying request line ...\n");
-		fl = &(_m->first_line);
-		urn.len = fl->u.request.uri.len;
-		urn.s = fl->u.request.uri.s;
-	}
-	/* check urn scheme */
-	if(urn.len > 3) {
-		search = urn.s;
-		if(((*(search + 0) == 'u') || (*(search + 0) == 'U'))
-				&& ((*(search + 1) == 'r') || (*(search + 1) == 'R'))
-				&& ((*(search + 2) == 'n') || (*(search + 2) == 'N'))
-				&& (*(search + 3) == ':')) {
-			LM_INFO("### LOST urn [%.*s]\n", urn.len, urn.s);
-		} else {
-			LM_ERR("service urn not found\n");
-			goto err;
-		}
-	} else {
-		LM_ERR("service urn not found\n");
-		goto err;
-	}
-	/* pidf from parameter */
-	if(_pidf) {
-		if(fixup_get_svalue(_m, (gparam_p)_pidf, &pidf) != 0) {
-			LM_ERR("cannot get pidf-lo\n");
-			goto err;
-		}
-	}
-	/* pidf from geolocation header */
-	if(pidf.len == 0) {
-		LM_WARN("no pidf parameter, trying geolocation header ...\n");
-		geohdr.s = lost_get_geolocation_header(_m, &geohdr.len);
-		if(!geohdr.s) {
-			LM_ERR("geolocation header not found\n");
-			goto err;
-		} else {
-
-			LM_DBG("geolocation header found\n");
-
-			/* pidf from multipart body, check cid scheme */
-			if(geohdr.len > 6) {
-				search = geohdr.s;
-				if((*(search + 0) == '<')
-						&& ((*(search + 1) == 'c') || (*(search + 1) == 'C'))
-						&& ((*(search + 2) == 'i') || (*(search + 2) == 'I'))
-						&& ((*(search + 3) == 'd') || (*(search + 3) == 'D'))
-						&& (*(search + 4) == ':')) {
-					search += 4;
-					*search = '<';
-					geo.s = search;
-					geo.len = geo.len - 4;
-
-					LM_DBG("cid: [%.*s]\n", geo.len, geo.s);
-
-					/* get body part - filter=>content id */
-					pidf.s = get_body_part_by_filter(
-							_m, 0, 0, geo.s, NULL, &pidf.len);
-					if(!pidf.s) {
-						LM_ERR("no multipart body found\n");
-						goto err;
-					}
-				}
-				/* no pidf-lo so far ... check http(s) scheme */
-				if(((*(search + 0) == 'h') || (*(search + 0) == 'H'))
-						&& ((*(search + 1) == 't') || (*(search + 1) == 'T'))
-						&& ((*(search + 2) == 't') || (*(search + 2) == 'T'))
-						&& ((*(search + 3) == 'p') || (*(search + 3) == 'P'))) {
-					geo.s = geohdr.s;
-					geo.len = geohdr.len;
-
-					if(*(search + 4) == ':') {
-					
-						LM_DBG("http url: [%.*s]\n", geo.len, geo.s);
-					
-					} else if(((*(search + 4) == 's') || (*(search + 4) == 'S'))
-							&& (*(search + 5) == ':')) {
-					
-						LM_DBG("https url: [%.*s]\n", geo.len, geo.s);
-					
-					} else {
-						LM_ERR("invalid url: [%.*s]\n", geo.len, geo.s);
-						goto err;
-					}
-
-					/* ! dereference pidf.lo at location server - HTTP GET */
-					/* ! requires hack in http_client module */
-					/* ! functions.c => http_client_query => query_params.oneline = 0; */
-					curlres = httpapi.http_client_query(_m, geo.s, &pidfhdr, NULL, NULL);
-					/* free memory */
-					lost_free_string(&geohdr);
-					geo.s = NULL;
-					geo.len = 0;
-					/* only HTTP 2xx responses are accepted */ 
-					if(curlres >= 300 || curlres < 100) {
-						LM_ERR("http GET failed with error: %d\n", curlres);
-						pidfhdr.s = NULL;
-						pidfhdr.len = 0;
-						goto err;
-					}
-
-					LM_DBG("http GET returned: %d\n", curlres);
-
-					if(!pidfhdr.s) {
-						LM_ERR("dereferencing location failed\n");
-						goto err;
-					}
-					pidf.s = pidfhdr.s;
-					pidf.len = pidfhdr.len;
-				}
-			} else {
-				LM_ERR("invalid geolocation header\n");
-				goto err;
-			}
-		}
-	}
-
-	/* no pidf-lo return error */
-	if(!pidf.s) {
-		LM_ERR("pidf-lo not found\n");
-		goto err;
-	}
-
-	LM_DBG("pidf-lo: [%.*s]\n", pidf.len, pidf.s);
-
-	/* read and parse pidf-lo */
-	doc = xmlReadMemory(pidf.s, pidf.len, 0, NULL,
-			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
-
-	if(!doc) {
-		LM_WARN("invalid xml (pidf-lo): [%.*s]\n", pidf.len, pidf.s);
-		doc = xmlRecoverMemory(pidf.s, pidf.len);
-		if(!doc) {
-			LM_ERR("xml (pidf-lo) recovery failed on: [%.*s]\n", pidf.len,
-					pidf.s);
-			goto err;
-		}
-
-		LM_DBG("xml (pidf-lo) recovered\n");
-	}
-
-	root = xmlDocGetRootElement(doc);
-	if(!root) {
-		LM_ERR("empty pidf-lo document\n");
-		goto err;
-	}
-	if((!xmlStrcmp(root->name, (const xmlChar *)"presence"))
-			|| (!xmlStrcmp(root->name, (const xmlChar *)"locationResponse"))) {
-		/* get the geolocation: point or circle, urn, ... */
-		loc = lost_new_loc(urn);
-		if(!loc) {
-			LM_ERR("location object allocation failed\n");
-			goto err;			
-		}
-		if(lost_parse_location_info(root, loc) < 0) {
-			LM_ERR("location element not found\n");
-			goto err;
-		}
-	} else {
-		LM_ERR("findServiceResponse or presence element not found in "
-			   "[%.*s]\n",
-				pidf.len, pidf.s);
-		goto err;
-	}
-
-	/* free memory */
-	lost_free_string(&pidfhdr);
-	pidf.s = NULL;
-	pidf.len = 0;
-
-	/* check if connection exits */
-	if(httpapi.http_connection_exists(&con) == 0) {
-		LM_ERR("connection: [%.*s] does not exist\n", con.len, con.s);
-		goto err;
-	}
-	/* assemble findService request */
-	res.s = lost_find_service_request(loc, &res.len);
-	/* free memory */
-	if(loc) {
-		lost_free_loc(loc);
-		loc = NULL;
-	}
-	xmlFreeDoc(doc);
-	doc = NULL;
-
-	if(!res.s) {
-		LM_ERR("lost request failed\n");
-		goto err;
-	}
-
-	LM_DBG("findService request: [%.*s]\n", res.len, res.s);
-
-	/* send findService request to mapping server - HTTP POST */
-	curlres = httpapi.http_connect(_m, &con, NULL, &ret, mtlost, &res);
-	/* only HTTP 2xx responses are accepted */ 
-	if(curlres >= 300 || curlres < 100) {
-		LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres);
-		ret.s = NULL;
-		ret.len = 0;
-		goto err;
-	}
-
-	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres);
-
-	/* free memory */
-	lost_free_string(&res);
-
-	if(!ret.s) {
-		LM_ERR("findService request failed\n");
-		goto err;
-	}
-
-	LM_DBG("findService response: [%.*s]\n", ret.len, ret.s);
-
-	/* read and parse the returned xml */
-	doc = xmlReadMemory(ret.s, ret.len, 0, 0,
-			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
-
-	if(!doc) {
-		LM_ERR("invalid xml document: [%.*s]\n", ret.len, ret.s);
-		doc = xmlRecoverMemory(ret.s, ret.len);
-		if(!doc) {
-			LM_ERR("xml document recovery failed on: [%.*s]\n", ret.len,
-					ret.s);
-			goto err;
-		}
-
-		LM_DBG("xml document recovered\n");
-	}
-	root = xmlDocGetRootElement(doc);
-	if(!root) {
-		LM_ERR("empty xml document: [%.*s]\n", ret.len, ret.s);
-		goto err;
-	}
-	/* check the root element, shall be findServiceResponse, or errors */
-	if((!xmlStrcmp(root->name, (const xmlChar *)"findServiceResponse"))) {
-		/* get the uri element */
-		uri.s = lost_get_content(root, uri_element, &uri.len);
-		if(!uri.s) {
-			LM_ERR("uri element not found: [%.*s]\n", ret.len, ret.s);
-			goto err;
-		}
-		LM_INFO("### LOST uri [%.*s]\n", uri.len, uri.s);
-		/* get the displayName element */
-		name.s = lost_get_content(root, name_element, &name.len);
-		if(!name.s) {
-			LM_ERR("displayName element not found: [%.*s]\n", ret.len, ret.s);
-			goto err;
-		}
-		LM_INFO("### LOST name [%.*s]\n", name.len, name.s);
-	} else if((!xmlStrcmp(root->name, (const xmlChar *)"errors"))) {
-
-		LM_DBG("findService error response received\n");
-
-		/* get the error patterm */
-		err.s = lost_get_childname(root, errors_element, &err.len);
-		if(!err.s) {
-			LM_ERR("error pattern element not found: [%.*s]\n", ret.len,
-					ret.s);
-			goto err;
-		}
-		LM_WARN("findService error response: [%.*s]\n", err.len, err.s);
-	} else {
-		LM_ERR("root element is not valid: [%.*s]\n", ret.len, ret.s);
-		goto err;
-	}
-
-	/* free memory */
-	xmlFreeDoc(doc);
-	doc = NULL;
-	lost_free_string(&ret);
-
-	/* set writable pvars */
-	pvname.rs = name;
-	pvname.rs.s = name.s;
-	pvname.rs.len = name.len;
-
-	pvname.flags = PV_VAL_STR;
-	psname = (pv_spec_t *)_name;
-	psname->setf(_m, &psname->pvp, (int)EQ_T, &pvname);
-
-	pvuri.rs = uri;
-	pvuri.rs.s = uri.s;
-	pvuri.rs.len = uri.len;
-
-	pvuri.flags = PV_VAL_STR;
-	psuri = (pv_spec_t *)_uri;
-	psuri->setf(_m, &psuri->pvp, (int)EQ_T, &pvuri);
-
-	pverr.rs = err;
-	pverr.rs.s = err.s;
-	pverr.rs.len = err.len;
-
-	pverr.flags = PV_VAL_STR;
-	pserr = (pv_spec_t *)_err;
-	pserr->setf(_m, &pserr->pvp, (int)EQ_T, &pverr);
-
-	return (err.len > 0) ? LOST_SERVER_ERROR : LOST_SUCCESS;
-
-err:
-	if(loc)
-		lost_free_loc(loc);
-	if(doc)
-		xmlFreeDoc(doc);
-
-	lost_free_string(&pidfhdr);
-	lost_free_string(&geohdr);
-	lost_free_string(&ret);
-
-	return LOST_CLIENT_ERROR;
-}
+/*
+ * lost module functions
+ *
+ * Copyright (C) 2019 Wolfgang Kampichler
+ * DEC112, FREQUENTIS AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Kamailio lost :: functions
+ * \ingroup lost
+ * Module: \ref lost
+ */
+/*****************/
+
+#include "../../modules/http_client/curl_api.h"
+
+#include "../../core/mod_fix.h"
+#include "../../core/pvar.h"
+#include "../../core/route_struct.h"
+#include "../../core/ut.h"
+#include "../../core/trim.h"
+#include "../../core/mem/mem.h"
+#include "../../core/parser/msg_parser.h"
+#include "../../core/parser/parse_body.h"
+#include "../../core/lvalue.h"
+
+#include "pidf.h"
+#include "utilities.h"
+
+#define LOST_SUCCESS 200
+#define LOST_CLIENT_ERROR 400
+#define LOST_SERVER_ERROR 500
+
+extern httpc_api_t httpapi;
+
+char mtheld[] = "application/held+xml;charset=utf-8";
+char mtlost[] = "application/lost+xml;charset=utf-8";
+
+char uri_element[] = "uri";
+char name_element[] = "displayName";
+char errors_element[] = "errors";
+
+/*
+ * lost_function_held(msg, con, pidf, url, err, id)
+ * assembles and runs HELD locationRequest, parses results
+ */
+int lost_function_held(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
+		char *_err, char *_id)
+{
+	pv_spec_t *pspidf;
+	pv_spec_t *psurl;
+	pv_spec_t *pserr;
+
+	pv_value_t pvpidf;
+	pv_value_t pvurl;
+	pv_value_t pverr;
+
+	xmlDocPtr doc = NULL;
+	xmlNodePtr root = NULL;
+
+	str did = {NULL, 0};
+	str que = {NULL, 0};
+	str con = {NULL, 0};
+	str geo = {NULL, 0};
+	str err = {NULL, 0};
+	str res = {NULL, 0};
+	str idhdr = {NULL, 0};
+
+	int curlres = 0;
+
+	if(_con == NULL || _pidf == NULL || _url == NULL || _err == NULL) {
+		LM_ERR("invalid parameter\n");
+		goto err;
+	}
+	/* connection from parameter */
+	if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) {
+		LM_ERR("cannot get connection string\n");
+		goto err;
+	}
+	/* id from parameter */
+	if(_id) {
+		if(fixup_get_svalue(_m, (gparam_p)_id, &did) != 0) {
+			LM_ERR("cannot get device id\n");
+			goto err;
+		}
+		if(!did.s) {
+			LM_ERR("no device found\n");
+			goto err;
+		}
+	} else {
+
+		LM_DBG("parsing P-A-I header\n");
+
+		/* id from P-A-I header */
+		idhdr.s = lost_get_pai_header(_m, &idhdr.len);
+		if(idhdr.len == 0) {
+			LM_WARN("P-A-I header not found, trying From header ...\n");
+
+			LM_DBG("parsing From header\n");
+			
+			/* id from From header */
+			idhdr.s = lost_get_from_header(_m, &idhdr.len);
+			if(idhdr.len == 0) {
+				LM_ERR("no device id found\n");
+				goto err;
+			}
+		}
+		did.s = idhdr.s;
+		did.len = idhdr.len;
+	}
+	LM_INFO("### HELD id [%.*s]\n", did.len, did.s);
+
+	/* check if connection exists */
+	if(httpapi.http_connection_exists(&con) == 0) {
+		LM_ERR("connection: [%s] does not exist\n", con.s);
+		goto err;
+	}
+
+	/* assemble locationRequest */
+	que.s = lost_held_location_request(did.s, &que.len);
+	/* free memory */
+	lost_free_string(&idhdr);
+	did.s = NULL;
+	did.len = 0;
+	if(!que.s) {
+		LM_ERR("held request document error\n");
+		goto err;
+	}
+
+	LM_DBG("held location request: [%s]\n", que.s);
+
+	/* send locationRequest to location server - HTTP POST */
+	curlres = httpapi.http_connect(_m, &con, NULL, &res, mtheld, &que);
+	/* only HTTP 2xx responses are accepted */ 
+	if(curlres >= 300 || curlres < 100) {
+		LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres);
+		res.s = NULL;
+		res.len = 0;
+		goto err;
+	}
+
+	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres);
+
+	/* free memory */
+	lost_free_string(&que);
+	/* read and parse the returned xml */
+	doc = xmlReadMemory(res.s, res.len, 0, NULL,
+			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
+	if(!doc) {
+		LM_WARN("invalid xml document: [%.*s]\n", res.len, res.s);
+		doc = xmlRecoverMemory(res.s, res.len);
+		if(!doc) {
+			LM_ERR("xml document recovery failed on: [%.*s]\n", res.len,
+					res.s);
+			goto err;
+		}
+
+		LM_DBG("xml document recovered\n");
+	}
+	root = xmlDocGetRootElement(doc);
+	if(!root) {
+		LM_ERR("empty xml document\n");
+		goto err;
+	}
+	/* check the root element, shall be locationResponse, or errors */
+	if(!xmlStrcmp(root->name, (const xmlChar *)"locationResponse")) {
+
+		LM_DBG("HELD location response [%.*s]\n", res.len, res.s);
+
+		/* get the locationUri element */
+		geo.s = lost_get_content(root, (char *)"locationURI", &geo.len);
+		if(!geo.s) {
+			LM_ERR("no locationURI element found\n");
+			goto err;
+		}
+	} else if(!xmlStrcmp(root->name, (const xmlChar *)"error")) {
+
+		LM_DBG("HELD error response [%.*s]\n", res.len, res.s);
+
+		/* get the error patterm */
+		err.s = lost_get_property(root, (char *)"code", &err.len);
+		if(!err.s) {
+			LM_ERR("error - code property not found: [%.*s]\n", res.len,
+					res.s);
+			goto err;
+		}
+		LM_WARN("locationRequest error response: [%.*s]\n", err.len, err.s);
+	} else {
+		LM_ERR("root element is not valid: [%.*s]\n", res.len, res.s);
+		goto err;
+	}
+	xmlFreeDoc(doc);
+
+	/* set writeable pvars */
+	pvpidf.rs = res;
+	pvpidf.rs.s = res.s;
+	pvpidf.rs.len = res.len;
+
+	pvpidf.flags = PV_VAL_STR;
+	pspidf = (pv_spec_t *)_pidf;
+	pspidf->setf(_m, &pspidf->pvp, (int)EQ_T, &pvpidf);
+
+	pvurl.rs = geo;
+	pvurl.rs.s = geo.s;
+	pvurl.rs.len = geo.len;
+
+	pvurl.flags = PV_VAL_STR;
+	psurl = (pv_spec_t *)_url;
+	psurl->setf(_m, &psurl->pvp, (int)EQ_T, &pvurl);
+
+	pverr.rs = err;
+	pverr.rs.s = err.s;
+	pverr.rs.len = err.len;
+
+	pverr.flags = PV_VAL_STR;
+	pserr = (pv_spec_t *)_err;
+	pserr->setf(_m, &pserr->pvp, (int)EQ_T, &pverr);
+
+	return (err.len > 0) ? LOST_SERVER_ERROR : LOST_SUCCESS;
+
+err:
+	if(doc)
+		xmlFreeDoc(doc);
+	
+	lost_free_string(&idhdr);
+	lost_free_string(&que);
+
+	return LOST_CLIENT_ERROR;
+}
+
+/*
+ * lost_function(msg, con, pidf, uri, name, err, pidf, urn)
+ * assembles and runs LOST findService request, parses results
+ */
+int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
+		char *_err, char *_pidf, char *_urn)
+{
+	pv_spec_t *psname;
+	pv_spec_t *psuri;
+	pv_spec_t *pserr;
+
+	pv_value_t pvname;
+	pv_value_t pvuri;
+	pv_value_t pverr;
+
+	p_loc_t loc = NULL;
+
+	xmlDocPtr doc = NULL;
+	xmlNodePtr root = NULL;
+
+	str uri = {NULL, 0};
+	str urn = {NULL, 0};
+	str err = {NULL, 0};
+	str res = {NULL, 0};
+	str con = {NULL, 0};
+	str ret = {NULL, 0};
+	str geo = {NULL, 0};
+	str geohdr = {NULL, 0};
+	str name = {NULL, 0};
+	str pidf = {NULL, 0};
+	str pidfhdr = {NULL, 0};
+
+	struct msg_start *fl;
+	char *search = NULL;
+	int curlres = 0;
+	
+	if(_con == NULL || _uri == NULL || _name == NULL || _err == NULL) {
+		LM_ERR("invalid parameter\n");
+		goto err;
+	}
+	if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) {
+		LM_ERR("cannot get connection string\n");
+		goto err;
+	}
+	/* urn from parameter */
+	if(_urn) {
+		if(fixup_get_svalue(_m, (gparam_p)_urn, &urn) != 0) {
+			LM_ERR("cannot get service urn\n");
+			goto err;
+		}
+	}
+	/* urn from request line */
+	if(urn.len == 0) {
+		LM_WARN("no sevice urn parameter, trying request line ...\n");
+		fl = &(_m->first_line);
+		urn.len = fl->u.request.uri.len;
+		urn.s = fl->u.request.uri.s;
+	}
+	/* check urn scheme */
+	if(urn.len > 3) {
+		search = urn.s;
+		if(((*(search + 0) == 'u') || (*(search + 0) == 'U'))
+				&& ((*(search + 1) == 'r') || (*(search + 1) == 'R'))
+				&& ((*(search + 2) == 'n') || (*(search + 2) == 'N'))
+				&& (*(search + 3) == ':')) {
+			LM_INFO("### LOST urn [%.*s]\n", urn.len, urn.s);
+		} else {
+			LM_ERR("service urn not found\n");
+			goto err;
+		}
+	} else {
+		LM_ERR("service urn not found\n");
+		goto err;
+	}
+	/* pidf from parameter */
+	if(_pidf) {
+		if(fixup_get_svalue(_m, (gparam_p)_pidf, &pidf) != 0) {
+			LM_ERR("cannot get pidf-lo\n");
+			goto err;
+		}
+	}
+	/* pidf from geolocation header */
+	if(pidf.len == 0) {
+		LM_WARN("no pidf parameter, trying geolocation header ...\n");
+		geohdr.s = lost_get_geolocation_header(_m, &geohdr.len);
+		if(!geohdr.s) {
+			LM_ERR("geolocation header not found\n");
+			goto err;
+		} else {
+
+			LM_DBG("geolocation header found\n");
+
+			/* pidf from multipart body, check cid scheme */
+			if(geohdr.len > 6) {
+				search = geohdr.s;
+				if((*(search + 0) == '<')
+						&& ((*(search + 1) == 'c') || (*(search + 1) == 'C'))
+						&& ((*(search + 2) == 'i') || (*(search + 2) == 'I'))
+						&& ((*(search + 3) == 'd') || (*(search + 3) == 'D'))
+						&& (*(search + 4) == ':')) {
+					search += 4;
+					*search = '<';
+					geo.s = search;
+					geo.len = geo.len - 4;
+
+					LM_DBG("cid: [%.*s]\n", geo.len, geo.s);
+
+					/* get body part - filter=>content id */
+					pidf.s = get_body_part_by_filter(
+							_m, 0, 0, geo.s, NULL, &pidf.len);
+					if(!pidf.s) {
+						LM_ERR("no multipart body found\n");
+						goto err;
+					}
+				}
+				/* no pidf-lo so far ... check http(s) scheme */
+				if(((*(search + 0) == 'h') || (*(search + 0) == 'H'))
+						&& ((*(search + 1) == 't') || (*(search + 1) == 'T'))
+						&& ((*(search + 2) == 't') || (*(search + 2) == 'T'))
+						&& ((*(search + 3) == 'p') || (*(search + 3) == 'P'))) {
+					geo.s = geohdr.s;
+					geo.len = geohdr.len;
+
+					if(*(search + 4) == ':') {
+					
+						LM_DBG("http url: [%.*s]\n", geo.len, geo.s);
+					
+					} else if(((*(search + 4) == 's') || (*(search + 4) == 'S'))
+							&& (*(search + 5) == ':')) {
+					
+						LM_DBG("https url: [%.*s]\n", geo.len, geo.s);
+					
+					} else {
+						LM_ERR("invalid url: [%.*s]\n", geo.len, geo.s);
+						goto err;
+					}
+
+					/* ! dereference pidf.lo at location server - HTTP GET */
+					/* ! requires hack in http_client module */
+					/* ! functions.c => http_client_query => query_params.oneline = 0; */
+					curlres = httpapi.http_client_query(_m, geo.s, &pidfhdr, NULL, NULL);
+					/* free memory */
+					lost_free_string(&geohdr);
+					geo.s = NULL;
+					geo.len = 0;
+					/* only HTTP 2xx responses are accepted */ 
+					if(curlres >= 300 || curlres < 100) {
+						LM_ERR("http GET failed with error: %d\n", curlres);
+						pidfhdr.s = NULL;
+						pidfhdr.len = 0;
+						goto err;
+					}
+
+					LM_DBG("http GET returned: %d\n", curlres);
+
+					if(!pidfhdr.s) {
+						LM_ERR("dereferencing location failed\n");
+						goto err;
+					}
+					pidf.s = pidfhdr.s;
+					pidf.len = pidfhdr.len;
+				}
+			} else {
+				LM_ERR("invalid geolocation header\n");
+				goto err;
+			}
+		}
+	}
+
+	/* no pidf-lo return error */
+	if(!pidf.s) {
+		LM_ERR("pidf-lo not found\n");
+		goto err;
+	}
+
+	LM_DBG("pidf-lo: [%.*s]\n", pidf.len, pidf.s);
+
+	/* read and parse pidf-lo */
+	doc = xmlReadMemory(pidf.s, pidf.len, 0, NULL,
+			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
+
+	if(!doc) {
+		LM_WARN("invalid xml (pidf-lo): [%.*s]\n", pidf.len, pidf.s);
+		doc = xmlRecoverMemory(pidf.s, pidf.len);
+		if(!doc) {
+			LM_ERR("xml (pidf-lo) recovery failed on: [%.*s]\n", pidf.len,
+					pidf.s);
+			goto err;
+		}
+
+		LM_DBG("xml (pidf-lo) recovered\n");
+	}
+
+	root = xmlDocGetRootElement(doc);
+	if(!root) {
+		LM_ERR("empty pidf-lo document\n");
+		goto err;
+	}
+	if((!xmlStrcmp(root->name, (const xmlChar *)"presence"))
+			|| (!xmlStrcmp(root->name, (const xmlChar *)"locationResponse"))) {
+		/* get the geolocation: point or circle, urn, ... */
+		loc = lost_new_loc(urn);
+		if(!loc) {
+			LM_ERR("location object allocation failed\n");
+			goto err;			
+		}
+		if(lost_parse_location_info(root, loc) < 0) {
+			LM_ERR("location element not found\n");
+			goto err;
+		}
+	} else {
+		LM_ERR("findServiceResponse or presence element not found in "
+			   "[%.*s]\n",
+				pidf.len, pidf.s);
+		goto err;
+	}
+
+	/* free memory */
+	lost_free_string(&pidfhdr);
+	pidf.s = NULL;
+	pidf.len = 0;
+
+	/* check if connection exits */
+	if(httpapi.http_connection_exists(&con) == 0) {
+		LM_ERR("connection: [%.*s] does not exist\n", con.len, con.s);
+		goto err;
+	}
+	/* assemble findService request */
+	res.s = lost_find_service_request(loc, &res.len);
+	/* free memory */
+	if(loc) {
+		lost_free_loc(loc);
+		loc = NULL;
+	}
+	xmlFreeDoc(doc);
+	doc = NULL;
+
+	if(!res.s) {
+		LM_ERR("lost request failed\n");
+		goto err;
+	}
+
+	LM_DBG("findService request: [%.*s]\n", res.len, res.s);
+
+	/* send findService request to mapping server - HTTP POST */
+	curlres = httpapi.http_connect(_m, &con, NULL, &ret, mtlost, &res);
+	/* only HTTP 2xx responses are accepted */ 
+	if(curlres >= 300 || curlres < 100) {
+		LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres);
+		ret.s = NULL;
+		ret.len = 0;
+		goto err;
+	}
+
+	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres);
+
+	/* free memory */
+	lost_free_string(&res);
+
+	if(!ret.s) {
+		LM_ERR("findService request failed\n");
+		goto err;
+	}
+
+	LM_DBG("findService response: [%.*s]\n", ret.len, ret.s);
+
+	/* read and parse the returned xml */
+	doc = xmlReadMemory(ret.s, ret.len, 0, 0,
+			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
+
+	if(!doc) {
+		LM_ERR("invalid xml document: [%.*s]\n", ret.len, ret.s);
+		doc = xmlRecoverMemory(ret.s, ret.len);
+		if(!doc) {
+			LM_ERR("xml document recovery failed on: [%.*s]\n", ret.len,
+					ret.s);
+			goto err;
+		}
+
+		LM_DBG("xml document recovered\n");
+	}
+	root = xmlDocGetRootElement(doc);
+	if(!root) {
+		LM_ERR("empty xml document: [%.*s]\n", ret.len, ret.s);
+		goto err;
+	}
+	/* check the root element, shall be findServiceResponse, or errors */
+	if((!xmlStrcmp(root->name, (const xmlChar *)"findServiceResponse"))) {
+		/* get the uri element */
+		uri.s = lost_get_content(root, uri_element, &uri.len);
+		if(!uri.s) {
+			LM_ERR("uri element not found: [%.*s]\n", ret.len, ret.s);
+			goto err;
+		}
+		LM_INFO("### LOST uri [%.*s]\n", uri.len, uri.s);
+		/* get the displayName element */
+		name.s = lost_get_content(root, name_element, &name.len);
+		if(!name.s) {
+			LM_ERR("displayName element not found: [%.*s]\n", ret.len, ret.s);
+			goto err;
+		}
+		LM_INFO("### LOST name [%.*s]\n", name.len, name.s);
+	} else if((!xmlStrcmp(root->name, (const xmlChar *)"errors"))) {
+
+		LM_DBG("findService error response received\n");
+
+		/* get the error patterm */
+		err.s = lost_get_childname(root, errors_element, &err.len);
+		if(!err.s) {
+			LM_ERR("error pattern element not found: [%.*s]\n", ret.len,
+					ret.s);
+			goto err;
+		}
+		LM_WARN("findService error response: [%.*s]\n", err.len, err.s);
+	} else {
+		LM_ERR("root element is not valid: [%.*s]\n", ret.len, ret.s);
+		goto err;
+	}
+
+	/* free memory */
+	xmlFreeDoc(doc);
+	doc = NULL;
+	lost_free_string(&ret);
+
+	/* set writable pvars */
+	pvname.rs = name;
+	pvname.rs.s = name.s;
+	pvname.rs.len = name.len;
+
+	pvname.flags = PV_VAL_STR;
+	psname = (pv_spec_t *)_name;
+	psname->setf(_m, &psname->pvp, (int)EQ_T, &pvname);
+
+	pvuri.rs = uri;
+	pvuri.rs.s = uri.s;
+	pvuri.rs.len = uri.len;
+
+	pvuri.flags = PV_VAL_STR;
+	psuri = (pv_spec_t *)_uri;
+	psuri->setf(_m, &psuri->pvp, (int)EQ_T, &pvuri);
+
+	pverr.rs = err;
+	pverr.rs.s = err.s;
+	pverr.rs.len = err.len;
+
+	pverr.flags = PV_VAL_STR;
+	pserr = (pv_spec_t *)_err;
+	pserr->setf(_m, &pserr->pvp, (int)EQ_T, &pverr);
+
+	return (err.len > 0) ? LOST_SERVER_ERROR : LOST_SUCCESS;
+
+err:
+	if(loc)
+		lost_free_loc(loc);
+	if(doc)
+		xmlFreeDoc(doc);
+
+	lost_free_string(&pidfhdr);
+	lost_free_string(&geohdr);
+	lost_free_string(&ret);
+
+	return LOST_CLIENT_ERROR;
+}

+ 40 - 40
src/modules/lost/functions.h

@@ -1,40 +1,40 @@
-/*
- * lost module functions
- *
- * Copyright (C) 2019 Wolfgang Kampichler
- * DEC112, FREQUENTIS AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*!
- * \file
- * \brief Kamailio lost :: functions
- * \ingroup lost
- * Module: \ref lost
- */
-
-#ifndef LOST_FUNCTIONS_H
-#define LOST_FUNCTIONS_H
-
-int lost_function_held(
-		struct sip_msg *, char *, char *, char *, char *, char *);
-int lost_function(
-		struct sip_msg *, char *, char *, char *, char *, char *, char *);
-
-#endif
+/*
+ * lost module functions
+ *
+ * Copyright (C) 2019 Wolfgang Kampichler
+ * DEC112, FREQUENTIS AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Kamailio lost :: functions
+ * \ingroup lost
+ * Module: \ref lost
+ */
+
+#ifndef LOST_FUNCTIONS_H
+#define LOST_FUNCTIONS_H
+
+int lost_function_held(
+		struct sip_msg *, char *, char *, char *, char *, char *);
+int lost_function(
+		struct sip_msg *, char *, char *, char *, char *, char *, char *);
+
+#endif

+ 339 - 339
src/modules/lost/lost.c

@@ -1,339 +1,339 @@
-/*
- * lost module
- *
- * Copyright (C) 2019 Wolfgang Kampichler
- * DEC112, FREQUENTIS AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*!
- * \file
- * \brief Kamailio lost ::
- * \ingroup lost
- * Module: \ref lost
- */
-
-#include "../../modules/http_client/curl_api.h"
-
-#include "../../core/mod_fix.h"
-#include "../../core/sr_module.h"
-#include "../../core/ut.h"
-#include "../../core/locking.h"
-
-#include "../../core/pvar.h"
-#include "../../core/mem/mem.h"
-#include "../../core/dprint.h"
-
-#include "../../core/script_cb.h"
-
-#include "functions.h"
-
-MODULE_VERSION
-
-/* Module parameter variables */
-httpc_api_t httpapi;
-
-/* Module management function prototypes */
-static int mod_init(void);
-static int child_init(int);
-static void destroy(void);
-
-/* Fixup functions to be defined later */
-static int fixup_lost_held_query(void **param, int param_no);
-static int fixup_free_lost_held_query(void **param, int param_no);
-static int fixup_lost_held_query_id(void **param, int param_no);
-static int fixup_free_lost_held_query_id(void **param, int param_no);
-
-static int fixup_lost_query(void **param, int param_no);
-static int fixup_free_lost_query(void **param, int param_no);
-static int fixup_lost_query_all(void **param, int param_no);
-static int fixup_free_lost_query_all(void **param, int param_no);
-
-/* Wrappers for http_query to be defined later */
-static int w_lost_held_query(
-		struct sip_msg *_m, char *_con, char *_pidf, char *_url, char *_err);
-static int w_lost_held_query_id(struct sip_msg *_m, char *_con, char *_id,
-		char *_pidf, char *_url, char *_err);
-static int w_lost_query(
-		struct sip_msg *_m, char *_con, char *_uri, char *_name, char *_err);
-static int w_lost_query_all(struct sip_msg *_m, char *_con, char *_pidf,
-		char *_urn, char *_uri, char *_name, char *_err);
-
-/* Exported functions */
-static cmd_export_t cmds[] = {
-		{"lost_held_query", (cmd_function)w_lost_held_query, 4,
-				fixup_lost_held_query, fixup_free_lost_held_query,
-				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
-		{"lost_held_query", (cmd_function)w_lost_held_query_id, 5,
-				fixup_lost_held_query_id, fixup_free_lost_held_query_id,
-				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
-		{"lost_query", (cmd_function)w_lost_query, 4, fixup_lost_query,
-				fixup_free_lost_query,
-				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
-		{"lost_query", (cmd_function)w_lost_query_all, 6, fixup_lost_query_all,
-				fixup_free_lost_query_all,
-				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
-		{0, 0, 0, 0, 0, 0}};
-
-
-/* Module interface */
-struct module_exports exports = {
-		"lost",			 /* module name*/
-		DEFAULT_DLFLAGS, /* dlopen flags */
-		cmds,			 /* exported functions */
-		0,				 /* exported parameters */
-		0,				 /* RPC method exports */
-		0,				 /* exported pseudo-variables */
-		0,				 /* response handling function */
-		mod_init,		 /* module initialization function */
-		child_init,		 /* per-child init function */
-		destroy			 /* module destroy function */
-};
-
-/* Module initialization function */
-static int mod_init(void)
-{
-	LM_DBG("init lost module\n");
-
-	if(httpc_load_api(&httpapi) != 0) {
-		LM_ERR("Can not bind to http_client API \n");
-		return -1;
-	}
-
-	LM_DBG("**** init lost module done.\n");
-
-	return 0;
-}
-
-/* Child initialization function */
-static int child_init(int rank)
-{
-	return 0;
-}
-
-static void destroy(void)
-{
-	;
-	/* do nothing */
-}
-
-/*
- * Fix 4 lost_held_query params: con (string/pvar)
- * and pidf, url, err (writable pvar).
- */
-static int fixup_lost_held_query(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_spve_null(param, 1);
-	}
-	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
-		if(fixup_pvar_null(param, 1) != 0) {
-			LM_ERR("failed to fixup result pvar\n");
-			return -1;
-		}
-		if(((pv_spec_t *)(*param))->setf == NULL) {
-			LM_ERR("result pvar is not writable\n");
-			return -1;
-		}
-		return 0;
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Free lost_held_query params.
- */
-static int fixup_free_lost_held_query(void **param, int param_no)
-{
-	if(param_no == 1) {
-		/* char strings don't need freeing */
-		return 0;
-	}
-	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
-		return fixup_free_pvar_null(param, 1);
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Fix 5 lost_held_query_id params: con (string/pvar) id (string that may contain
- * pvars) and pidf, url, err (writable pvar).
- */
-static int fixup_lost_held_query_id(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_spve_null(param, 1);
-	}
-	if(param_no == 2) {
-		return fixup_spve_null(param, 1);
-	}
-	if((param_no == 3) || (param_no == 4) || (param_no == 5)) {
-		if(fixup_pvar_null(param, 1) != 0) {
-			LM_ERR("failed to fixup result pvar\n");
-			return -1;
-		}
-		if(((pv_spec_t *)(*param))->setf == NULL) {
-			LM_ERR("result pvar is not writable\n");
-			return -1;
-		}
-		return 0;
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Free lost_held_query_id params.
- */
-static int fixup_free_lost_held_query_id(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_free_spve_null(param, 1);
-	}
-	if(param_no == 2) {
-		return fixup_free_spve_null(param, 1);
-	}
-	if((param_no == 3) || (param_no == 4) || (param_no == 5)) {
-		return fixup_free_pvar_null(param, 1);
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Fix 4 lost_query params: con (string/pvar)
- * and uri, name, err (writable pvar).
- */
-static int fixup_lost_query(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_spve_null(param, 1);
-	}
-	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
-		if(fixup_pvar_null(param, 1) != 0) {
-			LM_ERR("failed to fixup result pvar\n");
-			return -1;
-		}
-		if(((pv_spec_t *)(*param))->setf == NULL) {
-			LM_ERR("result pvar is not writable\n");
-			return -1;
-		}
-		return 0;
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Free lost_held_query_id params.
- */
-static int fixup_free_lost_query(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_free_spve_null(param, 1);
-	}
-	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
-		return fixup_free_pvar_null(param, 1);
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Fix 6 lost_query params: con (string/pvar) pidf, urn (string that may contain
- * pvars) and uri, name, err (writable pvar).
- */
-static int fixup_lost_query_all(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_spve_null(param, 1);
-	}
-	if((param_no == 2) || (param_no == 3)) {
-		return fixup_spve_null(param, 1);
-	}
-	if((param_no == 4) || (param_no == 5) || (param_no == 6)) {
-		if(fixup_pvar_null(param, 1) != 0) {
-			LM_ERR("failed to fixup result pvar\n");
-			return -1;
-		}
-		if(((pv_spec_t *)(*param))->setf == NULL) {
-			LM_ERR("result pvar is not writable\n");
-			return -1;
-		}
-		return 0;
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Free lost_held_query_id params.
- */
-static int fixup_free_lost_query_all(void **param, int param_no)
-{
-	if(param_no == 1) {
-		return fixup_free_spve_null(param, 1);
-	}
-	if((param_no == 2) || (param_no == 3)) {
-		return fixup_free_spve_null(param, 1);
-	}
-	if((param_no == 4) || (param_no == 5) || (param_no == 6)) {
-		return fixup_free_pvar_null(param, 1);
-	}
-	LM_ERR("invalid parameter number <%d>\n", param_no);
-	return -1;
-}
-
-/*
- * Wrapper for lost_held_query w/o id
- */
-static int w_lost_held_query(
-		struct sip_msg *_m, char *_con, char *_pidf, char *_url, char *_err)
-{
-	return lost_function_held(_m, _con, _pidf, _url, _err, NULL);
-}
-
-/*
- * Wrapper for lost_held_query with id
- */
-static int w_lost_held_query_id(struct sip_msg *_m, char *_con, char *_id,
-		char *_pidf, char *_url, char *_err)
-{
-	return lost_function_held(_m, _con, _pidf, _url, _err, _id);
-}
-
-/*
- * Wrapper for lost_query w/o pudf, urn
- */
-static int w_lost_query(
-		struct sip_msg *_m, char *_con, char *_uri, char *_name, char *_err)
-{
-	return lost_function(_m, _con, _uri, _name, _err, NULL, NULL);
-}
-
-/*
- * Wrapper for lost_query with pidf, urn
- */
-static int w_lost_query_all(struct sip_msg *_m, char *_con, char *_pidf,
-		char *_urn, char *_uri, char *_name, char *_err)
-{
-	return lost_function(_m, _con, _uri, _name, _err, _pidf, _urn);
-}
+/*
+ * lost module
+ *
+ * Copyright (C) 2019 Wolfgang Kampichler
+ * DEC112, FREQUENTIS AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Kamailio lost ::
+ * \ingroup lost
+ * Module: \ref lost
+ */
+
+#include "../../modules/http_client/curl_api.h"
+
+#include "../../core/mod_fix.h"
+#include "../../core/sr_module.h"
+#include "../../core/ut.h"
+#include "../../core/locking.h"
+
+#include "../../core/pvar.h"
+#include "../../core/mem/mem.h"
+#include "../../core/dprint.h"
+
+#include "../../core/script_cb.h"
+
+#include "functions.h"
+
+MODULE_VERSION
+
+/* Module parameter variables */
+httpc_api_t httpapi;
+
+/* Module management function prototypes */
+static int mod_init(void);
+static int child_init(int);
+static void destroy(void);
+
+/* Fixup functions to be defined later */
+static int fixup_lost_held_query(void **param, int param_no);
+static int fixup_free_lost_held_query(void **param, int param_no);
+static int fixup_lost_held_query_id(void **param, int param_no);
+static int fixup_free_lost_held_query_id(void **param, int param_no);
+
+static int fixup_lost_query(void **param, int param_no);
+static int fixup_free_lost_query(void **param, int param_no);
+static int fixup_lost_query_all(void **param, int param_no);
+static int fixup_free_lost_query_all(void **param, int param_no);
+
+/* Wrappers for http_query to be defined later */
+static int w_lost_held_query(
+		struct sip_msg *_m, char *_con, char *_pidf, char *_url, char *_err);
+static int w_lost_held_query_id(struct sip_msg *_m, char *_con, char *_id,
+		char *_pidf, char *_url, char *_err);
+static int w_lost_query(
+		struct sip_msg *_m, char *_con, char *_uri, char *_name, char *_err);
+static int w_lost_query_all(struct sip_msg *_m, char *_con, char *_pidf,
+		char *_urn, char *_uri, char *_name, char *_err);
+
+/* Exported functions */
+static cmd_export_t cmds[] = {
+		{"lost_held_query", (cmd_function)w_lost_held_query, 4,
+				fixup_lost_held_query, fixup_free_lost_held_query,
+				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
+		{"lost_held_query", (cmd_function)w_lost_held_query_id, 5,
+				fixup_lost_held_query_id, fixup_free_lost_held_query_id,
+				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
+		{"lost_query", (cmd_function)w_lost_query, 4, fixup_lost_query,
+				fixup_free_lost_query,
+				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
+		{"lost_query", (cmd_function)w_lost_query_all, 6, fixup_lost_query_all,
+				fixup_free_lost_query_all,
+				REQUEST_ROUTE | FAILURE_ROUTE | BRANCH_ROUTE},
+		{0, 0, 0, 0, 0, 0}};
+
+
+/* Module interface */
+struct module_exports exports = {
+		"lost",			 /* module name*/
+		DEFAULT_DLFLAGS, /* dlopen flags */
+		cmds,			 /* exported functions */
+		0,				 /* exported parameters */
+		0,				 /* RPC method exports */
+		0,				 /* exported pseudo-variables */
+		0,				 /* response handling function */
+		mod_init,		 /* module initialization function */
+		child_init,		 /* per-child init function */
+		destroy			 /* module destroy function */
+};
+
+/* Module initialization function */
+static int mod_init(void)
+{
+	LM_DBG("init lost module\n");
+
+	if(httpc_load_api(&httpapi) != 0) {
+		LM_ERR("Can not bind to http_client API \n");
+		return -1;
+	}
+
+	LM_DBG("**** init lost module done.\n");
+
+	return 0;
+}
+
+/* Child initialization function */
+static int child_init(int rank)
+{
+	return 0;
+}
+
+static void destroy(void)
+{
+	;
+	/* do nothing */
+}
+
+/*
+ * Fix 4 lost_held_query params: con (string/pvar)
+ * and pidf, url, err (writable pvar).
+ */
+static int fixup_lost_held_query(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_spve_null(param, 1);
+	}
+	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
+		if(fixup_pvar_null(param, 1) != 0) {
+			LM_ERR("failed to fixup result pvar\n");
+			return -1;
+		}
+		if(((pv_spec_t *)(*param))->setf == NULL) {
+			LM_ERR("result pvar is not writable\n");
+			return -1;
+		}
+		return 0;
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Free lost_held_query params.
+ */
+static int fixup_free_lost_held_query(void **param, int param_no)
+{
+	if(param_no == 1) {
+		/* char strings don't need freeing */
+		return 0;
+	}
+	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
+		return fixup_free_pvar_null(param, 1);
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Fix 5 lost_held_query_id params: con (string/pvar) id (string that may contain
+ * pvars) and pidf, url, err (writable pvar).
+ */
+static int fixup_lost_held_query_id(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_spve_null(param, 1);
+	}
+	if(param_no == 2) {
+		return fixup_spve_null(param, 1);
+	}
+	if((param_no == 3) || (param_no == 4) || (param_no == 5)) {
+		if(fixup_pvar_null(param, 1) != 0) {
+			LM_ERR("failed to fixup result pvar\n");
+			return -1;
+		}
+		if(((pv_spec_t *)(*param))->setf == NULL) {
+			LM_ERR("result pvar is not writable\n");
+			return -1;
+		}
+		return 0;
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Free lost_held_query_id params.
+ */
+static int fixup_free_lost_held_query_id(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_free_spve_null(param, 1);
+	}
+	if(param_no == 2) {
+		return fixup_free_spve_null(param, 1);
+	}
+	if((param_no == 3) || (param_no == 4) || (param_no == 5)) {
+		return fixup_free_pvar_null(param, 1);
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Fix 4 lost_query params: con (string/pvar)
+ * and uri, name, err (writable pvar).
+ */
+static int fixup_lost_query(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_spve_null(param, 1);
+	}
+	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
+		if(fixup_pvar_null(param, 1) != 0) {
+			LM_ERR("failed to fixup result pvar\n");
+			return -1;
+		}
+		if(((pv_spec_t *)(*param))->setf == NULL) {
+			LM_ERR("result pvar is not writable\n");
+			return -1;
+		}
+		return 0;
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Free lost_held_query_id params.
+ */
+static int fixup_free_lost_query(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_free_spve_null(param, 1);
+	}
+	if((param_no == 2) || (param_no == 3) || (param_no == 4)) {
+		return fixup_free_pvar_null(param, 1);
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Fix 6 lost_query params: con (string/pvar) pidf, urn (string that may contain
+ * pvars) and uri, name, err (writable pvar).
+ */
+static int fixup_lost_query_all(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_spve_null(param, 1);
+	}
+	if((param_no == 2) || (param_no == 3)) {
+		return fixup_spve_null(param, 1);
+	}
+	if((param_no == 4) || (param_no == 5) || (param_no == 6)) {
+		if(fixup_pvar_null(param, 1) != 0) {
+			LM_ERR("failed to fixup result pvar\n");
+			return -1;
+		}
+		if(((pv_spec_t *)(*param))->setf == NULL) {
+			LM_ERR("result pvar is not writable\n");
+			return -1;
+		}
+		return 0;
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Free lost_held_query_id params.
+ */
+static int fixup_free_lost_query_all(void **param, int param_no)
+{
+	if(param_no == 1) {
+		return fixup_free_spve_null(param, 1);
+	}
+	if((param_no == 2) || (param_no == 3)) {
+		return fixup_free_spve_null(param, 1);
+	}
+	if((param_no == 4) || (param_no == 5) || (param_no == 6)) {
+		return fixup_free_pvar_null(param, 1);
+	}
+	LM_ERR("invalid parameter number <%d>\n", param_no);
+	return -1;
+}
+
+/*
+ * Wrapper for lost_held_query w/o id
+ */
+static int w_lost_held_query(
+		struct sip_msg *_m, char *_con, char *_pidf, char *_url, char *_err)
+{
+	return lost_function_held(_m, _con, _pidf, _url, _err, NULL);
+}
+
+/*
+ * Wrapper for lost_held_query with id
+ */
+static int w_lost_held_query_id(struct sip_msg *_m, char *_con, char *_id,
+		char *_pidf, char *_url, char *_err)
+{
+	return lost_function_held(_m, _con, _pidf, _url, _err, _id);
+}
+
+/*
+ * Wrapper for lost_query w/o pudf, urn
+ */
+static int w_lost_query(
+		struct sip_msg *_m, char *_con, char *_uri, char *_name, char *_err)
+{
+	return lost_function(_m, _con, _uri, _name, _err, NULL, NULL);
+}
+
+/*
+ * Wrapper for lost_query with pidf, urn
+ */
+static int w_lost_query_all(struct sip_msg *_m, char *_con, char *_pidf,
+		char *_urn, char *_uri, char *_name, char *_err)
+{
+	return lost_function(_m, _con, _uri, _name, _err, _pidf, _urn);
+}

+ 137 - 137
src/modules/lost/pidf.c

@@ -1,137 +1,137 @@
-/*
- * $Id: pidf.c 1953 2007-04-04 08:50:33Z anca_vamanu $
- *
- * presence module - presence server implementation
- *
- * Copyright (C) 2006 Voice Sistem S.R.L.
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*! \file
- * \brief Kamailio lost ::  PIDF handling
- * \ingroup lost
- */
-
-
-/**
- * make strptime available
- * use 600 for 'Single UNIX Specification, Version 3'
- * _XOPEN_SOURCE creates conflict in header definitions in Solaris
- */
-#ifndef __OS_solaris
-#define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */
-#define _BSD_SOURCE \
-	1					  /* needed on linux to "fix" the effect
-										  of the above define on
-										  features.h/unistd.h syscall() */
-#define _DEFAULT_SOURCE 1 /* _BSD_SOURCE is deprecated */
-#define _DARWIN_C_SOURCE 1
-#else
-#define _XOPEN_SOURCE_EXTENDED 1 /* solaris */
-#endif
-
-#include <time.h>
-
-#undef _XOPEN_SOURCE
-#undef _XOPEN_SOURCE_EXTENDED
-
-#include <string.h>
-#include <stdlib.h>
-#include <libxml/parser.h>
-
-#include "../../core/mem/mem.h"
-#include "../../core/dprint.h"
-
-#include "pidf.h"
-
-xmlAttrPtr xmlNodeGetAttrByName(xmlNodePtr node, const char *name)
-{
-	xmlAttrPtr attr = node->properties;
-	while(attr) {
-		if(xmlStrcasecmp(attr->name, (unsigned char *)name) == 0)
-			return attr;
-		attr = attr->next;
-	}
-	return NULL;
-}
-
-char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name)
-{
-	xmlAttrPtr attr = xmlNodeGetAttrByName(node, name);
-	if(attr)
-		return (char *)xmlNodeGetContent(attr->children);
-	else
-		return NULL;
-}
-
-xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name)
-{
-	xmlNodePtr cur = node->children;
-	while(cur) {
-		if(xmlStrcasecmp(cur->name, (unsigned char *)name) == 0)
-			return cur;
-		cur = cur->next;
-	}
-	return NULL;
-}
-
-xmlNodePtr xmlNodeGetNodeByName(
-		xmlNodePtr node, const char *name, const char *ns)
-{
-	xmlNodePtr cur = node;
-	while(cur) {
-		xmlNodePtr match = NULL;
-		if(xmlStrcasecmp(cur->name, (unsigned char *)name) == 0) {
-			if(!ns || (cur->ns &&
-				xmlStrcasecmp(cur->ns->prefix, (unsigned char *)ns) == 0))
-			return cur;
-		}
-		match = xmlNodeGetNodeByName(cur->children, name, ns);
-		if(match)
-			return match;
-		cur = cur->next;
-	}
-	return NULL;
-}
-
-char *xmlNodeGetNodeContentByName(
-		xmlNodePtr root, const char *name, const char *ns)
-{
-	xmlNodePtr node = xmlNodeGetNodeByName(root, name, ns);
-	if(node)
-		return (char *)xmlNodeGetContent(node->children);
-	else
-		return NULL;
-}
-
-xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns)
-{
-	xmlNodePtr cur = doc->children;
-	return xmlNodeGetNodeByName(cur, name, ns);
-}
-
-char *xmlDocGetNodeContentByName(
-		xmlDocPtr doc, const char *name, const char *ns)
-{
-	xmlNodePtr node = xmlDocGetNodeByName(doc, name, ns);
-	if(node)
-		return (char *)xmlNodeGetContent(node->children);
-	else
-		return NULL;
-}
+/*
+ * $Id: pidf.c 1953 2007-04-04 08:50:33Z anca_vamanu $
+ *
+ * presence module - presence server implementation
+ *
+ * Copyright (C) 2006 Voice Sistem S.R.L.
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*! \file
+ * \brief Kamailio lost ::  PIDF handling
+ * \ingroup lost
+ */
+
+
+/**
+ * make strptime available
+ * use 600 for 'Single UNIX Specification, Version 3'
+ * _XOPEN_SOURCE creates conflict in header definitions in Solaris
+ */
+#ifndef __OS_solaris
+#define _XOPEN_SOURCE 600 /* glibc2 on linux, bsd */
+#define _BSD_SOURCE \
+	1					  /* needed on linux to "fix" the effect
+										  of the above define on
+										  features.h/unistd.h syscall() */
+#define _DEFAULT_SOURCE 1 /* _BSD_SOURCE is deprecated */
+#define _DARWIN_C_SOURCE 1
+#else
+#define _XOPEN_SOURCE_EXTENDED 1 /* solaris */
+#endif
+
+#include <time.h>
+
+#undef _XOPEN_SOURCE
+#undef _XOPEN_SOURCE_EXTENDED
+
+#include <string.h>
+#include <stdlib.h>
+#include <libxml/parser.h>
+
+#include "../../core/mem/mem.h"
+#include "../../core/dprint.h"
+
+#include "pidf.h"
+
+xmlAttrPtr xmlNodeGetAttrByName(xmlNodePtr node, const char *name)
+{
+	xmlAttrPtr attr = node->properties;
+	while(attr) {
+		if(xmlStrcasecmp(attr->name, (unsigned char *)name) == 0)
+			return attr;
+		attr = attr->next;
+	}
+	return NULL;
+}
+
+char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name)
+{
+	xmlAttrPtr attr = xmlNodeGetAttrByName(node, name);
+	if(attr)
+		return (char *)xmlNodeGetContent(attr->children);
+	else
+		return NULL;
+}
+
+xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name)
+{
+	xmlNodePtr cur = node->children;
+	while(cur) {
+		if(xmlStrcasecmp(cur->name, (unsigned char *)name) == 0)
+			return cur;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+xmlNodePtr xmlNodeGetNodeByName(
+		xmlNodePtr node, const char *name, const char *ns)
+{
+	xmlNodePtr cur = node;
+	while(cur) {
+		xmlNodePtr match = NULL;
+		if(xmlStrcasecmp(cur->name, (unsigned char *)name) == 0) {
+			if(!ns || (cur->ns &&
+				xmlStrcasecmp(cur->ns->prefix, (unsigned char *)ns) == 0))
+			return cur;
+		}
+		match = xmlNodeGetNodeByName(cur->children, name, ns);
+		if(match)
+			return match;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+char *xmlNodeGetNodeContentByName(
+		xmlNodePtr root, const char *name, const char *ns)
+{
+	xmlNodePtr node = xmlNodeGetNodeByName(root, name, ns);
+	if(node)
+		return (char *)xmlNodeGetContent(node->children);
+	else
+		return NULL;
+}
+
+xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns)
+{
+	xmlNodePtr cur = doc->children;
+	return xmlNodeGetNodeByName(cur, name, ns);
+}
+
+char *xmlDocGetNodeContentByName(
+		xmlDocPtr doc, const char *name, const char *ns)
+{
+	xmlNodePtr node = xmlDocGetNodeByName(doc, name, ns);
+	if(node)
+		return (char *)xmlNodeGetContent(node->children);
+	else
+		return NULL;
+}

+ 50 - 50
src/modules/lost/pidf.h

@@ -1,50 +1,50 @@
-/*
- * $Id: pidf.h 1401 2006-12-14 11:12:42Z anca_vamanu $
- *
- * presence module - presence server implementation
- *
- * Copyright (C) 2006 Voice Sistem S.R.L.
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*! \file
- * \brief Kamailio Presence_XML :: PIDF handling
- * \ref pidf.c
- * \ingroup lost
- */
-
-
-#ifndef PIDF_H
-#define PIDF_H
-
-#include "../../core/str.h"
-#include <libxml/parser.h>
-
-xmlNodePtr xmlNodeGetNodeByName(
-		xmlNodePtr node, const char *name, const char *ns);
-xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns);
-xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name);
-
-char *xmlDocGetNodeContentByName(
-		xmlDocPtr doc, const char *name, const char *ns);
-char *xmlNodeGetNodeContentByName(
-		xmlNodePtr root, const char *name, const char *ns);
-char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name);
-
-#endif
+/*
+ * $Id: pidf.h 1401 2006-12-14 11:12:42Z anca_vamanu $
+ *
+ * presence module - presence server implementation
+ *
+ * Copyright (C) 2006 Voice Sistem S.R.L.
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*! \file
+ * \brief Kamailio Presence_XML :: PIDF handling
+ * \ref pidf.c
+ * \ingroup lost
+ */
+
+
+#ifndef PIDF_H
+#define PIDF_H
+
+#include "../../core/str.h"
+#include <libxml/parser.h>
+
+xmlNodePtr xmlNodeGetNodeByName(
+		xmlNodePtr node, const char *name, const char *ns);
+xmlNodePtr xmlDocGetNodeByName(xmlDocPtr doc, const char *name, const char *ns);
+xmlNodePtr xmlNodeGetChildByName(xmlNodePtr node, const char *name);
+
+char *xmlDocGetNodeContentByName(
+		xmlDocPtr doc, const char *name, const char *ns);
+char *xmlNodeGetNodeContentByName(
+		xmlNodePtr root, const char *name, const char *ns);
+char *xmlNodeGetAttrContentByName(xmlNodePtr node, const char *name);
+
+#endif

+ 708 - 708
src/modules/lost/utilities.c

@@ -1,708 +1,708 @@
-/*
- * lost module utility functions
- *
- * Copyright (C) 2019 Wolfgang Kampichler
- * DEC112, FREQUENTIS AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*!
- * \file
- * \brief Kamailio lost :: utilities
- * \ingroup lost
- * Module: \ref lost
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <time.h>
-
-#include <libxml/xmlmemory.h>
-#include <libxml/parser.h>
-#include "../../core/parser/msg_parser.h"
-#include "../../core/parser/parse_content.h"
-#include "../../core/parser/parse_uri.h"
-#include "../../core/parser/parse_from.h"
-#include "../../core/parser/parse_ppi_pai.h"
-#include "../../core/dprint.h"
-#include "../../core/mem/mem.h"
-#include "../../core/mem/shm_mem.h"
-#include "../../core/rand/kam_rand.h"
-
-#include "pidf.h"
-#include "utilities.h"
-
-/*
- * lost_trim_content(dest, lgth)
- * removes whitespace that my occur in a content of an xml element
- */
-char *lost_trim_content(char *str, int *lgth)
-{
-	char *end;
-
-	while(isspace(*str))
-		str++;
-
-	if(*str == 0)
-		return NULL;
-
-	end = str + strlen(str) - 1;
-
-	while(end > str && isspace(*end))
-		end--;
-
-	*(end + 1) = '\0';
-
-	*lgth = (end + 1) - str;
-
-	return str;
-}
-
-/*
- * lost_rand_str(dest, length)
- * creates a random string used as temporary id in a findService request
- */
-void lost_rand_str(char *dest, size_t lgth)
-{
-	size_t index;
-	char charset[] = "0123456789"
-					 "abcdefghijklmnopqrstuvwxyz"
-					 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-	kam_srand(time(NULL));
-	while(lgth-- > 0) {
-		index = (double)kam_rand() / RAND_MAX * (sizeof charset - 1);
-		*dest++ = charset[index];
-	}
-	*dest = '\0';
-}
-
-/*
- * lost_free_loc(ptr)
- * frees a location object
- */
-void lost_free_loc(p_loc_t ptr)
-{
-	pkg_free(ptr->identity);
-	pkg_free(ptr->urn);
-	pkg_free(ptr->longitude);
-	pkg_free(ptr->latitude);
-	pkg_free(ptr);
-}
-
-/*
- * lost_free_string(ptr)
- * frees and resets a string
- */
-void lost_free_string(str *string)
-{
-	str ptr = *string;
-
-	if(ptr.s) {
-		pkg_free(ptr.s);
-		ptr.s = NULL;
-		ptr.len = 0;
-	}
-}
-
-/*
- * lost_new_loc(urn)
- * creates a new location object in private memory and returns a pointer
- */
-p_loc_t lost_new_loc(str rurn)
-{
-	s_loc_t *ptr = NULL;;
-	char *id = NULL;
-	char *urn = NULL;
-
-	ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));
-	if(ptr == NULL) {
-		goto err;
-	}
-
-	id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);
-	if(id == NULL) {
-		pkg_free(ptr);
-		goto err;
-	}
-
-	urn = (char *)pkg_malloc(rurn.len + 1);
-	if(urn == NULL) {
-		pkg_free(ptr);
-		pkg_free(id);
-		goto err;
-	}
-
-	memset(urn, 0, rurn.len + 1);
-	memcpy(urn, rurn.s, rurn.len);
-	urn[rurn.len] = '\0';
-
-	lost_rand_str(id, RANDSTRSIZE);
-
-	ptr->identity = id;
-	ptr->urn = urn;
-	ptr->longitude = NULL;
-	ptr->latitude = NULL;
-	ptr->radius = 0;
-	ptr->recursive = 0;
-
-	return ptr;
-
-err:	
-	LM_ERR("no more private memory\n");
-	return NULL;
-}
-
-/*
- * lost_get_content(node, name, lgth)
- * gets a nodes "name" content and returns string allocated in private memory
- */
-char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)
-{
-	xmlNodePtr cur = node;
-	char *content;
-	char *cnt = NULL;
-	int len;
-
-	*lgth = 0;
-	content = xmlNodeGetNodeContentByName(cur, name, NULL);
-	if (content == NULL) {
-		LM_ERR("could not get XML node content\n");
-		return cnt;
-	} else {
-		len = strlen(content);
-		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
-		if(cnt == NULL) {
-			LM_ERR("no more private memory\n");
-			xmlFree(content);
-			return cnt;
-		}
-		memset(cnt, 0, len + 1);
-		memcpy(cnt, content, len);
-		cnt[len] = '\0';
-	}
-
-	xmlFree(content);
-	*lgth = strlen(cnt);
-
-	return cnt;
-}
-
-/*
- * lost_get_property(node, name, lgth)
- * gets a nodes property "name" and returns string allocated in private memory
- */
-char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)
-{
-	xmlNodePtr cur = node;
-	char *content;
-	char *cnt = NULL;
-	int len;
-
-	*lgth = 0;
-	content = xmlNodeGetAttrContentByName(cur, name);
-	if (content == NULL) {
-		LM_ERR("could not get XML node content\n");
-		return cnt;
-	} else {
-		len = strlen(content);
-		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
-		if(cnt == NULL) {
-			LM_ERR("no more private memory\n");
-			xmlFree(content);
-			return cnt;
-		}
-		memset(cnt, 0, len + 1);
-		memcpy(cnt, content, len);
-		cnt[len] = '\0';
-	}
-
-	xmlFree(content);
-	*lgth = strlen(cnt);
-
-	return cnt;
-}
-
-/*
- * lost_get_childname(name, lgth)
- * gets a nodes child name and returns string allocated in private memory
- */
-char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)
-{
-	xmlNodePtr cur = node;
-	xmlNodePtr parent = NULL;
-	xmlNodePtr child = NULL;
-	char *cnt = NULL;
-	int len;
-
-	*lgth = 0;
-	parent = xmlNodeGetNodeByName(cur, name, NULL);
-	child = parent->children;
-
-	if(child) {
-		len = strlen((char *)child->name);
-		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
-		if(cnt == NULL) {
-			LM_ERR("no more private memory\n");
-			return cnt;
-		}
-
-		memset(cnt, 0, len + 1);
-		memcpy(cnt, child->name, len);
-		cnt[len] = '\0';
-
-		*lgth = strlen(cnt);
-	}
-	return cnt;
-}
-
-/*
- * lost_get_geolocation_header(msg, lgth)
- * gets the Geolocation header value and returns string allocated in
- * private memory
- */
-char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)
-{
-	struct hdr_field *hf;
-	char *res = NULL;
-
-	*lgth = 0;
-
-	if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
-		LM_ERR("failed to parse geolocation header\n");
-		return res;
-	}
-
-	for(hf = msg->headers; hf; hf = hf->next) {
-		if((hf->type == HDR_OTHER_T)
-				&& (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {
-			/* possible hit */
-			if(strncasecmp(
-					   hf->name.s, LOST_GEOLOC_HEADER, LOST_GEOLOC_HEADER_SIZE)
-					== 0) {
-
-				res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));
-				if(res == NULL) {
-					LM_ERR("no more private memory\n");
-					return res;
-				} else {
-					memset(res, 0, hf->body.len + 1);
-					memcpy(res, hf->body.s, hf->body.len + 1);
-					res[hf->body.len] = '\0';
-
-					*lgth = strlen(res);
-				}
-			} else {
-				LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
-						hf->body.len);
-			}
-			break;
-		}
-	}
-	return res;
-}
-
-/*
- * lost_get_pai_header(msg, lgth)
- * gets the P-A-I header value and returns string allocated in
- * private memory
- */
-char *lost_get_pai_header(struct sip_msg *msg, int *lgth)
-{
-	struct hdr_field *hf;
-	to_body_t *pai_body;
-	char *res = NULL;
-
-	*lgth = 0;
-
-	if (parse_headers(msg, HDR_PAI_F, 0) == -1) {
-		LM_ERR("could not parse P-A-I header\n");
-		return res;
-	}
-
-	for(hf = msg->headers; hf; hf = hf->next) {
-		if((hf->type == HDR_PAI_T)
-				&& (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {
-			/* possible hit */
-			if(strncasecmp(hf->name.s, LOST_PAI_HEADER, LOST_PAI_HEADER_SIZE)
-					== 0) {
-
-				LM_DBG("P-A-I body:  [%.*s]\n", hf->body.len, hf->body.s);
-
-				/* first, get some memory */
-				pai_body = pkg_malloc(sizeof(to_body_t));
-				if (pai_body == NULL) {
-					LM_ERR("no more private memory\n");
-					return res;
-				}
-				/* parse P-A-I body */
-				memset(pai_body, 0, sizeof(to_body_t));
-				parse_to(hf->body.s, hf->body.s + hf->body.len + 1, pai_body);
-				if (pai_body->error == PARSE_ERROR) {
-					LM_ERR("bad P-A-I header\n");
-					pkg_free(pai_body);
-					return res;
-				}
-				if (pai_body->error == PARSE_OK) {
-					res = (char *)pkg_malloc((pai_body->uri.len + 1) * sizeof(char));
-					if(res == NULL) {
-						LM_ERR("no more private memory\n");
-						pkg_free(pai_body);
-						return res;
-					} else {
-						memset(res, 0, pai_body->uri.len + 1);
-						memcpy(res, pai_body->uri.s, pai_body->uri.len + 1);
-						res[pai_body->uri.len] = '\0';
-						pkg_free(pai_body);
-
-						*lgth = strlen(res);
-					}
-				}
-			} else {
-				LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
-						hf->body.len);
-			}
-			break;
-		}
-	}
-	return res;
-}
-
-/*
- * lost_get_from_header(msg, lgth)
- * gets the From header value and returns string allocated in
- * private memory
- */
-char *lost_get_from_header(struct sip_msg *msg, int *lgth)
-{
-	to_body_t *f_body;
-	char *res = NULL;
-
-	*lgth = 0;
-
-	if(parse_headers(msg, HDR_FROM_F, 0) == -1) {
-		LM_ERR("failed to parse From header\n");
-		return res;
-	}
-
-	if(msg->from == NULL || get_from(msg) == NULL) {
-		LM_ERR("From header not found\n");
-		return res;
-	}
-	f_body = get_from(msg);
-
-	LM_DBG("From body:  [%.*s]\n", f_body->body.len, f_body->body.s);
-
-	res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));
-	if(res == NULL) {
-		LM_ERR("no more private memory\n");
-		return res;
-	} else {
-		memset(res, 0, f_body->uri.len + 1);
-		memcpy(res, f_body->uri.s, f_body->uri.len + 1);
-		res[f_body->uri.len] = '\0';
-
-		*lgth = strlen(res);
-	}
-	return res;
-}
-
-/*
- * lost_parse_location_info(node, loc)
- * parses locationResponse and writes results to location object
- */
-int lost_parse_location_info(xmlNodePtr node, p_loc_t loc)
-{
-	char bufLat[BUFSIZE];
-	char bufLon[BUFSIZE];
-	int iRadius;
-	char *content = NULL;
-	int ret = -1;
-
-	xmlNodePtr cur = node;
-
-	content = xmlNodeGetNodeContentByName(cur, "pos", NULL);
-	if(content) {
-		sscanf(content, "%s %s", bufLat, bufLon);
-
-		loc->latitude = (char *)pkg_malloc(strlen((char *)bufLat) + 1);
-		snprintf(loc->latitude, strlen((char *)bufLat) + 1, "%s",
-				(char *)bufLat);
-
-		loc->longitude = (char *)pkg_malloc(strlen((char *)bufLon) + 1);
-		snprintf(loc->longitude, strlen((char *)bufLon) + 1, "%s",
-				(char *)bufLon);
-
-		loc->radius = 0;
-		ret = 0;
-	}
-
-	content = xmlNodeGetNodeContentByName(cur, "radius", NULL);
-	if(content) {
-		iRadius = 0;
-
-		sscanf(content, "%d", &iRadius);
-		loc->radius = iRadius;
-		ret = 0;
-	}
-
-	if(ret < 0) {
-		LM_ERR("could not parse location information\n");
-	}
-	return ret;
-}
-
-/*
- * lost_held_location_request(id, lgth)
- * assembles and returns locationRequest string (allocated in private memory)
- */
-char *lost_held_location_request(char *id, int *lgth)
-{
-	int buffersize = 0;
-
-	char buf[BUFSIZE];
-	char *doc = NULL;
-
-	xmlChar *xmlbuff = NULL;
-	xmlDocPtr request = NULL;
-
-	xmlNodePtr ptrLocationRequest = NULL;
-	xmlNodePtr ptrLocationType = NULL;
-	xmlNodePtr ptrDevice = NULL;
-
-	xmlKeepBlanksDefault(1);
-	*lgth = 0;
-
-	/*
-https://tools.ietf.org/html/rfc6155
-
-<?xml version="1.0" encoding="UTF-8"?>
-<locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">
-    <locationType exact="true">geodetic locationURI</locationType>
-    <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
-        <uri>sip:[email protected]</uri>
-    </device>
-</locationRequest>
-*/
-
-	/* create request */
-	request = xmlNewDoc(BAD_CAST "1.0");
-	if(!request) {
-		LM_ERR("locationRequest xmlNewDoc() failed\n");
-		return doc;
-	}
-	/* locationRequest - element */
-	ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");
-	if(!ptrLocationRequest) {
-		LM_ERR("locationRequest xmlNewNode() failed\n");
-		xmlFreeDoc(request);
-		return doc;
-	}
-	xmlDocSetRootElement(request, ptrLocationRequest);
-	/* properties */
-	xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",
-			BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");
-	xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST "8");
-	/* locationType - element */
-	ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,
-			BAD_CAST "locationType", BAD_CAST "geodetic locationURI");
-	/* properties */
-	xmlNewProp(ptrLocationType, BAD_CAST "exact", BAD_CAST "false");
-	/* device - element */
-	ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);
-	if(!ptrDevice) {
-		LM_ERR("locationRequest xmlNewChild() failed\n");
-		xmlFreeDoc(request);
-		return doc;
-	}
-	/* properties */
-	xmlNewProp(ptrDevice, BAD_CAST "xmlns",
-			BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");
-	/* uri - element */
-	snprintf(buf, BUFSIZE, "%s", id);
-	xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST buf);
-
-	xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
-	if(!xmlbuff) {
-		LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");
-		xmlFreeDoc(request);
-		return doc;
-	}
-
-	doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
-	if(doc == NULL) {
-		LM_ERR("no more private memory\n");
-		xmlFree(xmlbuff);
-		xmlFreeDoc(request);
-		return doc;
-	}
-
-	memset(doc, 0, buffersize + 1);
-	memcpy(doc, (char *)xmlbuff, buffersize);
-	doc[buffersize] = '\0';
-
-	*lgth = strlen(doc);
-
-	xmlFree(xmlbuff);
-	xmlFreeDoc(request);
-
-	return doc;
-}
-
-/*
- * lost_find_service_request(loc, lgth)
- * assembles and returns findService request string (allocated in private memory)
- */
-char *lost_find_service_request(p_loc_t loc, int *lgth)
-{
-	int buffersize = 0;
-
-	char buf[BUFSIZE];
-	char *doc = NULL;
-
-	xmlChar *xmlbuff = NULL;
-	xmlDocPtr request = NULL;
-
-	xmlNodePtr ptrFindService = NULL;
-	xmlNodePtr ptrLocation = NULL;
-	xmlNodePtr ptrPoint = NULL;
-	xmlNodePtr ptrCircle = NULL;
-	xmlNodePtr ptrRadius = NULL;
-
-	xmlKeepBlanksDefault(1);
-	*lgth = 0;
-
-	/*
-https://tools.ietf.org/html/rfc5222
-
-<?xml version="1.0" encoding="UTF-8"?>
-<findService
- xmlns="urn:ietf:params:xml:ns:lost1"
- xmlns:p2="http://www.opengis.net/gml"
- serviceBoundary="value"
- recursive="true">
-    <location id="6020688f1ce1896d" profile="geodetic-2d">
-        <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">
-            <p2:pos>37.775 -122.422</p2:pos>
-        </p2:Point>
-    </location>
-    <service>urn:service:sos.police</service>
-</findService>
- */
-	/* create request */
-	request = xmlNewDoc(BAD_CAST "1.0");
-	if(!request) {
-		LM_ERR("findService request xmlNewDoc() failed\n");
-		return doc;
-	}
-	/* findService - element */
-	ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");
-	if(!ptrFindService) {
-		LM_ERR("findService xmlNewNode() failed\n");
-		xmlFreeDoc(request);
-		return doc;
-	}
-	xmlDocSetRootElement(request, ptrFindService);
-	/* set properties */
-	xmlNewProp(ptrFindService, BAD_CAST "xmlns",
-			BAD_CAST "urn:ietf:params:xml:ns:lost1");
-	xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",
-			BAD_CAST "http://www.opengis.net/gml");
-	xmlNewProp(
-			ptrFindService, BAD_CAST "serviceBoundary", BAD_CAST "reference");
-	xmlNewProp(ptrFindService, BAD_CAST "recursive", BAD_CAST "true");
-	/* location - element */
-	ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);
-	xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);
-	xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST "geodetic-2d");
-	/* set pos */
-	snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);
-	/* Point */
-	if(loc->radius == 0) {
-		ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);
-		if(!ptrPoint) {
-			LM_ERR("locationRequest xmlNewChild() failed\n");
-			xmlFreeDoc(request);
-			return doc;
-		}
-		xmlNewProp(ptrPoint, BAD_CAST "xmlns",
-				BAD_CAST "http://www.opengis.net/gml");
-		xmlNewProp(ptrPoint, BAD_CAST "srsName",
-				BAD_CAST "urn:ogc:def:crs:EPSG::4326");
-		/* pos */
-		xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);
-	} else {
-		/* circle - Point */
-		ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);
-		if(!ptrCircle) {
-			LM_ERR("locationRequest xmlNewChild() failed\n");
-			xmlFreeDoc(request);
-			return doc;
-		}
-		xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",
-				BAD_CAST "http://www.opengis.net/gml");
-		xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",
-				BAD_CAST "http://www.opengis.net/pidflo/1.0");
-		xmlNewProp(ptrCircle, BAD_CAST "srsName",
-				BAD_CAST "urn:ogc:def:crs:EPSG::4326");
-		/* pos */
-		xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);
-		/* circle - radius */
-		snprintf(buf, BUFSIZE, "%d", loc->radius);
-		ptrRadius = xmlNewChild(
-				ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);
-		if(!ptrRadius) {
-			LM_ERR("locationRequest xmlNewChild() failed\n");
-			xmlFreeDoc(request);
-			return doc;
-		}
-		xmlNewProp(ptrRadius, BAD_CAST "uom",
-				BAD_CAST "urn:ogc:def:uom:EPSG::9001");
-	}
-	/* service - element */
-	snprintf(buf, BUFSIZE, "%s", loc->urn);
-	xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);
-
-	xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
-	if(!xmlbuff) {
-		LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");
-		xmlFreeDoc(request);
-		return doc;
-	}
-
-	doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
-	if(doc == NULL) {
-		LM_ERR("no more private memory\n");
-		xmlFree(xmlbuff);
-		xmlFreeDoc(request);
-		return doc;
-	}
-
-	memset(doc, 0, buffersize + 1);
-	memcpy(doc, (char *)xmlbuff, buffersize);
-	doc[buffersize] = '\0';
-
-	*lgth = strlen(doc);
-
-	xmlFree(xmlbuff);
-	xmlFreeDoc(request);
-
-	return doc;
-}
+/*
+ * lost module utility functions
+ *
+ * Copyright (C) 2019 Wolfgang Kampichler
+ * DEC112, FREQUENTIS AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Kamailio lost :: utilities
+ * \ingroup lost
+ * Module: \ref lost
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include "../../core/parser/msg_parser.h"
+#include "../../core/parser/parse_content.h"
+#include "../../core/parser/parse_uri.h"
+#include "../../core/parser/parse_from.h"
+#include "../../core/parser/parse_ppi_pai.h"
+#include "../../core/dprint.h"
+#include "../../core/mem/mem.h"
+#include "../../core/mem/shm_mem.h"
+#include "../../core/rand/kam_rand.h"
+
+#include "pidf.h"
+#include "utilities.h"
+
+/*
+ * lost_trim_content(dest, lgth)
+ * removes whitespace that my occur in a content of an xml element
+ */
+char *lost_trim_content(char *str, int *lgth)
+{
+	char *end;
+
+	while(isspace(*str))
+		str++;
+
+	if(*str == 0)
+		return NULL;
+
+	end = str + strlen(str) - 1;
+
+	while(end > str && isspace(*end))
+		end--;
+
+	*(end + 1) = '\0';
+
+	*lgth = (end + 1) - str;
+
+	return str;
+}
+
+/*
+ * lost_rand_str(dest, length)
+ * creates a random string used as temporary id in a findService request
+ */
+void lost_rand_str(char *dest, size_t lgth)
+{
+	size_t index;
+	char charset[] = "0123456789"
+					 "abcdefghijklmnopqrstuvwxyz"
+					 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	kam_srand(time(NULL));
+	while(lgth-- > 0) {
+		index = (double)kam_rand() / RAND_MAX * (sizeof charset - 1);
+		*dest++ = charset[index];
+	}
+	*dest = '\0';
+}
+
+/*
+ * lost_free_loc(ptr)
+ * frees a location object
+ */
+void lost_free_loc(p_loc_t ptr)
+{
+	pkg_free(ptr->identity);
+	pkg_free(ptr->urn);
+	pkg_free(ptr->longitude);
+	pkg_free(ptr->latitude);
+	pkg_free(ptr);
+}
+
+/*
+ * lost_free_string(ptr)
+ * frees and resets a string
+ */
+void lost_free_string(str *string)
+{
+	str ptr = *string;
+
+	if(ptr.s) {
+		pkg_free(ptr.s);
+		ptr.s = NULL;
+		ptr.len = 0;
+	}
+}
+
+/*
+ * lost_new_loc(urn)
+ * creates a new location object in private memory and returns a pointer
+ */
+p_loc_t lost_new_loc(str rurn)
+{
+	s_loc_t *ptr = NULL;;
+	char *id = NULL;
+	char *urn = NULL;
+
+	ptr = (s_loc_t *)pkg_malloc(sizeof(s_loc_t));
+	if(ptr == NULL) {
+		goto err;
+	}
+
+	id = (char *)pkg_malloc(RANDSTRSIZE * sizeof(char) + 1);
+	if(id == NULL) {
+		pkg_free(ptr);
+		goto err;
+	}
+
+	urn = (char *)pkg_malloc(rurn.len + 1);
+	if(urn == NULL) {
+		pkg_free(ptr);
+		pkg_free(id);
+		goto err;
+	}
+
+	memset(urn, 0, rurn.len + 1);
+	memcpy(urn, rurn.s, rurn.len);
+	urn[rurn.len] = '\0';
+
+	lost_rand_str(id, RANDSTRSIZE);
+
+	ptr->identity = id;
+	ptr->urn = urn;
+	ptr->longitude = NULL;
+	ptr->latitude = NULL;
+	ptr->radius = 0;
+	ptr->recursive = 0;
+
+	return ptr;
+
+err:	
+	LM_ERR("no more private memory\n");
+	return NULL;
+}
+
+/*
+ * lost_get_content(node, name, lgth)
+ * gets a nodes "name" content and returns string allocated in private memory
+ */
+char *lost_get_content(xmlNodePtr node, const char *name, int *lgth)
+{
+	xmlNodePtr cur = node;
+	char *content;
+	char *cnt = NULL;
+	int len;
+
+	*lgth = 0;
+	content = xmlNodeGetNodeContentByName(cur, name, NULL);
+	if (content == NULL) {
+		LM_ERR("could not get XML node content\n");
+		return cnt;
+	} else {
+		len = strlen(content);
+		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
+		if(cnt == NULL) {
+			LM_ERR("no more private memory\n");
+			xmlFree(content);
+			return cnt;
+		}
+		memset(cnt, 0, len + 1);
+		memcpy(cnt, content, len);
+		cnt[len] = '\0';
+	}
+
+	xmlFree(content);
+	*lgth = strlen(cnt);
+
+	return cnt;
+}
+
+/*
+ * lost_get_property(node, name, lgth)
+ * gets a nodes property "name" and returns string allocated in private memory
+ */
+char *lost_get_property(xmlNodePtr node, const char *name, int *lgth)
+{
+	xmlNodePtr cur = node;
+	char *content;
+	char *cnt = NULL;
+	int len;
+
+	*lgth = 0;
+	content = xmlNodeGetAttrContentByName(cur, name);
+	if (content == NULL) {
+		LM_ERR("could not get XML node content\n");
+		return cnt;
+	} else {
+		len = strlen(content);
+		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
+		if(cnt == NULL) {
+			LM_ERR("no more private memory\n");
+			xmlFree(content);
+			return cnt;
+		}
+		memset(cnt, 0, len + 1);
+		memcpy(cnt, content, len);
+		cnt[len] = '\0';
+	}
+
+	xmlFree(content);
+	*lgth = strlen(cnt);
+
+	return cnt;
+}
+
+/*
+ * lost_get_childname(name, lgth)
+ * gets a nodes child name and returns string allocated in private memory
+ */
+char *lost_get_childname(xmlNodePtr node, const char *name, int *lgth)
+{
+	xmlNodePtr cur = node;
+	xmlNodePtr parent = NULL;
+	xmlNodePtr child = NULL;
+	char *cnt = NULL;
+	int len;
+
+	*lgth = 0;
+	parent = xmlNodeGetNodeByName(cur, name, NULL);
+	child = parent->children;
+
+	if(child) {
+		len = strlen((char *)child->name);
+		cnt = (char *)pkg_malloc((len + 1) * sizeof(char));
+		if(cnt == NULL) {
+			LM_ERR("no more private memory\n");
+			return cnt;
+		}
+
+		memset(cnt, 0, len + 1);
+		memcpy(cnt, child->name, len);
+		cnt[len] = '\0';
+
+		*lgth = strlen(cnt);
+	}
+	return cnt;
+}
+
+/*
+ * lost_get_geolocation_header(msg, lgth)
+ * gets the Geolocation header value and returns string allocated in
+ * private memory
+ */
+char *lost_get_geolocation_header(struct sip_msg *msg, int *lgth)
+{
+	struct hdr_field *hf;
+	char *res = NULL;
+
+	*lgth = 0;
+
+	if(parse_headers(msg, HDR_EOH_F, 0) == -1) {
+		LM_ERR("failed to parse geolocation header\n");
+		return res;
+	}
+
+	for(hf = msg->headers; hf; hf = hf->next) {
+		if((hf->type == HDR_OTHER_T)
+				&& (hf->name.len == LOST_GEOLOC_HEADER_SIZE - 2)) {
+			/* possible hit */
+			if(strncasecmp(
+					   hf->name.s, LOST_GEOLOC_HEADER, LOST_GEOLOC_HEADER_SIZE)
+					== 0) {
+
+				res = (char *)pkg_malloc((hf->body.len + 1) * sizeof(char));
+				if(res == NULL) {
+					LM_ERR("no more private memory\n");
+					return res;
+				} else {
+					memset(res, 0, hf->body.len + 1);
+					memcpy(res, hf->body.s, hf->body.len + 1);
+					res[hf->body.len] = '\0';
+
+					*lgth = strlen(res);
+				}
+			} else {
+				LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
+						hf->body.len);
+			}
+			break;
+		}
+	}
+	return res;
+}
+
+/*
+ * lost_get_pai_header(msg, lgth)
+ * gets the P-A-I header value and returns string allocated in
+ * private memory
+ */
+char *lost_get_pai_header(struct sip_msg *msg, int *lgth)
+{
+	struct hdr_field *hf;
+	to_body_t *pai_body;
+	char *res = NULL;
+
+	*lgth = 0;
+
+	if (parse_headers(msg, HDR_PAI_F, 0) == -1) {
+		LM_ERR("could not parse P-A-I header\n");
+		return res;
+	}
+
+	for(hf = msg->headers; hf; hf = hf->next) {
+		if((hf->type == HDR_PAI_T)
+				&& (hf->name.len == LOST_PAI_HEADER_SIZE - 2)) {
+			/* possible hit */
+			if(strncasecmp(hf->name.s, LOST_PAI_HEADER, LOST_PAI_HEADER_SIZE)
+					== 0) {
+
+				LM_DBG("P-A-I body:  [%.*s]\n", hf->body.len, hf->body.s);
+
+				/* first, get some memory */
+				pai_body = pkg_malloc(sizeof(to_body_t));
+				if (pai_body == NULL) {
+					LM_ERR("no more private memory\n");
+					return res;
+				}
+				/* parse P-A-I body */
+				memset(pai_body, 0, sizeof(to_body_t));
+				parse_to(hf->body.s, hf->body.s + hf->body.len + 1, pai_body);
+				if (pai_body->error == PARSE_ERROR) {
+					LM_ERR("bad P-A-I header\n");
+					pkg_free(pai_body);
+					return res;
+				}
+				if (pai_body->error == PARSE_OK) {
+					res = (char *)pkg_malloc((pai_body->uri.len + 1) * sizeof(char));
+					if(res == NULL) {
+						LM_ERR("no more private memory\n");
+						pkg_free(pai_body);
+						return res;
+					} else {
+						memset(res, 0, pai_body->uri.len + 1);
+						memcpy(res, pai_body->uri.s, pai_body->uri.len + 1);
+						res[pai_body->uri.len] = '\0';
+						pkg_free(pai_body);
+
+						*lgth = strlen(res);
+					}
+				}
+			} else {
+				LM_ERR("header '%.*s' length %d\n", hf->body.len, hf->body.s,
+						hf->body.len);
+			}
+			break;
+		}
+	}
+	return res;
+}
+
+/*
+ * lost_get_from_header(msg, lgth)
+ * gets the From header value and returns string allocated in
+ * private memory
+ */
+char *lost_get_from_header(struct sip_msg *msg, int *lgth)
+{
+	to_body_t *f_body;
+	char *res = NULL;
+
+	*lgth = 0;
+
+	if(parse_headers(msg, HDR_FROM_F, 0) == -1) {
+		LM_ERR("failed to parse From header\n");
+		return res;
+	}
+
+	if(msg->from == NULL || get_from(msg) == NULL) {
+		LM_ERR("From header not found\n");
+		return res;
+	}
+	f_body = get_from(msg);
+
+	LM_DBG("From body:  [%.*s]\n", f_body->body.len, f_body->body.s);
+
+	res = (char *)pkg_malloc((f_body->uri.len + 1) * sizeof(char));
+	if(res == NULL) {
+		LM_ERR("no more private memory\n");
+		return res;
+	} else {
+		memset(res, 0, f_body->uri.len + 1);
+		memcpy(res, f_body->uri.s, f_body->uri.len + 1);
+		res[f_body->uri.len] = '\0';
+
+		*lgth = strlen(res);
+	}
+	return res;
+}
+
+/*
+ * lost_parse_location_info(node, loc)
+ * parses locationResponse and writes results to location object
+ */
+int lost_parse_location_info(xmlNodePtr node, p_loc_t loc)
+{
+	char bufLat[BUFSIZE];
+	char bufLon[BUFSIZE];
+	int iRadius;
+	char *content = NULL;
+	int ret = -1;
+
+	xmlNodePtr cur = node;
+
+	content = xmlNodeGetNodeContentByName(cur, "pos", NULL);
+	if(content) {
+		sscanf(content, "%s %s", bufLat, bufLon);
+
+		loc->latitude = (char *)pkg_malloc(strlen((char *)bufLat) + 1);
+		snprintf(loc->latitude, strlen((char *)bufLat) + 1, "%s",
+				(char *)bufLat);
+
+		loc->longitude = (char *)pkg_malloc(strlen((char *)bufLon) + 1);
+		snprintf(loc->longitude, strlen((char *)bufLon) + 1, "%s",
+				(char *)bufLon);
+
+		loc->radius = 0;
+		ret = 0;
+	}
+
+	content = xmlNodeGetNodeContentByName(cur, "radius", NULL);
+	if(content) {
+		iRadius = 0;
+
+		sscanf(content, "%d", &iRadius);
+		loc->radius = iRadius;
+		ret = 0;
+	}
+
+	if(ret < 0) {
+		LM_ERR("could not parse location information\n");
+	}
+	return ret;
+}
+
+/*
+ * lost_held_location_request(id, lgth)
+ * assembles and returns locationRequest string (allocated in private memory)
+ */
+char *lost_held_location_request(char *id, int *lgth)
+{
+	int buffersize = 0;
+
+	char buf[BUFSIZE];
+	char *doc = NULL;
+
+	xmlChar *xmlbuff = NULL;
+	xmlDocPtr request = NULL;
+
+	xmlNodePtr ptrLocationRequest = NULL;
+	xmlNodePtr ptrLocationType = NULL;
+	xmlNodePtr ptrDevice = NULL;
+
+	xmlKeepBlanksDefault(1);
+	*lgth = 0;
+
+	/*
+https://tools.ietf.org/html/rfc6155
+
+<?xml version="1.0" encoding="UTF-8"?>
+<locationRequest xmlns="urn:ietf:params:xml:ns:geopriv:held" responseTime="8">
+    <locationType exact="true">geodetic locationURI</locationType>
+    <device xmlns="urn:ietf:params:xml:ns:geopriv:held:id">
+        <uri>sip:[email protected]</uri>
+    </device>
+</locationRequest>
+*/
+
+	/* create request */
+	request = xmlNewDoc(BAD_CAST "1.0");
+	if(!request) {
+		LM_ERR("locationRequest xmlNewDoc() failed\n");
+		return doc;
+	}
+	/* locationRequest - element */
+	ptrLocationRequest = xmlNewNode(NULL, BAD_CAST "locationRequest");
+	if(!ptrLocationRequest) {
+		LM_ERR("locationRequest xmlNewNode() failed\n");
+		xmlFreeDoc(request);
+		return doc;
+	}
+	xmlDocSetRootElement(request, ptrLocationRequest);
+	/* properties */
+	xmlNewProp(ptrLocationRequest, BAD_CAST "xmlns",
+			BAD_CAST "urn:ietf:params:xml:ns:geopriv:held");
+	xmlNewProp(ptrLocationRequest, BAD_CAST "responseTime", BAD_CAST "8");
+	/* locationType - element */
+	ptrLocationType = xmlNewChild(ptrLocationRequest, NULL,
+			BAD_CAST "locationType", BAD_CAST "geodetic locationURI");
+	/* properties */
+	xmlNewProp(ptrLocationType, BAD_CAST "exact", BAD_CAST "false");
+	/* device - element */
+	ptrDevice = xmlNewChild(ptrLocationRequest, NULL, BAD_CAST "device", NULL);
+	if(!ptrDevice) {
+		LM_ERR("locationRequest xmlNewChild() failed\n");
+		xmlFreeDoc(request);
+		return doc;
+	}
+	/* properties */
+	xmlNewProp(ptrDevice, BAD_CAST "xmlns",
+			BAD_CAST "urn:ietf:params:xml:ns:geopriv:held:id");
+	/* uri - element */
+	snprintf(buf, BUFSIZE, "%s", id);
+	xmlNewChild(ptrDevice, NULL, BAD_CAST "uri", BAD_CAST buf);
+
+	xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
+	if(!xmlbuff) {
+		LM_ERR("locationRequest xmlDocDumpFormatMemory() failed\n");
+		xmlFreeDoc(request);
+		return doc;
+	}
+
+	doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
+	if(doc == NULL) {
+		LM_ERR("no more private memory\n");
+		xmlFree(xmlbuff);
+		xmlFreeDoc(request);
+		return doc;
+	}
+
+	memset(doc, 0, buffersize + 1);
+	memcpy(doc, (char *)xmlbuff, buffersize);
+	doc[buffersize] = '\0';
+
+	*lgth = strlen(doc);
+
+	xmlFree(xmlbuff);
+	xmlFreeDoc(request);
+
+	return doc;
+}
+
+/*
+ * lost_find_service_request(loc, lgth)
+ * assembles and returns findService request string (allocated in private memory)
+ */
+char *lost_find_service_request(p_loc_t loc, int *lgth)
+{
+	int buffersize = 0;
+
+	char buf[BUFSIZE];
+	char *doc = NULL;
+
+	xmlChar *xmlbuff = NULL;
+	xmlDocPtr request = NULL;
+
+	xmlNodePtr ptrFindService = NULL;
+	xmlNodePtr ptrLocation = NULL;
+	xmlNodePtr ptrPoint = NULL;
+	xmlNodePtr ptrCircle = NULL;
+	xmlNodePtr ptrRadius = NULL;
+
+	xmlKeepBlanksDefault(1);
+	*lgth = 0;
+
+	/*
+https://tools.ietf.org/html/rfc5222
+
+<?xml version="1.0" encoding="UTF-8"?>
+<findService
+ xmlns="urn:ietf:params:xml:ns:lost1"
+ xmlns:p2="http://www.opengis.net/gml"
+ serviceBoundary="value"
+ recursive="true">
+    <location id="6020688f1ce1896d" profile="geodetic-2d">
+        <p2:Point id="point1" srsName="urn:ogc:def:crs:EPSG::4326">
+            <p2:pos>37.775 -122.422</p2:pos>
+        </p2:Point>
+    </location>
+    <service>urn:service:sos.police</service>
+</findService>
+ */
+	/* create request */
+	request = xmlNewDoc(BAD_CAST "1.0");
+	if(!request) {
+		LM_ERR("findService request xmlNewDoc() failed\n");
+		return doc;
+	}
+	/* findService - element */
+	ptrFindService = xmlNewNode(NULL, BAD_CAST "findService");
+	if(!ptrFindService) {
+		LM_ERR("findService xmlNewNode() failed\n");
+		xmlFreeDoc(request);
+		return doc;
+	}
+	xmlDocSetRootElement(request, ptrFindService);
+	/* set properties */
+	xmlNewProp(ptrFindService, BAD_CAST "xmlns",
+			BAD_CAST "urn:ietf:params:xml:ns:lost1");
+	xmlNewProp(ptrFindService, BAD_CAST "xmlns:p2",
+			BAD_CAST "http://www.opengis.net/gml");
+	xmlNewProp(
+			ptrFindService, BAD_CAST "serviceBoundary", BAD_CAST "reference");
+	xmlNewProp(ptrFindService, BAD_CAST "recursive", BAD_CAST "true");
+	/* location - element */
+	ptrLocation = xmlNewChild(ptrFindService, NULL, BAD_CAST "location", NULL);
+	xmlNewProp(ptrLocation, BAD_CAST "id", BAD_CAST loc->identity);
+	xmlNewProp(ptrLocation, BAD_CAST "profile", BAD_CAST "geodetic-2d");
+	/* set pos */
+	snprintf(buf, BUFSIZE, "%s %s", loc->latitude, loc->longitude);
+	/* Point */
+	if(loc->radius == 0) {
+		ptrPoint = xmlNewChild(ptrLocation, NULL, BAD_CAST "Point", NULL);
+		if(!ptrPoint) {
+			LM_ERR("locationRequest xmlNewChild() failed\n");
+			xmlFreeDoc(request);
+			return doc;
+		}
+		xmlNewProp(ptrPoint, BAD_CAST "xmlns",
+				BAD_CAST "http://www.opengis.net/gml");
+		xmlNewProp(ptrPoint, BAD_CAST "srsName",
+				BAD_CAST "urn:ogc:def:crs:EPSG::4326");
+		/* pos */
+		xmlNewChild(ptrPoint, NULL, BAD_CAST "pos", BAD_CAST buf);
+	} else {
+		/* circle - Point */
+		ptrCircle = xmlNewChild(ptrLocation, NULL, BAD_CAST "gs:Circle", NULL);
+		if(!ptrCircle) {
+			LM_ERR("locationRequest xmlNewChild() failed\n");
+			xmlFreeDoc(request);
+			return doc;
+		}
+		xmlNewProp(ptrCircle, BAD_CAST "xmlns:gml",
+				BAD_CAST "http://www.opengis.net/gml");
+		xmlNewProp(ptrCircle, BAD_CAST "xmlns:gs",
+				BAD_CAST "http://www.opengis.net/pidflo/1.0");
+		xmlNewProp(ptrCircle, BAD_CAST "srsName",
+				BAD_CAST "urn:ogc:def:crs:EPSG::4326");
+		/* pos */
+		xmlNewChild(ptrCircle, NULL, BAD_CAST "gml:pos", BAD_CAST buf);
+		/* circle - radius */
+		snprintf(buf, BUFSIZE, "%d", loc->radius);
+		ptrRadius = xmlNewChild(
+				ptrCircle, NULL, BAD_CAST "gs:radius", BAD_CAST buf);
+		if(!ptrRadius) {
+			LM_ERR("locationRequest xmlNewChild() failed\n");
+			xmlFreeDoc(request);
+			return doc;
+		}
+		xmlNewProp(ptrRadius, BAD_CAST "uom",
+				BAD_CAST "urn:ogc:def:uom:EPSG::9001");
+	}
+	/* service - element */
+	snprintf(buf, BUFSIZE, "%s", loc->urn);
+	xmlNewChild(ptrFindService, NULL, BAD_CAST "service", BAD_CAST buf);
+
+	xmlDocDumpFormatMemory(request, &xmlbuff, &buffersize, 0);
+	if(!xmlbuff) {
+		LM_ERR("findService request xmlDocDumpFormatMemory() failed\n");
+		xmlFreeDoc(request);
+		return doc;
+	}
+
+	doc = (char *)pkg_malloc((buffersize + 1) * sizeof(char));
+	if(doc == NULL) {
+		LM_ERR("no more private memory\n");
+		xmlFree(xmlbuff);
+		xmlFreeDoc(request);
+		return doc;
+	}
+
+	memset(doc, 0, buffersize + 1);
+	memcpy(doc, (char *)xmlbuff, buffersize);
+	doc[buffersize] = '\0';
+
+	*lgth = strlen(doc);
+
+	xmlFree(xmlbuff);
+	xmlFreeDoc(request);
+
+	return doc;
+}

+ 76 - 76
src/modules/lost/utilities.h

@@ -1,76 +1,76 @@
-/*
- * lost module utility functions
- *
- * Copyright (C) 2019 Wolfgang Kampichler
- * DEC112, FREQUENTIS AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * Kamailio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*!
- * \file
- * \brief Kamailio lost :: functions
- * \ingroup lost
- * Module: \ref lost
- */
-
-#ifndef LOST_UTILITIES_H
-#define LOST_UTILITIES_H
-
-#define LOST_GEOLOC_HEADER "Geolocation: "
-#define LOST_GEOLOC_HEADER_SIZE strlen(LOST_GEOLOC_HEADER)
-#define LOST_PAI_HEADER "P-Asserted-Identity: "
-#define LOST_PAI_HEADER_SIZE strlen(LOST_PAI_HEADER)
-
-#define BUFSIZE 128	/* temporary buffer to hold geolocation */
-#define RANDSTRSIZE 16 /* temporary id in a findService request */
-
-#define LOSTFREE(x) pkg_free(x); x = NULL;
-
-typedef struct
-{
-	char *identity;
-	char *urn;
-	char *longitude;
-	char *latitude;
-	char *uri;
-	char *ref;
-	int radius;
-	int recursive;
-} s_loc_t, *p_loc_t;
-
-void lost_rand_str(char *, size_t);
-void lost_free_loc(p_loc_t);
-void lost_free_string(str *);
-
-int lost_get_location_object(p_loc_t, xmlDocPtr, xmlNodePtr);
-int lost_parse_location_info(xmlNodePtr node, p_loc_t loc);
-
-char *lost_find_service_request(p_loc_t, int *);
-char *lost_held_location_request(char *, int *);
-char *lost_get_content(xmlNodePtr, const char *, int *);
-char *lost_get_property(xmlNodePtr, const char *, int *);
-char *lost_get_geolocation_header(struct sip_msg *, int *);
-char *lost_get_from_header(struct sip_msg *, int *);
-char *lost_get_pai_header(struct sip_msg *, int *);
-char *lost_get_childname(xmlNodePtr, const char *, int *);
-char *lost_trim_content(char *, int *);
-
-p_loc_t lost_new_loc(str);
-
-#endif
+/*
+ * lost module utility functions
+ *
+ * Copyright (C) 2019 Wolfgang Kampichler
+ * DEC112, FREQUENTIS AG
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+/*!
+ * \file
+ * \brief Kamailio lost :: functions
+ * \ingroup lost
+ * Module: \ref lost
+ */
+
+#ifndef LOST_UTILITIES_H
+#define LOST_UTILITIES_H
+
+#define LOST_GEOLOC_HEADER "Geolocation: "
+#define LOST_GEOLOC_HEADER_SIZE strlen(LOST_GEOLOC_HEADER)
+#define LOST_PAI_HEADER "P-Asserted-Identity: "
+#define LOST_PAI_HEADER_SIZE strlen(LOST_PAI_HEADER)
+
+#define BUFSIZE 128	/* temporary buffer to hold geolocation */
+#define RANDSTRSIZE 16 /* temporary id in a findService request */
+
+#define LOSTFREE(x) pkg_free(x); x = NULL;
+
+typedef struct
+{
+	char *identity;
+	char *urn;
+	char *longitude;
+	char *latitude;
+	char *uri;
+	char *ref;
+	int radius;
+	int recursive;
+} s_loc_t, *p_loc_t;
+
+void lost_rand_str(char *, size_t);
+void lost_free_loc(p_loc_t);
+void lost_free_string(str *);
+
+int lost_get_location_object(p_loc_t, xmlDocPtr, xmlNodePtr);
+int lost_parse_location_info(xmlNodePtr node, p_loc_t loc);
+
+char *lost_find_service_request(p_loc_t, int *);
+char *lost_held_location_request(char *, int *);
+char *lost_get_content(xmlNodePtr, const char *, int *);
+char *lost_get_property(xmlNodePtr, const char *, int *);
+char *lost_get_geolocation_header(struct sip_msg *, int *);
+char *lost_get_from_header(struct sip_msg *, int *);
+char *lost_get_pai_header(struct sip_msg *, int *);
+char *lost_get_childname(xmlNodePtr, const char *, int *);
+char *lost_trim_content(char *, int *);
+
+p_loc_t lost_new_loc(str);
+
+#endif