Asterisk - The Open Source Telephony Project GIT-master-55f4e6d
geoloc_eprofile.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2022, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19#include "asterisk.h"
20#include "asterisk/pbx.h"
21#include "asterisk/strings.h"
22#include "asterisk/xml.h"
23#include "geoloc_private.h"
24
28
32
36
37static struct ast_xslt_doc *eprofile_to_pidf_xslt;
38static struct ast_xslt_doc *pidf_to_eprofile_xslt;
39
41
42#define DUP_VARS(_dest, _source) \
43({ \
44 int _rc = 0; \
45 if (_source) { \
46 struct ast_variable *_vars = ast_variables_dup(_source); \
47 if (!_vars) { \
48 _rc = -1; \
49 } else { \
50 _dest = _vars; \
51 } \
52 } \
53 (_rc); \
54})
55
56static void geoloc_eprofile_destructor(void *obj)
57{
58 struct ast_geoloc_eprofile *eprofile = obj;
59
67}
68
70{
71 struct ast_geoloc_eprofile *eprofile = ao2_alloc_options(sizeof(*eprofile),
73
74 ast_string_field_init(eprofile, 256);
75 ast_string_field_set(eprofile, id, name); /* SAFE string fields handle NULL */
76
77 return eprofile;
78}
79
81{
82 struct ast_geoloc_location *loc = NULL;
83 RAII_VAR(struct ast_variable *, temp_locinfo, NULL, ast_variables_destroy);
84 RAII_VAR(struct ast_variable *, temp_effloc, NULL, ast_variables_destroy);
85 RAII_VAR(struct ast_variable *, temp_confidence, NULL, ast_variables_destroy);
86 const char *method = NULL;
87 const char *location_source = NULL;
89 struct ast_variable *var;
90 int rc = 0;
91
92 if (!eprofile) {
93 return -1;
94 }
95
96 if (!ast_strlen_zero(eprofile->location_reference)) {
98 if (!loc) {
99 ast_log(LOG_ERROR, "Profile '%s' referenced location '%s' does not exist!", eprofile->id,
100 eprofile->location_reference);
101 return -1;
102 }
103
104 format = loc->format;
105 method = loc->method;
106 location_source = loc->location_source;
107 rc = DUP_VARS(temp_locinfo, loc->location_info);
108 if (rc == 0) {
109 rc = DUP_VARS(temp_confidence, loc->confidence);
110 }
111 ao2_ref(loc, -1);
112 if (rc != 0) {
113 return -1;
114 }
115 } else {
116 format = eprofile->format;
117 method = eprofile->method;
118 location_source = eprofile->location_source;
119 rc = DUP_VARS(temp_locinfo, eprofile->location_info);
120 if (rc == 0) {
121 rc = DUP_VARS(temp_confidence, eprofile->confidence);
122 }
123 if (rc != 0) {
124 return -1;
125 }
126 }
127
128 rc = DUP_VARS(temp_effloc, temp_locinfo);
129 if (rc != 0) {
130 return -1;
131 }
132
133 if (eprofile->location_refinement) {
134 for (var = eprofile->location_refinement; var; var = var->next) {
135 struct ast_variable *newvar = ast_variable_new(var->name, var->value, "");
136 if (!newvar) {
137 return -1;
138 }
139 if (ast_variable_list_replace(&temp_effloc, newvar)) {
140 ast_variable_list_append(&temp_effloc, newvar);
141 }
142 }
143 }
144
145 eprofile->format = format;
147 ast_string_field_set(eprofile, location_source, location_source);
148
150 eprofile->location_info = temp_locinfo;
151 temp_locinfo = NULL;
153 eprofile->effective_location = temp_effloc;
154 temp_effloc = NULL;
155
156 return 0;
157}
158
160{
161 struct ast_geoloc_eprofile *eprofile;
162 const char *profile_id;
163 int rc = 0;
164
165 if (!src) {
166 return NULL;
167 }
168
169 profile_id = ast_strdupa(src->id);
170
171 eprofile = ast_geoloc_eprofile_alloc(profile_id);
172 if (!eprofile) {
173 return NULL;
174 }
175
176 eprofile->allow_routing_use = src->allow_routing_use;
177 eprofile->pidf_element = src->pidf_element;
179 eprofile->format = src->format;
180 eprofile->precedence = src->precedence;
181
182
184 if (rc == 0) {
185 ast_string_field_set(eprofile, notes, src->notes);
186 }
187 if (rc == 0) {
188 ast_string_field_set(eprofile, method, src->method);
189 }
190 if (rc == 0) {
192 }
193 if (rc == 0) {
194 rc = DUP_VARS(eprofile->location_info, src->location_info);
195 }
196 if (rc == 0) {
197 rc = DUP_VARS(eprofile->effective_location, src->effective_location);
198 }
199 if (rc == 0) {
201 }
202 if (rc == 0) {
203 rc = DUP_VARS(eprofile->location_variables, src->location_variables);
204 }
205 if (rc == 0) {
206 rc = DUP_VARS(eprofile->usage_rules, src->usage_rules);
207 }
208 if (rc == 0) {
209 rc = DUP_VARS(eprofile->confidence, src->confidence);
210 }
211 if (rc != 0) {
212 ao2_ref(eprofile, -1);
213 return NULL;
214 }
215
216
217 return eprofile;
218}
219
221{
222 struct ast_geoloc_eprofile *eprofile;
223 const char *profile_id;
224 int rc = 0;
225
226 if (!profile) {
227 return NULL;
228 }
229
230 profile_id = ast_sorcery_object_get_id(profile);
231
232 eprofile = ast_geoloc_eprofile_alloc(profile_id);
233 if (!eprofile) {
234 return NULL;
235 }
236
237 ao2_lock(profile);
238 eprofile->allow_routing_use = profile->allow_routing_use;
239 eprofile->pidf_element = profile->pidf_element;
241 eprofile->format = profile->format;
242
243
245 if (rc == 0) {
246 ast_string_field_set(eprofile, notes, profile->notes);
247 }
248 if (rc == 0) {
249 ast_string_field_set(eprofile, method, profile->method);
250 }
251 if (rc == 0) {
253 }
254 if (rc == 0) {
255 rc = DUP_VARS(eprofile->location_info, profile->location_info);
256 }
257 if (rc == 0) {
258 rc = DUP_VARS(eprofile->location_refinement, profile->location_refinement);
259 }
260 if (rc == 0) {
261 rc = DUP_VARS(eprofile->location_variables, profile->location_variables);
262 }
263 if (rc == 0) {
264 rc = DUP_VARS(eprofile->usage_rules, profile->usage_rules);
265 }
266 if (rc == 0) {
267 rc = DUP_VARS(eprofile->confidence, profile->confidence);
268 }
269 if (rc != 0) {
270 ao2_unlock(profile);
271 ao2_ref(eprofile, -1);
272 return NULL;
273 }
274
275 eprofile->precedence = profile->precedence;
276 ao2_unlock(profile);
277
278 if (ast_geoloc_eprofile_refresh_location(eprofile) != 0) {
279 ao2_ref(eprofile, -1);
280 return NULL;
281 }
282
283 return eprofile;
284}
285
286static int set_loc_src(struct ast_geoloc_eprofile *eprofile, const char *uri, const char *ref_str)
287{
288 char *local_uri = ast_strdupa(uri);
289 char *loc_src = NULL;
290
291 loc_src = strchr(local_uri, ';');
292 if (loc_src) {
293 *loc_src = '\0';
294 loc_src++;
295 }
296
297 if (!ast_strlen_zero(loc_src)) {
298 if (ast_begins_with(loc_src, "loc-src=")) {
299 struct ast_sockaddr loc_source_addr;
300 int rc = 0;
301 loc_src += 8;
302 rc = ast_sockaddr_parse(&loc_source_addr, loc_src, PARSE_PORT_FORBID);
303 if (rc == 1) {
304 ast_log(LOG_WARNING, "%s: URI '%s' has an invalid 'loc-src' parameter."
305 " RFC8787 states that IP addresses MUST be dropped.\n",
306 ref_str, uri);
307 return -1;
308 } else {
309 ast_string_field_set(eprofile, location_source, loc_src);
310 }
311 }
312 }
313 return 0;
314}
315
317 const char *ref_str)
318{
319 struct ast_geoloc_eprofile *eprofile = NULL;
320 char *ra = NULL;
321 char *local_uri;
322
323 if (ast_strlen_zero(uri)) {
324 return NULL;
325 }
326 local_uri = ast_strdupa(uri);
327
328 if (local_uri[0] == '<') {
329 local_uri++;
330 }
331 ra = strchr(local_uri, '>');
332 if (ra) {
333 *ra = '\0';
334 }
335
336 ast_strip(local_uri);
337
338 eprofile = ast_geoloc_eprofile_alloc(local_uri);
339 if (!eprofile) {
340 return NULL;
341 }
342
343 set_loc_src(eprofile, uri, ref_str);
344
345 eprofile->format = AST_GEOLOC_FORMAT_URI;
346 eprofile->location_info = ast_variable_new("URI", local_uri, "");
347
348 return eprofile;
349}
350
352 struct ast_variable *variables, struct ast_channel *chan)
353{
354 struct ast_variable *dest = NULL;
355 struct ast_variable *var = NULL;
356 struct varshead *vh = NULL;
357 struct ast_str *buf = ast_str_alloca(256);
358
359 if (!source || !chan) {
360 return NULL;
361 }
362
363 /*
364 * ast_str_substitute_variables does only minimal recursive resolution so we need to
365 * pre-resolve each variable in the "variables" list, then use that result to
366 * do the final pass on the "source" variable list.
367 */
368 if (variables) {
369 var = variables;
370 vh = ast_var_list_create();
371 if (!vh) {
372 return NULL;
373 }
374 for ( ; var; var = var->next) {
375 ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);
378 }
379 }
380
381 var = source;
382 for ( ; var; var = var->next) {
383 struct ast_variable *newvar = NULL;
384 ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);
385 newvar = ast_variable_new(var->name, ast_str_buffer(buf), "");
386 if (!newvar) {
389 return NULL;
390 }
391 ast_variable_list_append(&dest, newvar);
393 }
395
396 return dest;
397}
398
399
401 struct ast_channel *chan, struct ast_str **buf, const char *ref_str)
402{
403 const char *uri = NULL;
404 struct ast_variable *resolved = NULL;
405 char *result;
406 int we_created_buf = 0;
407
408 if (!eprofile || !buf || !chan) {
409 return NULL;
410 }
411
412 if (eprofile->format != AST_GEOLOC_FORMAT_URI) {
413 ast_log(LOG_ERROR, "%s: '%s' is not a URI profile. It's '%s'\n",
414 ref_str, eprofile->id, ast_geoloc_format_to_name(eprofile->format));
415 return NULL;
416 }
417
419 eprofile->location_variables, chan);
420 if (!resolved) {
421 return NULL;
422 }
423
424 uri = ast_variable_find_in_list(resolved, "URI");
425 result = uri ? ast_strdupa(uri) : NULL;
426 ast_variables_destroy(resolved);
427
428 if (ast_strlen_zero(result)) {
429 ast_log(LOG_ERROR, "%s: '%s' is a URI profile but had no, or an empty, 'URI' entry in location_info\n",
430 ref_str, eprofile->id);
431 return NULL;
432 }
433
434 if (!*buf) {
435 *buf = ast_str_create(256);
436 if (!*buf) {
437 return NULL;
438 }
439 we_created_buf = 1;
440 }
441
442 if (ast_str_append(buf, 0, "%s", result) <= 0) {
443 if (we_created_buf) {
444 ast_free(*buf);
445 *buf = NULL;
446 return NULL;
447 }
448 }
449
450 return ast_str_buffer(*buf);
451}
452
453static struct ast_variable *var_list_from_node(struct ast_xml_node *node,
454 const char *ref_str)
455{
456 struct ast_variable *list = NULL;
457 struct ast_xml_node *container;
458 struct ast_xml_node *child;
459 struct ast_variable *var;
460 SCOPE_ENTER(3, "%s\n", ref_str);
461
463 for (child = container; child; child = ast_xml_node_get_next(child)) {
464 const char *name = ast_xml_node_get_name(child);
465 const char *value = ast_xml_get_text(child);
466 const char *uom = ast_xml_get_attribute(child, "uom");
467
468 if (uom) {
469 /* '20 radians\0' */
470 char newval[strlen(value) + 1 + strlen(uom) + 1];
471 sprintf(newval, "%s %s", value, uom);
472 var = ast_variable_new(name, newval, "");
473 } else {
475 }
476
479
480 if (!var) {
482 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
483 }
485 }
486
487 if (TRACE_ATLEAST(5)) {
488 struct ast_str *buf = NULL;
489 ast_variable_list_join(list, ", ", "=", "\"", &buf);
490 ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
491 ast_free(buf);
492 }
493
494 SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
495}
496
497static struct ast_variable *var_list_from_loc_info(struct ast_xml_node *locinfo,
498 enum ast_geoloc_format format, const char *ref_str)
499{
500 struct ast_variable *list = NULL;
501 struct ast_variable *locinfo_list = NULL;
502 struct ast_xml_node *container;
503 struct ast_variable *var = NULL;
504 const char *attr;
505 SCOPE_ENTER(3, "%s\n", ref_str);
506
508 if (format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {
509 attr = ast_xml_get_attribute(container, "lang");
510 if (attr) {
511 var = ast_variable_new("lang", attr, "");
512 ast_xml_free_attr(attr);
513 if (!var) {
514 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
515 }
517 }
518 } else {
520 if (!var) {
521 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
522 }
524
525 attr = ast_xml_get_attribute(container, "srsName");
526 var = ast_variable_new("crs", attr, "");
527 ast_xml_free_attr(attr);
528 if (!var) {
530 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
531 }
533 }
534
535 locinfo_list = var_list_from_node(container, ref_str);
536 if (locinfo_list == NULL) {
537 ast_log(LOG_WARNING, "%s: There were no elements in the location info\n", ref_str);
538 SCOPE_EXIT_RTN_VALUE(list, "%s: There were no elements in the location info\n", ref_str);
539 }
540 ast_variable_list_append(&list, locinfo_list);
541
542 if (TRACE_ATLEAST(5)) {
543 struct ast_str *buf = NULL;
544 ast_variable_list_join(list, ", ", "=", "\"", &buf);
545 ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
546 ast_free(buf);
547 }
548
549 SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
550}
551
552static struct ast_variable *var_list_from_confidence(struct ast_xml_node *confidence,
553 const char *ref_str)
554{
555 struct ast_variable *list = NULL;
556 struct ast_variable *var;
557 const char *pdf;
558 const char *value;
559 SCOPE_ENTER(3, "%s\n", ref_str);
560
561 if (!confidence) {
562 SCOPE_EXIT_RTN_VALUE(NULL, "%s: No confidence\n", ref_str);
563 }
564
565 pdf = ast_xml_get_attribute(confidence, "pdf");
566 var = ast_variable_new("pdf", S_OR(pdf, "unknown"), "");
568 if (!var) {
569 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
570 }
572
573 value = ast_xml_get_text(confidence);
574 var = ast_variable_new("value", S_OR(value, "95"), "");
576 if (!var) {
578 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
579 }
581
582 if (TRACE_ATLEAST(5)) {
583 struct ast_str *buf = NULL;
584 ast_variable_list_join(list, ", ", "=", "\"", &buf);
585 ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
586 ast_free(buf);
587 }
588
589 SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
590}
591
593 struct ast_xml_doc *result_doc, const char *ref_str)
594{
595 struct ast_geoloc_eprofile *eprofile;
596 /*
597 * None of the ast_xml_nodes needs to be freed
598 * because they're just pointers into result_doc.
599 */
600 struct ast_xml_node *presence = NULL;
601 struct ast_xml_node *pidf_element = NULL;
602 struct ast_xml_node *location_info = NULL;
603 struct ast_xml_node *confidence = NULL;
604 struct ast_xml_node *usage_rules = NULL;
605 struct ast_xml_node *method = NULL;
606 struct ast_xml_node *note_well = NULL;
607 /*
608 * Like nodes, names of nodes are just
609 * pointers into result_doc and don't need to be freed.
610 */
611 const char *pidf_element_str;
612 /*
613 * Attributes and element text however are allocated on the fly
614 * so they DO need to be freed after use.
615 */
616 const char *id = NULL;
617 const char *format_str = NULL;
618 const char *method_str = NULL;
619 const char *note_well_str = NULL;
620
621 SCOPE_ENTER(3, "%s\n", ref_str);
622
623 if (!result_doc) {
624 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: result_doc was NULL", ref_str);
625 }
626
627 if (TRACE_ATLEAST(5)) {
628 char *doc_str = NULL;
629 int doc_len = 0;
630
631 ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
632 ast_trace(5, "xslt result doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
633 ast_xml_free_text(doc_str);
634 }
635
636 presence = ast_xml_get_root(result_doc);
637 if (!presence) {
638 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find 'presence' root element\n",
639 ref_str);
640 }
641
642 pidf_element = ast_xml_node_get_children(presence);
643 if (!pidf_element) {
644 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find a device, tuple or person element\n",
645 ref_str);
646 }
647
648 id = ast_xml_get_attribute(pidf_element, "id");
649 if (ast_strlen_zero(id)) {
651 id = ast_xml_get_attribute(presence, "entity");
652 }
653
654 if (ast_strlen_zero(id)) {
655 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Unable to find 'id' attribute\n", ref_str);
656 }
657
658 eprofile = ast_geoloc_eprofile_alloc(id);
660 if (!eprofile) {
661 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
662 }
663
664 location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
665 if (!location_info) {
666 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find a location-info element\n",
667 ref_str);
668 }
669
670 format_str = ast_xml_get_attribute(location_info, "format");
671 if (ast_strlen_zero(format_str)) {
672 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Unable to find 'format' attribute\n", ref_str);
673 }
674
675 eprofile->format = AST_GEOLOC_FORMAT_NONE;
676 if (strcasecmp(format_str, "gml") == 0) {
677 eprofile->format = AST_GEOLOC_FORMAT_GML;
678 } else if (strcasecmp(format_str, "civicAddress") == 0) {
680 }
681
682 if (eprofile->format == AST_GEOLOC_FORMAT_NONE) {
683 char *dup_format_str = ast_strdupa(format_str);
684 ast_xml_free_attr(format_str);
685 ao2_ref(eprofile, -1);
686 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unknown format '%s'\n", ref_str, dup_format_str);
687 }
688 ast_xml_free_attr(format_str);
689
690 pidf_element_str = ast_xml_node_get_name(pidf_element);
691 eprofile->pidf_element = ast_geoloc_pidf_element_str_to_enum(pidf_element_str);
692
693 eprofile->location_info = var_list_from_loc_info(location_info, eprofile->format, ref_str);
694 if (!eprofile->location_info) {
695 ao2_ref(eprofile, -1);
697 "%s: Unable to create location variables\n", ref_str);
698 }
699
700 /*
701 * The function calls that follow are all NULL tolerant
702 * so no need for explicit error checking.
703 */
704 usage_rules = ast_xml_find_child_element(pidf_element, "usage-rules", NULL, NULL);
705 eprofile->usage_rules = var_list_from_node(usage_rules, ref_str);
706 confidence = ast_xml_find_child_element(location_info, "confidence", NULL, NULL);
707 eprofile->confidence = var_list_from_confidence(confidence, ref_str);
708
709 method = ast_xml_find_child_element(pidf_element, "method", NULL, NULL);
710 method_str = ast_xml_get_text(method);
711 ast_string_field_set(eprofile, method, method_str);
712 ast_xml_free_text(method_str);
713
714 note_well = ast_xml_find_child_element(pidf_element, "note-well", NULL, NULL);
715 note_well_str = ast_xml_get_text(note_well);
716 ast_string_field_set(eprofile, notes, note_well_str);
717 ast_xml_free_text(note_well_str);
718
719 SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", ref_str);
720}
721
722static int is_pidf_lo(struct ast_xml_doc *result_doc)
723{
724 struct ast_xml_node *presence;
725 struct ast_xml_node *pidf_element;
726 struct ast_xml_node *location_info;
727 const char *pidf_element_name;
728
729 if (!result_doc) {
730 return 0;
731 }
732 presence = ast_xml_get_root(result_doc);
733 if (!presence || !ast_strings_equal("presence", ast_xml_node_get_name(presence))) {
734 return 0;
735 }
736
737 pidf_element = ast_xml_node_get_children(presence);
738 if (!pidf_element) {
739 return 0;
740 }
741 pidf_element_name = ast_xml_node_get_name(pidf_element);
742 if (!ast_strings_equal(pidf_element_name, "device") &&
743 !ast_strings_equal(pidf_element_name, "tuple") &&
744 !ast_strings_equal(pidf_element_name, "person")) {
745 return 0;
746 }
747
748 location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
749 if (!location_info) {
750 return 0;
751 }
752
753 return 1;
754}
755
757 struct ast_xml_doc *pidf_xmldoc, const char *geoloc_uri, const char *ref_str)
758{
759 struct ast_xml_doc *result_doc = NULL;
760 struct ast_geoloc_eprofile *eprofile = NULL;
761
762 SCOPE_ENTER(3, "%s\n", ref_str);
763
764 result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, NULL);
765 if (!is_pidf_lo(result_doc)) {
766 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Not a PIDF-LO. Skipping.\n", ref_str);
767 }
768
769 /*
770 * The document returned from the stylesheet application looks like this...
771 * <presence id="presence-entity">
772 * <tuple id="element-id">
773 * <location-info format="gml">shape="Ellipsoid", crs="3d", ...</location-info>
774 * <usage-rules>retransmission-allowed="no", retention-expiry="2010-11-14T20:00:00Z"</usage-rules>
775 * <method>Hybrid_A-GPS</method>
776 * </tuple>
777 * </presence>
778 *
779 * Regardless of whether the pidf-element was tuple, device or person and whether
780 * the format is gml or civicAddress, the presence, pidf-element and location-info
781 * elements should be there.
782 *
783 * The confidence, usage-rules and note-well elements are optional.
784 */
785
786 if (TRACE_ATLEAST(5)) {
787 char *doc_str = NULL;
788 int doc_len = 0;
789
790 ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
791 ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
792 ast_xml_free_text(doc_str);
793 doc_str = NULL;
794 doc_len = 0;
795 }
796
797 eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, ref_str);
798 ast_xml_close(result_doc);
799
800 if (eprofile && geoloc_uri) {
801 set_loc_src(eprofile, geoloc_uri, ref_str);
802 }
803
804 SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", ref_str);
805}
806
807/*!
808 * \internal
809 * \brief Create an common, intermediate XML document to pass to the outgoing XSLT process
810 *
811 * \param element_name The name of the top-level XML element to create
812 * \param eprofile The eprofile
813 * \param chan The channel to resolve variables against
814 * \param ref_string A reference string for error messages
815 * \return An XML doc
816 *
817 * \note Given that the document is simple and static, it was easier to just
818 * create the elements in a string buffer and call ast_xml_read_memory()
819 * at the end instead of creating
820 */
821static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_name, struct ast_geoloc_eprofile *eprofile,
822 struct ast_channel *chan, const char *ref_string)
823{
824 struct ast_variable *resolved_location = NULL;
825 struct ast_variable *resolved_usage = NULL;
826 struct ast_variable *var = NULL;
827 RAII_VAR(struct ast_xml_node *, pidf_node, NULL, ast_xml_free_node);
828 struct ast_xml_node *rtn_pidf_node;
829 struct ast_xml_node *loc_node;
830 struct ast_xml_node *confidence_node;
831 struct ast_xml_node *info_node;
832 struct ast_xml_node *rules_node;
833 struct ast_xml_node *method_node;
834 struct ast_xml_node *notes_node;
835 struct ast_xml_node *timestamp_node;
836 struct timeval tv = ast_tvnow();
837 struct tm tm = { 0, };
838 char timestr[32] = { 0, };
839 int rc = 0;
840
841 SCOPE_ENTER(3, "%s\n", ref_string);
842
843 if (!eprofile || !chan) {
844 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Either or both eprofile or chan were NULL\n", ref_string);
845 }
846
847 pidf_node = ast_xml_new_node(element_name);
848 if (!pidf_node) {
849 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n",
850 ref_string, element_name);
851 }
852
853 loc_node = ast_xml_new_child(pidf_node, "location-info");
854 if (!loc_node) {
855 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'location-info' XML node\n",
856 ref_string);
857 }
858 rc = ast_xml_set_attribute(loc_node, "format", ast_geoloc_format_to_name(eprofile->format));
859 if (rc != 0) {
860 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'format' XML attribute\n", ref_string);
861 }
862
863 resolved_location = geoloc_eprofile_resolve_varlist(eprofile->effective_location,
864 eprofile->location_variables, chan);
865 if (eprofile->format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {
866 info_node = geoloc_civicaddr_list_to_xml(resolved_location, ref_string);
867 } else {
868 info_node = geoloc_gml_list_to_xml(resolved_location, ref_string);
869 }
870 ast_variables_destroy(resolved_location);
871
872 if (!info_node) {
873 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML from '%s' list\n",
874 ref_string, ast_geoloc_format_to_name(eprofile->format));
875 }
876 if (!ast_xml_add_child(loc_node, info_node)) {
877 ast_xml_free_node(info_node);
878 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable add '%s' node to XML document\n",
879 ref_string, ast_geoloc_format_to_name(eprofile->format));
880 }
881
882 if (eprofile->confidence) {
883 const char *value = S_OR(ast_variable_find_in_list(eprofile->confidence, "value"), "95");
884 const char *pdf = S_OR(ast_variable_find_in_list(eprofile->confidence, "pdf"), "unknown");
885
886 confidence_node = ast_xml_new_child(loc_node, "confidence");
887 if (!confidence_node) {
888 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'confidence' XML node\n",
889 ref_string);
890 }
891 rc = ast_xml_set_attribute(confidence_node, "pdf", pdf);
892 if (rc != 0) {
893 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'pdf' attribute on 'confidence' element\n", ref_string);
894 }
895
896 ast_xml_set_text(confidence_node, value);
897 }
898
899 rules_node = ast_xml_new_child(pidf_node, "usage-rules");
900 if (!rules_node) {
901 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'usage-rules' XML node\n",
902 ref_string);
903 }
904 resolved_usage = geoloc_eprofile_resolve_varlist(eprofile->usage_rules,
905 eprofile->location_variables, chan);
906 for (var = resolved_usage; var; var = var->next) {
907 struct ast_xml_node *ur = ast_xml_new_child(rules_node, var->name);
908 ast_xml_set_text(ur, var->value);
909 }
910 ast_variables_destroy(resolved_usage);
911
912 if (!ast_strlen_zero(eprofile->method)) {
913 method_node = ast_xml_new_child(pidf_node, "method");
914 if (!method_node) {
915 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'method' XML node\n",
916 ref_string);
917 }
918 ast_xml_set_text(method_node, eprofile->method);
919 };
920
921 if (!ast_strlen_zero(eprofile->notes)) {
922 notes_node = ast_xml_new_child(pidf_node, "note-well");
923 if (!notes_node) {
924 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'note-well' XML node\n",
925 ref_string);
926 }
927 ast_xml_set_text(notes_node, eprofile->notes);
928 };
929
930 gmtime_r(&tv.tv_sec, &tm);
931 strftime(timestr, sizeof(timestr), "%FT%TZ", &tm);
932 timestamp_node = ast_xml_new_child(pidf_node, "timestamp");
933 if (!timestamp_node) {
934 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'timestamp' XML node\n",
935 ref_string);
936 }
937 ast_xml_set_text(timestamp_node, timestr);
938
939 rtn_pidf_node = pidf_node;
940 pidf_node = NULL;
941 SCOPE_EXIT_RTN_VALUE(rtn_pidf_node, "%s: Done\n", ref_string);
942}
943
944#define CREATE_NODE_LIST(node) \
945 if (!node) { \
946 node = ast_xml_new_child(root_node, \
947 geoloc_pidf_element_to_name(eprofile->pidf_element)); \
948 if (!pidfs[eprofile->pidf_element]) { \
949 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create pidf '%s' XML node\n", \
950 ref_string, geoloc_pidf_element_to_name(eprofile->pidf_element)); \
951 } \
952 }
953
955 struct ast_channel *chan, struct ast_str **buf, const char * ref_string)
956{
957 RAII_VAR(struct ast_xml_doc *, intermediate, NULL, ast_xml_close);
958 RAII_VAR(struct ast_xml_doc *, pidf_doc, NULL, ast_xml_close);
959 struct ast_xml_node *root_node;
960 struct ast_xml_node *pidfs[AST_PIDF_ELEMENT_LAST] = {NULL, };
961 struct ast_geoloc_eprofile *eprofile;
962 int eprofile_count = 0;
963 int i;
964 char *doc_str = NULL;
965 int doc_len = 0;
966 int rc = 0;
967 SCOPE_ENTER(3, "%s\n", ref_string);
968
969 if (!ds || !chan || !buf || !*buf || ast_strlen_zero(ref_string)) {
970 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Either or both datastore or chan were NULL\n",
971 ref_string);
972 }
973
974 intermediate = ast_xml_new();
975 if (!intermediate) {
976 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML document\n", ref_string);
977 }
978 root_node = ast_xml_new_node("presence");
979 if (!root_node) {
980 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create root XML node\n", ref_string);
981 }
982 ast_xml_set_root(intermediate, root_node);
983
984 eprofile_count = ast_geoloc_datastore_size(ds);
985 for (i = 0; i < eprofile_count; i++) {
986 struct ast_xml_node *temp_node = NULL;
987 struct ast_xml_node *curr_loc = NULL;
988 struct ast_xml_node *new_loc = NULL;
989 struct ast_xml_node *new_loc_child = NULL;
990 struct ast_xml_node *new_loc_child_dup = NULL;
991 const char *entity = NULL;
992 int has_no_entity = 0;
993 eprofile = ast_geoloc_datastore_get_eprofile(ds, i);
994 if (eprofile->format == AST_GEOLOC_FORMAT_URI) {
995 continue;
996 }
997
998 entity = ast_xml_get_attribute(root_node, "entity");
999 has_no_entity = ast_strlen_zero(entity);
1000 ast_xml_free_attr(entity);
1001 if (has_no_entity) {
1002 rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);
1003 if (rc != 0) {
1004 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);
1005 }
1006 }
1007
1008 temp_node = geoloc_eprofile_to_intermediate(ast_geoloc_pidf_element_to_name(eprofile->pidf_element),
1009 eprofile, chan, ref_string);
1010 if (!temp_node) {
1011 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create temp_node\n", ref_string);
1012 }
1013
1014 if (!pidfs[eprofile->pidf_element]) {
1015 pidfs[eprofile->pidf_element] = temp_node;
1016 ast_xml_add_child(root_node, temp_node);
1017 continue;
1018 }
1019
1020 curr_loc = ast_xml_find_child_element(pidfs[eprofile->pidf_element], "location-info", NULL, NULL);
1021 new_loc = ast_xml_find_child_element(temp_node, "location-info", NULL, NULL);
1022 new_loc_child = ast_xml_node_get_children(new_loc);
1023 new_loc_child_dup = ast_xml_copy_node_list(new_loc_child);
1024 ast_xml_add_child_list(curr_loc, new_loc_child_dup);
1025
1026 ast_xml_free_node(temp_node);
1027 }
1028
1029 if (TRACE_ATLEAST(5)) {
1030 ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
1031 ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
1032 ast_xml_free_text(doc_str);
1033 doc_str = NULL;
1034 doc_len = 0;
1035 }
1036
1037 pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, NULL);
1038 if (!pidf_doc) {
1039 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate docs\n",
1040 ref_string);
1041 }
1042
1043 ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);
1044 if (doc_len == 0 || !doc_str) {
1045 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump final PIDF-LO doc to string\n",
1046 ref_string);
1047 }
1048
1049 rc = ast_str_set(buf, 0, "%s", doc_str);
1050 ast_xml_free_text(doc_str);
1051 if (rc <= 0) {
1052 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",
1053 ref_string, rc);
1054 }
1055
1056 ast_trace(5, "Final doc:\n%s\n", ast_str_buffer(*buf));
1057
1058 SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: Done\n", ref_string);
1059}
1060
1062 struct ast_channel *chan, struct ast_str **buf, const char * ref_string)
1063{
1064 RAII_VAR(struct ast_xml_doc *, intermediate, NULL, ast_xml_close);
1065 RAII_VAR(struct ast_xml_doc *, pidf_doc, NULL, ast_xml_close);
1066 struct ast_xml_node *root_node;
1067 char *doc_str = NULL;
1068 int doc_len;
1069 int rc = 0;
1070 struct ast_xml_node *temp_node = NULL;
1071 const char *entity = NULL;
1072 int has_no_entity = 0;
1073 const char *params[] = { "suppress_empty_ca_elements", "false()", NULL };
1074
1075 SCOPE_ENTER(3, "%s\n", ref_string);
1076
1077 if (!eprofile || !chan || !buf || !*buf || ast_strlen_zero(ref_string)) {
1078 SCOPE_EXIT_RTN_VALUE(NULL, "%s: One of eprofile, chan or buf was NULL\n",
1079 ref_string);
1080 }
1081
1082 if (eprofile->format == AST_GEOLOC_FORMAT_URI) {
1083 SCOPE_EXIT_RTN_VALUE(NULL, "%s: eprofile '%s' was a URI format\n",
1084 ref_string, eprofile->id);
1085 }
1086
1087 intermediate = ast_xml_new();
1088 if (!intermediate) {
1089 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML document\n", ref_string);
1090 }
1091 root_node = ast_xml_new_node("presence");
1092 if (!root_node) {
1093 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create root XML node\n", ref_string);
1094 }
1095 ast_xml_set_root(intermediate, root_node);
1096
1097 entity = ast_xml_get_attribute(root_node, "entity");
1098 has_no_entity = ast_strlen_zero(entity);
1099 ast_xml_free_attr(entity);
1100 if (has_no_entity) {
1101 rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);
1102 if (rc != 0) {
1103 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);
1104 }
1105 }
1106
1108 ast_geoloc_pidf_element_to_name(eprofile->pidf_element), eprofile, chan, ref_string);
1109 if (!temp_node) {
1110 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create temp_node for eprofile '%s'\n",
1111 ref_string, eprofile->id);
1112 }
1113
1114 ast_xml_add_child(root_node, temp_node);
1115
1116 if (TRACE_ATLEAST(5)) {
1117 ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
1118 ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
1119 ast_xml_free_text(doc_str);
1120 doc_str = NULL;
1121 doc_len = 0;
1122 }
1123
1124 if (eprofile->suppress_empty_ca_elements) {
1125 params[1] = "true()";
1126 }
1127 pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, params);
1128 if (!pidf_doc) {
1129 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc\n",
1130 ref_string);
1131 }
1132
1133 ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);
1134 if (doc_len == 0 || !doc_str) {
1135 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump final PIDF-LO doc to string\n",
1136 ref_string);
1137 }
1138
1139 rc = ast_str_set(buf, 0, "%s", doc_str);
1140 ast_xml_free_text(doc_str);
1141 if (rc <= 0) {
1142 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",
1143 ref_string, rc);
1144 }
1145
1146 ast_trace(5, "Final doc:\n%s\n", ast_str_buffer(*buf));
1147
1148 SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: Done\n", ref_string);
1149}
1150
1151#ifdef TEST_FRAMEWORK
1152static void load_tests(void);
1153static void unload_tests(void);
1154#else
1155static void load_tests(void) {}
1156static void unload_tests(void) {}
1157#endif
1158
1159
1161{
1162 unload_tests();
1164 ast_xslt_close(pidf_to_eprofile_xslt);
1165 }
1166
1168 ast_xslt_close(eprofile_to_pidf_xslt);
1169 }
1170
1171 if (geoloc_sorcery) {
1173 }
1174
1176}
1177
1179{
1182
1185
1186 pidf_to_eprofile_xslt = ast_xslt_read_memory(
1188 if (!pidf_to_eprofile_xslt) {
1189 ast_log(LOG_ERROR, "Unable to read pidf_to_eprofile_xslt from memory\n");
1191 }
1192
1195
1196 eprofile_to_pidf_xslt = ast_xslt_read_memory(
1198 if (!eprofile_to_pidf_xslt) {
1199 ast_log(LOG_ERROR, "Unable to read eprofile_to_pidf_xslt from memory\n");
1200// geoloc_eprofile_unload();
1202 }
1203
1205
1206 load_tests();
1207
1209}
1210
1212{
1214}
1215
1216
1217#ifdef TEST_FRAMEWORK
1218#include "asterisk/test.h"
1219
1220AST_TEST_DEFINE(test_create_from_uri)
1221{
1222
1223 RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
1224 const char *uri = NULL;
1225 int rc = AST_TEST_PASS;
1226
1227 switch (cmd) {
1228 case TEST_INIT:
1229 info->name = "create_from_uri";
1230 info->category = "/geoloc/";
1231 info->summary = "Test create from uri";
1232 info->description = info->summary;
1233 return AST_TEST_NOT_RUN;
1234 case TEST_EXECUTE:
1235 break;
1236 }
1237
1238 eprofile = ast_geoloc_eprofile_create_from_uri("http://some_uri&a=b", __func__);
1239 ast_test_validate(test, eprofile != NULL);
1240 ast_test_validate(test, eprofile->format == AST_GEOLOC_FORMAT_URI);
1241 ast_test_validate(test, eprofile->location_info != NULL);
1242 uri = ast_variable_find_in_list(eprofile->location_info, "URI");
1243 ast_test_validate(test, uri != NULL);
1244 ast_test_validate(test, strcmp(uri, "http://some_uri&a=b") == 0);
1245
1246 return rc;
1247}
1248
1249static enum ast_test_result_state validate_eprofile(struct ast_test *test,
1250 struct ast_xml_doc * pidf_xmldoc,
1251 const char *path,
1252 const char *id,
1253 enum ast_geoloc_pidf_element pidf_element,
1254 enum ast_geoloc_format format,
1255 const char *method,
1256 const char *location,
1257 const char *usage
1258 )
1259{
1260 RAII_VAR(struct ast_str *, str, NULL, ast_free);
1261 RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
1262 RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);
1263
1264 if (!ast_strlen_zero(path)) {
1265 result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, NULL);
1266 ast_test_validate(test, (result_doc && ast_xml_node_get_children((struct ast_xml_node *)result_doc)));
1267
1268 eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, "test_create_from_xslt");
1269 } else {
1270 eprofile = ast_geoloc_eprofile_create_from_pidf(pidf_xmldoc, NULL, "test_create_from_pidf");
1271 }
1272
1273 ast_test_validate(test, eprofile != NULL);
1274 ast_test_status_update(test, "ID: '%s' pidf_element: '%s' format: '%s' method: '%s'\n", eprofile->id,
1275 ast_geoloc_pidf_element_to_name(eprofile->pidf_element),
1276 ast_geoloc_format_to_name(eprofile->format),
1277 eprofile->method);
1278
1279 ast_test_validate(test, ast_strings_equal(eprofile->id, id));
1280 ast_test_validate(test, eprofile->pidf_element == pidf_element);
1281 ast_test_validate(test, eprofile->format == format);
1282 ast_test_validate(test, ast_strings_equal(eprofile->method, method));
1283
1284 str = ast_variable_list_join(eprofile->location_info, ",", "=", NULL, NULL);
1285 ast_test_validate(test, str != NULL);
1286 ast_test_status_update(test, "location_vars expected: %s\n", location);
1287 ast_test_status_update(test, "location_vars received: %s\n", ast_str_buffer(str));
1288 ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), location));
1289 ast_free(str);
1290
1291 str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "'", NULL);
1292 ast_test_validate(test, str != NULL);
1293 ast_test_status_update(test, "usage_rules expected: %s\n", usage);
1294 ast_test_status_update(test, "usage_rules received: %s\n", ast_str_buffer(str));
1295 ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), usage));
1296
1297 return AST_TEST_PASS;
1298}
1299
1300AST_TEST_DEFINE(test_create_from_pidf)
1301{
1302
1303 RAII_VAR(struct ast_xml_doc *, pidf_xmldoc, NULL, ast_xml_close);
1305
1306 switch (cmd) {
1307 case TEST_INIT:
1308 info->name = "create_from_pidf";
1309 info->category = "/geoloc/";
1310 info->summary = "Test create from pidf scenarios";
1311 info->description = info->summary;
1312 return AST_TEST_NOT_RUN;
1313 case TEST_EXECUTE:
1314 break;
1315 }
1316
1318 ast_test_validate(test, pidf_xmldoc != NULL);
1319
1320 res = validate_eprofile(test, pidf_xmldoc,
1321 NULL,
1322 "point-2d",
1325 "Manual",
1326 "shape=Point,crs=2d,pos=-34.410649 150.87651",
1327 "retransmission-allowed='no',retention-expiry='2010-11-14T20:00:00Z'"
1328 );
1329 ast_test_validate(test, res == AST_TEST_PASS);
1330
1331 return res;
1332}
1333
1334static void load_tests(void) {
1335 AST_TEST_REGISTER(test_create_from_uri);
1336 AST_TEST_REGISTER(test_create_from_pidf);
1337}
1338static void unload_tests(void) {
1339 AST_TEST_UNREGISTER(test_create_from_uri);
1340 AST_TEST_UNREGISTER(test_create_from_pidf);
1341}
1342
1343#endif
const char * str
Definition: app_jack.c:147
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
static PGresult * result
Definition: cel_pgsql.c:84
void ast_var_list_destroy(struct varshead *head)
Definition: chanvars.c:109
static void AST_VAR_LIST_INSERT_TAIL(struct varshead *head, struct ast_var_t *var)
Definition: chanvars.h:51
#define ast_var_assign(name, value)
Definition: chanvars.h:40
struct varshead * ast_var_list_create(void)
Definition: chanvars.c:97
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static const char name[]
Definition: format_mp3.c:68
struct ast_xml_node * geoloc_civicaddr_list_to_xml(const struct ast_variable *resolved_location, const char *ref_string)
struct ast_sorcery * geoloc_get_sorcery(void)
const uint8_t _binary_res_geolocation_eprofile_to_pidf_xslt_start[]
struct ast_variable * geoloc_eprofile_resolve_varlist(struct ast_variable *source, struct ast_variable *variables, struct ast_channel *chan)
static size_t pidf_lo_test_xml_size
static void geoloc_eprofile_destructor(void *obj)
int ast_geoloc_eprofile_refresh_location(struct ast_geoloc_eprofile *eprofile)
Refresh the effective profile with any changed info.
struct ast_geoloc_eprofile * ast_geoloc_eprofile_dup(struct ast_geoloc_eprofile *src)
Duplicate an effective profile.
static struct ast_xslt_doc * pidf_to_eprofile_xslt
int geoloc_eprofile_reload(void)
int geoloc_eprofile_unload(void)
static struct ast_variable * var_list_from_node(struct ast_xml_node *node, const char *ref_str)
static struct ast_sorcery * geoloc_sorcery
const char * ast_geoloc_eprofiles_to_pidf(struct ast_datastore *ds, struct ast_channel *chan, struct ast_str **buf, const char *ref_string)
Convert a datastore containing eprofiles to a PIDF-LO document.
static struct ast_variable * var_list_from_confidence(struct ast_xml_node *confidence, const char *ref_str)
const char * ast_geoloc_eprofile_to_uri(struct ast_geoloc_eprofile *eprofile, struct ast_channel *chan, struct ast_str **buf, const char *ref_str)
Convert a URI eprofile to a URI string.
const uint8_t _binary_res_geolocation_eprofile_to_pidf_xslt_end[]
const uint8_t _binary_res_geolocation_pidf_to_eprofile_xslt_end[]
static size_t eprofile_to_pidf_xslt_size
const uint8_t _binary_res_geolocation_pidf_lo_test_xml_end[]
static int set_loc_src(struct ast_geoloc_eprofile *eprofile, const char *uri, const char *ref_str)
struct ast_geoloc_eprofile * ast_geoloc_eprofile_create_from_uri(const char *uri, const char *ref_str)
Allocate a new effective profile from a URI.
const uint8_t _binary_res_geolocation_pidf_to_eprofile_xslt_start[]
static int is_pidf_lo(struct ast_xml_doc *result_doc)
static void unload_tests(void)
struct ast_geoloc_eprofile * ast_geoloc_eprofile_alloc(const char *name)
Geolocation Effective Profile Functions.
struct ast_geoloc_eprofile * ast_geoloc_eprofile_create_from_pidf(struct ast_xml_doc *pidf_xmldoc, const char *geoloc_uri, const char *ref_str)
Allocate a new effective profile from an XML PIDF-LO document.
int geoloc_eprofile_load(void)
static struct ast_geoloc_eprofile * geoloc_eprofile_create_from_xslt_result(struct ast_xml_doc *result_doc, const char *ref_str)
const uint8_t _binary_res_geolocation_pidf_lo_test_xml_start[]
static size_t pidf_to_eprofile_xslt_size
static struct ast_xslt_doc * eprofile_to_pidf_xslt
static struct ast_xml_node * geoloc_eprofile_to_intermediate(const char *element_name, struct ast_geoloc_eprofile *eprofile, struct ast_channel *chan, const char *ref_string)
const char * ast_geoloc_eprofile_to_pidf(struct ast_geoloc_eprofile *eprofile, struct ast_channel *chan, struct ast_str **buf, const char *ref_string)
Convert a single eprofile to a PIDF-LO document.
static void load_tests(void)
static struct ast_variable * var_list_from_loc_info(struct ast_xml_node *locinfo, enum ast_geoloc_format format, const char *ref_str)
struct ast_geoloc_eprofile * ast_geoloc_eprofile_create_from_profile(struct ast_geoloc_profile *profile)
Allocate a new effective profile from an existing profile.
#define DUP_VARS(_dest, _source)
struct ast_xml_node * geoloc_gml_list_to_xml(const struct ast_variable *resolved_location, const char *ref_string)
Definition: geoloc_gml.c:238
#define TRACE_ATLEAST(level)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
#define SCOPE_ENTER(level,...)
#define ast_trace(level,...)
const char * ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
Gets the value of a variable from a variable list by name.
Definition: main/config.c:919
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
struct ast_str * ast_variable_list_join(const struct ast_variable *head, const char *item_separator, const char *name_value_separator, const char *quote_char, struct ast_str **str)
Join an ast_variable list with specified separators and quoted values.
Definition: main/config.c:700
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
Definition: main/config.c:667
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define LOG_ERROR
#define LOG_WARNING
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
def info(msg)
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
Core PBX routines and definitions.
void ast_str_substitute_variables_full2(struct ast_str **buf, ssize_t maxlen, struct ast_channel *c, struct varshead *headp, const char *templ, size_t *used, int use_both)
Perform variable/function/expression substitution on an ast_str.
static int notes
Definition: pval.c:66
struct ao2_container * container
Definition: res_fax.c:501
struct ast_geoloc_eprofile * ast_geoloc_datastore_get_eprofile(struct ast_datastore *ds, int ix)
Retrieve a specific eprofile from a datastore by index.
ast_geoloc_pidf_element
@ AST_PIDF_ELEMENT_TUPLE
@ AST_PIDF_ELEMENT_LAST
ast_geoloc_format
@ AST_GEOLOC_FORMAT_GML
@ AST_GEOLOC_FORMAT_CIVIC_ADDRESS
@ AST_GEOLOC_FORMAT_URI
@ AST_GEOLOC_FORMAT_NONE
int ast_geoloc_datastore_size(struct ast_datastore *ds)
Retrieves the number of eprofiles in the datastore.
const char * method
Definition: res_pjsip.c:1279
#define NULL
Definition: resample.c:96
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_alloca(init_len)
Definition: strings.h:848
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:693
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Checks whether a string begins with another.
Definition: strings.h:97
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Main Channel structure associated with a channel.
Structure for a data store object.
Definition: datastore.h:64
struct ast_variable * effective_location
const ast_string_field location_reference
enum ast_geoloc_format format
enum ast_geoloc_pidf_element pidf_element
const ast_string_field method
struct ast_variable * location_refinement
enum ast_geoloc_precedence precedence
const ast_string_field notes
const ast_string_field id
struct ast_variable * location_variables
struct ast_variable * confidence
struct ast_variable * usage_rules
const ast_string_field location_source
struct ast_variable * location_info
enum ast_geoloc_format format
const ast_string_field method
struct ast_variable * confidence
const ast_string_field location_source
struct ast_variable * location_info
const ast_string_field location_reference
enum ast_geoloc_format format
enum ast_geoloc_pidf_element pidf_element
const ast_string_field method
struct ast_variable * location_refinement
enum ast_geoloc_precedence precedence
const ast_string_field notes
struct ast_variable * location_variables
struct ast_variable * confidence
struct ast_variable * usage_rules
const ast_string_field location_source
struct ast_variable * location_info
Socket address structure.
Definition: netsock2.h:97
Full structure for sorcery.
Definition: sorcery.c:230
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
Definition: test_heap.c:38
int value
Definition: syslog.c:37
Test Framework API.
@ TEST_INIT
Definition: test.h:200
@ TEST_EXECUTE
Definition: test.h:201
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
#define AST_TEST_DEFINE(hdr)
Definition: test.h:126
ast_test_result_state
Definition: test.h:193
@ AST_TEST_PASS
Definition: test.h:195
@ AST_TEST_NOT_RUN
Definition: test.h:194
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
char * usage
Definition: utils/frame.c:37
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
Asterisk XML abstraction layer.
#define ast_xml_find_child_element(_parent_node, _name, _attrname, _attrvalue)
Find a direct child element by name.
Definition: xml.h:201
struct ast_xml_node * ast_xml_copy_node_list(struct ast_xml_node *list)
Create a copy of a n ode list.
Definition: xml.c:184
struct ast_xml_node * ast_xml_add_child(struct ast_xml_node *parent, struct ast_xml_node *child)
Add a child node, to a specified parent node.
Definition: xml.c:168
struct ast_xml_node * ast_xml_node_get_children(struct ast_xml_node *node)
Get the node's children.
Definition: xml.c:395
const char * ast_xml_get_attribute(struct ast_xml_node *node, const char *attrname)
Get a node attribute by name.
Definition: xml.c:267
const char * ast_xml_get_text(struct ast_xml_node *node)
Get an element content string.
Definition: xml.c:353
struct ast_xml_node * ast_xml_new_child(struct ast_xml_node *parent, const char *child_name)
Add a child node inside a passed parent node.
Definition: xml.c:156
struct ast_xml_node * ast_xml_new_node(const char *name)
Create a XML node.
Definition: xml.c:144
void ast_xml_close(struct ast_xml_doc *doc)
Close an already open document and free the used structure.
Definition: xml.c:211
void ast_xml_doc_dump_memory(struct ast_xml_doc *doc, char **buffer, int *length)
Dump the specified document to a buffer.
Definition: xml.c:385
const char * ast_xml_node_get_name(struct ast_xml_node *node)
Get the name of a node.
Definition: xml.c:390
void ast_xml_free_attr(const char *attribute)
Free an attribute returned by ast_xml_get_attribute()
Definition: xml.c:253
struct ast_xml_node * ast_xml_node_get_next(struct ast_xml_node *node)
Get the next node in the same level.
Definition: xml.c:400
struct ast_xml_doc * ast_xml_new(void)
Create a XML document.
Definition: xml.c:136
int ast_xml_set_attribute(struct ast_xml_node *node, const char *name, const char *value)
Set an attribute to a node.
Definition: xml.c:284
void ast_xml_set_text(struct ast_xml_node *node, const char *content)
Set an element content string.
Definition: xml.c:362
struct ast_xml_node * ast_xml_add_child_list(struct ast_xml_node *parent, struct ast_xml_node *child)
Add a list of child nodes, to a specified parent node.
Definition: xml.c:176
void ast_xml_free_text(const char *text)
Free a content element that was returned by ast_xml_get_text()
Definition: xml.c:260
void ast_xml_set_root(struct ast_xml_doc *doc, struct ast_xml_node *node)
Specify the root node of a XML document.
Definition: xml.c:221
struct ast_xml_doc * ast_xml_read_memory(char *buffer, size_t size)
Open an XML document that resides in memory.
Definition: xml.c:192
void ast_xml_free_node(struct ast_xml_node *node)
Free node.
Definition: xml.c:243
struct ast_xml_node * ast_xml_get_root(struct ast_xml_doc *doc)
Get the document root node.
Definition: xml.c:230