Asterisk - The Open Source Telephony Project GIT-master-80b953f
Loading...
Searching...
No Matches
Data Structures | Functions | Variables
config.c File Reference

Common config file handling for res_cdrel_custom. More...

#include "cdrel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/paths.h"
Include dependency graph for res/cdrel_custom/config.c:

Go to the source code of this file.

Data Structures

struct  field_parse_result
 

Functions

struct cdrel_configs * cdrel_load_module (enum cdrel_backend_type backend_type, enum cdrel_record_type record_type, const char *filename, const char *backend_name, void *log_cb)
 Perform initial module load.
 
int cdrel_reload_module (enum cdrel_backend_type output_type, enum cdrel_record_type record_type, struct cdrel_configs **configs, const char *filename)
 Perform module reload.
 
int cdrel_unload_module (enum cdrel_backend_type backend_type, enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *backend_name)
 Perform module unload.
 
static struct cdrel_configconfig_alloc (enum cdrel_record_type record_type, enum cdrel_backend_type backend_type, enum cdrel_config_type config_type, const char *config_filename, const char *output_filename, const char *template)
 
static void config_free (struct cdrel_config *config)
 
static struct cdrel_fieldfield_alloc (struct cdrel_config *config, const char *input_field_template)
 
static void field_template_vector_free (struct ast_vector_string *fields)
 
static int load_config_file (enum cdrel_backend_type output_type, enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *filename, int reload)
 
static int load_database_columns (struct cdrel_config *config, const char *columns, int *column_count)
 
static struct cdrel_configload_database_config (enum cdrel_record_type record_type, struct ast_category *category, const char *config_filename)
 
static int load_database_config_file (enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *config_filename, int reload)
 
static int load_fields (struct cdrel_config *config, struct ast_vector_string *fields)
 
static struct cdrel_configload_text_file_advanced_config (enum cdrel_record_type record_type, struct ast_category *category, const char *config_filename)
 
static int load_text_file_config_file (enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *config_filename, int reload)
 
static struct cdrel_configload_text_file_legacy_config (enum cdrel_record_type record_type, const char *config_filename, const char *output_filename, const char *template)
 
static int load_text_file_legacy_mappings (enum cdrel_record_type record_type, struct cdrel_configs *configs, struct ast_category *category, const char *config_filename)
 
static char * make_stmt_placeholders (int columns)
 
static int open_database (struct cdrel_config *config)
 
static struct field_parse_result parse_field (enum cdrel_record_type record_type, char *input_field_template)
 
static int parse_legacy_template (enum cdrel_record_type record_type, const char *config_filename, const char *output_filename, const char *input_template, struct ast_vector_string *fields)
 
static int register_backend (enum cdrel_record_type record_type, const char *backend_name, void *log_cb)
 
static int unregister_backend (enum cdrel_record_type record_type, const char *backend_name)
 

Variables

static const char * allowed_functions []
 
static const char * dirname_map [cdrel_backend_type_end][cdrel_record_type_end]
 
static const char * special_vars []
 

Detailed Description

Common config file handling for res_cdrel_custom.

Author
George Joseph gjose.nosp@m.ph@s.nosp@m.angom.nosp@m.a.co.nosp@m.m

This file is a 'bit' complex. The reasoning is that the functions do as much work as possible at module load time to reduce the workload at run time.

Definition in file res/cdrel_custom/config.c.

Function Documentation

◆ cdrel_load_module()

struct cdrel_configs * cdrel_load_module ( enum cdrel_backend_type  backend_type,
enum cdrel_record_type  record_type,
const char *  config_filename,
const char *  backend_name,
void *  logging_cb 
)

Perform initial module load.

Needs to be called by each "custom" module

Parameters
backend_typeOne of cdrel_backend_type.
record_typeOne of cdrel_record_type.
config_filenameThe config file name.
backend_nameThe name to register the backend as.
logging_cbThe logging callback to register with CDR or CEL.
Returns
A pointer to a VECTOR or config objects read from the config file.

Definition at line 1431 of file res/cdrel_custom/config.c.

1434{
1435 struct cdrel_configs *configs = ast_calloc(1, sizeof(*configs));
1436 if (!configs) {
1437 return NULL;
1438 }
1439 ast_debug(1, "Loading %s %s\n", RECORD_TYPE_STR(record_type), MODULE_TYPE_STR(backend_type));
1440
1441 if (AST_VECTOR_INIT(configs, 5) != 0) {
1442 cdrel_unload_module(backend_type, record_type, configs, backend_name);
1443 return NULL;
1444 }
1445
1446 if (load_config_file(backend_type, record_type, configs, filename, 0) != 0) {
1447 cdrel_unload_module(backend_type, record_type, configs, backend_name);
1448 return NULL;
1449 }
1450
1451 if (register_backend(record_type, backend_name, log_cb)) {
1452 cdrel_unload_module(backend_type, record_type, configs, backend_name);
1453 return NULL;
1454 }
1455
1456 return configs;
1457}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define MODULE_TYPE_STR(_mt)
Definition cdrel.h:45
#define RECORD_TYPE_STR(_rt)
Definition cdrel.h:42
#define ast_debug(level,...)
Log a DEBUG message.
static int register_backend(enum cdrel_record_type record_type, const char *backend_name, void *log_cb)
static int load_config_file(enum cdrel_backend_type output_type, enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *filename, int reload)
int cdrel_unload_module(enum cdrel_backend_type backend_type, enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *backend_name)
Perform module unload.
#define NULL
Definition resample.c:96
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124

References ast_calloc, ast_debug, AST_VECTOR_INIT, cdrel_unload_module(), load_config_file(), MODULE_TYPE_STR, NULL, RECORD_TYPE_STR, and register_backend().

Referenced by load_module(), load_module(), load_module(), and load_module().

◆ cdrel_reload_module()

int cdrel_reload_module ( enum cdrel_backend_type  backend_type,
enum cdrel_record_type  record_type,
struct cdrel_configs **  configs,
const char *  config_filename 
)

Perform module reload.

Needs to be called by each "custom" module

Warning
This function MUST be called with the module's config_lock held for writing to prevent reloads from happening while we're logging.
Parameters
backend_typeOne of cdrel_backend_type.
record_typeOne of cdrel_record_type.
configsA pointer to the VECTOR of config objects returned by cdrel_load_module.
config_filenameThe config file name.
Return values
AST_MODULE_LOAD_SUCCESS
AST_MODULE_LOAD_DECLINE

Definition at line 1391 of file res/cdrel_custom/config.c.

1393{
1394 int res = 0;
1395 struct cdrel_configs *old_configs = *configs;
1396 struct cdrel_configs *new_configs = NULL;
1397
1398 /*
1399 * Save new config to a temporary vector to make sure the
1400 * configs are valid before swapping them in.
1401 */
1402 new_configs = ast_malloc(sizeof(*new_configs));
1403 if (!new_configs) {
1405 }
1406
1407 if (AST_VECTOR_INIT(new_configs, AST_VECTOR_SIZE(old_configs)) != 0) {
1409 }
1410
1411 res = load_config_file(output_type, record_type, new_configs, filename, 1);
1412 if (res != 0) {
1413 AST_VECTOR_RESET(new_configs, config_free);
1414 AST_VECTOR_PTR_FREE(new_configs);
1416 }
1417
1418 /* Now swap the new ones in. */
1419 *configs = new_configs;
1420
1421 /* Free the old ones. */
1422 AST_VECTOR_RESET(old_configs, config_free);
1423 AST_VECTOR_PTR_FREE(old_configs);
1424
1426
1427
1428 return -1;
1429}
#define ast_malloc(len)
A wrapper for malloc()
Definition astmm.h:191
@ 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
static void config_free(struct cdrel_config *config)
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition vector.h:636
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_PTR_FREE(vec)
Deallocates this vector pointer.
Definition vector.h:200

References ast_malloc, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, AST_VECTOR_INIT, AST_VECTOR_PTR_FREE, AST_VECTOR_RESET, AST_VECTOR_SIZE, config_free(), load_config_file(), and NULL.

Referenced by reload(), reload(), reload(), and reload().

◆ cdrel_unload_module()

int cdrel_unload_module ( enum cdrel_backend_type  backend_type,
enum cdrel_record_type  record_type,
struct cdrel_configs *  configs,
const char *  backend_name 
)

Perform module unload.

Needs to be called by each "custom" module

