Browse code

Merge 5f1959cd42ff925009dd9e0fdd87f9d0487ec4fe into 42d90d3665256c3d38945193b0a14ad199221bc6

Wolfgang Kampichler authored on 08/04/2021 19:32:05 • GitHub committed on 08/04/2021 19:32:05
Showing 17 changed files
... ...
@@ -475,8 +475,9 @@ int part_multipart_headers_cmp (char *buffer,
475 475
 					;
476 476
 				}
477 477
 			} else {
478
+				/* Nothing matched */
478 479
 				error = -9;
479
-				error_msg = "We reached the end of the buffer";
480
+				error_msg = "Unsuccessfully reached the end of the buffer";
480 481
 			}
481 482
 			found = found_content_type * found_content_id * found_content_length;
482 483
 			if ((!found) && (!error)) {
... ...
@@ -504,7 +505,7 @@ int part_multipart_headers_cmp (char *buffer,
504 505
 	}
505 506
 
506 507
 	if (error < 0) {
507
-		if(error == -2) {
508
+		if ((error == -2) || (error == -9)) {
508 509
 			LM_DBG("result code: \"%i\" text: \"%s\".\n", error, error_msg);
509 510
 		} else {
510 511
 			LM_ERR("error code: \"%i\" error text: \"%s\".\n", error, error_msg);
... ...
@@ -31,6 +31,7 @@ int bind_httpc_api(httpc_api_t *api)
31 31
 	}
32 32
 	api->http_connect = curl_con_query_url;
33 33
 	api->http_client_query = http_client_query;
34
+	api->http_client_query_c = http_client_query_c;
34 35
 	api->http_connection_exists = http_connection_exists;
35 36
 	api->http_get_content_type = http_get_content_type;
36 37
 
... ...
@@ -37,6 +37,8 @@ typedef int (*httpcapi_httpconnect_f)(struct sip_msg *msg,
37 37
 		const char *contenttype, const str *_post);
38 38
 typedef int (*httpcapi_httpquery_f)(
39 39
 		struct sip_msg *_m, char *_url, str *_dst, char *_post, char *_hdrs);
40
+typedef int (*httpcapi_httpquery_c_f)(
41
+		struct sip_msg *_m, char *_url, str *_dst, char *_post, char *_ctype, char *_hdrs);
40 42
 typedef int (*httpcapi_curlcon_exists_f)(str *_name);
41 43
 typedef char *(*httpcapi_res_content_type_f)(const str *_name);
42 44
 
... ...
@@ -45,6 +47,7 @@ typedef struct httpc_api
45 47
 {
46 48
 	httpcapi_httpconnect_f http_connect;
47 49
 	httpcapi_httpquery_f http_client_query;
50
+	httpcapi_httpquery_c_f http_client_query_c;
48 51
 	httpcapi_curlcon_exists_f http_connection_exists;
49 52
 	httpcapi_res_content_type_f http_get_content_type;
50 53
 } httpc_api_t;
... ...
@@ -637,10 +637,10 @@ int curl_con_query_url(struct sip_msg *_m, const str *connection,
637 637
 /*!
638 638
  * Performs http request and saves possible result (first body line of reply)
639 639
  * to pvar.
640
- * This is the same http_query as used to be in the utils module.
640
+ * Similar to http_client_request but supports setting a content type attribute.
641 641
  */
642
-int http_client_request(
643
-		sip_msg_t *_m, char *_url, str *_dst, char *_body, char *_hdrs, char *_met)
642
+int http_client_request_c(sip_msg_t *_m, char *_url, str *_dst, char *_body,
643
+		char* _ctype, char *_hdrs, char *_met)
644 644
 {
645 645
 	int res;
646 646
 	curl_query_t query_params;
... ...
@@ -649,7 +649,7 @@ int http_client_request(
649 649
 	query_params.username = NULL;
650 650
 	query_params.secret = NULL;
651 651
 	query_params.authmethod = default_authmethod;
652
-	query_params.contenttype = NULL;
652
+	query_params.contenttype = _ctype;
653 653
 	query_params.hdrs = _hdrs;
654 654
 	query_params.post = _body;
655 655
 	query_params.clientcert = NULL;
... ...
@@ -691,6 +691,17 @@ int http_client_request(
691 691
 	return res;
692 692
 }
693 693
 
694
+/*!
695
+ * Performs http request and saves possible result (first body line of reply)
696
+ * to pvar.
697
+ * This is the same http_query as used to be in the utils module.
698
+ */
699
+int http_client_request(
700
+		sip_msg_t *_m, char *_url, str *_dst, char *_body, char *_hdrs, char *_met)
701
+{
702
+	return http_client_request_c(_m, _url, _dst, _body, NULL, _hdrs, _met);
703
+}
704
+
694 705
 /*!
695 706
  * Performs http_query and saves possible result (first body line of reply)
696 707
  * to pvar.
... ...
@@ -702,6 +713,17 @@ int http_client_query(
702 713
 	return http_client_request(_m, _url, _dst, _post, _hdrs, 0);
703 714
 }
704 715
 
716
+/*!
717
+ * Performs http_query and saves possible result (first body line of reply)
718
+ * to pvar.
719
+ * This is the same http_query as used to be in the utils module.
720
+ */
721
+int http_client_query_c(
722
+		struct sip_msg *_m, char *_url, str *_dst, char *_post, char *_ctype, char *_hdrs)
723
+{
724
+	return http_client_request_c(_m, _url, _dst, _post, _ctype, _hdrs, 0);
725
+}
726
+
705 727
 char *http_get_content_type(const str *connection)
706 728
 {
707 729
 	curl_con_t *conn = NULL;
... ...
@@ -52,6 +52,13 @@ int curl_get_redirect(struct sip_msg *_m, const str *connection, str *result);
52 52
 int http_client_query(
53 53
 		struct sip_msg *_m, char *_url, str *_dst, char *_post, char *_hdrs);
54 54
 
55
+/*
56
+ * Performs http_client_query and saves possible result
57
+ * (first body line of reply) to pvar.
58
+ */
59
+int http_client_query_c(
60
+		struct sip_msg *_m, char *_url, str *_dst, char *_post, char *_ctype, char *_hdrs);
61
+
55 62
 /*
56 63
  * Performs http request and saves possible result
57 64
  * (first body line of reply) to pvar.
... ...
@@ -59,7 +66,12 @@ int http_client_query(
59 66
 int http_client_request(
60 67
 		sip_msg_t *_m, char *_url, str *_dst, char *_body, char *_hdrs, char *_met);
61 68
 
62
-
69
+/*
70
+ * Performs http request and saves possible result
71
+ * (first body line of reply) to pvar.
72
+ */
73
+int http_client_request_c(
74
+		sip_msg_t *_m, char *_url, str *_dst, char *_body, char *_ctype, char *_hdrs, char *_met);
63 75
 
64 76
 
65 77
 char *http_get_content_type(const str *connection);
... ...
@@ -25,7 +25,7 @@
25 25
 	    </editor>
26 26
 	</authorgroup>
27 27
 	<copyright>
28
-		<year>2018-2020</year>
28
+		<year>2018-2021</year>
29 29
 		<holder>Wolfgang Kampichler</holder>
30 30
 	</copyright>
31 31
 	</bookinfo>
... ...
@@ -39,6 +39,13 @@
39 39
         location via HTTP(S).
40 40
         </para>
41 41
         <para>
42
+        The function lost_held_dereference allows &kamailio; to assemble a HELD
43
+        dereference request as defined in RFC6155
44
+        (<ulink url="https://tools.ietf.org/html/rfc6753"/>) to dereference location
45
+        information represented as PIDF-LO for a given URL. Required parameters are
46
+        an URL, responseTime, and responseType. The response is represented as PIDF-LO.
47
+        </para>
48
+        <para>
42 49
         The function lost_query allows &kamailio; to assemble a LOST
43 50
         findService request  as defined in RFC5222
44 51
         (<ulink url="https://tools.ietf.org/html/rfc5255"/>) to query 
... ...
@@ -126,17 +133,18 @@
126 133
             prepared to wait for a response.
127 134
             </para>
128 135
             <para>
129
-            The value is expressed as a non-negative integer in units of
130
-            milliseconds. Note: The time value is indicative only. 
136
+            The value is expressed as integer, either -1 'emergencyDispatch', 0 'emergencyRouting',
137
+            a non-negative integer (>0) in units of milliseconds.
138
+            Note: The time value is indicative only. 
131 139
             </para>
132 140
             <para>
133
-            Default: 0 (response time not set)
141
+            Default: 0 ('emergencyRouting')
134 142
             </para>
135 143
             <example>
136 144
             <title>Set <varname>response_time</varname> parameter</title>
137 145
                 <programlisting format="linespecific">
138 146
     ...
139
-    modparam("lost", "response_time", 5000)
147
+    modparam("lost", "response_time", 0)
140 148
     ...
141 149
                 </programlisting>
142 150
             </example>
... ...
@@ -168,7 +176,58 @@
168 176
             <title>Set <varname>location_type</varname> parameter</title>
169 177
                 <programlisting format="linespecific">
170 178
     ...
171
-    modparam("lost", "location_type, "civic geodetic locationURI")
179
+    modparam("lost", "location_type", "civic geodetic locationURI")
180
+    ...
181
+                </programlisting>
182
+            </example>
183
+        </section>
184
+        <section id="lost.p.post_request">
185
+            <title><varname>post_request</varname> (int)</title>
186
+            <para>
187
+            Dereferencing the location can be done using either the HTTP GET or POST method. This parameter
188
+            globally defines whether only HTTP POST method should be used. Values are 0 (GET) or 1 (POST).
189
+            </para>
190
+            <para>
191
+            Default: 0 (GET)
192
+            </para>
193
+            <example>
194
+            <title>Set <varname>post_request</varname> parameter</title>
195
+                <programlisting format="linespecific">
196
+    ...
197
+    modparam("lost", "post_request", 1)
198
+    ...
199
+                </programlisting>
200
+            </example>
201
+        </section>
202
+        <section id="lost.p.location_profile">
203
+            <title><varname>location_profile</varname> (int)</title>
204
+            <para>
205
+            A Presence Information Data Format Location Object (PIDF-LO) may contain geodetic or civic location
206
+            profile or combinations. A LoST <emphasis>findService</emphasis> contains only one location, which
207
+            is selected via this parameter as follows:
208
+            </para>
209
+			<itemizedlist>
210
+                <listitem><para>
211
+                    <emphasis>0</emphasis> - takes the first location of any type
212
+                </para></listitem>
213
+                <listitem><para>
214
+                    <emphasis>1</emphasis> - takes the last last of any type
215
+                </para></listitem>
216
+                <listitem><para>
217
+                    <emphasis>2</emphasis> - takes the first geodetic location
218
+                </para></listitem>
219
+                <listitem><para>
220
+                    <emphasis>3</emphasis> - takes the first civic location
221
+                </para></listitem>
222
+            </itemizedlist>
223
+            <para>
224
+            Default: 0 (first).
225
+            </para>
226
+            <example>
227
+            <title>Set <varname>location_profile</varname> parameter</title>
228
+                <programlisting format="linespecific">
229
+    ...
230
+    modparam("lost", "location_profile, 2)
172 231
     ...
173 232
                 </programlisting>
174 233
             </example>
... ...
@@ -225,6 +284,55 @@
225 284
                 <programlisting format="linespecific">
226 285
     ...
227 286
     modparam("lost", "geoheader_order", 0)
287
+    ...
288
+                </programlisting>
289
+            </example>
290
+        </section>
291
+        <section id="lost.p.recursion">
292
+            <title><varname>recursion</varname> (int)</title>
293
+            <para>
294
+            A Geolocation header may include a list of locationValues. This
295
+            parameter sets the order of the URI used to retrieve location
296
+            information, either the first element of a certain type or the
297
+            last. Values are 0 (first) or 1 (last).
298
+            </para>
299
+            <para>
300
+            Default: 1 (allowed)
301
+            </para>
302
+            <example>
303
+            <title>Set <varname>recursion</varname> parameter</title>
304
+                <programlisting format="linespecific">
305
+    ...
306
+    modparam("lost", "recursion", 0)
307
+    ...
308
+                </programlisting>
309
+            </example>
310
+        </section>
311
+        <section id="lost.p.verbose">
312
+            <title><varname>verbose</varname> (int)</title>
313
+            <para>
314
+            Detailed output of LoST findService, redirect or error response as shown below.
315
+            Values are 0 (disabled) or 1 (enabled).
316
+            <programlisting format="linespecific">
317
+    ### LOST expires:   [2031-01-27T14:54:21+00:00]
318
+    ### LOST lastUpdated:       [2021-01-29T14:54:21+00:00]
319
+    ### LOST source:    [ecrf.demo.gridgears.xx]
320
+    ### LOST sourceId:  [06ac5b1c-d6c8-42bd-a667-5d1b90bb3d95]
321
+    ### LOST displayName:       [Polizeinotruf (de)]
322
+    ### LOST serviceNumber:     [112]
323
+    ### LOST service:   [urn:service:sos]
324
+    ### LOST uri:       [sip:112@demo.dec112.xx]
325
+    ### LOST via:       [ecrf.demo.gridgears.xx]
326
+            </programlisting>
327
+            </para>
328
+            <para>
329
+            Default: 0
330
+            </para>
331
+            <example>
332
+            <title>Set <varname>verbose</varname> parameter</title>
333
+                <programlisting format="linespecific">
334
+    ...
335
+    modparam("lost", "verbose", 1)
228 336
     ...
229 337
                 </programlisting>
230 338
             </example>
... ...
@@ -262,7 +370,7 @@
262 370
                     </para></listitem>
263 371
                     <listitem><para>
264 372
 						<emphasis>error</emphasis> - any error code returned in the
265
-                        HELD locationRequest response
373
+                        HELD response
266 374
                     </para></listitem>
267 375
 			    </itemizedlist>
268 376
 			<para>
... ...
@@ -290,6 +398,58 @@ xlog("L_INFO", "HELD locationRequest: Result code $var(res)\nUrl: $var(url)\n$va
290 398
 				</programlisting>
291 399
 			</example>
292 400
 		</section>
401
+		<section id="lost.f.lost_held_dereference">
402
+			<title>
403
+				<function moreinfo="none">lost_held_dereference(url, rtime, rtype, pidf-lo, error)</function>
404
+			</title>
405
+			<para>
406
+			Sends a HELD POST locationRequest to a given URL. Attributes are responseTime and resposeType.
407
+            The <emphasis>locationType</emphasis> property "exact" is set to "false".
408
+	    	</para>
409
+			    <itemizedlist>
410
+                    <listitem><para>
411
+						<emphasis>url</emphasis> - a URL received via Geolocation header to dereference
412
+                        location
413
+                    </para></listitem>
414
+				    <listitem><para>
415
+						<emphasis>rtime</emphasis> - the response time as defined
416
+                        in <xref linkend="lost.p.response_time"/>
417
+				    </para></listitem>
418
+                    <listitem><para>
419
+						<emphasis>rtype</emphasis> - the response type (location) as defined
420
+                        in <xref linkend="lost.p.location_type"/>
421
+                    </para></listitem>
422
+                    <listitem><para>
423
+						<emphasis>pidf-lo</emphasis> - the PIDF-LO returned in the
424
+                        HELD locationRequest response
425
+                    </para></listitem>
426
+                    <listitem><para>
427
+						<emphasis>error</emphasis> - any error code returned in the
428
+                        HELD response
429
+                    </para></listitem>
430
+			    </itemizedlist>
431
+			<para>
432
+			The return value is 200 on success, 400 if an internal error occured, or 500 if an
433
+            error code is returned in the HELD response.
434
+	    	</para>
435
+			<para>
436
+			This function can be used from REQUEST_ROUTE,
437
+			ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE.
438
+			</para>
439
+			<example>
440
+				<title><function>lost_held_dereference()</function> usage</title>
441
+				<programlisting format="linespecific">
442
+...
443
+# HELD location dereference
444
+if ($hdr(Geolocation)=~"^&lt;http.*$") {
445
+    $var(url) = $(hdr(Geolocation){s.select,0,;});
446
+    $var(res) = lost_held_dereference("$(var(url){s.unbracket})", "emergencyDispatch", "civic geodetic", "$var(pidf)", "$var(err)");
447
+    xlog("L_INFO", "HELD location dereference: Result code $var(res)\n$var(pidf)");
448
+...
449
+}
450
+				</programlisting>
451
+			</example>
452
+		</section>
293 453
 		<section id="lost.f.lost_query">
294 454
 			<title>
295 455
 				<function moreinfo="none">lost_query(con, [pidf-lo, urn,] uri, name, error)</function>
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * lost module functions
3 3
  *
4
- * Copyright (C) 2020 Wolfgang Kampichler
4
+ * Copyright (C) 2021 Wolfgang Kampichler
5 5
  * DEC112, FREQUENTIS AG
6 6
  *
7 7
  * This file is part of Kamailio, a free SIP server.
... ...
@@ -44,6 +44,8 @@
44 44
 
45 45
 #include "pidf.h"
46 46
 #include "utilities.h"
47
+#include "response.h"
48
+#include "naptr.h"
47 49
 
48 50
 #define LOST_SUCCESS 200
49 51
 #define LOST_CLIENT_ERROR 400
... ...
@@ -52,12 +54,23 @@
52 54
 #define HELD_DEFAULT_TYPE "geodetic locationURI"
53 55
 #define HELD_DEFAULT_TYPE_LEN (sizeof(HELD_DEFAULT_TYPE) - 1)
54 56
 
57
+#define NAPTR_LOST_SERVICE_HTTP "LoST:http"
58
+#define NAPTR_LOST_SERVICE_HTTPS "LoST:https"
59
+#define NAPTR_LIS_SERVICE_HELD "LIS:HELD"
60
+
61
+#define ACCEPT_HDR                      \
62
+	"Accept: "                          \
63
+	"application/pidf+xml,application/" \
64
+	"held+xml;q=0.5"
65
+
55 66
 extern httpc_api_t httpapi;
56 67
 
57 68
 extern int lost_geoloc_type;
58 69
 extern int lost_geoloc_order;
70
+extern int lost_verbose;
59 71
 extern int held_resp_time;
60 72
 extern int held_exact_type;
73
+extern int held_post_req;
61 74
 extern str held_loc_type;
62 75
 
63 76
 char mtheld[] = "application/held+xml;charset=utf-8";
... ...
@@ -137,7 +150,8 @@ char *lost_held_type(char *type, int *exact, int *lgth)
137 150
 	return ret;
138 151
 
139 152
 err:
140
-	LM_ERR("no more private memory\n");
153
+	PKG_MEM_ERROR;
154
+	/* clean up */
141 155
 	if(ret != NULL) {
142 156
 		pkg_free(ret);
143 157
 	}
... ...
@@ -160,42 +174,67 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
160 174
 	pv_value_t pvurl;
161 175
 	pv_value_t pverr;
162 176
 
163
-	p_held_t held = NULL;
177
+	p_lost_held_t held = NULL;
164 178
 
165 179
 	xmlDocPtr doc = NULL;
166 180
 	xmlNodePtr root = NULL;
167 181
 	xmlNodePtr cur_node = NULL;
168 182
 
169
-	str did = {NULL, 0};
170
-	str que = {NULL, 0};
171
-	str con = {NULL, 0};
172
-	str geo = {NULL, 0};
173
-	str err = {NULL, 0};
174
-	str res = {NULL, 0};
175
-	str idhdr = {NULL, 0};
176
-	str pidfuri = {NULL, 0};
177
-	str rtype = {HELD_DEFAULT_TYPE, HELD_DEFAULT_TYPE_LEN};
178
-
179
-	int curlres = 0;
183
+	str geo = STR_NULL; /* return value geolocation uri */
184
+	str res = STR_NULL; /* return value pidf */
185
+	str err = STR_NULL; /* return value error */
186
+
187
+	str url = STR_NULL;
188
+	str did = STR_NULL;
189
+	str que = STR_NULL;
190
+	str con = STR_NULL;
191
+	str host = STR_NULL;
192
+	str name = STR_NULL;
193
+	str idhdr = STR_NULL;
194
+	str pidfurl = STR_NULL;
195
+
196
+	static str rtype = STR_STATIC_INIT(HELD_DEFAULT_TYPE);
197
+	static str sheld = STR_STATIC_INIT(NAPTR_LIS_SERVICE_HELD);
198
+
199
+	char ustr[MAX_URI_SIZE];
200
+	char istr[NI_MAXHOST];
201
+	char *ipstr = NULL;
202
+	char *lisurl = NULL;
203
+	char *heldreq = NULL;
204
+
205
+	int len = 0;
206
+	int curl = 0;
207
+	int flag = 0;
208
+	int naptr = 0;
180 209
 	int presence = 0;
181 210
 
182
-	if(_con == NULL || _pidf == NULL || _url == NULL || _err == NULL) {
211
+	if(_pidf == NULL || _url == NULL || _err == NULL) {
183 212
 		LM_ERR("invalid parameter\n");
184 213
 		goto err;
185 214
 	}
215
+
186 216
 	/* module parameter */
187 217
 	if(held_loc_type.len > 0) {
188 218
 		rtype.s = held_loc_type.s;
189 219
 		rtype.len = held_loc_type.len;
190 220
 	}
191 221
 	/* connection from parameter */
192
-	if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) {
193
-		LM_ERR("cannot get connection string\n");
194
-		goto err;
222
+	if(_con) {
223
+		if(get_str_fparam(&con, _m, (gparam_p)_con) != 0) {
224
+			LM_ERR("cannot get connection string\n");
225
+			goto err;
226
+		}
227
+		/* check if connection exists */
228
+		if(con.s != NULL && con.len > 0) {
229
+			if(httpapi.http_connection_exists(&con) == 0) {
230
+				LM_ERR("connection: [%s] does not exist\n", con.s);
231
+				goto err;
232
+			}
233
+		}
195 234
 	}
196 235
 	/* id from parameter */
197 236
 	if(_id) {
198
-		if(fixup_get_svalue(_m, (gparam_p)_id, &did) != 0) {
237
+		if(get_str_fparam(&did, _m, (gparam_p)_id) != 0) {
199 238
 			LM_ERR("cannot get device id\n");
200 239
 			goto err;
201 240
 		}
... ...
@@ -225,30 +264,15 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
225 264
 		did.len = idhdr.len;
226 265
 	}
227 266
 	LM_INFO("### HELD id [%.*s]\n", did.len, did.s);
228
-
229
-	/* check if connection exists */
230
-	if(httpapi.http_connection_exists(&con) == 0) {
231
-		LM_ERR("connection: [%s] does not exist\n", con.s);
232
-		lost_free_string(&idhdr);
233
-		goto err;
234
-	}
235
-
236 267
 	/* assemble locationRequest */
237 268
 	held = lost_new_held(did, rtype, held_resp_time, held_exact_type);
238
-
239 269
 	if(held == NULL) {
240 270
 		LM_ERR("held object allocation failed\n");
241
-		lost_free_string(&idhdr);
271
+		lost_free_string(&idhdr); /* clean up */
242 272
 		goto err;
243 273
 	}
244 274
 	que.s = lost_held_location_request(held, &que.len);
245
-
246
-	/* free memory */
247
-	did.s = NULL;
248
-	did.len = 0;
249
-	lost_free_held(held);
250
-	lost_free_string(&idhdr);
251
-
275
+	lost_free_held(&held); /* clean up */
252 276
 	if(que.len == 0) {
253 277
 		LM_ERR("held request document error\n");
254 278
 		que.s = NULL;
... ...
@@ -258,17 +282,95 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
258 282
 	LM_DBG("held location request: [%s]\n", que.s);
259 283
 
260 284
 	/* send locationRequest to location server - HTTP POST */
261
-	curlres = httpapi.http_connect(_m, &con, NULL, &res, mtheld, &que);
285
+	if(con.s != NULL && con.len > 0) {
286
+
287
+		LM_DBG("using connection [%.*s]\n", con.len, con.s);
288
+
289
+		/* send via connection */
290
+		curl = httpapi.http_connect(_m, &con, NULL, &res, mtheld, &que);
291
+	} else {
292
+		/* we have no connection ... do a NAPTR lookup */
293
+		if(lost_parse_host(did.s, &host, &flag) > 0) {
294
+
295
+			LM_DBG("no conn. trying NATPR lookup [%.*s]\n", host.len, host.s);
296
+
297
+			/* remove '[' and ']' from string (IPv6) */
298
+			if(flag == AF_INET6) {
299
+				host.s++;
300
+				host.len = host.len - 2;
301
+			}
302
+			/* is it a name or ip ... check nameinfo (reverse lookup) */
303
+			len = 0;
304
+			ipstr = lost_copy_string(host, &len);
305
+			if(len > 0) {
306
+				name.s = &(istr[0]);
307
+				name.len = NI_MAXHOST;
308
+				if(lost_get_nameinfo(ipstr, &name, flag) > 0) {
309
+
310
+					LM_DBG("ip [%s] to name [%.*s]\n", ipstr, name.len, name.s);
311
+
312
+					/* change ip string to name */
313
+					host.s = name.s;
314
+					host.len = name.len;
315
+				} else {
316
+
317
+					/* keep string */
318
+					LM_DBG("no nameinfo for [%s]\n", ipstr);
319
+				}
320
+				pkg_free(ipstr); /* clean up */
321
+			}
322
+			url.s = &(ustr[0]);
323
+			url.len = MAX_URI_SIZE;
324
+			if((naptr = lost_naptr_lookup(host, &sheld, &url)) == 0) {
325
+				LM_ERR("NAPTR failed on [%.*s]\n", host.len, host.s);
326
+				lost_free_string(&que); /* clean up */
327
+				lost_free_string(&idhdr);
328
+				goto err;
329
+			}
330
+		} else {
331
+			LM_ERR("failed to get location service for [%.*s]\n", did.len,
332
+					did.s);
333
+			lost_free_string(&que); /* clean up */
334
+			lost_free_string(&idhdr);
335
+			goto err;
336
+		}
337
+
338
+		LM_DBG("NATPR lookup returned [%.*s]\n", url.len, url.s);
339
+
340
+		/* curl doesn't like str */
341
+		len = 0;
342
+		lisurl = lost_copy_string(url, &len);
343
+		/* send to service */
344
+		if(lisurl != NULL && len > 0) {
345
+			curl = httpapi.http_client_query_c(
346
+					_m, lisurl, &res, que.s, mtheld, ACCEPT_HDR);
347
+			pkg_free(lisurl); /*clean up */
348
+		} else {
349
+			goto err;
350
+		}
351
+	}
262 352
 	/* only HTTP 2xx responses are accepted */
263
-	if(curlres >= 300 || curlres < 100) {
264
-		LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres);
353
+	if(curl >= 300 || curl < 100) {
354
+		if(con.s != NULL && con.len > 0) {
355
+			LM_ERR("POST [%.*s] failed with error: %d\n", con.len, con.s, curl);
356
+		} else {
357
+			LM_ERR("POST [%.*s] failed with error: %d\n", url.len, url.s, curl);
358
+		}
265 359
 		lost_free_string(&res);
266 360
 		goto err;
267 361
 	}
362
+	if(con.s != NULL && con.len > 0) {
363
+
364
+		LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curl);
268 365
 
269
-	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres);
366
+	} else {
270 367
 
271
-	/* free memory */
368
+		LM_DBG("[%.*s] returned: %d\n", url.len, url.s, curl);
369
+	}
370
+	did.s = NULL;
371
+	did.len = 0;
372
+	/* clean up */
373
+	lost_free_string(&idhdr);
272 374
 	lost_free_string(&que);
273 375
 	/* read and parse the returned xml */
274 376
 	doc = xmlReadMemory(res.s, res.len, 0, NULL,
... ...
@@ -288,7 +390,7 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
288 390
 		LM_ERR("empty xml document\n");
289 391
 		goto err;
290 392
 	}
291
-	/* check the root element ... shall be locationResponse, or errors */
393
+	/* check the root element ... shall be locationResponse, or error */
292 394
 	if(xmlStrcmp(root->name, (const xmlChar *)"locationResponse") == 0) {
293 395
 
294 396
 		LM_DBG("HELD location response [%.*s]\n", res.len, res.s);
... ...
@@ -320,46 +422,59 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
320 422
 				}
321 423
 			}
322 424
 		}
323
-
324 425
 		/* if we do not have a presence node but a location URI */
325 426
 		/* dereference pidf.lo at location server via HTTP GET */
326
-		if((presence == 0) && (geo.len > 0)) {
327
-
427
+		if((presence == 0) && (geo.s != NULL && geo.len > 0)) {
328 428
 			LM_INFO("presence node not found in HELD response, trying URI "
329 429
 					"...\n");
330
-
331
-			curlres =
332
-					httpapi.http_client_query(_m, geo.s, &pidfuri, NULL, NULL);
430
+			if(held_post_req == 0) {
431
+				curl = httpapi.http_client_query_c(
432
+						_m, geo.s, &pidfurl, NULL, mtheld, ACCEPT_HDR);
433
+			} else {
434
+				len = 0;
435
+				heldreq = lost_held_post_request(&len, 0, NULL);
436
+				if(len > 0) {
437
+
438
+					LM_DBG("held POST request: [%.*s]\n", len, heldreq);
439
+
440
+					curl = httpapi.http_client_query_c(
441
+							_m, geo.s, &pidfurl, heldreq, mtheld, ACCEPT_HDR);
442
+					pkg_free(heldreq); /* clean up */
443
+				} else {
444
+					LM_ERR("could not create POST request\n");
445
+					lost_free_string(&pidfurl); /* clean up */
446
+					goto err;
447
+				}
448
+			}
333 449
 			/* only HTTP 2xx responses are accepted */
334
-			if(curlres >= 300 || curlres < 100) {
335
-				LM_ERR("dereferencing location failed: %d\n", curlres);
336
-				/* free memory */
337
-				lost_free_string(&pidfuri);
450
+			if(curl >= 300 || curl < 100) {
451
+				LM_ERR("GET [%.*s] failed with error: %d\n", pidfurl.len,
452
+						pidfurl.s, curl);
453
+				/* clean up */
454
+				lost_free_string(&pidfurl);
338 455
 				goto err;
339 456
 			}
340
-
341
-			if(pidfuri.len == 0) {
342
-
457
+			if(pidfurl.len == 0) {
343 458
 				LM_WARN("HELD location request failed [%.*s]\n", geo.len,
344 459
 						geo.s);
345
-
346 460
 			} else {
347 461
 
348
-				LM_DBG("HELD location response [%.*s]\n", pidfuri.len,
349
-						pidfuri.s);
462
+				LM_DBG("HELD location response [%.*s]\n", pidfurl.len,
463
+						pidfurl.s);
350 464
 
351
-				res.s = pidfuri.s;
352
-				res.len = pidfuri.len;
465
+				res.s = pidfurl.s;
466
+				res.len = pidfurl.len;
353 467
 			}
354 468
 		}
469
+		/* error received */
355 470
 	} else if(xmlStrcmp(root->name, (const xmlChar *)"error") == 0) {
356 471
 
357 472
 		LM_DBG("HELD error response [%.*s]\n", res.len, res.s);
358 473
 
359
-		/* get the error patterm */
474
+		/* get the error property */
360 475
 		err.s = lost_get_property(root, (char *)"code", &err.len);
361 476
 		if(err.len == 0) {
362
-			LM_ERR("error - code property not found: [%.*s]\n", res.len, res.s);
477
+			LM_ERR("error - property not found: [%.*s]\n", res.len, res.s);
363 478
 			goto err;
364 479
 		}
365 480
 		LM_WARN("locationRequest error response: [%.*s]\n", err.len, err.s);
... ...
@@ -367,6 +482,8 @@ int lost_held_function(struct sip_msg *_m, char *_con, char *_pidf, char *_url,
367 482
 		LM_ERR("root element is not valid: [%.*s]\n", res.len, res.s);
368 483
 		goto err;
369 484
 	}
485
+
486
+	/* clean up */
370 487
 	xmlFreeDoc(doc);
371 488
 	doc = NULL;
372 489
 
... ...
@@ -405,6 +522,228 @@ err:
405 522
 	return LOST_CLIENT_ERROR;
406 523
 }
407 524
 
525
+
526
+/*
527
+ * lost_held_dereference(msg, url, pidf, err, rtime, rtype)
528
+ * assembles and runs HELD locationRequest (POST), returns result as pidf
529
+ */
530
+int lost_held_dereference(struct sip_msg *_m, char *_url, char *_pidf,
531
+		char *_err, char *_rtime, char *_rtype)
532
+{
533
+	pv_spec_t *pspidf;
534
+	pv_spec_t *pserr;
535
+
536
+	pv_value_t pvpidf;
537
+	pv_value_t pverr;
538
+
539
+	xmlDocPtr doc = NULL;
540
+	xmlNodePtr root = NULL;
541
+
542
+	str url = STR_NULL;
543
+	str rtm = STR_NULL;
544
+	str rtp = STR_NULL;
545
+
546
+	str res = STR_NULL; /* return value location response */
547
+	str err = STR_NULL; /* return value error */
548
+
549
+	char *ptr = NULL;
550
+	char *lisurl = NULL;
551
+	char *heldreq = NULL;
552
+	char *rtype = NULL;
553
+
554
+	long ltime = 0;
555
+	long rtime = 0;
556
+
557
+	int len = 0;
558
+	int curl = 0;
559
+	int exact = 0;
560
+
561
+	if(_url == NULL || _rtime == NULL || _pidf == NULL || _rtype == NULL
562
+			|| _err == NULL) {
563
+		LM_ERR("invalid parameter\n");
564
+		goto err;
565
+	}
566
+
567
+	/* dereference url from parameter */
568
+	if(_url) {
569
+		if(get_str_fparam(&url, _m, (gparam_p)_url) != 0) {
570
+			LM_ERR("cannot get dereference url\n");
571
+			goto err;
572
+		}
573
+		if(url.len == 0) {
574
+			LM_ERR("no dereference url found\n");
575
+			goto err;
576
+		}
577
+	}
578
+
579
+	/* response time from parameter */
580
+	if(_rtime) {
581
+		if(get_str_fparam(&rtm, _m, (gparam_p)_rtime) != 0) {
582
+			LM_ERR("cannot get response time\n");
583
+			goto err;
584
+		}
585
+		if(rtm.len == 0) {
586
+			LM_WARN("no response time found\n");
587
+			ltime = 0;
588
+		} else {
589
+			ltime = strtol(rtm.s, &ptr, 10);
590
+		}
591
+	}
592
+
593
+	/* response type from parameter */
594
+	if(_rtype) {
595
+		if(get_str_fparam(&rtp, _m, (gparam_p)_rtype) != 0) {
596
+			LM_ERR("cannot get response type\n");
597
+			goto err;
598
+		}
599
+		if(rtp.len == 0) {
600
+			LM_WARN("no response type found\n");
601
+			rtype = NULL;
602
+		} else {
603
+			len = 0;
604
+			/* response type string sanity check */
605
+			rtype = lost_held_type(rtp.s, &exact, &len);
606
+			if(len == 0) {
607
+				LM_WARN("cannot normalize [%.*s]\n", rtp.len, rtp.s);
608
+				rtype = NULL;
609
+			}
610
+		}
611
+	}
612
+
613
+	if((ltime > 0) && (strlen(ptr) == 0)) {
614
+		/* responseTime: milliseconds */
615
+		rtime = ltime;
616
+	} else if((ltime == 0) && (strlen(ptr) > 0)) {
617
+		if(strncasecmp(ptr, HELD_ED, strlen(HELD_ED)) == 0) {
618
+			/* responseTime: emergencyDispatch */
619
+			rtime = -1;
620
+		} else if(strncasecmp(ptr, HELD_ER, strlen(HELD_ER)) == 0) {
621
+			/* responseTime: emergencyRouting */
622
+			rtime = 0;
623
+		}
624
+	}
625
+
626
+	/* get the HELD request body */
627
+	heldreq = lost_held_post_request(&len, rtime, rtype);
628
+
629
+	/* clean up */
630
+	if(rtype != NULL) {
631
+		pkg_free(rtype);
632
+	}
633
+
634
+	if(heldreq != NULL && len == 0) {
635
+		LM_ERR("could not create POST request\n");
636
+		goto err;
637
+	}
638
+
639
+	LM_DBG("POST request: [%.*s]\n", len, heldreq);
640
+
641
+	/* curl doesn't like str */
642
+	len = 0;
643
+	lisurl = lost_copy_string(url, &len);
644
+	if(lisurl != NULL && len > 0) {
645
+
646
+		LM_DBG("POST url: [%.*s]\n", len, lisurl);
647
+
648
+		curl = httpapi.http_client_query_c(
649
+				_m, lisurl, &res, heldreq, mtheld, ACCEPT_HDR);
650
+		pkg_free(lisurl); /* clean up */
651
+		pkg_free(heldreq);
652
+	} else {
653
+		LM_ERR("could not copy POST url\n");
654
+		pkg_free(heldreq); /* clean up */
655
+		goto err;
656
+	}
657
+
658
+	/* only HTTP 2xx responses are accepted */
659
+	if(curl >= 300 || curl < 100) {
660
+		LM_ERR("POST [%.*s] failed with error: %d\n", url.len, url.s, curl);
661
+		goto err;
662
+	}
663
+	if(res.s != NULL && res.len > 0) {
664
+
665
+		LM_DBG("LbR pidf-lo: [%.*s]\n", res.len, res.s);
666
+
667
+	} else {
668
+		LM_ERR("dereferencing location failed\n");
669
+		goto err;
670
+	}
671
+
672
+	/* read and parse the returned xml */
673
+	doc = xmlReadMemory(res.s, res.len, 0, NULL,
674
+			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
675
+	if(doc == NULL) {
676
+		LM_WARN("invalid xml document: [%.*s]\n", res.len, res.s);
677
+		doc = xmlRecoverMemory(res.s, res.len);
678
+		if(doc == NULL) {
679
+			LM_ERR("xml document recovery failed on: [%.*s]\n", res.len, res.s);
680
+			goto err;
681
+		}
682
+
683
+		LM_DBG("xml document recovered\n");
684
+	}
685
+	root = xmlDocGetRootElement(doc);
686
+	if(root == NULL) {
687
+		LM_ERR("empty xml document\n");
688
+		goto err;
689
+	}
690
+
691
+	/* check the root element ... shall be locationResponse, or error */
692
+	if(xmlStrcmp(root->name, (const xmlChar *)"presence") == 0) {
693
+
694
+		LM_DBG("HELD location response [%.*s]\n", res.len, res.s);
695
+
696
+		/* error received */
697
+	} else if(xmlStrcmp(root->name, (const xmlChar *)"error") == 0) {
698
+
699
+		LM_DBG("HELD error response [%.*s]\n", res.len, res.s);
700
+
701
+		/* get the error property */
702
+		err.s = lost_get_property(root, (char *)"code", &err.len);
703
+		if(err.len == 0) {
704
+			LM_ERR("error - property not found: [%.*s]\n", res.len, res.s);
705
+			goto err;
706
+		}
707
+		LM_WARN("locationRequest error response: [%.*s]\n", err.len, err.s);
708
+	} else {
709
+		LM_ERR("root element is not valid: [%.*s]\n", res.len, res.s);
710
+		goto err;
711
+	}
712
+
713
+	/* clean up */
714
+	xmlFreeDoc(doc);
715
+	doc = NULL;
716
+
717
+	/* set writeable pvars */
718
+	pvpidf.rs = res;
719
+	pvpidf.rs.s = res.s;
720
+	pvpidf.rs.len = res.len;
721
+
722
+	pvpidf.flags = PV_VAL_STR;
723
+	pspidf = (pv_spec_t *)_pidf;
724
+	pspidf->setf(_m, &pspidf->pvp, (int)EQ_T, &pvpidf);
725
+
726
+	pverr.rs = err;
727
+	pverr.rs.s = err.s;
728
+	pverr.rs.len = err.len;
729
+
730
+	pverr.flags = PV_VAL_STR;
731
+	pserr = (pv_spec_t *)_err;
732
+	pserr->setf(_m, &pserr->pvp, (int)EQ_T, &pverr);
733
+
734
+	return (err.len > 0) ? LOST_SERVER_ERROR : LOST_SUCCESS;
735
+
736
+err:
737
+	if(doc != NULL) {
738
+		xmlFreeDoc(doc);
739
+	}
740
+	if(res.s != NULL && res.len > 0) {
741
+		lost_free_string(&res);
742
+	}
743
+
744
+	return LOST_CLIENT_ERROR;
745
+}
746
+
408 747
 /*
409 748
  * lost_function(msg, con, pidf, uri, name, err, pidf, urn)
410 749
  * assembles and runs LOST findService request, parses results
... ...
@@ -420,110 +759,121 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
420 759
 	pv_value_t pvuri;
421 760
 	pv_value_t pverr;
422 761
 
423
-	p_loc_t loc = NULL;
424
-	p_geolist_t geolist = NULL;
425
-	int geotype;
426
-
427
-	str url = {NULL, 0};
428
-	str uri = {NULL, 0};
429
-	str urn = {NULL, 0};
430
-	str err = {NULL, 0};
431
-	str req = {NULL, 0};
432
-	str con = {NULL, 0};
433
-	str ret = {NULL, 0};
434
-	str name = {NULL, 0};
435
-	str pidf = {NULL, 0};
436
-	str geohdr = {NULL, 0};
437
-	str pidfhdr = {NULL, 0};
762
+	p_lost_loc_t loc = NULL;
763
+	p_lost_geolist_t geolist = NULL;
764
+	p_lost_fsr_t fsrdata = NULL;
765
+
766
+	str name = STR_NULL; /* return value displayName */
767
+	str uri = STR_NULL;	 /* return value uri */
768
+	str err = STR_NULL;	 /* return value error */
769
+
770
+	str tmp = STR_NULL;
771
+	str url = STR_NULL;
772
+	str urn = STR_NULL;
773
+	str req = STR_NULL;
774
+	str con = STR_NULL;
775
+	str ret = STR_NULL;
776
+	str pidf = STR_NULL;
777
+	str oldurl = STR_NULL;
778
+	str losturl = STR_NULL;
779
+
780
+	static str shttp = STR_STATIC_INIT(NAPTR_LOST_SERVICE_HTTP);
781
+	static str shttps = STR_STATIC_INIT(NAPTR_LOST_SERVICE_HTTPS);
438 782
 
439 783
 	struct msg_start *fl;
784
+
785
+	char ustr[MAX_URI_SIZE];
440 786
 	char *search = NULL;
441 787
 	char *geoval = NULL;
442
-	int curlres = 0;
443
-	int geoitems = 0;
788
+	char *urlrep = NULL;
789
+	char *heldreq = NULL;
444 790
 
445
-	xmlDocPtr doc = NULL;
446
-	xmlNodePtr root = NULL;
791
+	int geotype = 0;
792
+	int redirect = 0;
793
+	int curl = 0;
794
+	int len = 0;
795
+	int naptr = 0;
796
+	int geoitems = 0;
447 797
 
448 798
 	if(_con == NULL || _uri == NULL || _name == NULL || _err == NULL) {
449 799
 		LM_ERR("invalid parameter\n");
450 800
 		goto err;
451 801
 	}
452
-	if(fixup_get_svalue(_m, (gparam_p)_con, &con) != 0) {
453
-		LM_ERR("cannot get connection string\n");
454
-		goto err;
802
+	/* connection from parameter */
803
+	if(_con) {
804
+		if(get_str_fparam(&con, _m, (gparam_p)_con) != 0) {
805
+			LM_ERR("cannot get connection string\n");
806
+			goto err;
807
+		}
808
+		/* check if connection exists */
809
+		if(con.s != NULL && con.len > 0) {
810
+			if(httpapi.http_connection_exists(&con) == 0) {
811
+				LM_WARN("connection: [%.*s] does not exist\n", con.len, con.s);
812
+				/* check if NAPTR lookup works with connection parameter */
813
+				losturl.s = &(ustr[0]);
814
+				losturl.len = MAX_URI_SIZE;
815
+				if((naptr = lost_naptr_lookup(con, &shttps, &losturl)) == 0) {
816
+					naptr = lost_naptr_lookup(con, &shttp, &losturl);
817
+				}
818
+				if(naptr == 0) {
819
+					LM_ERR("NAPTR failed on [%.*s]\n", con.len, con.s);
820
+					goto err;
821
+				}
822
+			}
823
+		}
455 824
 	}
456 825
 	/* urn from parameter */
457 826
 	if(_urn) {
458
-		if(fixup_get_svalue(_m, (gparam_p)_urn, &urn) != 0) {
459
-			LM_ERR("cannot get service urn\n");
827
+		if(get_str_fparam(&urn, _m, (gparam_p)_urn) != 0) {
828
+			LM_ERR("cannot get service urn parameter\n");
460 829
 			goto err;
461 830
 		}
462 831
 	}
463 832
 	/* urn from request line */
464 833
 	if(urn.len == 0) {
465
-		LM_WARN("no sevice urn parameter, trying request line ...\n");
834
+
835
+		LM_DBG("no service urn parameter, trying request line ...\n");
836
+
466 837
 		fl = &(_m->first_line);
467 838
 		urn.len = fl->u.request.uri.len;
468 839
 		urn.s = fl->u.request.uri.s;
469 840
 	}
470 841
 	/* check urn scheme */
471
-	if(urn.len > 3) {
472
-		search = urn.s;
473
-		if(((*(search + 0) == 'u') || (*(search + 0) == 'U'))
474
-				&& ((*(search + 1) == 'r') || (*(search + 1) == 'R'))
475
-				&& ((*(search + 2) == 'n') || (*(search + 2) == 'N'))
476
-				&& (*(search + 3) == ':')) {
477
-			LM_INFO("### LOST urn\t[%.*s]\n", urn.len, urn.s);
478
-		} else {
479
-			LM_ERR("service urn not found\n");
480
-			goto err;
481
-		}
842
+	search = urn.s;
843
+	if(is_urn(search) > 0) {
844
+		LM_INFO("### LOST urn\t[%.*s]\n", urn.len, urn.s);
482 845
 	} else {
483 846
 		LM_ERR("service urn not found\n");
484 847
 		goto err;
485 848
 	}
486 849
 	/* pidf from parameter */
487 850
 	if(_pidf) {
488
-		if(fixup_get_svalue(_m, (gparam_p)_pidf, &pidf) != 0) {
489
-			LM_WARN("cannot get pidf-lo parameter\n");
851
+		if(get_str_fparam(&pidf, _m, (gparam_p)_pidf) != 0) {
852
+			LM_ERR("cannot get pidf parameter\n");
490 853
 		} else {
491 854
 
492
-			LM_DBG("parsing pidf-lo from paramenter\n");
855
+			LM_DBG("parsing pidf parameter ...\n");
493 856
 
494
-			if(pidf.len > 0) {
857
+			if(pidf.s != NULL && pidf.len > 0) {
495 858
 
496
-				LM_DBG("pidf-lo: [%.*s]\n", pidf.len, pidf.s);
859
+				LM_DBG("pidf: [%.*s]\n", pidf.len, pidf.s);
497 860
 
498
-				/* parse the pidf-lo */
861
+				/* parse the pidf and get loc object */
499 862
 				loc = lost_parse_pidf(pidf, urn);
500
-				/* free memory */
501
-				pidf.s = NULL;
502
-				pidf.len = 0;
503
-			} else {
504
-				LM_WARN("no valid pidf parameter ...\n");
505 863
 			}
506 864
 		}
507 865
 	}
508
-
509
-	/* no pidf-lo so far ... check geolocation header */
866
+	/* neither valifd pidf parameter nor loc ... check geolocation header */
510 867
 	if(loc == NULL) {
511 868
 
512
-		LM_DBG("looking for geolocation header ...\n");
869
+		/* parse Geolocation header */
513 870
 
514
-		geohdr.s = lost_get_geolocation_header(_m, &geohdr.len);
515
-		if(geohdr.len == 0) {
516
-			LM_ERR("geolocation header not found\n");
517
-			goto err;
518
-		}
871
+		LM_DBG("parsing geolocation header ...\n");
519 872
 
520
-		LM_DBG("geolocation header found\n");
873
+		geolist = lost_get_geolocation_header(_m, &geoitems);
521 874
 
522
-		/* parse Geolocation header */
523
-		geolist = lost_new_geoheader_list(geohdr, &geoitems);
524 875
 		if(geoitems == 0) {
525
-			LM_ERR("invalid geolocation header\n");
526
-			lost_free_string(&geohdr);
876
+			LM_ERR("geolocation header not found\n");
527 877
 			goto err;
528 878
 		}
529 879
 
... ...
@@ -535,7 +885,6 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
535 885
 
536 886
 			lost_reverse_geoheader_list(&geolist);
537 887
 		}
538
-
539 888
 		switch(lost_geoloc_type) {
540 889
 			case ANY: /* type: 0 */
541 890
 				geoval = lost_get_geoheader_value(geolist, ANY, &geotype);
... ...
@@ -580,36 +929,26 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
580 929
 
581 930
 				break;
582 931
 		}
583
-
584 932
 		if(geoval == NULL) {
585 933
 			LM_ERR("invalid geolocation header\n");
586
-			/* free memory */
587
-			lost_delete_geoheader_list(geolist);
588
-			lost_free_string(&geohdr);
589 934
 			goto err;
590 935
 		}
591
-
592 936
 		LM_INFO("### LOST loc\t[%s]\n", geoval);
593
-
937
+		/* clean up */
938
+		pidf.s = NULL;
939
+		pidf.len = 0;
594 940
 		/* use location by value */
595 941
 		if(geotype == CID) {
596
-
597 942
 			/* get body part - filter=>content-indirection */
598 943
 			pidf.s = get_body_part_by_filter(_m, 0, 0, geoval, NULL, &pidf.len);
599
-			if(pidf.len > 0) {
944
+			if(pidf.s != NULL && pidf.len > 0) {
600 945
 
601 946
 				LM_DBG("LbV pidf-lo: [%.*s]\n", pidf.len, pidf.s);
602 947
 
603
-				/* parse the pidf-lo */
604
-				loc = lost_parse_pidf(pidf, urn);
605
-				/* free memory */
606
-				pidf.s = NULL;
607
-				pidf.len = 0;
608 948
 			} else {
609 949
 				LM_WARN("no multipart body found\n");
610 950
 			}
611 951
 		}
612
-
613 952
 		/* use location by reference */
614 953
 		if((geotype == HTTPS) || (geotype == HTTP)) {
615 954
 			url.s = geoval;
... ...
@@ -617,60 +956,67 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
617 956
 			/* ! dereference pidf.lo at location server - HTTP GET */
618 957
 			/* ! requires hack in http_client module */
619 958
 			/* ! functions.c => http_client_query => query_params.oneline = 0; */
620
-			curlres =
621
-					httpapi.http_client_query(_m, url.s, &pidfhdr, NULL, NULL);
622
-			/* free memory */
623
-			url.s = NULL;
624
-			url.len = 0;
959
+			if(held_post_req == 0) {
960
+				curl = httpapi.http_client_query_c(
961
+						_m, url.s, &ret, NULL, mtheld, ACCEPT_HDR);
962
+			} else {
963
+				len = 0;
964
+				heldreq = lost_held_post_request(&len, 0, NULL);
965
+				if(len > 0) {
966
+
967
+					LM_DBG("POST request: [%.*s]\n", len, heldreq);
968
+
969
+					curl = httpapi.http_client_query_c(
970
+							_m, url.s, &ret, heldreq, mtheld, ACCEPT_HDR);
971
+					pkg_free(heldreq); /* clean up */
972
+				} else {
973
+					LM_ERR("could not create POST request\n");
974
+					goto err;
975
+				}
976
+			}
625 977
 			/* only HTTP 2xx responses are accepted */
626
-			if(curlres >= 300 || curlres < 100) {
627
-				LM_ERR("http GET failed with error: %d\n", curlres);
628
-				/* free memory */
629
-				lost_delete_geoheader_list(geolist);
630
-				lost_free_string(&pidfhdr);
631
-				lost_free_string(&geohdr);
978
+			if(curl >= 300 || curl < 100) {
979
+				if(held_post_req == 0) {
980
+					LM_ERR("GET [%.*s] failed with error: %d\n", url.len, url.s,
981
+							curl);
982
+				} else {
983
+					LM_ERR("POST [%.*s] failed with error: %d\n", url.len,
984
+							url.s, curl);
985
+				}
986
+				/* clean up */
987
+				lost_free_string(&ret);
632 988
 				goto err;
633 989
 			}
634
-
635
-			pidf.s = pidfhdr.s;
636
-			pidf.len = pidfhdr.len;
637
-
638
-			if(pidf.len > 0) {
990
+			url.s = NULL;
991
+			url.len = 0;
992
+			pidf.s = ret.s;
993
+			pidf.len = ret.len;
994
+			if(pidf.s != NULL && pidf.len > 0) {
639 995
 
640 996
 				LM_DBG("LbR pidf-lo: [%.*s]\n", pidf.len, pidf.s);
641 997
 
642
-				/* parse the pidf-lo */
643
-				loc = lost_parse_pidf(pidf, urn);
644
-				/* free memory */
645
-				pidf.s = NULL;
646
-				pidf.len = 0;
647 998
 			} else {
648 999
 				LM_WARN("dereferencing location failed\n");
649 1000
 			}
650 1001
 		}
651
-		/* free memory */
652
-		lost_delete_geoheader_list(geolist);
653
-		lost_free_string(&geohdr);
654
-		lost_free_string(&pidfhdr);
1002
+		/* clean up */
1003
+		lost_free_geoheader_list(&geolist);
1004
+		lost_free_string(&ret);
655 1005
 	}
656
-
657
-	if(loc == NULL) {
1006
+	if(pidf.s == NULL && pidf.len == 0) {
658 1007
 		LM_ERR("location object not found\n");
659 1008
 		goto err;
660 1009
 	}
661
-
662
-	/* check if connection exits */
663
-	if(httpapi.http_connection_exists(&con) == 0) {
664
-		LM_ERR("connection: [%.*s] does not exist\n", con.len, con.s);
1010
+	/* parse the pidf and get loc object */
1011
+	loc = lost_parse_pidf(pidf, urn);
1012
+	if(loc == NULL) {
1013
+		LM_ERR("parsing pidf failed\n");
665 1014
 		goto err;
666 1015
 	}
667 1016
 	/* assemble findService request */
668 1017
 	req.s = lost_find_service_request(loc, &req.len);
669
-	/* free memory */
670
-	lost_free_loc(loc);
671
-	loc = NULL;
672
-
673
-	if(req.len == 0) {
1018
+	lost_free_loc(&loc); /* clean up */
1019
+	if(req.s == NULL && req.len == 0) {
674 1020
 		LM_ERR("lost request failed\n");
675 1021
 		goto err;
676 1022
 	}
... ...
@@ -678,18 +1024,28 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
678 1024
 	LM_DBG("findService request: [%.*s]\n", req.len, req.s);
679 1025
 
680 1026
 	/* send findService request to mapping server - HTTP POST */
681
-	curlres = httpapi.http_connect(_m, &con, NULL, &ret, mtlost, &req);
1027
+	if(naptr) {
1028
+		/* copy url */
1029
+		len = 0;
1030
+		urlrep = lost_copy_string(url, &len);
1031
+		if(len > 0) {
1032
+			/* send request */
1033
+			curl = httpapi.http_client_query(_m, urlrep, &ret, req.s, mtlost);
1034
+			pkg_free(urlrep); /*clean up */
1035
+		} else {
1036
+			goto err;
1037
+		}
1038
+	} else {
1039
+		curl = httpapi.http_connect(_m, &con, NULL, &ret, mtlost, &req);
1040
+	}
682 1041
 	/* only HTTP 2xx responses are accepted */
683
-	if(curlres >= 300 || curlres < 100) {
684
-		LM_ERR("[%.*s] failed with error: %d\n", con.len, con.s, curlres);
1042
+	if(curl >= 300 || curl < 100) {
1043
+		LM_ERR("POST [%.*s] failed with error: %d\n", con.len, con.s, curl);
685 1044
 		lost_free_string(&ret);
686 1045
 		goto err;
687 1046
 	}
688 1047
 
689
-	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curlres);
690
-
691
-	/* free memory */
692
-	lost_free_string(&req);
1048
+	LM_DBG("[%.*s] returned: %d\n", con.len, con.s, curl);
693 1049
 
694 1050
 	if(ret.len == 0) {
695 1051
 		LM_ERR("findService request failed\n");
... ...
@@ -698,70 +1054,140 @@ int lost_function(struct sip_msg *_m, char *_con, char *_uri, char *_name,
698 1054
 
699 1055
 	LM_DBG("findService response: [%.*s]\n", ret.len, ret.s);
700 1056
 
701
-	/* read and parse the returned xml */
702
-	doc = xmlReadMemory(ret.s, ret.len, 0, 0,
703
-			XML_PARSE_NOBLANKS | XML_PARSE_NONET | XML_PARSE_NOCDATA);
704
-
705
-	if(doc == NULL) {
706
-		LM_ERR("invalid xml document: [%.*s]\n", ret.len, ret.s);
707
-		doc = xmlRecoverMemory(ret.s, ret.len);
708
-		if(doc == NULL) {
709
-			LM_ERR("xml document recovery failed on: [%.*s]\n", ret.len, ret.s);
710
-			goto err;
1057
+	/* at least parse one request */
1058
+	redirect = 1;
1059
+	while(redirect) {
1060
+		fsrdata = lost_parse_findServiceResponse(ret);
1061
+		if (lost_verbose == 1) {
1062
+			lost_print_findServiceResponse(fsrdata);
711 1063
 		}
712
-
713
-		LM_DBG("xml document recovered\n");
714
-	}
715
-	root = xmlDocGetRootElement(doc);
716
-	if(root == NULL) {
717
-		LM_ERR("empty xml document: [%.*s]\n", ret.len, ret.s);
718
-		/* free memory */
719
-		lost_free_string(&ret);
720
-		goto err;
721
-	}
722
-	/* check the root element, shall be findServiceResponse, or errors */
723
-	if((!xmlStrcmp(root->name, (const xmlChar *)"findServiceResponse"))) {
724
-		/* get the uri element */
725
-		uri.s = lost_get_content(root, uri_element, &uri.len);
726
-		if(uri.len == 0) {
727
-			LM_ERR("uri element not found: [%.*s]\n", ret.len, ret.s);
728
-			/* free memory */
729
-			lost_free_string(&ret);
730
-			goto err;
731
-		}
732
-		LM_INFO("### LOST uri\t[%.*s]\n", uri.len, uri.s);
733
-		/* get the displayName element */
734
-		name.s = lost_get_content(root, name_element, &name.len);
735
-		if(name.len == 0) {
736
-			LM_ERR("displayName element not found: [%.*s]\n", ret.len, ret.s);
737
-			/* free memory */
738
-			lost_free_string(&ret);
739
-			goto err;
740
-		}
741
-		LM_INFO("### LOST din\t[%.*s]\n", name.len, name.s);
742
-	} else if((!xmlStrcmp(root->name, (const xmlChar *)"errors"))) {
743
-
744
-		LM_DBG("findService error response received\n");
745
-
746
-		/* get the error patterm */
747
-		err.s = lost_get_childname(root, errors_element, &err.len);
748
-		LM_DBG("findService error response: [%.*s]\n", err.len, err.s);
749
-		if(err.len == 0) {
750
-			LM_ERR("error pattern element not found: [%.*s]\n", ret.len, ret.s);
751
-			/* free memory */
752
-			lost_free_string(&ret);
753
-			goto err;
1064
+		switch(fsrdata->category) {
1065
+			case RESPONSE:
1066
+				if(fsrdata->uri != NULL) {
1067
+					/* get the first uri element */
1068
+					if((tmp.s = fsrdata->uri->value) != NULL) {
1069
+						tmp.len = strlen(fsrdata->uri->value);
1070
+						if(pkg_str_dup(&uri, &tmp) < 0) {
1071
+							LM_ERR("could not copy: [%.*s]\n", tmp.len, tmp.s);
1072
+							goto err;
1073
+						}
1074
+					}
1075
+				} else {
1076
+					LM_ERR("uri not found: [%.*s]\n", ret.len, ret.s);
1077
+					goto err;
1078
+				}
1079
+				if(fsrdata->mapping != NULL) {
1080
+					/* get the displayName element */
1081
+					if((tmp.s = fsrdata->mapping->name->text) != NULL) {
1082
+						tmp.len = strlen(fsrdata->mapping->name->text);
1083
+						if(pkg_str_dup(&name, &tmp) < 0) {
1084