diff --git a/src/modules/lost/functions.c b/src/modules/lost/functions.c index d38f9bf66ea..9f042650ce9 100644 --- a/src/modules/lost/functions.c +++ b/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; +} diff --git a/src/modules/lost/functions.h b/src/modules/lost/functions.h index 52b8b1b21e0..7267af8a641 100755 --- a/src/modules/lost/functions.h +++ b/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 diff --git a/src/modules/lost/lost.c b/src/modules/lost/lost.c index 5bdba54eb2e..ae5da276af3 100644 --- a/src/modules/lost/lost.c +++ b/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); +} diff --git a/src/modules/lost/pidf.c b/src/modules/lost/pidf.c index c018313bdc0..25302cd5e81 100755 --- a/src/modules/lost/pidf.c +++ b/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 - -#undef _XOPEN_SOURCE -#undef _XOPEN_SOURCE_EXTENDED - -#include -#include -#include - -#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 + +#undef _XOPEN_SOURCE +#undef _XOPEN_SOURCE_EXTENDED + +#include +#include +#include + +#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; +} diff --git a/src/modules/lost/pidf.h b/src/modules/lost/pidf.h index 78c5d84dcf6..c0b1e4b89e5 100755 --- a/src/modules/lost/pidf.h +++ b/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 - -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 + +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 diff --git a/src/modules/lost/utilities.c b/src/modules/lost/utilities.c index e40d5d4ac22..f32de7f2d5d 100644 --- a/src/modules/lost/utilities.c +++ b/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 -#include -#include -#include -#include - -#include -#include -#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 - - - - geodetic locationURI - - sip:user@example.net - - -*/ - - /* 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 - - - - - - 37.775 -122.422 - - - urn:service:sos.police - - */ - /* 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 +#include +#include +#include +#include + +#include +#include +#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 + + + + geodetic locationURI + + sip:user@example.net + + +*/ + + /* 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 + + + + + + 37.775 -122.422 + + + urn:service:sos.police + + */ + /* 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; +} diff --git a/src/modules/lost/utilities.h b/src/modules/lost/utilities.h index 68722148b21..cb8f5292824 100644 --- a/src/modules/lost/utilities.h +++ b/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