Warning
This function MUST be called with the module's config_lock held for writing to prevent the module from being unloaded while we're logging.
Parameters
backend_typeOne of cdrel_backend_type.
record_typeOne of cdrel_record_type.
configsA pointer to the VECTOR of config objects returned by cdrel_load_module.
backend_nameThe backend name to unregister.
Return values
0Success.
-1Failure.

Definition at line 1459 of file res/cdrel_custom/config.c.

1461{
1462 if (unregister_backend(record_type, backend_name) != 0) {
1463 return -1;
1464 }
1465
1468
1469 return 0;
1470}
static int unregister_backend(enum cdrel_record_type record_type, const char *backend_name)

References AST_VECTOR_PTR_FREE, AST_VECTOR_RESET, config_free(), and unregister_backend().

Referenced by cdrel_load_module(), unload_module(), unload_module(), unload_module(), and unload_module().

◆ config_alloc()

static struct cdrel_config * config_alloc ( enum cdrel_record_type  record_type,
enum cdrel_backend_type  backend_type,
enum cdrel_config_type  config_type,
const char *  config_filename,
const char *  output_filename,
const char *  template 
)
static

Definition at line 655 of file res/cdrel_custom/config.c.

658{
660 struct cdrel_config *rtn_config = NULL;
661 const char *file_suffix = "";
662 int res = 0;
663
665
667 if (!config) {
668 return NULL;
669 }
670
672 return NULL;
673 }
674
675 config->record_type = record_type;
676 config->backend_type = backend_type;
677 config->dummy_channel_alloc = cdrel_dummy_channel_allocators[record_type];
678 config->config_type = config_type;
679
680 /* Set defaults */
681 config->format_type = cdrel_format_dsv;
682 config->separator[0] = ',';
683 switch(backend_type) {
685 config->quote[0] = '"';
686 config->quoting_method = cdrel_quoting_method_all;
687 break;
688 case cdrel_backend_db:
689 config->quote[0] = '\0';
690 config->format_type = cdrel_format_sql;
691 config->quoting_method = cdrel_quoting_method_none;
692 if (!ast_ends_with(output_filename, ".db")) {
693 file_suffix = ".db";
694 }
695 break;
696 default:
697 ast_log(LOG_ERROR, "%s->%s: Unknown backend type '%d'\n", cdrel_basename(config_filename),
699 break;
700 }
701 config->quote_escape[0] = config->quote[0];
702
703 res = ast_string_field_set(config, template, template);
704 if (res != 0) {
705 return NULL;
706 }
707
708 if (output_filename[0] == '/') {
709 res = ast_string_field_build(config, output_filename, "%s%s", output_filename, file_suffix);
710 } else {
711 const char *subdir = dirname_map[backend_type][record_type];
712 res = ast_string_field_build(config, output_filename, "%s/%s%s%s%s",
713 ast_config_AST_LOG_DIR, S_OR(subdir, ""), ast_strlen_zero(subdir) ? "" : "/", output_filename, file_suffix);
714 }
715 if (res != 0) {
716 return NULL;
717 }
718 ast_mutex_init(&config->lock);
719
720 rtn_config = config;
721 config = NULL;
722 return rtn_config;
723}
#define ast_log
Definition astobj2.c:42
const char * cdrel_basename(const char *path)
@ cdrel_quoting_method_all
Definition cdrel.h:62
@ cdrel_quoting_method_none
Definition cdrel.h:61
@ cdrel_format_dsv
Definition cdrel.h:48
@ cdrel_format_sql
Definition cdrel.h:50
cdrel_dummy_channel_alloc cdrel_dummy_channel_allocators[cdrel_format_type_end]
static const char config[]
static char * config_filename
Definition extconf.c:2118
#define LOG_ERROR
#define ast_mutex_init(pmutex)
Definition lock.h:193
const char * ast_config_AST_LOG_DIR
Definition options.c:160
static const char * dirname_map[cdrel_backend_type_end][cdrel_record_type_end]
@ cdrel_backend_db
@ cdrel_backend_text
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
#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 int force_inline attribute_pure ast_ends_with(const char *str, const char *suffix)
Checks whether a string ends with another.
Definition strings.h:116
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
enum cdrel_config_type config_type
Definition cdrel.h:295
const ast_string_field output_filename
Definition cdrel.h:289
enum cdrel_record_type record_type
Definition cdrel.h:282
enum cdrel_backend_type backend_type
Definition cdrel.h:294
#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

References ast_calloc_with_stringfields, ast_config_AST_LOG_DIR, ast_debug, ast_ends_with(), ast_log, ast_mutex_init, ast_string_field_build, ast_string_field_set, ast_strlen_zero(), cdrel_backend_db, cdrel_backend_text, cdrel_basename(), cdrel_dummy_channel_allocators, cdrel_format_dsv, cdrel_format_sql, cdrel_quoting_method_all, cdrel_quoting_method_none, config, config_filename, config_free(), dirname_map, LOG_ERROR, NULL, RAII_VAR, and S_OR.

◆ config_free()

static void config_free ( struct cdrel_config config)
static

Definition at line 618 of file res/cdrel_custom/config.c.

619{
620 if (!config) {
621 return;
622 }
623
624 if (config->insert) {
625 sqlite3_finalize(config->insert);
626 config->insert = NULL;
627 }
628
629 if (config->db) {
630 sqlite3_close(config->db);
631 config->db = NULL;
632 }
633
637 AST_VECTOR_FREE(&config->fields);
639}
#define ast_free(a)
Definition astmm.h:180
#define ast_mutex_destroy(a)
Definition lock.h:195
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185

References ast_free, ast_mutex_destroy, ast_string_field_free_memory, AST_VECTOR_FREE, AST_VECTOR_RESET, config, and NULL.

Referenced by cdrel_reload_module(), cdrel_unload_module(), config_alloc(), load_database_config(), load_database_config_file(), load_text_file_advanced_config(), load_text_file_config_file(), and load_text_file_legacy_mappings().

◆ field_alloc()

static struct cdrel_field * field_alloc ( struct cdrel_config config,
const char *  input_field_template 
)
static

Definition at line 336 of file res/cdrel_custom/config.c.

