Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
geoloc_gml.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2022, Sangoma Technologies Corporation
3 *
4 * George Joseph <gjoseph@sangoma.com>
5 *
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
11 *
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
15 */
16
17#include "asterisk.h"
18#include "asterisk/config.h"
19#include "asterisk/cli.h"
21#include "geoloc_private.h"
22
24 const char *name;
27 int (*validator)(const char *name, const char *value, const struct ast_variable *varlist,
28 char **result);
29};
30
31#define MAX_SHAPE_ATTRIBUTES 9
37
38#define SET_RESULT(__result, ...) \
39({ \
40 if (__result) { \
41 __ast_asprintf(__FILE__, __LINE__, __PRETTY_FUNCTION__, result, __VA_ARGS__); \
42 } \
43})
44
45static int crs_validator(const char *name, const char *value, const struct ast_variable *varlist,
46 char **result)
47{
48 if (!ast_strings_equal(value, "2d") && !ast_strings_equal(value, "3d")) {
49 SET_RESULT(result, "Invalid crs '%s'. Must be either '2d' or '3d'", value);
50 return 0;
51 }
52 return 1;
53}
54
55static int pos_validator(const char *name, const char *value, const struct ast_variable *varlist,
56 char **result)
57{
58 const char *crs = S_OR(ast_variable_find_in_list(varlist, "crs"), "2d");
59 float lat;
60 float lon;
61 float alt;
62 int count;
63
64 count = sscanf(value, "%f %f %f", &lat, &lon, &alt);
65 if (ast_strings_equal(crs, "3d") && count != 3) {
66 SET_RESULT(result, "Invalid 3d position '%s'. Must be 3 floating point values.", value);
67 return 0;
68 }
69 if (ast_strings_equal(crs, "2d") && count != 2) {
70 SET_RESULT(result, "Invalid 2d position '%s'. Must be 2 floating point values.", value);
71 return 0;
72 }
73 return 1;
74}
75
76static int float_validator(const char *name, const char *value, const struct ast_variable *varlist,
77 char **result)
78{
79 float val;
80 if (sscanf(value, "%f", &val) != 1) {
81 SET_RESULT(result, "Invalid floating point value '%s' in '%s'.", value, name);
82 return 0;
83 }
84 return 1;
85}
86
94
95static enum angle_parse_result angle_parser(const char *name, const char *value,
96 char **angle, char **uom, char **result)
97{
98 char *tmp_angle = NULL;
99 char *tmp_uom = NULL;
100 float f_angle;
101 char *junk;
102 char *work = ast_strdupa(value);
103
104 tmp_angle = ast_strsep(&work, ' ', AST_STRSEP_ALL);
105 if (ast_strlen_zero(tmp_angle)) {
106 SET_RESULT(result, "Empty angle in '%s'", name);
108 }
109 f_angle = strtof(tmp_angle, &junk);
110 if (!ast_strlen_zero(junk)) {
111 SET_RESULT(result, "Invalid angle '%s' in '%s'", value, name);
113 }
114
115 tmp_uom = ast_strsep(&work, ' ', AST_STRSEP_ALL);
116 if (ast_strlen_zero(tmp_uom)) {
117 tmp_uom = "degrees";
118 }
119
120 if (ast_begins_with(tmp_uom, "deg")) {
121 tmp_uom = "degrees";
122 } else if (ast_begins_with(tmp_uom, "rad")) {
123 tmp_uom = "radians";
124 } else {
125 SET_RESULT(result, "Invalid UOM '%s' in '%s'. Must be 'degrees' or 'radians'.", value, name);
127 }
128
129 if (ast_strings_equal(tmp_uom, "degrees") && f_angle > 360.0) {
130 SET_RESULT(result, "Angle '%s' must be <= 360.0 for UOM '%s' in '%s'", tmp_angle, tmp_uom, name);
132 }
133
134 if (ast_strings_equal(tmp_uom, "radians") && f_angle > 100.0) {
135 SET_RESULT(result, "Angle '%s' must be <= 100.0 for UOM '%s' in '%s'", tmp_angle, tmp_uom, name);
137 }
138
139 if (angle) {
140 *angle = ast_strdup(tmp_angle);
141 }
142 if (uom) {
143 *uom = ast_strdup(tmp_uom);
144 }
146}
147
148static int angle_validator(const char *name, const char *value, const struct ast_variable *varlist,
149 char **result)
150{
152
153 return rc == ANGLE_PARSE_RESULT_SUCCESS;
154}
155
156#define _SENTRY {NULL, -1, -1, NULL}
157
158#define CRS_OPT {"crs", 0, 1, crs_validator}
159#define CRS_REQ {"crs", 1, 1, crs_validator}
160
162 { "Point", "any", { CRS_OPT, {"pos", 1, 1, pos_validator}, _SENTRY }},
163 { "Polygon", "any", { CRS_OPT, {"pos", 3, -1, pos_validator}, _SENTRY }},
164 { "Circle", "2d", { CRS_OPT, {"pos", 1, 1, pos_validator}, {"radius", 1, 1, float_validator}, _SENTRY }},
165 { "Ellipse", "2d", { CRS_OPT, {"pos", 1, 1, pos_validator}, {"semiMajorAxis", 1, 1, float_validator},
166 {"semiMinorAxis", 1, 1, float_validator}, {"orientation", 1, 1, angle_validator}, _SENTRY }},
167 { "ArcBand", "2d", { CRS_OPT, {"pos", 1, 1, pos_validator}, {"innerRadius", 1, 1, float_validator},
168 {"outerRadius", 1, 1, float_validator}, {"startAngle", 1, 1, angle_validator},
169 {"openingAngle", 1, 1, angle_validator},
170 _SENTRY }},
171 { "Sphere", "3d", { CRS_REQ, {"pos", 1, 1, pos_validator}, {"radius", 1, 1, float_validator}, _SENTRY }},
172 { "Ellipsoid", "3d", { CRS_REQ, {"pos", 1, 1, pos_validator}, {"semiMajorAxis", 1, 1, float_validator},
173 {"semiMinorAxis", 1, 1, float_validator}, {"verticalAxis", 1, 1, float_validator},
174 {"orientation", 1, 1, angle_validator}, _SENTRY }},
175 { "Prism", "3d", { CRS_REQ, {"pos", 3, -1, pos_validator}, {"height", 1, 1, float_validator}, _SENTRY }},
176};
177
178static int find_shape_index(const char *shape)
179{
180 int i = 0;
181 int shape_count = ARRAY_LEN(gml_shape_defs);
182
183 for (i = 0; i < shape_count; i++) {
185 return i;
186 }
187 }
188 return -1;
189}
190
191static int find_attribute_index(int shape_index, const char *name)
192{
193 int i = 0;
194
195 for (i = 0; i < MAX_SHAPE_ATTRIBUTES; i++) {
196 if (gml_shape_defs[shape_index].required_attributes[i].name == NULL) {
197 return -1;
198 }
200 return i;
201 }
202 }
203 return -1;
204}
205
206static enum ast_geoloc_validate_result validate_def_varlist(int shape_index, const struct ast_variable *varlist,
207 char **result)
208{
209 const struct ast_variable *var;
210 int i;
211
212 for (var = varlist; var; var = var->next) {
213 int vname_index = -1;
214 if (ast_strings_equal("shape", var->name)) {
215 continue;
216 }
217
218 vname_index = find_attribute_index(shape_index, var->name);
219 if (vname_index < 0) {
220 SET_RESULT(result, "Invalid variable name '%s'\n", var->name);
222 }
223 if (!gml_shape_defs[shape_index].required_attributes[vname_index].validator(var->name, var->value,
224 varlist, result)) {
226 }
227 }
228
229 for (i = 0; i < ARRAY_LEN(gml_shape_defs[shape_index].required_attributes); i++) {
230 int count = 0;
231 if (gml_shape_defs[shape_index].required_attributes[i].name == NULL) {
232 break;
233 }
234
235 for (var = varlist; var; var = var->next) {
236 if (ast_strings_equal(gml_shape_defs[shape_index].required_attributes[i].name, var->name)) {
237 count++;
238 }
239 }
240 if (count < gml_shape_defs[shape_index].required_attributes[i].min_required) {
241 SET_RESULT(result, "Number of '%s' variables %d is < %d",
242 gml_shape_defs[shape_index].required_attributes[i].name,
243 count,
244 gml_shape_defs[shape_index].required_attributes[i].min_required);
246 }
247 if (gml_shape_defs[shape_index].required_attributes[i].max_allowed > 0 &&
248 count > gml_shape_defs[shape_index].required_attributes[i].max_allowed) {
249 SET_RESULT(result, "Number of '%s' variables %d is > %d",
250 gml_shape_defs[shape_index].required_attributes[i].name,
251 count,
252 gml_shape_defs[shape_index].required_attributes[i].max_allowed);
254 }
255 }
256
258}
259
261 char **result)
262{
263 const char *shape_type = ast_variable_find_in_list(varlist, "shape");
264 int shape_index = -1;
265 const char *crs = ast_variable_find_in_list(varlist, "crs");
266
267 if (!shape_type) {
268 SET_RESULT(result, "Missing 'shape'");
270 }
271
272 shape_index = find_shape_index(shape_type);
273 if (shape_index < 0) {
274 SET_RESULT(result, "Invalid shape '%s'", shape_type);
276 }
277
278 if (ast_strlen_zero(crs)) {
279 struct ast_variable *vcrs = NULL;
280 if (ast_strings_equal("any", gml_shape_defs[shape_index].crs)) {
281 crs = "2d";
282 } else {
283 crs = gml_shape_defs[shape_index].crs;
284 }
285
286 vcrs = ast_variable_new("crs", "2d", "");
287 if (vcrs) {
288 ast_variable_list_append(&varlist, vcrs);
289 }
290 }
291 if (!crs_validator("crs", crs, varlist, result)) {
293 }
294
295 if (!ast_strings_equal("any", gml_shape_defs[shape_index].crs)
296 && !ast_strings_equal(crs, gml_shape_defs[shape_index].crs)) {
297 SET_RESULT(result, "Invalid crs '%s' for shape '%s'", crs, shape_type);
299 }
300
301 return validate_def_varlist(shape_index, varlist, result);
302}
303
304static char *handle_gml_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
305{
306 int i;
307
308 switch (cmd) {
309 case CLI_INIT:
310 e->command = "geoloc show gml_shape_defs";
311 e->usage =
312 "Usage: geoloc show gml_shape_defs\n"
313 " Show the GML Shape definitions.\n";
314 return NULL;
315 case CLI_GENERATE:
316 return NULL;
317 }
318
319 ast_cli(a->fd, "%-16s %-3s %-32s\n", "Shape", "CRS", "Attributes name(min,max)");
320 ast_cli(a->fd, "================ === ===============================\n");
321
322 for (i = 0; i < ARRAY_LEN(gml_shape_defs); i++) {
323 int j;
324 ast_cli(a->fd, "%-16s %-3s", gml_shape_defs[i].shape_type, gml_shape_defs[i].crs);
325 for (j = 0; j < ARRAY_LEN(gml_shape_defs[i].required_attributes); j++) {
326 if (gml_shape_defs[i].required_attributes[j].name == NULL) {
327 break;
328 }
329 if (gml_shape_defs[i].required_attributes[j].max_allowed >= 0) {
330 ast_cli(a->fd, " %s(%d,%d)", gml_shape_defs[i].required_attributes[j].name,
333 } else {
334 ast_cli(a->fd, " %s(%d,unl)", gml_shape_defs[i].required_attributes[j].name,
336 }
337 }
338 ast_cli(a->fd, "\n");
339 }
340 ast_cli(a->fd, "\n");
341
342 return CLI_SUCCESS;
343}
344
345static struct ast_cli_entry geoloc_gml_cli[] = {
346 AST_CLI_DEFINE(handle_gml_show, "Show the GML Shape definitions"),
347};
348
349struct ast_xml_node *geoloc_gml_list_to_xml(struct ast_variable *resolved_location,
350 const char *ref_string)
351{
352 const char *shape;
353 const char *crs;
354 struct ast_variable *var;
355 struct ast_xml_node *gml_node;
356 struct ast_xml_node *child_node;
358 RAII_VAR(char *, result, NULL, ast_free);
359 int rc = 0;
360
361 SCOPE_ENTER(3, "%s", ref_string);
362
363 if (!resolved_location) {
364 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: resolved_location was NULL\n",
365 ref_string);
366 }
367
368 res = ast_geoloc_gml_validate_varlist(resolved_location, &result);
369 if (res != AST_GEOLOC_VALIDATE_SUCCESS) {
371 ref_string, result);
372 }
373
374 shape = ast_variable_find_in_list(resolved_location, "shape");
375 if (ast_strlen_zero(shape)) {
376 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: There's no 'shape' parameter\n",
377 ref_string);
378 }
379
380 crs = ast_variable_find_in_list(resolved_location, "crs");
381 if (ast_strlen_zero(crs)) {
382 struct ast_variable *vcrs = ast_variable_new("crs", "2d", "");
383 if (vcrs) {
384 ast_variable_list_append(&resolved_location, vcrs);
385 }
386 crs = "2d";
387 }
388
389 gml_node = ast_xml_new_node(shape);
390 if (!gml_node) {
391 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n", shape, ref_string);
392 }
393 rc = ast_xml_set_attribute(gml_node, "crs", crs);
394 if (rc != 0) {
395 ast_xml_free_node(gml_node);
396 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'crs' XML attribute\n", ref_string);
397 }
398
399 for (var = (struct ast_variable *)resolved_location; var; var = var->next) {
400
401 if (ast_strings_equal(var->name, "shape") || ast_strings_equal(var->name, "crs")) {
402 continue;
403 }
404
405 child_node = ast_xml_new_child(gml_node, var->name);
406 if (!child_node) {
407 ast_xml_free_node(gml_node);
408 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create '%s' XML node\n", var->name, ref_string);
409 }
410
411 if (ast_strings_equal(var->name, "orientation") || ast_strings_equal(var->name, "startAngle")
412 || ast_strings_equal(var->name, "openingAngle")) {
413 RAII_VAR(char *, angle, NULL, ast_free);
414 RAII_VAR(char *, uom, NULL, ast_free);
415
416 enum angle_parse_result rc = angle_parser(var->name, var->value, &angle, &uom, &result);
417 if (rc != ANGLE_PARSE_RESULT_SUCCESS) {
418 ast_xml_free_node(gml_node);
419 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: %s\n", ref_string, result);
420 }
421 rc = ast_xml_set_attribute(child_node, "uom", uom);
422 if (rc != 0) {
423 ast_xml_free_node(gml_node);
424 SCOPE_EXIT_LOG_RTN_VALUE(NULL, LOG_ERROR, "%s: Unable to create 'uom' XML attribute\n", ref_string);
425 }
426 ast_xml_set_text(child_node, angle);
427 } else {
428 ast_xml_set_text(child_node, var->value);
429 }
430 }
431
432 SCOPE_EXIT_RTN_VALUE(gml_node, "%s: Done\n", ref_string);
433}
434
441
448
450{
452}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
#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
static PGresult * result
Definition cel_pgsql.c:84
Standard Command Line Interface.
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
static const char name[]
Definition format_mp3.c:68
static enum ast_geoloc_validate_result validate_def_varlist(int shape_index, const struct ast_variable *varlist, char **result)
Definition geoloc_gml.c:206
enum ast_geoloc_validate_result ast_geoloc_gml_validate_varlist(struct ast_variable *varlist, char **result)
Validate that the variables in the list represent a valid GML shape.
Definition geoloc_gml.c:260
static int find_attribute_index(int shape_index, const char *name)
Definition geoloc_gml.c:191
static int angle_validator(const char *name, const char *value, const struct ast_variable *varlist, char **result)
Definition geoloc_gml.c:148
static int crs_validator(const char *name, const char *value, const struct ast_variable *varlist, char **result)
Definition geoloc_gml.c:45
#define SET_RESULT(__result,...)
Definition geoloc_gml.c:38
#define _SENTRY
Definition geoloc_gml.c:156
static int pos_validator(const char *name, const char *value, const struct ast_variable *varlist, char **result)
Definition geoloc_gml.c:55
static int float_validator(const char *name, const char *value, const struct ast_variable *varlist, char **result)
Definition geoloc_gml.c:76
#define MAX_SHAPE_ATTRIBUTES
Definition geoloc_gml.c:31
struct ast_xml_node * geoloc_gml_list_to_xml(struct ast_variable *resolved_location, const char *ref_string)
Definition geoloc_gml.c:349
angle_parse_result
Definition geoloc_gml.c:87
@ ANGLE_PARSE_ERROR_INVALID_UOM
Definition geoloc_gml.c:92
@ ANGLE_PARSE_ERROR_NO_ANGLE
Definition geoloc_gml.c:89
@ ANGLE_PARSE_RESULT_SUCCESS
Definition geoloc_gml.c:88
@ ANGLE_PARSE_ERROR_ANGLE_OUT_OF_RANGE
Definition geoloc_gml.c:91
@ ANGLE_PARSE_ERROR_INVALID_ANGLE
Definition geoloc_gml.c:90
static int find_shape_index(const char *shape)
Definition geoloc_gml.c:178
#define CRS_REQ
Definition geoloc_gml.c:159
static struct ast_cli_entry geoloc_gml_cli[]
Definition geoloc_gml.c:345
#define CRS_OPT
Definition geoloc_gml.c:158
int geoloc_gml_reload(void)
Definition geoloc_gml.c:449
static char * handle_gml_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition geoloc_gml.c:304
static struct geoloc_gml_shape_def gml_shape_defs[]
Definition geoloc_gml.c:161
int geoloc_gml_unload(void)
Definition geoloc_gml.c:435
static enum angle_parse_result angle_parser(const char *name, const char *value, char **angle, char **uom, char **result)
Definition geoloc_gml.c:95
int geoloc_gml_load(void)
Definition geoloc_gml.c:442
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
#define SCOPE_ENTER(level,...)
Configuration File Parser.
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)
#define LOG_ERROR
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
ast_geoloc_validate_result
@ AST_GEOLOC_VALIDATE_INVALID_CRS
@ AST_GEOLOC_VALIDATE_TOO_MANY_VARNAMES
@ AST_GEOLOC_VALIDATE_MISSING_SHAPE
@ AST_GEOLOC_VALIDATE_INVALID_VALUE
@ AST_GEOLOC_VALIDATE_SUCCESS
@ AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES
@ AST_GEOLOC_VALIDATE_INVALID_CRS_FOR_SHAPE
@ AST_GEOLOC_VALIDATE_INVALID_SHAPE
@ AST_GEOLOC_VALIDATE_INVALID_VARNAME
#define NULL
Definition resample.c:96
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
@ AST_STRSEP_ALL
Definition strings.h:258
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_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition utils.c:1871
descriptor for a cli entry.
Definition cli.h:171
char * command
Definition cli.h:186
const char * usage
Definition cli.h:177
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
const char * name
Definition geoloc_gml.c:24
int(* validator)(const char *name, const char *value, const struct ast_variable *varlist, char **result)
Definition geoloc_gml.c:27
const char * crs
Definition geoloc_gml.c:34
const char * shape_type
Definition geoloc_gml.c:33
struct geoloc_gml_attr required_attributes[MAX_SHAPE_ATTRIBUTES]
Definition geoloc_gml.c:35
int value
Definition syslog.c:37
static struct test_val a
#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
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
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
void ast_xml_free_node(struct ast_xml_node *node)
Free node.
Definition xml.c:243