diff --git a/Makefile.am b/Makefile.am index ce09e7e730..6c442ca24d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,6 +55,7 @@ src/switch_ivr.c \ src/switch_stun.c\ src/switch_log.c\ src/switch_xml.c\ +src/switch_config.c\ src/softtimer.c\ libs/stfu/stfu.c\ src/switch_cpp.cpp\ diff --git a/src/include/switch.h b/src/include/switch.h index 9014057520..2f86f7c12f 100644 --- a/src/include/switch.h +++ b/src/include/switch.h @@ -105,6 +105,7 @@ #include #include #include +#include #include /** \mainpage FreeSWITCH diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 13fc9dbdd9..94fa05005e 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -303,6 +303,7 @@ SWITCH_DECLARE(char *) switch_strip_spaces(const char *str); SWITCH_DECLARE(const char *) switch_stristr(const char *str, const char *instr); SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip); SWITCH_DECLARE(char *) switch_replace_char(char *str, char from, char to, switch_bool_t dup); +SWITCH_DECLARE(switch_bool_t) switch_ast2regex(char *pat, char *rbuf, size_t len); /*! \brief Escape a string by prefixing a list of characters with an escape character diff --git a/src/mod/dialplans/mod_dialplan_asterisk/Makefile b/src/mod/dialplans/mod_dialplan_asterisk/Makefile new file mode 100644 index 0000000000..c6d645e6aa --- /dev/null +++ b/src/mod/dialplans/mod_dialplan_asterisk/Makefile @@ -0,0 +1,2 @@ +BASE=../../../.. +include /usr/src/freeswitch.trunk/build/modmake.rules diff --git a/src/mod/dialplans/mod_dialplan_asterisk/mod_dialplan_asterisk.c b/src/mod/dialplans/mod_dialplan_asterisk/mod_dialplan_asterisk.c new file mode 100644 index 0000000000..35046cd112 --- /dev/null +++ b/src/mod/dialplans/mod_dialplan_asterisk/mod_dialplan_asterisk.c @@ -0,0 +1,189 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * mod_dialplan_asterisk.c -- Asterisk extensions.conf style dialplan parser. + * + */ +#include +#include +#include +#include + +SWITCH_MODULE_LOAD_FUNCTION(mod_dialplan_asterisk_load); +SWITCH_MODULE_DEFINITION(mod_dialplan_asterisk, mod_dialplan_asterisk_load, NULL, NULL); + +SWITCH_STANDARD_DIALPLAN(asterisk_dialplan_hunt) +{ + switch_caller_extension_t *extension = NULL; + switch_channel_t *channel; + char *cf = "extensions.conf"; + switch_config_t cfg; + char *var, *val; + const char *context = NULL; + + if (arg) { + cf = arg; + } + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if (!caller_profile) { + caller_profile = switch_channel_get_caller_profile(channel); + } + + if (caller_profile) { + context = caller_profile->context ? caller_profile->context : "default"; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Obtaining Profile!\n"); + return NULL; + } + + if (!switch_config_open_file(&cfg, cf)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return NULL; + } + + while (switch_config_next_pair(&cfg, &var, &val)) { + if (!strcasecmp(cfg.category, context)) { + if (!strcasecmp(var, "exten")) { + int argc; + char *argv[4] = { 0 }; + char *pattern = NULL; + char *pri = NULL; + char *app = NULL; + char *arg = NULL; + char expression[1024] = ""; + char substituted[2048] = ""; + char *field_data = caller_profile->destination_number; + int proceed = 0; + switch_regex_t *re = NULL; + int ovector[30] = {0}; + + + switch_replace_char(val, '|',',', SWITCH_FALSE); + argc = switch_separate_string(val, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + if (argc < 3) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "parse error line %d!\n", cfg.lineno); + continue; + } + + pattern = argv[0]; + + if (*pattern == '_') { + pattern++; + if (switch_ast2regex(pattern, expression, sizeof(expression))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "converting [%s] to real regex [%s] you should try them!\n", + pattern, expression); + } + if (!(proceed = switch_regex_perform(field_data, expression, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) { + switch_regex_safe_free(re); + continue; + } + + } else { + if (strcasecmp(pattern, caller_profile->destination_number)) { + continue; + } + } + + switch_channel_set_variable(channel, "EXTEN", caller_profile->destination_number); + switch_channel_set_variable(channel, "CHANNEL", switch_channel_get_name(channel)); + switch_channel_set_variable(channel, "UNIQUEID", switch_core_session_get_uuid(session)); + + pri = argv[1]; + app = argv[2]; + + if (argc == 4) { + arg = argv[3]; + } else { + if ((arg = strchr(app, '('))) { + *arg++ = '\0'; + char *p = strrchr(arg, ')'); + if (p) { + *p = '\0'; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "parse error line %d!\n", cfg.lineno); + continue; + } + } + + if (strchr(expression, '(')) { + switch_perform_substitution(re, proceed, arg, field_data, substituted, sizeof(substituted), ovector); + arg = substituted; + } + switch_regex_safe_free(re); + + if (!extension) { + if ((extension = switch_caller_extension_new(session, caller_profile->destination_number, + caller_profile->destination_number)) == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "memory error!\n"); + break; + } + } + + switch_caller_extension_add_application(session, extension, app, arg); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "param '%s' not implemented at line %d!\n", var, cfg.lineno); + } + } + } + + switch_config_close_file(&cfg); + + if (extension) { + switch_channel_set_state(channel, CS_EXECUTE); + } + + return extension; +} + + +SWITCH_MODULE_LOAD_FUNCTION(mod_dialplan_asterisk_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); + SWITCH_ADD_DIALPLAN(dp_interface, "asterisk", asterisk_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 expandtab: + */ diff --git a/src/mod/dialplans/mod_dialplan_asterisk/mod_dialplan_asterisk.vcproj b/src/mod/dialplans/mod_dialplan_asterisk/mod_dialplan_asterisk.vcproj new file mode 100644 index 0000000000..bd5e142c1f --- /dev/null +++ b/src/mod/dialplans/mod_dialplan_asterisk/mod_dialplan_asterisk.vcproj @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/switch_channel.c b/src/switch_channel.c index 5b982fdcd5..fde8d9bdf0 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -1269,6 +1269,7 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel char *data, *indup; size_t sp = 0, len = 0, olen = 0, vtype = 0, br = 0, cpos, block = 128; const char *sub_val = NULL; + char *cloned_sub_val = NULL; char *func_val = NULL; int nv = 0; @@ -1393,13 +1394,43 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel if (vtype == 1) { char *expanded = NULL; - + int offset = 0; + int ooffset = 0; + char *p; + if ((expanded = switch_channel_expand_variables(channel, (char *)vname)) == vname) { expanded = NULL; } else { vname = expanded; } + if ((p = strchr(vname, ':'))) { + *p++ = '\0'; + offset = atoi(p); + if ((p = strchr(p, ':'))) { + p++; + ooffset = atoi(p); + } + } + sub_val = switch_channel_get_variable(channel, vname); + if (offset || ooffset) { + cloned_sub_val = strdup(sub_val); + assert(cloned_sub_val); + sub_val = cloned_sub_val; + } + + if (offset >= 0) { + sub_val += offset; + } else if (abs(offset) <= strlen(sub_val)) { + sub_val = cloned_sub_val + (strlen(cloned_sub_val) + offset); + } + + if (ooffset > 0 && ooffset < strlen(sub_val)) { + if ((p = (char *)sub_val + ooffset)) { + *p = '\0'; + } + } + switch_safe_free(expanded); } else { switch_stream_handle_t stream = { 0 }; @@ -1450,9 +1481,11 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel } switch_safe_free(func_val); + switch_safe_free(cloned_sub_val); sub_val = NULL; vname = NULL; vtype = 0; + br = 0; } if (len + 1 >= olen) { resize(1); diff --git a/src/switch_utils.c b/src/switch_utils.c index 91c2e7db2a..258baa1878 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -222,6 +222,28 @@ SWITCH_DECLARE(switch_bool_t) switch_is_lan_addr(const char *ip) } +SWITCH_DECLARE(switch_bool_t) switch_ast2regex(char *pat, char *rbuf, size_t len) +{ + char *p = pat; + memset(rbuf, 0, len); + + while(p && *p) { + if (*p == 'N') { + strncat(rbuf, "[2-9]", len - strlen(rbuf)); + } else if (*p == 'X') { + strncat(rbuf, "[0-9]", len - strlen(rbuf)); + } else if (*p == 'Z') { + strncat(rbuf, "[1-9]", len - strlen(rbuf)); + } else if (*p == '.') { + strncat(rbuf, ".*", len - strlen(rbuf)); + } else if (strlen(rbuf) < len - 1) { + *(rbuf + strlen(rbuf)) = *p; + } + p++; + } + + return strcmp(pat,rbuf) ? SWITCH_TRUE : SWITCH_FALSE; +} SWITCH_DECLARE(char *) switch_replace_char(char *str, char from, char to, switch_bool_t dup) {