337{
338 RAII_VAR(struct cdrel_field *, field, NULL, ast_free);
339 const struct cdrel_field *registered_field = NULL;
340 struct cdrel_field *rtn_field = NULL;
341 char *field_name = NULL;
342 char *data = NULL;
343 char *tmp_data = NULL;
344 char *closeparen = NULL;
345 char *qualifier = NULL;
346 enum cdrel_data_type forced_output_data_type = cdrel_data_type_end;
347 struct ast_flags field_flags = { 0 };
348
349 /*
350 * The database fields are specified field-by-field for legacy so we treat them
351 * as literals containing expressions which will be evaluated record-by-record.
352 */
353 if (config->backend_type == cdrel_backend_db && config->config_type == cdrel_config_legacy) {
354 registered_field = get_registered_field_by_name(config->record_type, "literal");
355 ast_assert(registered_field != NULL);
356 rtn_field = ast_calloc(1, sizeof(*field) + strlen(input_field_template) + 1);
357 if (!rtn_field) {
358 return NULL;
359 }
360 memcpy(rtn_field, registered_field, sizeof(*registered_field));
361 strcpy(rtn_field->data, input_field_template); /* Safe */
362 return rtn_field;
363 }
364
365 /*
366 * If the field template is a quoted string, it's a literal.
367 * We don't check for qualifiers.
368 */
369 if (input_field_template[0] == '"' || input_field_template[0] == '\'') {
370 data = ast_strip_quoted(ast_strdupa(input_field_template), "\"'", "\"'");
371 ast_set_flag(&field_flags, cdrel_flag_literal);
372 ast_debug(3, " Using qualifier 'literal' for field '%s' flags: %s\n", data,
373 ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
374 field_name = "literal";
375 } else {
376 field_name = ast_strdupa(input_field_template);
377 data = strchr(field_name, '(');
378
379 if (data) {
380 *data = '\0';
381 data++;
382 closeparen = strchr(data, ')');
383 if (closeparen) {
384 *closeparen = '\0';
385 }
386 }
387 }
388
389 if (!ast_strlen_zero(data) && !ast_test_flag(&field_flags, cdrel_flag_literal)) {
390 char *data_swap = NULL;
391 tmp_data = ast_strdupa(data);
392
393 while((qualifier = ast_strsep(&tmp_data, '^', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
395 if (ast_strlen_zero(qualifier)) {
396 continue;
397 }
398 fodt = cdrel_data_type_from_str(qualifier);
399 if (fodt < cdrel_data_type_end) {
401 if (fodt == cdrel_type_uservar) {
402 ast_set_flag(&field_flags, cdrel_flag_uservar);
403 ast_debug(3, " Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
404 field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
405 data_swap = ast_strdupa(field_name);
406 field_name = "uservar";
407 } else if (fodt == cdrel_type_literal) {
408 ast_set_flag(&field_flags, cdrel_flag_literal);
409 ast_debug(3, " Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
410 field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
411 data_swap = ast_strdupa(field_name);
412 field_name = "literal";
413 } else {
414 forced_output_data_type = fodt;
415 ast_debug(3, " Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
416 field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
417 }
418 continue;
419 }
420 if (strcasecmp(qualifier, "quote") == 0) {
421 ast_set_flag(&field_flags, cdrel_flag_quote);
422 ast_debug(3, " Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
423 field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
424 continue;
425 }
426 if (strcasecmp(qualifier, "noquote") == 0) {
427 ast_set_flag(&field_flags, cdrel_flag_noquote);
428 ast_debug(3, " Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
429 field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
430 continue;
431 }
432 if (strchr(qualifier, '%') != NULL) {
433 data_swap = ast_strdupa(qualifier);
435 forced_output_data_type = cdrel_type_string;
436 ast_debug(3, " Using qualifier '%s' for field '%s' flags: %s\n", qualifier,
437 field_name, ast_str_tmp(128, cdrel_get_field_flags(&field_flags, &STR_TMP)));
438 }
439 }
440 if (ast_test_flag(&field_flags, cdrel_flag_quote) && ast_test_flag(&field_flags, cdrel_flag_noquote)) {
441 ast_log(LOG_WARNING, "%s->%s: Field '%s(%s)' has both quote and noquote\n",
442 config->config_filename, config->output_filename, field_name, data);
443 return NULL;
444 }
445 data = data_swap;
446 }
447
448 /*
449 * Check again for literal.
450 */
451 if (ast_test_flag(&field_flags, cdrel_flag_literal)) {
452 if (config->format_type == cdrel_format_json && !strchr(data, ':')) {
453 ast_log(LOG_WARNING, "%s->%s: Literal field '%s' must be formatted as \"name: value\" when using the 'json' format\n",
454 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
455 input_field_template);
456 return NULL;
457 }
458 }
459
460 /*
461 * Now look the field up by just the field name without any data.
462 */
463 registered_field = get_registered_field_by_name(config->record_type, field_name);
464 if (!registered_field) {
465 ast_log(LOG_WARNING, "%s->%s: Field '%s' not found\n",
466 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename), field_name);
467 return NULL;
468 }
469
470 if (ast_test_flag(&field_flags, cdrel_flag_format_spec)
471 && registered_field->input_data_type != cdrel_type_timeval) {
472 ast_log(LOG_WARNING, "%s->%s: Custom format '%s' ignored for field '%s'."
473 " Only timeval types can use custom format strings.\n",
474 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
475 data, field_name);
476 forced_output_data_type = cdrel_data_type_end;
478 data = NULL;
479 }
480
481 field = ast_calloc(1, sizeof(*registered_field) + strlen(input_field_template) + 1);
482 if (!field) {
483 return NULL;
484 }
485 memcpy(field, registered_field, sizeof(*field));
486
487 if (!ast_strlen_zero(data)) {
488 strcpy(field->data, data); /* Safe */
489 }
490
491 /*
492 * For user variables, we use the field name from the data
493 * we set above.
494 */
495 if (field->input_data_type == cdrel_type_uservar) {
496 field->name = field->data;
497 }
498
499 if (field->input_data_type == cdrel_type_literal && config->format_type == cdrel_format_json) {
500 /*
501 * data should look something like this... lname: lvalue
502 * We'll need to make field->name point to "lname" and
503 * field->data point to "lvalue" so that when output the
504 * json will look like... "lname": "lvalue".
505 * Since field->data is already long enough to to handle both,
506 * we'll do this...
507 * field->data = lvalue\0lname\0
508 * field->name = ^
509 */
510 char *ptr = strchr(data, ':');/* Safe since we checked data for a ':' above */
511 *ptr = '\0';
512 ptr++;
513 /*
514 * data: lname\0 lvalue
515 * ptr: ^
516 */
517 strcpy(field->data, ast_strip_quoted(ptr, "\"", "\"")); /* Safe */
518 /*
519 * field->data: lvalue\0
520 */
521 ptr = field->data + strlen(field->data);
522 ptr++;
523 /*
524 * field->data: lvalue\0
525 * ptr: ^
526 * data: lname\0 lvalue
527 */
528 strcpy(ptr, data); /* Safe */
529 /*
530 * field->data: lvalue\0lname\0
531 */
532 field->name = ptr;
533 /*
534 * field->data: lvalue\0lname\0
535 * field->name: ^
536 */
537 }
538
539 if (forced_output_data_type < cdrel_data_type_end) {
540 field->output_data_type = forced_output_data_type;
541 }
542 field->flags = field_flags;
543
544 /*
545 * Unless the field has the 'noquote' flag, we'll set the 'quote'
546 * flag if quoting method is 'all' or 'non_numeric'.
547 */
548 if (!ast_test_flag(&field->flags, cdrel_flag_noquote)) {
549 if (config->quoting_method == cdrel_quoting_method_all) {
550 ast_set_flag(&field->flags, cdrel_flag_quote);
551 } else if (config->quoting_method == cdrel_quoting_method_non_numeric) {
552 if (field->output_data_type > cdrel_data_type_strings_end) {
553 ast_set_flag(&field->flags, cdrel_flag_noquote);
554 } else {
555 ast_set_flag(&field->flags, cdrel_flag_quote);
556 }
557 }
558 }
559
560 if (config->quoting_method == cdrel_quoting_method_none) {
561 ast_clear_flag(&field->flags, cdrel_flag_quote);
562 ast_set_flag(&field->flags, cdrel_flag_noquote);
563 }
564
565 ast_debug(2, "%s->%s: Field '%s' processed -> name:'%s' input_type:%s output_type:%s flags:'%s' data:'%s'\n",
566 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename), input_field_template,
567 field->name, DATA_TYPE_STR(field->input_data_type),
568 DATA_TYPE_STR(field->output_data_type),
569 ast_str_tmp(128, cdrel_get_field_flags(&field->flags, &STR_TMP)),
570 field->data);
571
572 rtn_field = field;
573 field = NULL;
574 return rtn_field;
575}
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
const struct cdrel_field * get_registered_field_by_name(enum cdrel_record_type record_type, const char *name)
Definition registry.c:113
enum cdrel_data_type cdrel_data_type_from_str(const char *str)
#define DATA_TYPE_STR(_dt)
Definition cdrel.h:92
cdrel_data_type
Definition cdrel.h:72
@ cdrel_data_type_strings_end
Definition cdrel.h:82
@ cdrel_type_uservar
Definition cdrel.h:78
@ cdrel_type_literal
Definition cdrel.h:75
@ cdrel_type_string
Definition cdrel.h:73
@ cdrel_data_type_end
Definition cdrel.h:88
@ cdrel_type_timeval
Definition cdrel.h:74
@ cdrel_quoting_method_non_numeric
Definition cdrel.h:64
@ cdrel_format_json
Definition cdrel.h:49
@ cdrel_flag_literal
Definition cdrel.h:108
@ cdrel_flag_quote
Definition cdrel.h:104
@ cdrel_flag_format_spec
Definition cdrel.h:109
@ cdrel_flag_noquote
Definition cdrel.h:105
@ cdrel_flag_uservar
Definition cdrel.h:107
@ cdrel_flag_type_forced
Definition cdrel.h:106
@ cdrel_config_legacy
Definition cdrel.h:55
const char * cdrel_get_field_flags(struct ast_flags *flags, struct ast_str **str)
#define LOG_WARNING
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition strings.h:1189
@ AST_STRSEP_TRIM
Definition strings.h:256
@ AST_STRSEP_STRIP
Definition strings.h:255
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition utils.c:1852
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition utils.c:1869
Structure used to handle boolean flags.
Definition utils.h:220
char data[1]
Definition cdrel.h:277
enum cdrel_data_type input_data_type
Definition cdrel.h:274
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ast_assert(a)
Definition utils.h:779
#define ast_clear_flag(p, flag)
Definition utils.h:78
#define ast_set_flag(p, flag)
Definition utils.h:71

References ast_assert, ast_calloc, ast_clear_flag, ast_debug, ast_free, ast_log, ast_set_flag, ast_str_tmp, ast_strdupa, ast_strip_quoted(), ast_strlen_zero(), ast_strsep(), AST_STRSEP_STRIP, AST_STRSEP_TRIM, ast_test_flag, cdrel_backend_db, cdrel_basename(), cdrel_config_legacy, cdrel_data_type_end, cdrel_data_type_from_str(), cdrel_data_type_strings_end, cdrel_flag_format_spec, cdrel_flag_literal, cdrel_flag_noquote, cdrel_flag_quote, cdrel_flag_type_forced, cdrel_flag_uservar, cdrel_format_json, cdrel_get_field_flags(), cdrel_quoting_method_all, cdrel_quoting_method_non_numeric, cdrel_quoting_method_none, cdrel_type_literal, cdrel_type_string, cdrel_type_timeval, cdrel_type_uservar, config, cdrel_field::data, DATA_TYPE_STR, get_registered_field_by_name(), cdrel_field::input_data_type, LOG_WARNING, NULL, and RAII_VAR.

Referenced by load_fields().

◆ field_template_vector_free()

static void field_template_vector_free ( struct ast_vector_string fields)
static

◆ load_config_file()

static int load_config_file ( enum cdrel_backend_type  output_type,
enum cdrel_record_type  record_type,
struct cdrel_configs *  configs,
const char *  filename,
int  reload 
)
static

Definition at line 1378 of file res/cdrel_custom/config.c.

1380{
1381 switch(output_type) {
1382 case cdrel_backend_text:
1383 return load_text_file_config_file(record_type, configs, filename, reload);
1384 case cdrel_backend_db:
1385 return load_database_config_file(record_type, configs, filename, reload);
1386 default:
1387 return -1;
1388 }
1389}
static int load_database_config_file(enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *config_filename, int reload)
static int load_text_file_config_file(enum cdrel_record_type record_type, struct cdrel_configs *configs, const char *config_filename, int reload)
static int reload(void)

References cdrel_backend_db, cdrel_backend_text, load_database_config_file(), load_text_file_config_file(), cdrel_config::record_type, and reload().

Referenced by cdrel_load_module(), and cdrel_reload_module().

◆ load_database_columns()

static int load_database_columns ( struct cdrel_config config,
const char *  columns,
int *  column_count 
)
static

Definition at line 735 of file res/cdrel_custom/config.c.

736{
737 char *col = NULL;
738 char *cols = NULL;
739 RAII_VAR(struct ast_str *, column_string, NULL, ast_free);
740
741 ast_debug(1, "%s->%s: Loading columns\n", cdrel_basename(config->config_filename),
742 cdrel_basename(config->output_filename));
743
744 if (!(column_string = ast_str_create(1024))) {
745 return -1;
746 }
747
748 cols = ast_strdupa(columns);
749 *column_count = 0;
750
751 /* We need to trim and remove any single or double quotes from each column name. */
752 while((col = ast_strsep(&cols, ',', AST_STRSEP_TRIM))) {
753 col = ast_strip(ast_strip_quoted(col, "'\"", "'\""));
754 if (ast_str_append(&column_string, 0, "%s%s", *column_count ? "," : "", col) <= 0) {
755 return -1;
756 }
757 (*column_count)++;
758 }
759
760 if (ast_string_field_set(config, db_columns, ast_str_buffer(column_string)) != 0) {
761 return -1;
762 }
763
764 return 0;
765}
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
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
Support for dynamic strings.
Definition strings.h:623

References ast_debug, ast_free, ast_str_append(), ast_str_buffer(), ast_str_create, ast_strdupa, ast_string_field_set, ast_strip(), ast_strip_quoted(), ast_strsep(), AST_STRSEP_TRIM, cdrel_basename(), config, NULL, and RAII_VAR.

Referenced by load_database_config().

◆ load_database_config()

static struct cdrel_config * load_database_config ( enum cdrel_record_type  record_type,
struct ast_category category,
const char *  config_filename 
)
static

Definition at line 896 of file res/cdrel_custom/config.c.

898{
899 const char *category_name = ast_category_get_name(category);
901 struct cdrel_config *rtn_config = NULL;
902 int res = 0;
903 int column_count = 0;
904 int value_count = 0;
905 int field_check_passed = 0;
906 const char *template = ast_variable_find(category, "values");
908 const char *value;
909 char *tmp_fields = NULL;
910 RAII_VAR(struct ast_vector_string *, field_templates, ast_calloc(1, sizeof(*field_templates)), field_template_vector_free);
911
912 if (!ast_strlen_zero(template)) {
914 } else {
915 template = ast_variable_find(category, "fields");
916 if (!ast_strlen_zero(template)) {
918 }
919 }
920 if (ast_strlen_zero(template)) {
921 ast_log(LOG_WARNING, "%s->%s: Neither 'values' nor 'fields' specified\n",
923 return NULL;
924 }
925
926 res = AST_VECTOR_INIT(field_templates, 25);
927 if (res != 0) {
928 return NULL;
929 }
930
931 /*
932 * Let's try and and parse a legacy config to see if we can turn
933 * it into an advanced condig.
934 */
937 category_name, template, field_templates);
938 if (field_check_passed) {
940 ast_log(LOG_NOTICE, "%s->%s: Legacy config upgraded to advanced\n",
942 } else {
943 AST_VECTOR_RESET(field_templates, ast_free);
944 ast_log(LOG_NOTICE, "%s->%s: Unable to upgrade legacy config to advanced. Continuing to process as legacy\n",
946 }
947 }
948
949 /*
950 * If we could, the fields vector will be populated so we don't need to do it again.
951 * If it was an advanced config or a legacy one we couldn't parse,
952 * we need to split the string into the vector.
953 */
954 if (AST_VECTOR_SIZE(field_templates) == 0) {
955 tmp_fields = ast_strdupa(template);
956 while((value = ast_strsep(&tmp_fields, ',', AST_STRSEP_TRIM))) {
957 res = AST_VECTOR_APPEND(field_templates, ast_strdup(value));
958 if (res != 0) {
959 return NULL;
960 }
961 }
962 }
963
965 config_filename, category_name, template);
966 if (!config) {
967 return NULL;
968 }
969
970 config->busy_timeout = 1000;
971
973 S_OR(ast_variable_find(category, "table"), config->record_type == cdrel_record_cdr ? "cdr" : "cel"));
974 if (res != 0) {
975 return NULL;
976 }
977
978 /* sqlite3_busy_timeout in miliseconds */
979 if ((value = ast_variable_find(category, "busy_timeout")) != NULL) {
980 if (ast_parse_arg(value, PARSE_INT32|PARSE_DEFAULT, &config->busy_timeout, 1000) != 0) {
981 ast_log(LOG_WARNING, "%s->%s: Invalid busy_timeout value '%s' specified. Using 1000 instead.\n",
982 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename), value);
983 }
984 }
985
986 /* Columns */
987 value = ast_variable_find(category, "columns");
988 if (ast_strlen_zero(value)) {
989 ast_log(LOG_WARNING, "%s->%s: The 'columns' parameter is missing",
990 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename));
991 return NULL;
992 }
993
994 if (load_database_columns(config, value, &column_count) != 0) {
995 return NULL;
996 }
997
998 if (AST_VECTOR_INIT(&config->fields, AST_VECTOR_SIZE(field_templates)) != 0) {
999 return NULL;
1000 }
1001
1002 if (load_fields(config, field_templates) != 0) {
1003 return NULL;
1004 }
1005
1006 value_count = AST_VECTOR_SIZE(&config->fields);
1007
1008 if (value_count != column_count) {
1009 ast_log(LOG_WARNING, "%s->%s: There are %d columns but %d values\n",
1010 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
1011 column_count, value_count);
1012 return NULL;
1013 }
1014
1015 res = open_database(config);
1016 if (res != 0) {
1017 return NULL;
1018 }
1019
1020 ast_log(LOG_NOTICE, "%s->%s: Logging %s records to table '%s'\n",
1021 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
1022 RECORD_TYPE_STR(config->record_type),
1023 config->db_table);
1024
1025 rtn_config = config;
1026 config = NULL;
1027 return rtn_config;
1028}
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
cdrel_config_type
Definition cdrel.h:54
@ cdrel_config_advanced
Definition cdrel.h:56
const char * ast_category_get_name(const struct ast_category *category)
Return the name of the category.
int ast_parse_arg(const char *arg, enum ast_parse_flags flags, void *p_result,...)
The argument parsing routine.
const char * ast_variable_find(const struct ast_category *category, const char *variable)
Gets a variable value from a specific category structure by name.
#define LOG_NOTICE
static void field_template_vector_free(struct ast_vector_string *fields)
static int load_fields(struct cdrel_config *config, struct ast_vector_string *fields)
static int open_database(struct cdrel_config *config)
static int parse_legacy_template(enum cdrel_record_type record_type, const char *config_filename, const char *output_filename, const char *input_template, struct ast_vector_string *fields)
static int load_database_columns(struct cdrel_config *config, const char *columns, int *column_count)
@ cdrel_record_cdr
String vector definitions.
Definition vector.h:55
const ast_string_field db_table
Definition cdrel.h:289
int value
Definition syslog.c:37
static struct prometheus_general_config * config_alloc(void)
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition vector.h:267

References ast_calloc, ast_category_get_name(), ast_free, ast_log, ast_parse_arg(), ast_strdup, ast_strdupa, ast_string_field_set, ast_strlen_zero(), ast_strsep(), AST_STRSEP_TRIM, ast_variable_find(), AST_VECTOR_APPEND, AST_VECTOR_INIT, AST_VECTOR_RESET, AST_VECTOR_SIZE, cdrel_backend_db, cdrel_basename(), cdrel_config_advanced, cdrel_config_legacy, cdrel_record_cdr, config, config_alloc(), config_filename, config_free(), field_template_vector_free(), load_database_columns(), load_fields(), LOG_NOTICE, LOG_WARNING, NULL, open_database(), PARSE_DEFAULT, PARSE_INT32, parse_legacy_template(), RAII_VAR, RECORD_TYPE_STR, S_OR, and value.

Referenced by load_database_config_file().

◆ load_database_config_file()

static int load_database_config_file ( enum cdrel_record_type  record_type,
struct cdrel_configs *  configs,
const char *  config_filename,
int  reload 
)
static

Definition at line 1041 of file res/cdrel_custom/config.c.

1043{
1044 struct ast_config *cfg;
1045 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1046 struct ast_category *category = NULL;
1047
1048 ast_debug(1, "%s: %soading\n", config_filename, reload ? "Rel" : "L");
1049 cfg = ast_config_load(config_filename, config_flags);
1050 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1051 ast_log(LOG_ERROR, "Unable to load %s. Not logging %ss to custom database\n",
1052 config_filename, RECORD_TYPE_STR(record_type));
1053 return -1;
1054 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1055 ast_debug(1, "%s: Config file unchanged, not reloading\n", config_filename);
1056 return 0;
1057 }
1058
1059 while ((category = ast_category_browse_filtered(cfg, NULL, category, NULL))) {
1060 struct cdrel_config *config = NULL;
1061
1063 if (!config) {
1064 continue;
1065 }
1066
1067 if (AST_VECTOR_APPEND(configs, config) != 0) {
1069 break;
1070 }
1071 }
1072
1073 ast_config_destroy(cfg);
1074
1075 ast_log(LOG_NOTICE, "%s: Loaded %d configs\n", config_filename, (int)AST_VECTOR_SIZE(configs));
1076
1077 /* Only fail if no configs were valid. */
1078 return AST_VECTOR_SIZE(configs) > 0 ? 0 : -1;
1079}
#define ast_config_load(filename, flags)
Load a config file.
#define CONFIG_STATUS_FILEUNCHANGED
@ CONFIG_FLAG_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
struct ast_category * ast_category_browse_filtered(struct ast_config *config, const char *category_name, struct ast_category *prev, const char *filter)
Browse categories with filters.
static struct cdrel_config * load_database_config(enum cdrel_record_type record_type, struct ast_category *category, const char *config_filename)

References ast_category_browse_filtered(), ast_config_destroy(), ast_config_load, ast_debug, ast_log, AST_VECTOR_APPEND, AST_VECTOR_SIZE, config, config_filename, CONFIG_FLAG_FILEUNCHANGED, config_free(), CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, load_database_config(), LOG_ERROR, LOG_NOTICE, NULL, RECORD_TYPE_STR, and reload().

Referenced by load_config_file().

◆ load_fields()

static int load_fields ( struct cdrel_config config,
struct ast_vector_string fields 
)
static

Definition at line 591 of file res/cdrel_custom/config.c.

592{
593 int res = 0;
594 int ix = 0;
595
596 ast_debug(1, "%s->%s: Loading fields\n", cdrel_basename(config->config_filename),
597 cdrel_basename(config->output_filename));
598
599 for (ix = 0; ix < AST_VECTOR_SIZE(fields); ix++) {
600 char *field_name = AST_VECTOR_GET(fields, ix);
601 struct cdrel_field *field = NULL;
602
603 field = field_alloc(config, field_name);
604 if (!field) {
605 res = -1;
606 continue;
607 }
608
609 if (AST_VECTOR_APPEND(&config->fields, field) != 0) {
610 ast_free(field);
611 return -1;
612 }
613 }
614
615 return res;
616}
static struct cdrel_field * field_alloc(struct cdrel_config *config, const char *input_field_template)
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691

References ast_debug, ast_free, AST_VECTOR_APPEND, AST_VECTOR_GET, AST_VECTOR_SIZE, cdrel_basename(), config, field_alloc(), and NULL.

Referenced by load_database_config(), load_text_file_advanced_config(), and load_text_file_legacy_config().

◆ load_text_file_advanced_config()

static struct cdrel_config * load_text_file_advanced_config ( enum cdrel_record_type  record_type,
struct ast_category category,
const char *  config_filename 
)
static

Definition at line 1158 of file res/cdrel_custom/config.c.

1160{
1161 const char *category_name = ast_category_get_name(category);
1163 struct cdrel_config *rtn_config = NULL;
1164 const char *value;
1165 int res = 0;
1166 const char *fields_value = ast_variable_find(category, "fields");
1167 char *tmp_fields = NULL;
1169
1170 if (ast_strlen_zero(fields_value)) {
1171 ast_log(LOG_WARNING, "%s->%s: Missing 'fields' parameter\n",
1172 cdrel_basename(config_filename), category_name);
1173 return NULL;
1174 }
1175
1177 config_filename, category_name, fields_value);
1178
1179 value = ast_variable_find(category, "format");
1180 if (!ast_strlen_zero(value)) {
1181 if (ast_strings_equal(value, "json")) {
1182 config->format_type = cdrel_format_json;
1183 config->separator[0] = ',';
1184 config->quote[0] = '"';
1185 config->quote_escape[0] = '\\';
1186 config->quoting_method = cdrel_quoting_method_non_numeric;
1187 } else if (ast_strings_equal(value, "dsv")) {
1188 config->format_type = cdrel_format_dsv;
1189 } else {
1190 ast_log(LOG_WARNING, "%s->%s: Invalid format '%s'\n",
1191 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename), value);
1192 return NULL;
1193 }
1194 }
1195
1196 if (config->format_type != cdrel_format_json) {
1197 value = ast_variable_find(category, "separator_character");
1198 if (!ast_strlen_zero(value)) {
1200 }
1201
1202 value = ast_variable_find(category, "quote_character");
1203 if (!ast_strlen_zero(value)) {
1204 ast_copy_string(config->quote, value, 2);
1205 }
1206
1207 value = ast_variable_find(category, "quote_escape_character");
1208 if (!ast_strlen_zero(value)) {
1209 ast_copy_string(config->quote_escape, value, 2);
1210 }
1211
1212 value = ast_variable_find(category, "quoting_method");
1213 if (!ast_strlen_zero(value)) {
1214 if (ast_strings_equal(value, "all")) {
1215 config->quoting_method = cdrel_quoting_method_all;
1216 } else if (ast_strings_equal(value, "minimal")) {
1217 config->quoting_method = cdrel_quoting_method_minimal;
1218 } else if (ast_strings_equal(value, "non_numeric")) {
1219 config->quoting_method = cdrel_quoting_method_non_numeric;
1220 } else if (ast_strings_equal(value, "none")) {
1221 config->quoting_method = cdrel_quoting_method_none;
1222 } else {
1223 ast_log(LOG_WARNING, "%s->%s: Invalid quoting method '%s'\n",
1224 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename), value);
1225 return NULL;
1226 }
1227 }
1228 }
1229
1230 res = AST_VECTOR_INIT(fields, 20);
1231 if (res != 0) {
1232 return NULL;
1233 }
1234 tmp_fields = ast_strdupa(fields_value);
1235 while((value = ast_strsep(&tmp_fields, ',', AST_STRSEP_TRIM))) {
1237 if (res != 0) {
1238 return NULL;
1239 }
1240 }
1241
1242 if (AST_VECTOR_INIT(&config->fields, AST_VECTOR_SIZE(fields)) != 0) {
1243 return NULL;
1244 }
1245
1246 if (load_fields(config, fields) != 0) {
1247 return NULL;
1248 }
1249
1250 ast_log(LOG_NOTICE, "%s->%s: Logging %s records\n",
1251 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
1252 RECORD_TYPE_STR(config->record_type));
1253
1254 rtn_config = config;
1255 config = NULL;
1256
1257 return rtn_config;
1258}
@ cdrel_quoting_method_minimal
Definition cdrel.h:63
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition strings.c:238
char * ast_unescape_c(char *s)
Convert some C escape sequences.
Definition utils.c:2017
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
struct cdrel_config::@455 fields

