+++ /dev/null
-/*
- * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
- *
- * Version: MPL 1.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- *
- * The Initial Developer of the Original Code is
- * Anthony Minessale II <anthm@freeswitch.org>
- * Portions created by the Initial Developer are Copyright (C)
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Anthony Minessale II <anthm@freeswitch.org>
-
- *
- * mod_yaml.c -- YAML Module
- *
- */
-#include <switch.h>
-#include <yaml.h>
-
-SWITCH_MODULE_LOAD_FUNCTION(mod_yaml_load);
-SWITCH_MODULE_DEFINITION(mod_yaml, mod_yaml_load, NULL, NULL);
-
-static void print_error(yaml_parser_t *parser)
-{
- switch (parser->error) {
- case YAML_MEMORY_ERROR:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory error: Not enough memory for parsing\n");
- break;
-
- case YAML_READER_ERROR:
- if (parser->problem_value != -1) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reader error: %s: #%X at %d\n", parser->problem,
- parser->problem_value, (int) parser->problem_offset);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Reader error: %s at %d\n", parser->problem, (int) parser->problem_offset);
- }
- break;
-
- case YAML_SCANNER_ERROR:
- if (parser->context) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scanner error: %s at line %d, column %d\n"
- "%s at line %d, column %d\n", parser->context,
- (int) parser->context_mark.line + 1, (int) parser->context_mark.column + 1,
- parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Scanner error: %s at line %d, column %d\n",
- parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
- }
- break;
-
- case YAML_PARSER_ERROR:
- if (parser->context) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parser error: %s at line %d, column %d\n"
- "%s at line %d, column %d\n", parser->context,
- (int) parser->context_mark.line + 1, (int) parser->context_mark.column + 1,
- parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parser error: %s at line %d, column %d\n",
- parser->problem, (int) parser->problem_mark.line + 1, (int) parser->problem_mark.column + 1);
- }
- break;
-
- default:
- /* Couldn't happen. */
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Internal error\n");
- break;
- }
-}
-
-
-static switch_xml_t parse_file(FILE * input, const char *file_name)
-{
- yaml_parser_t parser;
- yaml_event_t event = { 0 };
- char *scalar_data;
- int done = 0;
- int depth = 0;
- char name[128] = "";
- char value[128] = "";
- char category[128] = "";
- int nv = 0, p_off = 0;
- switch_xml_t xml, param, top, current = NULL;
-
- yaml_parser_initialize(&parser);
- yaml_parser_set_input_file(&parser, input);
-
-
- if (!(xml = switch_xml_new("document"))) {
- return NULL;
- }
-
- switch_xml_set_attr_d(xml, "type", "freeswitch/xml");
- current = switch_xml_add_child_d(xml, "section", 0);
- switch_xml_set_attr_d(current, "name", "configuration");
-
- top = switch_xml_add_child_d(current, "configuration", 0);
- switch_xml_set_attr_d(top, "name", file_name);
-
- while (!done) {
- if (!yaml_parser_parse(&parser, &event)) {
- print_error(&parser);
- break;
- } else {
- switch (event.type) {
- case YAML_MAPPING_START_EVENT:
- depth++;
- break;
- case YAML_MAPPING_END_EVENT:
- depth--;
- break;
- case YAML_STREAM_END_EVENT:
- done = 1;
- break;
- case YAML_SCALAR_EVENT:
- scalar_data = (char *) event.data.scalar.value;
- switch (depth) {
- case 1:
- if (!(current = switch_xml_add_child_d(top, scalar_data, depth - 1))) {
- done = 1;
- }
- switch_set_string(category, scalar_data);
- nv = 0;
- p_off = 0;
- break;
- case 2:
- if (current) {
- if (nv == 0) {
- switch_set_string(name, scalar_data);
- nv++;
- } else {
- switch_set_string(value, scalar_data);
- param = switch_xml_add_child_d(current, "param", p_off++);
- switch_xml_set_attr_d_buf(param, "name", name);
- switch_xml_set_attr_d(param, "value", scalar_data);
- nv = 0;
- }
- }
- break;
- }
-
- break;
- default:
- break;
- }
- }
-
- yaml_event_delete(&event);
- }
-
- yaml_parser_delete(&parser);
-
- if (input) {
- fclose(input);
- }
-#ifdef DEBUG_XML
- if (xml) {
- char *foo = switch_xml_toxml(xml, SWITCH_FALSE);
- printf("%s\n", foo);
- free(foo);
- }
-#endif
-
- return xml;
-
-}
-
-static switch_xml_t yaml_fetch(const char *section,
- const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params, void *user_data)
-{
- char *path;
- FILE *input;
- switch_xml_t xml = NULL;
-
- path = switch_mprintf("%s/yaml/%s.yaml", SWITCH_GLOBAL_dirs.conf_dir, key_value);
- if ((input = fopen(path, "r"))) {
- xml = parse_file(input, key_value);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "cannot open %s\n", path);
- }
-
- switch_safe_free(path);
- return xml;
-}
-
-
-static switch_caller_extension_t *parse_dp(FILE * input, switch_core_session_t *session, switch_caller_profile_t *caller_profile)
-{
- yaml_parser_t parser;
- yaml_event_t event = { 0 };
- char *scalar_data;
- int done = 0;
- int depth = 0;
- char name[128] = "";
- char value[128] = "";
- char category[128] = "";
- char *last_field = NULL;
- int nv = 0;
- switch_caller_extension_t *extension = NULL;
- switch_channel_t *channel = switch_core_session_get_channel(session);
- int context_hit = 0;
- int proceed = 0;
- switch_regex_t *re = NULL;
- int ovector[30];
- int parens = 0;
-
- if (!caller_profile) {
- if (!(caller_profile = switch_channel_get_caller_profile(channel))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Obtaining Profile!\n");
- return NULL;
- }
- }
-
- if (!caller_profile->context) {
- caller_profile->context = "default";
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Processing %s->%s@%s\n",
- caller_profile->caller_id_name, caller_profile->destination_number, caller_profile->context);
-
- yaml_parser_initialize(&parser);
- yaml_parser_set_input_file(&parser, input);
-
- while (!done) {
- if (!yaml_parser_parse(&parser, &event)) {
- print_error(&parser);
- break;
- } else {
- switch (event.type) {
- case YAML_MAPPING_START_EVENT:
- depth++;
- break;
- case YAML_MAPPING_END_EVENT:
- depth--;
- break;
- case YAML_STREAM_END_EVENT:
- done = 1;
- break;
- case YAML_SCALAR_EVENT:
- scalar_data = (char *) event.data.scalar.value;
- switch (depth) {
- case 1:
- switch_set_string(category, scalar_data);
- context_hit = (!strcasecmp(category, caller_profile->context));
- nv = 0;
- break;
- case 2:
- if (context_hit) {
- char *field = switch_core_session_strdup(session, scalar_data);
- char *p, *e, *expression = NULL, *field_expanded = NULL, *expression_expanded = NULL;
- const char *field_data = NULL;
-
- parens = 0;
- proceed = 0;
- switch_regex_safe_free(re);
-
- if ((p = strstr(field, "=~"))) {
- *p = '\0';
- e = p - 1;
- while (*e == ' ') {
- *e-- = '\0';
- }
- e = p + 2;
- while (*e == ' ') {
- *e++ = '\0';
- }
- expression = e;
- }
-
- if (field && expression) {
- if ((expression_expanded = switch_channel_expand_variables(channel, expression)) == expression) {
- expression_expanded = NULL;
- } else {
- expression = expression_expanded;
- }
-
- if (strchr(field, '$')) {
- if ((field_expanded = switch_channel_expand_variables(channel, field)) == field) {
- field_expanded = NULL;
- field_data = field;
- } else {
- field_data = field_expanded;
- }
- } else {
- field_data = switch_caller_get_field_by_name(caller_profile, field);
- }
- if (!field_data) {
- field_data = "";
- }
- switch_safe_free(last_field);
- last_field = strdup(field_data);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "test conditions %s(%s) =~ /%s/\n", field, field_data, expression);
- if (!(proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Regex mismatch\n");
- }
-
- if (strchr(expression, '(')) {
- parens++;
- }
-
- switch_safe_free(field_expanded);
- switch_safe_free(expression_expanded);
- }
- }
- break;
- case 3:
- if (nv == 0) {
- if (!strcasecmp(scalar_data, "exit")) {
- yaml_event_delete(&event);
- goto end;
- }
- switch_set_string(name, scalar_data);
- nv++;
- } else {
- switch_set_string(value, scalar_data);
- nv = 0;
- if (proceed) {
- uint32_t len = 0;
- char *substituted = NULL;
- char *app_data;
-
-
- if (!extension) {
- extension = switch_caller_extension_new(session, "YAML", caller_profile->destination_number);
- switch_assert(extension);
- }
-
- if (parens) {
- len = (uint32_t) (strlen(value) + strlen(last_field) + 10) * proceed;
- switch_zmalloc(substituted, len);
- switch_perform_substitution(re, proceed, value, last_field, substituted, len, ovector);
- app_data = substituted;
- } else {
- app_data = value;
- }
-
- switch_caller_extension_add_application(session, extension, name, app_data);
- switch_safe_free(substituted);
- }
- }
- break;
- }
-
- break;
- default:
- break;
- }
- }
-
- yaml_event_delete(&event);
- }
-
- end:
-
- switch_safe_free(last_field);
- switch_regex_safe_free(re);
- yaml_parser_delete(&parser);
-
- if (input) {
- fclose(input);
- }
-#ifdef DEBUG_XML
- if (xml) {
- char *foo = switch_xml_toxml(xml, SWITCH_FALSE);
- printf("%s\n", foo);
- free(foo);
- }
-#endif
-
- return extension;
-
-}
-
-SWITCH_STANDARD_DIALPLAN(yaml_dialplan_hunt)
-{
- switch_caller_extension_t *extension = NULL;
- char *alt_path = (char *) arg;
- char *path = NULL;
- FILE *input;
-
- if (!zstr(alt_path)) {
- path = strdup(alt_path);
- } else {
- path = switch_mprintf("%s/yaml/extensions.yaml", SWITCH_GLOBAL_dirs.conf_dir);
- }
-
- if ((input = fopen(path, "r"))) {
- extension = parse_dp(input, session, caller_profile);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
- }
-
- switch_safe_free(path);
- return extension;
-}
-
-
-static switch_status_t do_config(void)
-{
- yaml_parser_t parser;
- yaml_event_t event = { 0 };
- char *path;
- const char *cfg = "mod_yaml.yaml";
- FILE *input;
- switch_status_t status = SWITCH_STATUS_FALSE;
- char *scalar_data;
- int done = 0;
- int depth = 0;
- char name[128] = "";
- char value[128] = "";
- char category[128] = "";
- int nv = 0;
-
- path = switch_mprintf("%s/yaml/%s", SWITCH_GLOBAL_dirs.conf_dir, cfg);
-
- if (!(input = fopen(path, "r"))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
- goto end;
- }
-
- yaml_parser_initialize(&parser);
- yaml_parser_set_input_file(&parser, input);
-
- while (!done) {
- if (!yaml_parser_parse(&parser, &event)) {
- print_error(&parser);
- break;
- } else {
- switch (event.type) {
- case YAML_MAPPING_START_EVENT:
- depth++;
- break;
- case YAML_MAPPING_END_EVENT:
- depth--;
- break;
- case YAML_STREAM_END_EVENT:
- done = 1;
- break;
- case YAML_SCALAR_EVENT:
- scalar_data = (char *) event.data.scalar.value;
- switch (depth) {
- case 1:
- switch_set_string(category, scalar_data);
- nv = 0;
- break;
- case 2:
- if (nv == 0) {
- switch_set_string(name, scalar_data);
- nv++;
- } else {
- switch_set_string(value, scalar_data);
- if (!strcasecmp(category, "settings")) {
- if (!strcasecmp(name, "bind_config") && switch_true_buf(value)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Binding To XML Config\n");
- switch_xml_bind_search_function(yaml_fetch, switch_xml_parse_section_string("config"), NULL);
- }
- }
- nv = 0;
- }
- break;
- }
-
- break;
- default:
- break;
- }
- }
-
- yaml_event_delete(&event);
- }
-
- yaml_parser_delete(&parser);
- status = SWITCH_STATUS_SUCCESS;
-
- end:
-
- if (input) {
- fclose(input);
- }
-
- switch_safe_free(path);
-
- return status;
-
-}
-
-SWITCH_MODULE_LOAD_FUNCTION(mod_yaml_load)
-{
- switch_dialplan_interface_t *dp_interface;
-
- /* connect my internal structure to the blank pointer passed to me */
- *module_interface = switch_loadable_module_create_module_interface(pool, modname);
-
- if (do_config() != SWITCH_STATUS_SUCCESS) {
- return SWITCH_STATUS_TERM;
- }
-
- SWITCH_ADD_DIALPLAN(dp_interface, "YAML", yaml_dialplan_hunt);
-
- /* indicate that the module should continue to be loaded */
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-/* For Emacs:
- * Local Variables:
- * mode:c
- * indent-tabs-mode:t
- * tab-width:4
- * c-basic-offset:4
- * End:
- * For VIM:
- * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
- */