Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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
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) {
186 }
187 if (rc == 0) {
188 ast_string_field_set(eprofile, notes, src->notes);
189 }
190 if (rc == 0) {
191 ast_string_field_set(eprofile, method, src->method);
192 }
193 if (rc == 0) {
195 }
196 if (rc == 0) {
197 rc = DUP_VARS(eprofile->location_info, src->location_info);
198 }
199 if (rc == 0) {
200 rc = DUP_VARS(eprofile->effective_location, src->effective_location);
201 }
202 if (rc == 0) {
204 }
205 if (rc == 0) {
206 rc = DUP_VARS(eprofile->location_variables, src->location_variables);
207 }
208 if (rc == 0) {
209 rc = DUP_VARS(eprofile->usage_rules, src->usage_rules);
210 }
211 if (rc == 0) {
212 rc = DUP_VARS(eprofile->confidence, src->confidence);
213 }
214 if (rc == 0) {
215 rc = ast_string_field_set(eprofile, device_id, src->device_id);
216 }
217 if (rc != 0) {
218 ao2_ref(eprofile, -1);
219 return NULL;
220 }
221
222
223 return eprofile;
224}
225
227{
228 struct ast_geoloc_eprofile *eprofile;
229 const char *profile_id;
230 int rc = 0;
231
232 if (!profile) {
233 return NULL;
234 }
235
236 profile_id = ast_sorcery_object_get_id(profile);
237
238 eprofile = ast_geoloc_eprofile_alloc(profile_id);
239 if (!eprofile) {
240 return NULL;
241 }
242
243 ao2_lock(profile);
244 eprofile->allow_routing_use = profile->allow_routing_use;
245 eprofile->pidf_element = profile->pidf_element;
247 eprofile->format = profile->format;
248
250 if (rc == 0) {
251 rc = ast_string_field_set(eprofile, pidf_element_id, profile->pidf_element_id);
252 }
253 if (rc == 0) {
254 ast_string_field_set(eprofile, notes, profile->notes);
255 }
256 if (rc == 0) {
257 ast_string_field_set(eprofile, method, profile->method);
258 }
259 if (rc == 0) {
261 }
262 if (rc == 0) {
263 rc = DUP_VARS(eprofile->location_info, profile->location_info);
264 }
265 if (rc == 0) {
266 rc = DUP_VARS(eprofile->location_refinement, profile->location_refinement);
267 }
268 if (rc == 0) {
269 rc = DUP_VARS(eprofile->location_variables, profile->location_variables);
270 }
271 if (rc == 0) {
272 rc = DUP_VARS(eprofile->usage_rules, profile->usage_rules);
273 }
274 if (rc == 0) {
275 rc = DUP_VARS(eprofile->confidence, profile->confidence);
276 }
277 if (rc == 0) {
278 rc = ast_string_field_set(eprofile, device_id, profile->device_id);
279 }
280 if (rc != 0) {
281 ao2_unlock(profile);
282 ao2_ref(eprofile, -1);
283 return NULL;
284 }
285
286 eprofile->precedence = profile->precedence;
287 ao2_unlock(profile);
288
289 if (ast_geoloc_eprofile_refresh_location(eprofile) != 0) {
290 ao2_ref(eprofile, -1);
291 return NULL;
292 }
293
294 return eprofile;
295}
296
297static int set_loc_src(struct ast_geoloc_eprofile *eprofile, const char *uri, const char *ref_str)
298{
299 char *local_uri = ast_strdupa(uri);
300 char *loc_src = NULL;
301
302 loc_src = strchr(local_uri, ';');
303 if (loc_src) {
304 *loc_src = '\0';
305 loc_src++;
306 }
307
308 if (!ast_strlen_zero(loc_src)) {
309 if (ast_begins_with(loc_src, "loc-src=")) {
310 struct ast_sockaddr loc_source_addr;
311 int rc = 0;
312 loc_src += 8;
313 rc = ast_sockaddr_parse(&loc_source_addr, loc_src, PARSE_PORT_FORBID);
314 if (rc == 1) {
315 ast_log(LOG_WARNING, "%s: URI '%s' has an invalid 'loc-src' parameter."
316 " RFC8787 states that IP addresses MUST be dropped.\n",
317 ref_str, uri);
318 return -1;
319 } else {
320 ast_string_field_set(eprofile, location_source, loc_src);
321 }
322 }
323 }
324 return 0;
325}
326
328 const char *ref_str)
329{
330 struct ast_geoloc_eprofile *eprofile = NULL;
331 char *ra = NULL;
332 char *local_uri;
333
334 if (ast_strlen_zero(uri)) {
335 return NULL;
336 }
337 local_uri = ast_strdupa(uri);
338
339 if (local_uri[0] == '<') {
340 local_uri++;
341 }
342 ra = strchr(local_uri, '>');
343 if (ra) {
344 *ra = '\0';
345 }
346
347 ast_strip(local_uri);
348
349 eprofile = ast_geoloc_eprofile_alloc(local_uri);
350 if (!eprofile) {
351 return NULL;
352 }
353
354 set_loc_src(eprofile, uri, ref_str);
355
356 eprofile->format = AST_GEOLOC_FORMAT_URI;
357 eprofile->location_info = ast_variable_new("URI", local_uri, "");
358
359 return eprofile;
360}
361
363 struct ast_variable *variables, struct ast_channel *chan)
364{
365 struct ast_variable *dest = NULL;
366 struct ast_variable *var = NULL;
367 struct varshead *vh = NULL;
368 struct ast_str *buf = ast_str_alloca(256);
369
370 if (!source || !chan) {
371 return NULL;
372 }
373
374 /*
375 * ast_str_substitute_variables does only minimal recursive resolution so we need to
376 * pre-resolve each variable in the "variables" list, then use that result to
377 * do the final pass on the "source" variable list.
378 */
379 if (variables) {
380 var = variables;
381 vh = ast_var_list_create();
382 if (!vh) {
383 return NULL;
384 }
385 for ( ; var; var = var->next) {
386 ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);
389 }
390 }
391
392 var = source;
393 for ( ; var; var = var->next) {
394 struct ast_variable *newvar = NULL;
395 ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);
396 newvar = ast_variable_new(var->name, ast_str_buffer(buf), "");
397 if (!newvar) {
400 return NULL;
401 }
402 ast_variable_list_append(&dest, newvar);
404 }
406
407 return dest;
408}
409
410char *geoloc_eprofile_resolve_string(const char *source,
411 struct ast_variable *variables, struct ast_channel *chan)
412{
413 struct varshead *vh = NULL;
414 struct ast_str *buf = ast_str_alloca(256);
415
416 if (!source || !chan) {
417 return NULL;
418 }
419
420 /*
421 * ast_str_substitute_variables does only minimal recursive resolution so we need to
422 * pre-resolve each variable in the "variables" list, then use that result to
423 * do the final pass on the "source" variable list.
424 */
425 if (variables) {
426 struct ast_variable *var = variables;
427 vh = ast_var_list_create();
428 if (!vh) {
429 return NULL;
430 }
431 for ( ; var; var = var->next) {
432 ast_str_substitute_variables_full2(&buf, 0, chan, vh, var->value, NULL, 1);
435 }
436 }
437
438 ast_str_substitute_variables_full2(&buf, 0, chan, vh, source, NULL, 1);
440
442}
443
445 struct ast_channel *chan, struct ast_str **buf, const char *ref_str)
446{
447 const char *uri = NULL;
448 struct ast_variable *resolved = NULL;
449 char *result;
450 int we_created_buf = 0;
451
452 if (!eprofile || !buf || !chan) {
453 return NULL;
454 }
455
456 if (eprofile->format != AST_GEOLOC_FORMAT_URI) {
457 ast_log(LOG_ERROR, "%s: '%s' is not a URI profile. It's '%s'\n",
458 ref_str, eprofile->id, ast_geoloc_format_to_name(eprofile->format));
459 return NULL;
460 }
461
463 eprofile->location_variables, chan);
464 if (!resolved) {
465 return NULL;
466 }
467
468 uri = ast_variable_find_in_list(resolved, "URI");
469 result = uri ? ast_strdupa(uri) : NULL;
470 ast_variables_destroy(resolved);
471
472 if (ast_strlen_zero(result)) {
473 ast_log(LOG_ERROR, "%s: '%s' is a URI profile but had no, or an empty, 'URI' entry in location_info\n",
474 ref_str, eprofile->id);
475 return NULL;
476 }
477
478 if (!*buf) {
479 *buf = ast_str_create(256);
480 if (!*buf) {
481 return NULL;
482 }
483 we_created_buf = 1;
484 }
485
486 if (ast_str_append(buf, 0, "%s", result) <= 0) {
487 if (we_created_buf) {
488 ast_free(*buf);
489 *buf = NULL;
490 return NULL;
491 }
492 }
493
494 return ast_str_buffer(*buf);
495}
496
497static struct ast_variable *var_list_from_node(struct ast_xml_node *node,
498 const char *ref_str)
499{
500 struct ast_variable *list = NULL;
501 struct ast_xml_node *container;
502 struct ast_xml_node *child;
503 struct ast_variable *var;
504 SCOPE_ENTER(3, "%s\n", ref_str);
505
507 for (child = container; child; child = ast_xml_node_get_next(child)) {
508 const char *name = ast_xml_node_get_name(child);
509 const char *value = ast_xml_get_text(child);
510 const char *uom = ast_xml_get_attribute(child, "uom");
511
512 if (uom) {
513 /* '20 radians\0' */
514 char newval[strlen(value) + 1 + strlen(uom) + 1];
515 sprintf(newval, "%s %s", value, uom);
516 var = ast_variable_new(name, newval, "");
517 } else {
519 }
520
523
524 if (!var) {
526 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
527 }
529 }
530
531 if (TRACE_ATLEAST(5)) {
532 struct ast_str *buf = NULL;
533 ast_variable_list_join(list, ", ", "=", "\"", &buf);
534 ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
535 ast_free(buf);
536 }
537
538 SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
539}
540
541static struct ast_variable *var_list_from_loc_info(struct ast_xml_node *locinfo,
542 enum ast_geoloc_format format, const char *ref_str)
543{
544 struct ast_variable *list = NULL;
545 struct ast_variable *locinfo_list = NULL;
546 struct ast_xml_node *container;
547 struct ast_variable *var = NULL;
548 const char *attr;
549 SCOPE_ENTER(3, "%s\n", ref_str);
550
552 if (format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {
553 attr = ast_xml_get_attribute(container, "lang");
554 if (attr) {
555 var = ast_variable_new("lang", attr, "");
556 ast_xml_free_attr(attr);
557 if (!var) {
558 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
559 }
561 }
562 } else {
564 if (!var) {
565 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
566 }
568
569 attr = ast_xml_get_attribute(container, "srsName");
570 var = ast_variable_new("crs", attr, "");
571 ast_xml_free_attr(attr);
572 if (!var) {
574 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
575 }
577 }
578
579 locinfo_list = var_list_from_node(container, ref_str);
580 if (locinfo_list == NULL) {
581 ast_log(LOG_WARNING, "%s: There were no elements in the location info\n", ref_str);
582 SCOPE_EXIT_RTN_VALUE(list, "%s: There were no elements in the location info\n", ref_str);
583 }
584 ast_variable_list_append(&list, locinfo_list);
585
586 if (TRACE_ATLEAST(5)) {
587 struct ast_str *buf = NULL;
588 ast_variable_list_join(list, ", ", "=", "\"", &buf);
589 ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
590 ast_free(buf);
591 }
592
593 SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
594}
595
596static struct ast_variable *var_list_from_confidence(struct ast_xml_node *confidence,
597 const char *ref_str)
598{
599 struct ast_variable *list = NULL;
600 struct ast_variable *var;
601 const char *pdf;
602 const char *value;
603 SCOPE_ENTER(3, "%s\n", ref_str);
604
605 if (!confidence) {
606 SCOPE_EXIT_RTN_VALUE(NULL, "%s: No confidence\n", ref_str);
607 }
608
609 pdf = ast_xml_get_attribute(confidence, "pdf");
610 var = ast_variable_new("pdf", S_OR(pdf, "unknown"), "");
612 if (!var) {
613 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
614 }
616
617 value = ast_xml_get_text(confidence);
618 var = ast_variable_new("value", S_OR(value, "95"), "");
620 if (!var) {
622 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
623 }
625
626 if (TRACE_ATLEAST(5)) {
627 struct ast_str *buf = NULL;
628 ast_variable_list_join(list, ", ", "=", "\"", &buf);
629 ast_trace(5, "%s: Result: %s\n", ref_str, ast_str_buffer(buf));
630 ast_free(buf);
631 }
632
633 SCOPE_EXIT_RTN_VALUE(list, "%s: Done\n", ref_str);
634}
635
637 struct ast_xml_doc *result_doc, const char *ref_str)
638{
639 struct ast_geoloc_eprofile *eprofile;
640 /*
641 * None of the ast_xml_nodes needs to be freed
642 * because they're just pointers into result_doc.
643 */
644 struct ast_xml_node *presence = NULL;
645 struct ast_xml_node *pidf_element = NULL;
646 struct ast_xml_node *location_info = NULL;
647 struct ast_xml_node *confidence = NULL;
648 struct ast_xml_node *usage_rules = NULL;
649 struct ast_xml_node *method = NULL;
650 struct ast_xml_node *note_well = NULL;
651 struct ast_xml_node *device_id = NULL;
652 /*
653 * Like nodes, names of nodes are just
654 * pointers into result_doc and don't need to be freed.
655 */
656 const char *pidf_element_str;
657 /*
658 * Attributes and element text however are allocated on the fly
659 * so they DO need to be freed after use.
660 */
661 const char *id = NULL;
662 const char *pidf_element_id = NULL;
663 const char *format_str = NULL;
664 const char *method_str = NULL;
665 const char *note_well_str = NULL;
666 const char *device_id_str = NULL;
667
668 SCOPE_ENTER(3, "%s\n", ref_str);
669
670 if (!result_doc) {
671 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: result_doc was NULL", ref_str);
672 }
673
674 if (TRACE_ATLEAST(5)) {
675 char *doc_str = NULL;
676 int doc_len = 0;
677
678 ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
679 ast_trace(5, "xslt result doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
680 ast_xml_free_text(doc_str);
681 }
682
683 presence = ast_xml_get_root(result_doc);
684 if (!presence) {
685 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find 'presence' root element\n",
686 ref_str);
687 }
688 id = ast_xml_get_attribute(presence, "entity");
689
690 pidf_element = ast_xml_node_get_children(presence);
691 if (!pidf_element) {
692 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find a device, tuple or person element\n",
693 ref_str);
694 }
695
696 eprofile = ast_geoloc_eprofile_alloc(S_OR(id, "unknown"));
698 if (!eprofile) {
699 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Allocation failure\n", ref_str);
700 }
701
702 pidf_element_id = ast_xml_get_attribute(pidf_element, "id");
703 if (!ast_strlen_zero(pidf_element_id)) {
704 ast_string_field_set(eprofile, pidf_element_id, pidf_element_id);
705 }
706 ast_xml_free_attr(pidf_element_id);
707
708 location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
709 if (!location_info) {
710 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Can't find a location-info element\n",
711 ref_str);
712 }
713
714 format_str = ast_xml_get_attribute(location_info, "format");
715 if (ast_strlen_zero(format_str)) {
716 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Unable to find 'format' attribute\n", ref_str);
717 }
718
719 eprofile->format = AST_GEOLOC_FORMAT_NONE;
720 if (strcasecmp(format_str, "gml") == 0) {
721 eprofile->format = AST_GEOLOC_FORMAT_GML;
722 } else if (strcasecmp(format_str, "civicAddress") == 0) {
724 }
725
726 if (eprofile->format == AST_GEOLOC_FORMAT_NONE) {
727 char *dup_format_str = ast_strdupa(format_str);
728 ast_xml_free_attr(format_str);
729 ao2_ref(eprofile, -1);
730 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unknown format '%s'\n", ref_str, dup_format_str);
731 }
732 ast_xml_free_attr(format_str);
733
734 pidf_element_str = ast_xml_node_get_name(pidf_element);
735 eprofile->pidf_element = ast_geoloc_pidf_element_str_to_enum(pidf_element_str);
736
737 eprofile->location_info = var_list_from_loc_info(location_info, eprofile->format, ref_str);
738 if (!eprofile->location_info) {
739 ao2_ref(eprofile, -1);
741 "%s: Unable to create location variables\n", ref_str);
742 }
743
744 /*
745 * The function calls that follow are all NULL tolerant
746 * so no need for explicit error checking.
747 */
748 usage_rules = ast_xml_find_child_element(pidf_element, "usage-rules", NULL, NULL);
749 eprofile->usage_rules = var_list_from_node(usage_rules, ref_str);
750 confidence = ast_xml_find_child_element(location_info, "confidence", NULL, NULL);
751 eprofile->confidence = var_list_from_confidence(confidence, ref_str);
752
753 method = ast_xml_find_child_element(pidf_element, "method", NULL, NULL);
754 method_str = ast_xml_get_text(method);
755 ast_string_field_set(eprofile, method, method_str);
756 ast_xml_free_text(method_str);
757
758 note_well = ast_xml_find_child_element(pidf_element, "note-well", NULL, NULL);
759 note_well_str = ast_xml_get_text(note_well);
760 ast_string_field_set(eprofile, notes, note_well_str);
761 ast_xml_free_text(note_well_str);
762
763 device_id = ast_xml_find_child_element(pidf_element, "deviceID", NULL, NULL);
764 device_id_str = ast_xml_get_text(device_id);
765 ast_string_field_set(eprofile, device_id, device_id_str);
766 ast_xml_free_text(device_id_str);
767
768 SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", ref_str);
769}
770
771static int is_pidf_lo(struct ast_xml_doc *result_doc)
772{
773 struct ast_xml_node *presence;
774 struct ast_xml_node *pidf_element;
775 struct ast_xml_node *location_info;
776 const char *pidf_element_name;
777
778 if (!result_doc) {
779 return 0;
780 }
781 presence = ast_xml_get_root(result_doc);
782 if (!presence || !ast_strings_equal("presence", ast_xml_node_get_name(presence))) {
783 return 0;
784 }
785
786 pidf_element = ast_xml_node_get_children(presence);
787 if (!pidf_element) {
788 return 0;
789 }
790 pidf_element_name = ast_xml_node_get_name(pidf_element);
791 if (!ast_strings_equal(pidf_element_name, "device") &&
792 !ast_strings_equal(pidf_element_name, "tuple") &&
793 !ast_strings_equal(pidf_element_name, "person")) {
794 return 0;
795 }
796
797 location_info = ast_xml_find_child_element(pidf_element, "location-info", NULL, NULL);
798 if (!location_info) {
799 return 0;
800 }
801
802 return 1;
803}
804
806 struct ast_xml_doc *pidf_xmldoc, const char *geoloc_uri, const char *ref_str)
807{
808 struct ast_xml_doc *result_doc = NULL;
809 struct ast_geoloc_eprofile *eprofile = NULL;
810
811 SCOPE_ENTER(3, "%s\n", ref_str);
812
813 result_doc = ast_xslt_apply(pidf_to_eprofile_xslt, pidf_xmldoc, NULL);
814 if (!is_pidf_lo(result_doc)) {
815 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Not a PIDF-LO. Skipping.\n", ref_str);
816 }
817
818 /*
819 * The document returned from the stylesheet application looks like this...
820 * <presence id="presence-entity">
821 * <tuple id="element-id">
822 * <location-info format="gml">shape="Ellipsoid", crs="3d", ...</location-info>
823 * <usage-rules>retransmission-allowed="no", retention-expiry="2010-11-14T20:00:00Z"</usage-rules>
824 * <method>Hybrid_A-GPS</method>
825 * </tuple>
826 * </presence>
827 *
828 * Regardless of whether the pidf-element was tuple, device or person and whether
829 * the format is gml or civicAddress, the presence, pidf-element and location-info
830 * elements should be there.
831 *
832 * The confidence, usage-rules and note-well elements are optional.
833 */
834
835 if (TRACE_ATLEAST(5)) {
836 char *doc_str = NULL;
837 int doc_len = 0;
838
839 ast_xml_doc_dump_memory(result_doc, &doc_str, &doc_len);
840 ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
841 ast_xml_free_text(doc_str);
842 doc_str = NULL;
843 doc_len = 0;
844 }
845
846 eprofile = geoloc_eprofile_create_from_xslt_result(result_doc, ref_str);
847 ast_xml_close(result_doc);
848
849 if (eprofile && geoloc_uri) {
850 set_loc_src(eprofile, geoloc_uri, ref_str);
851 }
852
853 SCOPE_EXIT_RTN_VALUE(eprofile, "%s: Done.\n", ref_str);
854}
855
856/*!
857 * \internal
858 * \brief Create an common, intermediate XML document to pass to the outgoing XSLT process
859 *
860 * \param element_name The name of the top-level XML element to create
861 * \param eprofile The eprofile
862 * \param chan The channel to resolve variables against
863 * \param ref_string A reference string for error messages
864 * \return An XML doc
865 *
866 * \note Given that the document is simple and static, it was easier to just
867 * create the elements in a string buffer and call ast_xml_read_memory()
868 * at the end instead of creating
869 */
870static struct ast_xml_node *geoloc_eprofile_to_intermediate(const char *element_name, struct ast_geoloc_eprofile *eprofile,
871 struct ast_channel *chan, const char *ref_string)
872{
873 struct ast_variable *resolved_location = NULL;
874 struct ast_variable *resolved_usage = NULL;
875 struct ast_variable *var = NULL;
876 RAII_VAR(struct ast_xml_node *, pidf_node, NULL, ast_xml_free_node);
877 struct ast_xml_node *rtn_pidf_node;
878 struct ast_xml_node *loc_node;
879 struct ast_xml_node *confidence_node;
880 struct ast_xml_node *info_node;
881 struct ast_xml_node *rules_node;
882 struct ast_xml_node *method_node;
883 struct ast_xml_node *notes_node;
884 struct ast_xml_node *timestamp_node;
885 struct ast_xml_node *device_id_node;
886 struct timeval tv = ast_tvnow();
887 struct tm tm = { 0, };
888 char timestr[32] = { 0, };
889 int rc = 0;
890
891 SCOPE_ENTER(3, "%s\n", ref_string);
892
893 if (!eprofile || !chan) {
894 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Either or both eprofile or chan were NULL\n", ref_string);
895 }
896
897 pidf_node = ast_xml_new_node(element_name);
898 if (!pidf_node) {
899 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n",
900 ref_string, element_name);
901 }
902 if (!ast_strlen_zero(eprofile->pidf_element_id)) {
903 char *resolved_pidf_element_id = geoloc_eprofile_resolve_string(eprofile->pidf_element_id,
904 eprofile->location_variables, chan);
905 if (!resolved_pidf_element_id) {
907 }
908 rc = ast_xml_set_attribute(pidf_node, "id", resolved_pidf_element_id);
909 ast_free(resolved_pidf_element_id);
910 if (rc != 0) {
911 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'id' XML attribute\n", ref_string);
912 }
913 }
914
915 loc_node = ast_xml_new_child(pidf_node, "location-info");
916 if (!loc_node) {
917 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'location-info' XML node\n",
918 ref_string);
919 }
920 rc = ast_xml_set_attribute(loc_node, "format", ast_geoloc_format_to_name(eprofile->format));
921 if (rc != 0) {
922 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'format' XML attribute\n", ref_string);
923 }
924
925 resolved_location = geoloc_eprofile_resolve_varlist(eprofile->effective_location,
926 eprofile->location_variables, chan);
927 if (eprofile->format == AST_GEOLOC_FORMAT_CIVIC_ADDRESS) {
928 info_node = geoloc_civicaddr_list_to_xml(resolved_location, ref_string);
929 } else {
930 info_node = geoloc_gml_list_to_xml(resolved_location, ref_string);
931 }
932 ast_variables_destroy(resolved_location);
933
934 if (!info_node) {
935 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML from '%s' list\n",
936 ref_string, ast_geoloc_format_to_name(eprofile->format));
937 }
938 if (!ast_xml_add_child(loc_node, info_node)) {
939 ast_xml_free_node(info_node);
940 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable add '%s' node to XML document\n",
941 ref_string, ast_geoloc_format_to_name(eprofile->format));
942 }
943
944 if (eprofile->confidence) {
945 const char *value = S_OR(ast_variable_find_in_list(eprofile->confidence, "value"), "95");
946 const char *pdf = S_OR(ast_variable_find_in_list(eprofile->confidence, "pdf"), "unknown");
947
948 confidence_node = ast_xml_new_child(loc_node, "confidence");
949 if (!confidence_node) {
950 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'confidence' XML node\n",
951 ref_string);
952 }
953 rc = ast_xml_set_attribute(confidence_node, "pdf", pdf);
954 if (rc != 0) {
955 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'pdf' attribute on 'confidence' element\n", ref_string);
956 }
957
958 ast_xml_set_text(confidence_node, value);
959 }
960
961 rules_node = ast_xml_new_child(pidf_node, "usage-rules");
962 if (!rules_node) {
963 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'usage-rules' XML node\n",
964 ref_string);
965 }
966 resolved_usage = geoloc_eprofile_resolve_varlist(eprofile->usage_rules,
967 eprofile->location_variables, chan);
968 for (var = resolved_usage; var; var = var->next) {
969 struct ast_xml_node *ur = ast_xml_new_child(rules_node, var->name);
970 ast_xml_set_text(ur, var->value);
971 }
972 ast_variables_destroy(resolved_usage);
973
974 if (!ast_strlen_zero(eprofile->method)) {
975 method_node = ast_xml_new_child(pidf_node, "method");
976 if (!method_node) {
977 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'method' XML node\n",
978 ref_string);
979 }
980 ast_xml_set_text(method_node, eprofile->method);
981 };
982
983 if (!ast_strlen_zero(eprofile->notes)) {
984 notes_node = ast_xml_new_child(pidf_node, "note-well");
985 if (!notes_node) {
986 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'note-well' XML node\n",
987 ref_string);
988 }
989 ast_xml_set_text(notes_node, eprofile->notes);
990 };
991
992 gmtime_r(&tv.tv_sec, &tm);
993 strftime(timestr, sizeof(timestr), "%FT%TZ", &tm);
994 timestamp_node = ast_xml_new_child(pidf_node, "timestamp");
995 if (!timestamp_node) {
996 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'timestamp' XML node\n",
997 ref_string);
998 }
999 ast_xml_set_text(timestamp_node, timestr);
1000
1001 if (!ast_strlen_zero(eprofile->device_id)) {
1002 char *resolved_device_id = geoloc_eprofile_resolve_string(eprofile->device_id,
1003 eprofile->location_variables, chan);
1004 if (!resolved_device_id) {
1006 }
1007 device_id_node = ast_xml_new_child(pidf_node, "deviceID");
1008 if (!device_id_node) {
1009 ast_free(resolved_device_id);
1010 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'deviceID' XML node\n",
1011 ref_string);
1012 }
1013 ast_xml_set_text(device_id_node, resolved_device_id);
1014 ast_free(resolved_device_id);
1015 }
1016
1017
1018 rtn_pidf_node = pidf_node;
1019 pidf_node = NULL;
1020 SCOPE_EXIT_RTN_VALUE(rtn_pidf_node, "%s: Done\n", ref_string);
1021}
1022
1023#define CREATE_NODE_LIST(node) \
1024 if (!node) { \
1025 node = ast_xml_new_child(root_node, \
1026 geoloc_pidf_element_to_name(eprofile->pidf_element)); \
1027 if (!pidfs[eprofile->pidf_element]) { \
1028 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create pidf '%s' XML node\n", \
1029 ref_string, geoloc_pidf_element_to_name(eprofile->pidf_element)); \
1030 } \
1031 }
1032
1034 struct ast_channel *chan, struct ast_str **buf, const char * ref_string)
1035{
1036 RAII_VAR(struct ast_xml_doc *, intermediate, NULL, ast_xml_close);
1037 RAII_VAR(struct ast_xml_doc *, pidf_doc, NULL, ast_xml_close);
1038 struct ast_xml_node *root_node;
1039 struct ast_xml_node *pidfs[AST_PIDF_ELEMENT_LAST] = {NULL, };
1040 struct ast_geoloc_eprofile *eprofile;
1041 int eprofile_count = 0;
1042 int i;
1043 char *doc_str = NULL;
1044 int doc_len = 0;
1045 int rc = 0;
1046 SCOPE_ENTER(3, "%s\n", ref_string);
1047
1048 if (!ds || !chan || !buf || !*buf || ast_strlen_zero(ref_string)) {
1049 SCOPE_EXIT_RTN_VALUE(NULL, "%s: Either or both datastore or chan were NULL\n",
1050 ref_string);
1051 }
1052
1053 intermediate = ast_xml_new();
1054 if (!intermediate) {
1055 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML document\n", ref_string);
1056 }
1057 root_node = ast_xml_new_node("presence");
1058 if (!root_node) {
1059 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create root XML node\n", ref_string);
1060 }
1061 ast_xml_set_root(intermediate, root_node);
1062
1063 eprofile_count = ast_geoloc_datastore_size(ds);
1064 for (i = 0; i < eprofile_count; i++) {
1065 struct ast_xml_node *temp_node = NULL;
1066 struct ast_xml_node *curr_loc = NULL;
1067 struct ast_xml_node *new_loc = NULL;
1068 struct ast_xml_node *new_loc_child = NULL;
1069 struct ast_xml_node *new_loc_child_dup = NULL;
1070 const char *entity = NULL;
1071 int has_no_entity = 0;
1072 eprofile = ast_geoloc_datastore_get_eprofile(ds, i);
1073 if (eprofile->format == AST_GEOLOC_FORMAT_URI) {
1074 continue;
1075 }
1076
1077 entity = ast_xml_get_attribute(root_node, "entity");
1078 has_no_entity = ast_strlen_zero(entity);
1079 ast_xml_free_attr(entity);
1080 if (has_no_entity) {
1081 rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);
1082 if (rc != 0) {
1083 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);
1084 }
1085 }
1086
1087 temp_node = geoloc_eprofile_to_intermediate(ast_geoloc_pidf_element_to_name(eprofile->pidf_element),
1088 eprofile, chan, ref_string);
1089 if (!temp_node) {
1090 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create temp_node\n", ref_string);
1091 }
1092
1093 if (!pidfs[eprofile->pidf_element]) {
1094 pidfs[eprofile->pidf_element] = temp_node;
1095 ast_xml_add_child(root_node, temp_node);
1096 continue;
1097 }
1098
1099 curr_loc = ast_xml_find_child_element(pidfs[eprofile->pidf_element], "location-info", NULL, NULL);
1100 new_loc = ast_xml_find_child_element(temp_node, "location-info", NULL, NULL);
1101 new_loc_child = ast_xml_node_get_children(new_loc);
1102 new_loc_child_dup = ast_xml_copy_node_list(new_loc_child);
1103 ast_xml_add_child_list(curr_loc, new_loc_child_dup);
1104
1105 ast_xml_free_node(temp_node);
1106 }
1107
1108 if (TRACE_ATLEAST(5)) {
1109 ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
1110 ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
1111 ast_xml_free_text(doc_str);
1112 doc_str = NULL;
1113 doc_len = 0;
1114 }
1115
1116 pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, NULL);
1117 if (!pidf_doc) {
1118 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate docs\n",
1119 ref_string);
1120 }
1121
1122 ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);
1123 if (doc_len == 0 || !doc_str) {
1124 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump final PIDF-LO doc to string\n",
1125 ref_string);
1126 }
1127
1128 rc = ast_str_set(buf, 0, "%s", doc_str);
1129 ast_xml_free_text(doc_str);
1130 if (rc <= 0) {
1131 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",
1132 ref_string, rc);
1133 }
1134
1135 ast_trace(5, "Final doc:\n%s\n", ast_str_buffer(*buf));
1136
1137 SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: Done\n", ref_string);
1138}
1139
1140static struct ast_xml_doc *geoloc_eprofile_to_xmldoc(struct ast_geoloc_eprofile *eprofile,
1141 struct ast_channel *chan, struct ast_str **buf, const char * ref_string)
1142{
1143 RAII_VAR(struct ast_xml_doc *, intermediate, NULL, ast_xml_close);
1144 struct ast_xml_doc *pidf_doc = NULL;
1145 struct ast_xml_node *root_node;
1146 char *doc_str = NULL;
1147 int doc_len;
1148 int rc = 0;
1149 struct ast_xml_node *temp_node = NULL;
1150 const char *entity = NULL;
1151 int has_no_entity = 0;
1152 const char *params[] = { "suppress_empty_ca_elements", "false()", NULL };
1153
1154 SCOPE_ENTER(3, "%s\n", ref_string);
1155
1156 if (!eprofile || !chan || !buf || !*buf || ast_strlen_zero(ref_string)) {
1157 SCOPE_EXIT_RTN_VALUE(NULL, "%s: One of eprofile, chan or buf was NULL\n",
1158 ref_string);
1159 }
1160
1161 if (eprofile->format == AST_GEOLOC_FORMAT_URI) {
1162 SCOPE_EXIT_RTN_VALUE(NULL, "%s: eprofile '%s' was a URI format\n",
1163 ref_string, eprofile->id);
1164 }
1165
1166 intermediate = ast_xml_new();
1167 if (!intermediate) {
1168 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create XML document\n", ref_string);
1169 }
1170 root_node = ast_xml_new_node("presence");
1171 if (!root_node) {
1172 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create root XML node\n", ref_string);
1173 }
1174 ast_xml_set_root(intermediate, root_node);
1175
1176 entity = ast_xml_get_attribute(root_node, "entity");
1177 has_no_entity = ast_strlen_zero(entity);
1178 ast_xml_free_attr(entity);
1179 if (has_no_entity) {
1180 rc = ast_xml_set_attribute(root_node, "entity", eprofile->id);
1181 if (rc != 0) {
1182 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to set 'entity' XML attribute\n", ref_string);
1183 }
1184 }
1185
1187 ast_geoloc_pidf_element_to_name(eprofile->pidf_element), eprofile, chan, ref_string);
1188 if (!temp_node) {
1189 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create temp_node for eprofile '%s'\n",
1190 ref_string, eprofile->id);
1191 }
1192
1193 ast_xml_add_child(root_node, temp_node);
1194
1195 if (TRACE_ATLEAST(5)) {
1196 ast_xml_doc_dump_memory(intermediate, &doc_str, &doc_len);
1197 ast_trace(5, "Intermediate doc len: %d\n%s\n", doc_len, doc_len ? doc_str : "<empty>");
1198 ast_xml_free_text(doc_str);
1199 doc_str = NULL;
1200 doc_len = 0;
1201 }
1202
1203 if (eprofile->suppress_empty_ca_elements) {
1204 params[1] = "true()";
1205 }
1206 pidf_doc = ast_xslt_apply(eprofile_to_pidf_xslt, intermediate, params);
1207 if (!pidf_doc) {
1208 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc\n",
1209 ref_string);
1210 }
1211
1212 SCOPE_EXIT_RTN_VALUE(pidf_doc, "%s: Done\n", ref_string);
1213}
1214
1216 struct ast_channel *chan, struct ast_str **buf, const char * ref_string)
1217{
1218
1219 RAII_VAR(struct ast_xml_doc *, pidf_doc, NULL, ast_xml_close);
1220 char *doc_str = NULL;
1221 int doc_len = 0;
1222 int rc = 0;
1223 SCOPE_ENTER(3, "%s\n", ref_string);
1224
1225 pidf_doc = geoloc_eprofile_to_xmldoc(eprofile, chan, buf, ref_string);
1226 if (!pidf_doc) {
1227 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create final PIDF-LO doc from intermediate doc\n",
1228 ref_string);
1229 }
1230
1231 ast_xml_doc_dump_memory(pidf_doc, &doc_str, &doc_len);
1232 if (doc_len == 0 || !doc_str) {
1233 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to dump final PIDF-LO doc to string\n",
1234 ref_string);
1235 }
1236
1237 rc = ast_str_set(buf, 0, "%s", doc_str);
1238 ast_xml_free_text(doc_str);
1239 if (rc <= 0) {
1240 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to extend buffer (%d)\n",
1241 ref_string, rc);
1242 }
1243
1244 ast_trace(5, "Final doc:\n%s\n", ast_str_buffer(*buf));
1245
1246 SCOPE_EXIT_RTN_VALUE(ast_str_buffer(*buf), "%s: Done\n", ref_string);
1247
1248}
1249
1250#ifdef TEST_FRAMEWORK
1251static void load_tests(void);
1252static void unload_tests(void);
1253#else
1254static void load_tests(void) {}
1255static void unload_tests(void) {}
1256#endif
1257
1258
1260{
1261 unload_tests();
1263 ast_xslt_close(pidf_to_eprofile_xslt);
1264 }
1265
1267 ast_xslt_close(eprofile_to_pidf_xslt);
1268 }
1269
1270 if (geoloc_sorcery) {
1272 }
1273
1275}
1276
1309
1311{
1313}
1314
1315
1316#ifdef TEST_FRAMEWORK
1317#include "asterisk/test.h"
1318
1319AST_TEST_DEFINE(test_create_from_uri)
1320{
1321
1322 RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
1323 const char *uri = NULL;
1324 int rc = AST_TEST_PASS;
1325
1326 switch (cmd) {
1327 case TEST_INIT:
1328 info->name = "create_from_uri";
1329 info->category = "/geoloc/";
1330 info->summary = "Test create from uri";
1331 info->description = info->summary;
1332 return AST_TEST_NOT_RUN;
1333 case TEST_EXECUTE:
1334 break;
1335 }
1336
1337 eprofile = ast_geoloc_eprofile_create_from_uri("http://some_uri&a=b", __func__);
1338 ast_test_validate(test, eprofile != NULL);
1339 ast_test_validate(test, eprofile->format == AST_GEOLOC_FORMAT_URI);
1340 ast_test_validate(test, eprofile->location_info != NULL);
1341 uri = ast_variable_find_in_list(eprofile->location_info, "URI");
1342 ast_test_validate(test, uri != NULL);
1343 ast_test_validate(test, strcmp(uri, "http://some_uri&a=b") == 0);
1344
1345 return rc;
1346}
1347
1348static enum ast_test_result_state validate_eprofile(struct ast_test *test,
1349 struct ast_geoloc_eprofile *eprofile,
1350 struct ast_xml_doc * pidf_xmldoc,
1351 const char *id,
1352 const char *pidf_element_id,
1353 enum ast_geoloc_pidf_element pidf_element,
1354 enum ast_geoloc_format format,
1355 const char *method,
1356 const char *location,
1357 const char *usage,
1358 const char *device_id
1359 )
1360{
1361 RAII_VAR(struct ast_str *, str, NULL, ast_free);
1362 RAII_VAR(struct ast_xml_doc *, result_doc, NULL, ast_xml_close);
1363
1364 ast_test_status_update(test, "eprofile: ID: '%s' pidf_element: '%s' peid: %s format: '%s' method: '%s' device_id: '%s'\n",
1365 eprofile->id,
1366 ast_geoloc_pidf_element_to_name(eprofile->pidf_element),
1367 eprofile->pidf_element_id,
1368 ast_geoloc_format_to_name(eprofile->format),
1369 eprofile->method, eprofile->device_id);
1370 ast_test_status_update(test, "xml: ID: '%s' pidf_element: '%s' peid: %s format: '%s' method: '%s' device_id: '%s'\n",
1371 id,
1372 ast_geoloc_pidf_element_to_name(pidf_element),
1373 pidf_element_id,
1374 ast_geoloc_format_to_name(format),
1375 method, device_id);
1376
1377 ast_test_validate(test, ast_strings_equal(eprofile->id, id));
1378 ast_test_validate(test, eprofile->pidf_element == pidf_element);
1379 ast_test_validate(test, ast_strings_equal(eprofile->pidf_element_id, pidf_element_id));
1380 ast_test_validate(test, eprofile->format == format);
1381 ast_test_validate(test, ast_strings_equal(eprofile->method, method));
1382 ast_test_validate(test, ast_strings_equal(eprofile->device_id, device_id));
1383
1384 str = ast_variable_list_join(eprofile->location_info, ",", "=", NULL, NULL);
1385 ast_test_validate(test, str != NULL);
1386 ast_test_status_update(test, "location_vars expected: %s\n", location);
1387 ast_test_status_update(test, "location_vars received: %s\n", ast_str_buffer(str));
1388 ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), location));
1389 ast_free(str);
1390
1391 str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "'", NULL);
1392 ast_test_validate(test, str != NULL);
1393 ast_test_status_update(test, "usage_rules expected: %s\n", usage);
1394 ast_test_status_update(test, "usage_rules received: %s\n", ast_str_buffer(str));
1395 ast_test_validate(test, ast_strings_equal(ast_str_buffer(str), usage));
1396
1397 return AST_TEST_PASS;
1398}
1399
1400static char *normalize_string(char *in)
1401{
1402 char *out = ast_strip(in);
1403 char *ptr = out;
1404
1405 while (*ptr != '\0') {
1406 if (*ptr == '\n') {
1407 char *next = ast_skip_blanks(ptr);
1408 *ptr = ' ';
1409 ptr++;
1410 next = ast_strdup(next);
1411 strcpy(ptr, next); /* Safe */
1412 ast_free(next);
1413 }
1414 ptr++;
1415 }
1416 return out;
1417}
1418
1419struct test_xpath_element {
1420 const char *path;
1421 int validate_content;
1422};
1423
1424static enum ast_test_result_state validate_xml(struct ast_test *test,
1425 struct ast_geoloc_eprofile *eprofile,
1426 struct ast_xml_doc * pidf_xmldoc,
1427 struct ast_xml_doc * eprofile_xmldoc
1428 )
1429{
1432 struct ast_xml_namespace_def def = {"def", "urn:ietf:params:xml:ns:pidf"};
1433 struct ast_xml_namespace_def dm = {"dm", "urn:ietf:params:xml:ns:pidf:data-model"};
1434 struct ast_xml_namespace_def ca = {"ca", "urn:ietf:params:xml:ns:pidf:geopriv10:civicAddr"};
1435 struct ast_xml_namespace_def gbp = {"gbp", "urn:ietf:params:xml:ns:pidf:geopriv10:basicPolicy"};
1436 struct ast_xml_namespace_def gml = {"gml", "http://www.opengis.net/gml"};
1437 struct ast_xml_namespace_def gp = {"gp", "urn:ietf:params:xml:ns:pidf:geopriv10"};
1438 struct ast_xml_namespace_def con = {"con", "urn:ietf:params:xml:ns:geopriv:conf"};
1439 struct ast_xml_namespace_def gs = {"gs", "http://www.opengis.net/pidflo/1.0"};
1440
1441 struct test_xpath_element elements[] = {
1442 {"//def:tuple/@id", 1},
1443 {"//gml:Point/@srsName", 1},
1444 {"//gml:pos/text()", 1},
1445 {"//con:confidence/text()", 1},
1446 {"//con:confidence/@pdf", 1},
1447 {"//gp:usage-rules", 0},
1448 {"//gbp:retransmission-allowed/text()", 1},
1449 {"//gbp:retention-expiry/text()", 1},
1450 {"//gp:method/text()", 1},
1451 {"//gp:note-well/text()", 1},
1452 {"//dm:deviceID/text()", 1},
1453 {"//def:timestamp", 0},
1454 };
1455 int i;
1456
1457 AST_VECTOR_INIT(&ns, 12);
1458 AST_VECTOR_APPEND(&ns, def);
1459 AST_VECTOR_APPEND(&ns, dm);
1460 AST_VECTOR_APPEND(&ns, ca);
1461 AST_VECTOR_APPEND(&ns, gbp);
1462 AST_VECTOR_APPEND(&ns, gml);
1463 AST_VECTOR_APPEND(&ns, gp);
1464 AST_VECTOR_APPEND(&ns, con);
1465 AST_VECTOR_APPEND(&ns, gs);
1466
1467
1468 for (i = 0; i < ARRAY_LEN(elements); i++) {
1469 struct ast_xml_xpath_results *aresults = ast_xml_query_with_namespaces(eprofile_xmldoc, elements[i].path, &ns);
1470 struct ast_xml_xpath_results *bresults = ast_xml_query_with_namespaces(pidf_xmldoc, elements[i].path, &ns);
1471 if (aresults && bresults) {
1472 struct ast_xml_node *anode = ast_xml_xpath_get_first_result(aresults);
1473 struct ast_xml_node *bnode = ast_xml_xpath_get_first_result(bresults);
1474 if (elements[i].validate_content) {
1475 char *atext = normalize_string(ast_strdupa(S_OR(ast_xml_get_text(anode), "")));
1476 char *btext = normalize_string(ast_strdupa(S_OR(ast_xml_get_text(bnode), "")));
1477 int pass = ast_strings_equal(atext, btext);
1478 ast_test_status_update(test, "Element: %s eprofile: %s pidf: %s Result: %s\n",
1479 elements[i].path, atext, btext, pass ? "pass" : "FAIL");
1480 if (!pass) {
1481 ast_log(LOG_ERROR, "Element: %s eprofile: %s pidf: %s Result: FAIL\n",
1482 elements[i].path, atext, btext);
1483 res = AST_TEST_FAIL;
1484 }
1485 } else {
1486 int pass = !!anode && !!bnode;
1487 ast_test_status_update(test, "Element: %s eprofile: %s pidf: %s Result: %s\n",
1488 elements[i].path, anode ? "exists" : "doesn't exist", bnode ? "exists" : "doesn't exist",
1489 pass ? "pass" : "FAIL");
1490 if (!pass) {
1491 ast_log(LOG_ERROR, "Element: %s eprofile: %s pidf: %s\n",
1492 elements[i].path, anode ? "exists" : "doesn't exist", bnode ? "exists" : "doesn't exist");
1493 }
1494 }
1495 } else {
1496 if (!aresults) {
1497 ast_log(LOG_ERROR, "No xpath eprofile result for %s\n", elements[i].path);
1498 res = AST_TEST_FAIL;
1499 }
1500 if (!bresults) {
1501 ast_log(LOG_ERROR, "No xpath pidf result for %s\n", elements[i].path);
1502 res = AST_TEST_FAIL;
1503 }
1504 }
1505 }
1506
1507 return res;
1508}
1509
1510AST_TEST_DEFINE(test_create_from_pidf)
1511{
1512
1513 RAII_VAR(struct ast_xml_doc *, pidf_xmldoc, NULL, ast_xml_close);
1514 RAII_VAR(struct ast_xml_doc *, eprofile_xmldoc, NULL, ast_xml_close);
1515 RAII_VAR(struct ast_geoloc_eprofile *, eprofile, NULL, ao2_cleanup);
1516 RAII_VAR(struct ast_str *, buf, NULL, ast_free);
1517 RAII_VAR(struct ast_channel *, mock_channel, NULL, ast_hangup);
1518
1520
1521 switch (cmd) {
1522 case TEST_INIT:
1523 info->name = "create_from_pidf";
1524 info->category = "/geoloc/";
1525 info->summary = "Test create from pidf scenarios";
1526 info->description = info->summary;
1527 return AST_TEST_NOT_RUN;
1528 case TEST_EXECUTE:
1529 break;
1530 }
1531
1533 ast_test_validate(test, pidf_xmldoc != NULL);
1534
1535 eprofile = ast_geoloc_eprofile_create_from_pidf(pidf_xmldoc, NULL, "test_create_from_pidf");
1536 ast_test_validate(test, eprofile != NULL);
1537
1538
1539 res = validate_eprofile(test, eprofile, pidf_xmldoc,
1540 "pres:alice@asterisk.org",
1541 "point-2d",
1544 "Manual",
1545 "shape=Point,crs=2d,pos=-34.410649 150.87651",
1546 "retransmission-allowed='no',retention-expiry='2010-11-14T20:00:00Z'",
1547 "mac:112233445566"
1548 );
1549 if (res != AST_TEST_PASS) {
1550 return res;
1551 }
1552
1553 buf = ast_str_create(1024);
1554 if (!buf) {
1555 ast_log(LOG_ERROR, "Unable to allocate buf\n");
1556 return AST_TEST_FAIL;
1557 }
1558
1559 mock_channel = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, "TestChannel");
1560 eprofile->effective_location = ast_variables_dup(eprofile->location_info);
1561 eprofile_xmldoc = geoloc_eprofile_to_xmldoc(eprofile, mock_channel, &buf, "session_name");
1562
1563 return validate_xml(test, eprofile, pidf_xmldoc, eprofile_xmldoc);
1564}
1565
1566static void load_tests(void) {
1567 AST_TEST_REGISTER(test_create_from_uri);
1568 AST_TEST_REGISTER(test_create_from_pidf);
1569}
1570static void unload_tests(void) {
1571 AST_TEST_UNREGISTER(test_create_from_uri);
1572 AST_TEST_UNREGISTER(test_create_from_pidf);
1573}
1574
1575#endif
const char * str
Definition app_jack.c:150
#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_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#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_hangup(struct ast_channel *chan)
Hang up a channel.
Definition channel.c:2538
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
Definition channel.h:1299
@ AST_STATE_DOWN
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
char * geoloc_eprofile_resolve_string(const char *source, struct ast_variable *variables, struct ast_channel *chan)
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_doc * geoloc_eprofile_to_xmldoc(struct ast_geoloc_eprofile *eprofile, struct ast_channel *chan, struct ast_str **buf, const char *ref_string)
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(struct ast_variable *resolved_location, const char *ref_string)
Definition geoloc_gml.c:349
#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.
#define ast_variable_new(name, value, filename)
#define ast_variable_list_append(head, new_var)
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
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.
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
#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
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
static char pass[512]
struct ao2_container * container
Definition res_fax.c:603
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:1273
#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:2381
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:1917
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
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
#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
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
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
char *attribute_pure ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition strings.h:161
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
const ast_string_field device_id
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
const ast_string_field pidf_element_id
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
const ast_string_field device_id
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
const ast_string_field pidf_element_id
struct ast_variable * location_info
Socket address structure.
Definition netsock2.h:97
Full structure for sorcery.
Definition sorcery.c:231
Support for dynamic strings.
Definition strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Namespace definition.
Definition xml.h:325
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_FAIL
Definition test.h:196
@ 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
FILE * out
Definition utils/frame.c:33
char * usage
Definition utils/frame.c:37
FILE * in
Definition utils/frame.c:33
#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:981
#define ARRAY_LEN(a)
Definition utils.h:706
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267
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_xpath_results * ast_xml_query_with_namespaces(struct ast_xml_doc *doc, const char *xpath_str, struct ast_xml_namespace_def_vector *namespaces)
Execute an XPath query on an XML document with namespaces.
Definition xml.c:463
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
struct ast_xml_node * ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results)
Return the first result node of an XPath query.
Definition xml.c:415
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