References ast_calloc, ast_category_get_name(), ast_copy_string(), ast_log, ast_strdup, ast_strdupa, ast_strings_equal(), ast_strlen_zero(), ast_strsep(), AST_STRSEP_TRIM, ast_unescape_c(), ast_variable_find(), AST_VECTOR_APPEND, AST_VECTOR_INIT, AST_VECTOR_SIZE, cdrel_backend_text, cdrel_basename(), cdrel_config_advanced, cdrel_format_dsv, cdrel_format_json, cdrel_quoting_method_all, cdrel_quoting_method_minimal, cdrel_quoting_method_non_numeric, cdrel_quoting_method_none, config, config_alloc(), config_filename, config_free(), field_template_vector_free(), cdrel_config::fields, load_fields(), LOG_NOTICE, LOG_WARNING, NULL, RAII_VAR, cdrel_config::record_type, RECORD_TYPE_STR, and value.

Referenced by load_text_file_config_file().

◆ load_text_file_config_file()

static int load_text_file_config_file ( enum cdrel_record_type  record_type,
struct cdrel_configs *  configs,
const char *  config_filename,
int  reload 
)
static

Definition at line 1310 of file res/cdrel_custom/config.c.

1312{
1313 struct ast_config *cfg;
1314 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1315 struct ast_category *category = NULL;
1316
1317 ast_debug(1, "%s: %soading\n", config_filename, reload ? "Rel" : "L");
1318 cfg = ast_config_load(config_filename, config_flags);
1319 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
1320 ast_log(LOG_ERROR, "Unable to load %s. Not logging %ss to custom files\n",
1321 config_filename, RECORD_TYPE_STR(record_type));
1322 return -1;
1323 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1324 ast_debug(1, "%s: Config file unchanged, not reloading\n", config_filename);
1325 return 0;
1326 }
1327
1328 while ((category = ast_category_browse_filtered(cfg, NULL, category, NULL))) {
1329 const char *category_name = ast_category_get_name(category);
1330
1331 if (ast_strings_equal(category_name, "mappings")) {
1333 } else {
1336 if (!config) {
1337 continue;
1338 }
1339 if (AST_VECTOR_APPEND(configs, config) != 0) {
1341 return -1;
1342 }
1343 }
1344 }
1345
1346 ast_config_destroy(cfg);
1347
1348 ast_log(LOG_NOTICE, "%s: Loaded %d configs\n", config_filename, (int)AST_VECTOR_SIZE(configs));
1349
1350 /* Only fail if no configs were valid. */
1351 return AST_VECTOR_SIZE(configs) > 0 ? 0 : -1;
1352}
static int load_text_file_legacy_mappings(enum cdrel_record_type record_type, struct cdrel_configs *configs, struct ast_category *category, const char *config_filename)
static struct cdrel_config * load_text_file_advanced_config(enum cdrel_record_type record_type, struct ast_category *category, const char *config_filename)

References ast_category_browse_filtered(), ast_category_get_name(), ast_config_destroy(), ast_config_load, ast_debug, ast_log, ast_strings_equal(), AST_VECTOR_APPEND, AST_VECTOR_SIZE, config, config_filename, CONFIG_FLAG_FILEUNCHANGED, config_free(), CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEUNCHANGED, load_text_file_advanced_config(), load_text_file_legacy_mappings(), LOG_ERROR, LOG_NOTICE, NULL, cdrel_config::record_type, RECORD_TYPE_STR, and reload().

Referenced by load_config_file().

◆ load_text_file_legacy_config()

static struct cdrel_config * load_text_file_legacy_config ( enum cdrel_record_type  record_type,
const char *  config_filename,
const char *  output_filename,
const char *  template 
)
static

Definition at line 1091 of file res/cdrel_custom/config.c.

1093{
1094 struct cdrel_config *config = NULL;
1095 int field_check_passed = 0;
1096 int res = 0;
1098
1099 res = AST_VECTOR_INIT(fields, 25);
1100 if (res != 0) {
1101 return NULL;
1102 }
1103
1104 /*
1105 * Let's try and and parse a legacy config to see if we can turn
1106 * it into an advanced condig.
1107 */
1109 output_filename, template, fields);
1110
1111 /*
1112 * If we couldn't, treat as legacy.
1113 */
1114 if (!field_check_passed) {
1116 config_filename, output_filename, template);
1117 ast_log(LOG_NOTICE, "%s->%s: Logging legacy %s records\n",
1118 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
1119 RECORD_TYPE_STR(config->record_type));
1120 return config;
1121 }
1122
1124 config_filename, output_filename, template);
1125 if (!config) {
1126 return NULL;
1127 }
1128 config->format_type = cdrel_format_dsv;
1129 config->quote[0] = '"';
1130 config->quote_escape[0] = '"';
1131 config->separator[0] = ',';
1132 config->quoting_method = cdrel_quoting_method_all;
1133
1134 if (AST_VECTOR_INIT(&config->fields, AST_VECTOR_SIZE(fields)) != 0) {
1135 return NULL;
1136 }
1137
1138 if (load_fields(config, fields) != 0) {
1139 return NULL;
1140 }
1141
1142 ast_log(LOG_NOTICE, "%s->%s: Logging legacy %s records as advanced\n",
1143 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
1144 RECORD_TYPE_STR(config->record_type));
1145
1146 return config;
1147}

References ast_calloc, ast_log, AST_VECTOR_INIT, AST_VECTOR_SIZE, cdrel_backend_text, cdrel_basename(), cdrel_config_advanced, cdrel_config_legacy, cdrel_format_dsv, cdrel_quoting_method_all, config, config_alloc(), config_filename, field_template_vector_free(), cdrel_config::fields, load_fields(), LOG_NOTICE, NULL, cdrel_config::output_filename, parse_legacy_template(), RAII_VAR, cdrel_config::record_type, and RECORD_TYPE_STR.

Referenced by load_text_file_legacy_mappings().

◆ load_text_file_legacy_mappings()

static int load_text_file_legacy_mappings ( enum cdrel_record_type  record_type,
struct cdrel_configs *  configs,
struct ast_category category,
const char *  config_filename 
)
static

Definition at line 1271 of file res/cdrel_custom/config.c.

1274{
1275 struct ast_variable *var = NULL;
1276
1277 for (var = ast_category_first(category); var; var = var->next) {
1278 struct cdrel_config *config = NULL;
1279
1280 if (ast_strlen_zero(var->name) || ast_strlen_zero(var->value)) {
1281 ast_log(LOG_WARNING, "%s: %s mapping must have both a filename and a template at line %d\n",
1282 cdrel_basename(config_filename), RECORD_TYPE_STR(config->record_type), var->lineno);
1283 continue;
1284 }
1285
1287 if (!config) {
1288 continue;
1289 }
1290
1291 if (AST_VECTOR_APPEND(configs, config) != 0) {
1293 return -1;
1294 }
1295 }
1296
1297 return 0;
1298}
#define var
Definition ast_expr2f.c:605
struct ast_variable * ast_category_first(struct ast_category *cat)
given a pointer to a category, return the root variable.
static struct cdrel_config * load_text_file_legacy_config(enum cdrel_record_type record_type, const char *config_filename, const char *output_filename, const char *template)
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next

References ast_category_first(), ast_log, ast_strlen_zero(), AST_VECTOR_APPEND, cdrel_basename(), config, config_filename, config_free(), load_text_file_legacy_config(), LOG_WARNING, ast_variable::next, NULL, cdrel_config::record_type, RECORD_TYPE_STR, and var.

Referenced by load_text_file_config_file().

◆ make_stmt_placeholders()

static char * make_stmt_placeholders ( int  columns)
static

Definition at line 767 of file res/cdrel_custom/config.c.

768{
769 char *placeholders = ast_malloc(2 * columns), *c = placeholders;
770 if (placeholders) {
771 for (; columns; columns--) {
772 *c++ = '?';
773 *c++ = ',';
774 }
775 *(c - 1) = 0;
776 }
777 return placeholders;
778}
static struct test_val c

References ast_malloc, and c.

Referenced by open_database().

◆ open_database()

static int open_database ( struct cdrel_config config)
static

Definition at line 788 of file res/cdrel_custom/config.c.

789{
790 char *sql = NULL;
791 int res = 0;
792 char *placeholders = NULL;
793
794 ast_debug(1, "%s->%s: opening database\n", cdrel_basename(config->config_filename),
795 cdrel_basename(config->output_filename));
796 res = sqlite3_open(config->output_filename, &config->db);
797 if (res != SQLITE_OK) {
798 ast_log(LOG_WARNING, "%s->%s: Could not open database\n", cdrel_basename(config->config_filename),
799 cdrel_basename(config->output_filename));
800 return -1;
801 }
802
803 sqlite3_busy_timeout(config->db, config->busy_timeout);
804
805 /* is the table there? */
806 sql = sqlite3_mprintf("SELECT COUNT(*) FROM %q;", config->db_table);
807 if (!sql) {
808 return -1;
809 }
810 res = sqlite3_exec(config->db, sql, NULL, NULL, NULL);
811 sqlite3_free(sql);
812 if (res != SQLITE_OK) {
813 /*
814 * Create the table.
815 * We don't use %q for the column list here since we already escaped when building it
816 */
817 sql = sqlite3_mprintf("CREATE TABLE %q (AcctId INTEGER PRIMARY KEY, %s)",
818 config->db_table, config->db_columns);
819 res = sqlite3_exec(config->db, sql, NULL, NULL, NULL);
820 sqlite3_free(sql);
821 if (res != SQLITE_OK) {
822 ast_log(LOG_WARNING, "%s->%s: Unable to create table '%s': %s\n",
823 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
824 config->db_table, sqlite3_errmsg(config->db));
825 return -1;
826 }
827 } else {
828 /*
829 * If the table exists, make sure the number of columns
830 * matches the config.
831 */
832 sqlite3_stmt *get_stmt;
833 int existing_columns = 0;
834 int config_columns = AST_VECTOR_SIZE(&config->fields);
835
836 sql = sqlite3_mprintf("SELECT * FROM %q;", config->db_table);
837 if (!sql) {
838 return -1;
839 }
840 res = sqlite3_prepare_v2(config->db, sql, -1, &get_stmt, NULL);
841 sqlite3_free(sql);
842 if (res != SQLITE_OK) {
843 ast_log(LOG_WARNING, "%s->%s: Unable to get column count for table '%s': %s\n",
844 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
845 config->db_table, sqlite3_errmsg(config->db));
846 return -1;
847 }
848 /*
849 * prepare figures out the number of columns that would be in a result
850 * set. We don't need to execute the statement.
851 */
852 existing_columns = sqlite3_column_count(get_stmt);
853 sqlite3_finalize(get_stmt);
854 /* config_columns doesn't include the sequence field */
855 if ((config_columns + 1) != existing_columns) {
856 ast_log(LOG_WARNING, "%s->%s: The number of fields in the config (%d) doesn't equal the"
857 " nummber of data columns (%d) in the existing %s table. This config is disabled.\n",
858 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
859 config_columns, existing_columns - 1, config->db_table);
860 return -1;
861 }
862 }
863
864 placeholders = make_stmt_placeholders(AST_VECTOR_SIZE(&config->fields));
865 if (!placeholders) {
866 return -1;
867 }
868
869 /* Inserting NULL in the ID column still generates an ID */
870 sql = sqlite3_mprintf("INSERT INTO %q VALUES (NULL,%s)", config->db_table, placeholders);
871 ast_free(placeholders);
872 if (!sql) {
873 return -1;
874 }
875
876 res = sqlite3_prepare_v3(config->db, sql, -1, SQLITE_PREPARE_PERSISTENT, &config->insert, NULL);
877 if (res != SQLITE_OK) {
878 ast_log(LOG_ERROR, "%s->%s: Unable to prepare INSERT statement '%s': %s\n",
879 cdrel_basename(config->config_filename), cdrel_basename(config->output_filename),
880 sql, sqlite3_errmsg(config->db));
881 return -1;
882 }
883
884 return 0;
885}
static char * make_stmt_placeholders(int columns)

References ast_debug, ast_free, ast_log, AST_VECTOR_SIZE, cdrel_basename(), config, LOG_ERROR, LOG_WARNING, make_stmt_placeholders(), and NULL.

Referenced by load_database_config().

◆ parse_field()

static struct field_parse_result parse_field ( enum cdrel_record_type  record_type,
char *  input_field_template 
)
static

Definition at line 95 of file res/cdrel_custom/config.c.

96{
97 char *tmp_field = NULL;
98 struct field_parse_result result = { 0, };
99
100 /*
101 * If the template starts with a double-quote, it's automatically
102 * a literal.
103 */
104 if (input_field_template[0] == '"') {
105 result.result = ast_strdup(ast_strip_quoted(ast_strdupa(input_field_template), "\"", "\""));
106 result.csv_quote = 1;
107 result.is_literal = 1;
108 return result;
109 }
110
111 /*
112 * If it starts with a single quote, it's probably a legacy SQL template
113 * so we need to force quote it on output.
114 */
115 tmp_field = ast_strip(ast_strdupa(input_field_template));
116
117 if (tmp_field[0] == '\'') {
118 result.csv_quote = 1;
119 }
120
121 /*
122 * I really hate the fact that ast_strip really trims whitespace
123 * and ast_strip_quoted will strip anything in pairs.
124 * Anyway, get rid of any remaining enclosing quotes.
125 */
126 tmp_field = ast_strip(ast_strip_quoted(tmp_field, "\"'", "\"'"));
127
128 /*
129 * If the template now starts with a '$' it's either a dialplan function
130 * call or one of the special CEL field names.
131 *
132 * Examples: ${CSV_QUOTE(${CALLERID(name)})}
133 * ${eventtime}
134 * We're going to iterate over function removal until there's just
135 * a plain text string left.
136 *
137 */
138 while (tmp_field[0] == '$') {
139 char *ptr = NULL;
140 /*
141 * A function name longer that 64 characters is highly unlikely but
142 * we'll check later.
143 */
144 char func_name[65];
145
146 /*
147 * Skip over the '$'
148 * {CSV_QUOTE(${CALLERID(name)})}
149 * {eventtime}
150 */
151 tmp_field++;
152 /*
153 * Remove any enclosing brace-like characters
154 * CSV_QUOTE(${CALLERID(name)})
155 * eventtime
156 */
157 tmp_field = ast_strip(ast_strip_quoted(tmp_field, "[{(", "]})"));
158
159 /*
160 * Check what's left to see if it matches a special variable.
161 * If it does (like "eventtime" in the example), we're done.
162 */
163 if (strstr(special_vars[record_type], tmp_field) != NULL) {
164 result.functions++;
165 break;
166 }
167
168 /*
169 * At this point, it has to be a function name so find the
170 * openening '('.
171 * CSV_QUOTE(${CALLERID(name)})
172 * ^
173 * If we don't find one, it's something we don't recognise
174 * so bail.
175 */
176 ptr = strchr(tmp_field, '(');
177 if (!ptr) {
178 result.parse_failed++;
179 continue;
180 }
181
182 /*
183 * Copy from the beginning to the '(' to func_name,
184 * not exceeding func_name's size.
185 *
186 * CSV_QUOTE(${CALLERID(name)})
187 * ^
188 * CSV_QUOTE
189 *
190 * Then check that it's a function we can handle.
191 * If not, bail.
192 */
193 ast_copy_string(func_name, tmp_field, MIN(sizeof(func_name), ptr - tmp_field + 1));
194 if (strstr(allowed_functions[record_type], func_name) == NULL) {
195 result.parse_failed++;
196 result.unknown_functions++;
197 continue;
198 }
199 result.functions++;
200 /*
201 * If the function is CSV_QUOTE, we need to set the csv_quote flag.
202 */
203 if (strcmp("CSV_QUOTE", func_name) == 0) {
204 result.csv_quote = 1;
205 } else if (strcmp("CDR", func_name) == 0) {
206 result.cdr = 1;
207 }
208
209 /*
210 * ptr still points to the opening '(' so now strip it and the
211 * matching parens.
212 *
213 * ${CALLERID(name)}
214 *
215 */
216 tmp_field = ast_strip_quoted(ptr, "(", ")");
217 if (tmp_field[0] == '"' || tmp_field[0] == '\'') {
218 result.result = ast_strdup(ast_strip_quoted(tmp_field, "\"'", "\"'"));
219 result.csv_quote = 1;
220 result.is_literal = 1;
221 return result;
222 }
223
224 /* Repeat the loop until there are no more functions or variables */
225 }
226
227 /*
228 * If the parse failed we'll send back the entire template.
229 */
230 if (result.parse_failed) {
231 tmp_field = input_field_template;
232 } else {
233 /*
234 * If there were no functions or variables parsed then we'll
235 * assume it's a literal.
236 */
237 if (result.functions == 0) {
238 result.is_literal = 1;
239 }
240 }
241
242 result.result = ast_strdup(tmp_field);
243 if (result.result == NULL) {
244 result.parse_failed = 1;
245 }
246
247 return result;
248}
static PGresult * result
Definition cel_pgsql.c:84
static const char * special_vars[]
static const char * allowed_functions[]
#define MIN(a, b)
Definition utils.h:252

References allowed_functions, ast_copy_string(), ast_strdup, ast_strdupa, ast_strip(), ast_strip_quoted(), MIN, NULL, result, field_parse_result::result, and special_vars.

Referenced by parse_legacy_template().

◆ parse_legacy_template()

static int parse_legacy_template ( enum cdrel_record_type  record_type,
const char *  config_filename,
const char *  output_filename,
const char *  input_template,
struct ast_vector_string fields 
)
static

Definition at line 265 of file res/cdrel_custom/config.c.

267{
268 char *template = ast_strdupa(input_template);
269 char *field_template = NULL;
270 int res = 0;
271
272 /*
273 * We have no choice but to assume that a legacy config template uses commas
274 * as field delimiters. We don't have a reliable way to determine this ourselves.
275 */
276 while((field_template = ast_strsep(&template, ',', AST_STRSEP_TRIM))) {
277 char *uservar = "";
278 char *literal = "";
279 /* Try to parse the field. */
280 struct field_parse_result result = parse_field(record_type, field_template);
281
282 ast_debug(2, "field: '%s' literal: %d quote: %d cdr: %d failed: %d funcs: %d unknfuncs: %d\n", result.result,
283 result.is_literal, result.csv_quote, result.cdr,
284 result.parse_failed, result.functions, result.unknown_functions);
285
286 /*
287 * If it failed,
288 */
289 if (!result.result || result.parse_failed) {
290 ast_free(result.result);
291 return 0;
292 }
293 if (result.is_literal) {
294 literal = "literal^";
295 }
296
297 if (!get_registered_field_by_name(record_type, result.result)) {
298 ast_debug(3, " %s->%s: field '%s' not found\n", cdrel_basename(config_filename),
299 cdrel_basename(output_filename), result.result);
300 /*
301 * If the result was found in a CDR function, treat it as a CDR user variable
302 * otherwise treat it as a literal.
303 */
304 if (result.cdr) {
305 uservar = "uservar^";
306 } else {
307 literal = "literal^";
308 }
309 }
310 res = ast_asprintf(&field_template, "%s(%s%s)", result.result, S_OR(literal,uservar), result.csv_quote ? "quote" : "noquote");
311 ast_free(result.result);
312
313 if (!field_template || res < 0) {
314 ast_free(field_template);
315 return 0;
316 }
317 res = AST_VECTOR_APPEND(fields, field_template);
318 if (res != 0) {
319 ast_free(field_template);
320 return 0;
321 }
322 ast_debug(2, " field template: %s\n", field_template);
323 }
324
325 return 1;
326}
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
static struct field_parse_result parse_field(enum cdrel_record_type record_type, char *input_field_template)

References ast_asprintf, ast_debug, ast_free, ast_strdupa, ast_strsep(), AST_STRSEP_TRIM, AST_VECTOR_APPEND, cdrel_basename(), config_filename, get_registered_field_by_name(), NULL, parse_field(), result, and S_OR.

Referenced by load_database_config(), and load_text_file_legacy_config().

◆ register_backend()

static int register_backend ( enum cdrel_record_type  record_type,
const char *  backend_name,
void *  log_cb 
)
static

Definition at line 1354 of file res/cdrel_custom/config.c.

1355{
1356 switch(record_type) {
1357 case cdrel_record_cdr:
1358 return ast_cdr_register(backend_name, "", log_cb);
1359 case cdrel_backend_db:
1360 return ast_cel_backend_register(backend_name, log_cb);
1361 default:
1362 return -1;
1363 }
1364}
int ast_cdr_register(const char *name, const char *desc, ast_cdrbe be)
Register a CDR handling engine.
Definition cdr.c:3076
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition cel.c:1836

References ast_cdr_register(), ast_cel_backend_register(), cdrel_backend_db, cdrel_record_cdr, and cdrel_config::record_type.

Referenced by cdrel_load_module().

◆ unregister_backend()

static int unregister_backend ( enum cdrel_record_type  record_type,
const char *  backend_name 
)
static

Definition at line 1366 of file res/cdrel_custom/config.c.

1367{
1368 switch(record_type) {
1369 case cdrel_record_cdr:
1370 return ast_cdr_unregister(backend_name);
1371 case cdrel_record_cel:
1372 return ast_cel_backend_unregister(backend_name);
1373 default:
1374 return -1;
1375 }
1376}
int ast_cdr_unregister(const char *name)
Unregister a CDR handling engine.
Definition cdr.c:3121
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition cel.c:1824
@ cdrel_record_cel

References ast_cdr_unregister(), ast_cel_backend_unregister(), cdrel_record_cdr, cdrel_record_cel, and cdrel_config::record_type.

Referenced by cdrel_unload_module().

Variable Documentation

◆ allowed_functions

const char* allowed_functions[]
static
Initial value:
= {
[cdrel_record_cdr] = "CSV_QUOTE CDR CALLERID CHANNEL",
[cdrel_record_cel] = "CSV_QUOTE CALLERID CHANNEL eventtype eventtime eventenum userdeftype eventextra BRIDGEPEER",
}

Definition at line 67 of file res/cdrel_custom/config.c.

67 {
68 [cdrel_record_cdr] = "CSV_QUOTE CDR CALLERID CHANNEL",
69 [cdrel_record_cel] = "CSV_QUOTE CALLERID CHANNEL eventtype eventtime eventenum userdeftype eventextra BRIDGEPEER",
70};

Referenced by parse_field().

◆ dirname_map

const char* dirname_map[cdrel_backend_type_end][cdrel_record_type_end]
static

Definition at line 41 of file res/cdrel_custom/config.c.

41 {
43 [cdrel_record_cdr] = "cdr-custom",
44 [cdrel_record_cel] = "cel-custom",
45 },
49 }
50};

Referenced by config_alloc().

◆ special_vars

const char* special_vars[]
static
Initial value:
= {
[cdrel_record_cel] = "eventtype eventtime eventenum userdeftype eventextra BRIDGEPEER",
}

Definition at line 72 of file res/cdrel_custom/config.c.

72 {
73 [cdrel_record_cdr] = "",
74 [cdrel_record_cel] = "eventtype eventtime eventenum userdeftype eventextra BRIDGEPEER",
75};

Referenced by parse_field().