2009-01-14 02:18:51 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2010-02-06 03:38:24 +00:00
* Copyright ( C ) 2005 - 2010 , Anthony Minessale II < anthm @ freeswitch . org >
2009-01-14 02:18:51 +00:00
*
* 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
2009-02-04 21:20:54 +00:00
* Anthony Minessale II < anthm @ freeswitch . org >
2009-01-14 02:18:51 +00:00
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Raymond Chandler < intralanman @ gmail . com >
* Rupa Schomaker < rupa @ rupa . com >
*
* mod_lcr . c - - Least Cost Routing Module
*
*/
# include <switch.h>
2009-07-21 18:49:02 +00:00
# define LCR_SYNTAX "lcr <digits> [<lcr profile>] [caller_id] [intrastate] [as xml]"
2009-02-11 05:07:37 +00:00
# define LCR_ADMIN_SYNTAX "lcr_admin show profiles"
2009-01-14 02:18:51 +00:00
2010-06-19 20:08:06 -05:00
# define LCR_HEADERS_COUNT 7
2009-03-27 20:01:54 +00:00
# define LCR_HEADERS_DIGITS 0
# define LCR_HEADERS_CARRIER 1
# define LCR_HEADERS_RATE 2
# define LCR_HEADERS_DIALSTRING 3
# define LCR_HEADERS_CODEC 4
# define LCR_HEADERS_CID 5
2010-06-19 20:08:06 -05:00
# define LCR_HEADERS_LIMIT 6
2009-03-27 20:01:54 +00:00
2009-04-09 20:58:34 +00:00
static char headers [ LCR_HEADERS_COUNT ] [ 32 ] = {
2009-01-14 02:18:51 +00:00
" Digit Match " ,
" Carrier " ,
" Rate " ,
" Dialstring " ,
2009-03-27 20:01:54 +00:00
" Codec " ,
2010-06-19 20:08:06 -05:00
" CID Regexp " ,
" Limit " ,
2009-01-14 02:18:51 +00:00
} ;
/* sql for random function */
2009-04-09 20:58:34 +00:00
static char * db_random = NULL ;
2009-01-14 02:18:51 +00:00
struct lcr_obj {
char * carrier_name ;
char * gw_prefix ;
char * gw_suffix ;
char * digit_str ;
char * prefix ;
char * suffix ;
char * dialstring ;
float rate ;
char * rate_str ;
2009-09-30 14:52:19 +00:00
float user_rate ;
char * user_rate_str ;
2009-01-14 02:18:51 +00:00
size_t lstrip ;
size_t tstrip ;
size_t digit_len ;
2009-03-20 20:15:39 +00:00
char * codec ;
2009-03-27 20:01:54 +00:00
char * cid ;
2010-06-19 20:08:06 -05:00
char * limit_realm ;
char * limit_id ;
int limit_max ;
switch_event_t * fields ;
2009-02-11 21:33:22 +00:00
struct lcr_obj * prev ;
2009-01-14 02:18:51 +00:00
struct lcr_obj * next ;
} ;
struct max_obj {
size_t carrier_name ;
size_t digit_str ;
size_t rate ;
2009-03-27 20:01:54 +00:00
size_t codec ;
size_t cid ;
2009-01-14 02:18:51 +00:00
size_t dialstring ;
2010-06-19 20:08:06 -05:00
size_t limit ;
2009-01-14 02:18:51 +00:00
} ;
typedef struct lcr_obj lcr_obj_t ;
typedef lcr_obj_t * lcr_route ;
typedef struct max_obj max_obj_t ;
typedef max_obj_t * max_len ;
struct profile_obj {
char * name ;
uint16_t id ;
char * order_by ;
2009-02-11 00:18:50 +00:00
char * custom_sql ;
2010-06-19 20:08:06 -05:00
char * export_fields_str ;
int export_fields_cnt ;
char * * export_fields ;
char * limit_type ;
2009-02-20 20:36:04 +00:00
switch_bool_t custom_sql_has_percent ;
switch_bool_t custom_sql_has_vars ;
2009-07-16 15:38:16 +00:00
switch_bool_t profile_has_intrastate ;
switch_bool_t profile_has_intralata ;
switch_bool_t profile_has_npanxx ;
2010-06-19 20:08:06 -05:00
2009-02-11 21:33:22 +00:00
switch_bool_t reorder_by_rate ;
2009-03-16 15:54:44 +00:00
switch_bool_t quote_in_list ;
2009-06-02 16:38:29 +00:00
switch_bool_t info_in_headers ;
2010-06-19 08:08:42 -05:00
switch_bool_t enable_sip_redir ;
2009-01-14 02:18:51 +00:00
} ;
typedef struct profile_obj profile_t ;
struct callback_obj {
lcr_route head ;
2009-02-12 01:18:43 +00:00
switch_hash_t * dedup_hash ;
2009-01-14 02:18:51 +00:00
int matches ;
2009-02-03 21:20:09 +00:00
switch_memory_pool_t * pool ;
2009-01-14 02:18:51 +00:00
char * lookup_number ;
2009-03-27 20:01:54 +00:00
char * cid ;
2009-06-19 14:46:51 +00:00
switch_bool_t intrastate ;
2009-07-16 15:38:16 +00:00
switch_bool_t intralata ;
2009-02-11 21:33:22 +00:00
profile_t * profile ;
2009-02-20 20:36:04 +00:00
switch_core_session_t * session ;
2009-03-20 20:15:39 +00:00
switch_event_t * event ;
2009-01-14 02:18:51 +00:00
} ;
typedef struct callback_obj callback_t ;
static struct {
switch_memory_pool_t * pool ;
char * dbname ;
char * odbc_dsn ;
2009-11-26 05:38:43 +00:00
char * odbc_user ;
char * odbc_pass ;
2009-01-14 02:18:51 +00:00
switch_mutex_t * mutex ;
switch_hash_t * profile_hash ;
profile_t * default_profile ;
void * filler1 ;
} globals ;
SWITCH_MODULE_LOAD_FUNCTION ( mod_lcr_load ) ;
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_lcr_shutdown ) ;
SWITCH_MODULE_DEFINITION ( mod_lcr , mod_lcr_load , mod_lcr_shutdown , NULL ) ;
2009-07-17 22:41:40 +00:00
static const char * do_cid ( switch_memory_pool_t * pool , const char * cid , const char * number , switch_core_session_t * session )
2009-03-27 20:01:54 +00:00
{
switch_regex_t * re = NULL ;
int proceed = 0 , ovector [ 30 ] ;
char * substituted = NULL ;
uint32_t len = 0 ;
char * src = NULL ;
char * dst = NULL ;
2009-07-17 22:41:40 +00:00
char * tmp_regex = NULL ;
char * src_regex = NULL ;
char * dst_regex = NULL ;
switch_channel_t * channel = NULL ;
2010-06-19 20:08:06 -05:00
2009-10-23 16:03:42 +00:00
if ( ! zstr ( cid ) ) {
2009-03-27 20:01:54 +00:00
len = strlen ( cid ) ;
} else {
goto done ;
}
2010-06-19 20:08:06 -05:00
2009-03-27 20:01:54 +00:00
src = switch_core_strdup ( pool , cid ) ;
/* check that this is a valid regexp and split the string */
2010-06-19 20:08:06 -05:00
if ( ( src [ 0 ] = = ' / ' ) & & src [ len - 1 ] = = ' / ' ) {
2009-03-27 20:01:54 +00:00
/* strip leading / trailing slashes */
2010-06-19 20:08:06 -05:00
src [ len - 1 ] = ' \0 ' ;
2009-03-27 20:01:54 +00:00
src + + ;
2010-06-19 20:08:06 -05:00
2009-03-27 20:01:54 +00:00
/* break on first / */
dst = strchr ( src , ' / ' ) ;
* dst = ' \0 ' ;
dst + + ;
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " src: %s, dst: %s \n " , src , dst ) ;
2009-03-27 20:01:54 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Not a valid regexp: %s \n " , src ) ;
2009-03-27 20:01:54 +00:00
goto done ;
}
2009-07-17 22:41:40 +00:00
/* if a session is provided, check if the source part of the regex has any channel variables, then expand them */
2009-12-11 01:20:26 +00:00
if ( session ) {
2009-07-17 22:41:40 +00:00
channel = switch_core_session_get_channel ( session ) ;
switch_assert ( channel ) ;
2009-12-11 01:20:26 +00:00
if ( switch_string_var_check_const ( src ) | | switch_string_has_escaped_data ( src ) ) {
2009-07-17 22:41:40 +00:00
tmp_regex = switch_channel_expand_variables ( channel , src ) ;
src_regex = switch_core_strdup ( pool , tmp_regex ) ;
switch_safe_free ( tmp_regex ) ;
src = src_regex ;
}
2009-12-11 01:20:26 +00:00
if ( switch_string_var_check_const ( dst ) | | switch_string_has_escaped_data ( dst ) ) {
2009-07-17 22:41:40 +00:00
tmp_regex = switch_channel_expand_variables ( channel , dst ) ;
dst_regex = switch_core_strdup ( pool , tmp_regex ) ;
switch_safe_free ( tmp_regex ) ;
dst = dst_regex ;
}
2010-06-19 20:08:06 -05:00
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " expanded src: %s, dst: %s \n " , src , dst ) ;
2009-07-17 22:41:40 +00:00
}
2010-06-19 20:08:06 -05:00
2009-03-27 20:01:54 +00:00
if ( ( proceed = switch_regex_perform ( number , src , & re , ovector , sizeof ( ovector ) / sizeof ( ovector [ 0 ] ) ) ) ) {
2010-06-19 20:08:06 -05:00
len = ( uint32_t ) ( strlen ( src ) + strlen ( dst ) + 10 ) * proceed ; /* guestimate size */
2009-03-27 20:01:54 +00:00
if ( ! ( substituted = switch_core_alloc ( pool , len ) ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Memory Error! \n " ) ;
2009-03-27 20:01:54 +00:00
goto done ;
}
memset ( substituted , 0 , len ) ;
switch_perform_substitution ( re , proceed , dst , number , substituted , len , ovector ) ;
} else {
goto done ;
}
switch_regex_safe_free ( re ) ;
2010-06-19 20:08:06 -05:00
2009-03-27 20:01:54 +00:00
return substituted ;
2010-06-19 20:08:06 -05:00
done :
2009-03-27 20:01:54 +00:00
switch_regex_safe_free ( re ) ;
return number ;
}
2010-06-19 20:08:06 -05:00
static char * get_bridge_data ( switch_memory_pool_t * pool , char * dialed_number , char * caller_id , lcr_route cur_route , profile_t * profile , switch_core_session_t * session )
2009-01-15 21:51:15 +00:00
{
2009-01-14 02:18:51 +00:00
size_t lstrip ;
2010-06-19 20:08:06 -05:00
size_t tstrip ;
2009-01-14 02:18:51 +00:00
char * data = NULL ;
char * destination_number = NULL ;
2010-06-19 20:08:06 -05:00
char * orig_destination_number = NULL ;
2009-03-20 20:15:39 +00:00
char * codec = NULL ;
2009-03-27 20:01:54 +00:00
char * cid = NULL ;
2009-06-02 16:38:29 +00:00
char * header = NULL ;
2009-09-30 14:52:19 +00:00
char * user_rate = NULL ;
2010-06-19 20:08:06 -05:00
char * export_fields = NULL ;
2009-01-14 02:18:51 +00:00
2009-02-03 21:20:09 +00:00
orig_destination_number = destination_number = switch_core_strdup ( pool , dialed_number ) ;
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
tstrip = ( ( cur_route - > digit_len - cur_route - > tstrip ) + 1 ) ;
lstrip = cur_route - > lstrip ;
2010-06-19 20:08:06 -05:00
2009-05-15 20:03:17 +00:00
if ( cur_route - > tstrip > 0 ) {
if ( strlen ( destination_number ) > tstrip ) {
destination_number [ tstrip ] = ' \0 ' ;
2010-02-06 03:38:24 +00:00
}
2010-06-19 20:08:06 -05:00
else {
destination_number [ 0 ] = ' \0 ' ;
}
}
2009-05-15 20:03:17 +00:00
if ( cur_route - > lstrip > 0 ) {
if ( strlen ( destination_number ) > lstrip ) {
destination_number + = lstrip ;
2010-06-19 20:08:06 -05:00
}
else {
2009-05-15 20:03:17 +00:00
destination_number [ 0 ] = ' \0 ' ;
}
2010-06-19 20:08:06 -05:00
}
2009-03-20 20:15:39 +00:00
codec = " " ;
2009-10-23 16:03:42 +00:00
if ( ! zstr ( cur_route - > codec ) ) {
2009-03-20 20:15:39 +00:00
codec = switch_core_sprintf ( pool , " ,absolute_codec_string=%s " , cur_route - > codec ) ;
}
2010-06-19 20:08:06 -05:00
2009-03-27 20:01:54 +00:00
cid = " " ;
2009-10-23 16:03:42 +00:00
if ( ! zstr ( cur_route - > cid ) ) {
2010-06-19 20:08:06 -05:00
cid = switch_core_sprintf ( pool , " ,origination_caller_id_number=%s " ,
do_cid ( pool , cur_route - > cid , caller_id , session ) ) ;
2009-03-27 20:01:54 +00:00
}
2010-06-19 20:08:06 -05:00
2009-06-02 16:38:29 +00:00
header = " " ;
if ( profile - > info_in_headers ) {
2010-06-19 20:08:06 -05:00
header = switch_core_sprintf ( pool , " ,sip_h_X-LCR-INFO=lcr_rate=%s;lcr_carrier=%s " ,
cur_route - > rate_str ,
cur_route - > carrier_name ) ;
2009-06-02 16:38:29 +00:00
}
2010-06-19 20:08:06 -05:00
2009-10-23 16:03:42 +00:00
if ( zstr ( cur_route - > user_rate_str ) ) {
2009-09-30 14:52:19 +00:00
user_rate = " " ;
} else {
user_rate = switch_core_sprintf ( pool , " ,lcr_user_rate=%s " , cur_route - > user_rate_str ) ;
}
2010-06-19 20:08:06 -05:00
export_fields = " " ;
if ( profile - > export_fields_cnt > 0 ) {
int i = 0 ;
char * val = NULL ;
for ( i = 0 ; i < profile - > export_fields_cnt ; i + + ) {
val = switch_event_get_header ( cur_route - > fields , profile - > export_fields [ i ] ) ;
if ( val ) {
export_fields = switch_core_sprintf ( pool , " %s,%s=%s " ,
export_fields ,
profile - > export_fields [ i ] ,
val ) ;
}
}
}
2010-06-19 08:08:42 -05:00
if ( profile - > enable_sip_redir ) {
2010-06-19 20:08:06 -05:00
data = switch_core_sprintf ( pool , " %s%s%s%s%s "
, cur_route - > gw_prefix , cur_route - > prefix
, destination_number , cur_route - > suffix , cur_route - > gw_suffix ) ;
2010-06-19 08:08:42 -05:00
} else {
2010-06-19 20:08:06 -05:00
data = switch_core_sprintf ( pool , " [lcr_carrier=%s,lcr_rate=%s%s%s%s%s%s]%s%s%s%s%s "
, cur_route - > carrier_name , cur_route - > rate_str
, user_rate , codec , cid , header , export_fields
, cur_route - > gw_prefix , cur_route - > prefix
, destination_number , cur_route - > suffix , cur_route - > gw_suffix ) ;
}
if ( session & & ( switch_string_var_check_const ( data ) | | switch_string_has_escaped_data ( data ) ) ) {
data = switch_channel_expand_variables ( switch_core_session_get_channel ( session ) , data ) ;
2010-06-19 08:08:42 -05:00
}
if ( session & & ( switch_string_var_check_const ( data ) | | switch_string_has_escaped_data ( data ) ) ) {
data = switch_channel_expand_variables ( switch_core_session_get_channel ( session ) , data ) ;
}
2010-04-10 13:22:13 -05:00
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Returning Dialstring %s \n " , data ) ;
2009-01-14 02:18:51 +00:00
return data ;
}
2009-04-09 20:58:34 +00:00
static profile_t * locate_profile ( const char * profile_name )
2009-02-11 21:33:22 +00:00
{
profile_t * profile = NULL ;
2010-06-19 20:08:06 -05:00
2009-10-23 16:03:42 +00:00
if ( zstr ( profile_name ) ) {
2009-02-11 21:33:22 +00:00
profile = globals . default_profile ;
} else if ( ! ( profile = switch_core_hash_find ( globals . profile_hash , profile_name ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error invalid profile %s \n " , profile_name ) ;
}
2010-06-19 20:08:06 -05:00
2009-02-11 21:33:22 +00:00
return profile ;
}
2009-04-09 20:58:34 +00:00
static void init_max_lens ( max_len maxes )
2009-01-15 21:51:15 +00:00
{
2009-03-27 20:01:54 +00:00
maxes - > digit_str = ( headers [ LCR_HEADERS_DIGITS ] = = NULL ? 0 : strlen ( headers [ LCR_HEADERS_DIGITS ] ) ) ;
maxes - > carrier_name = ( headers [ LCR_HEADERS_CARRIER ] = = NULL ? 0 : strlen ( headers [ LCR_HEADERS_CARRIER ] ) ) ;
maxes - > dialstring = ( headers [ LCR_HEADERS_DIALSTRING ] = = NULL ? 0 : strlen ( headers [ LCR_HEADERS_DIALSTRING ] ) ) ;
2009-01-14 02:18:51 +00:00
maxes - > rate = 8 ;
2009-03-27 20:01:54 +00:00
maxes - > codec = ( headers [ LCR_HEADERS_CODEC ] = = NULL ? 0 : strlen ( headers [ LCR_HEADERS_CODEC ] ) ) ;
maxes - > cid = ( headers [ LCR_HEADERS_CID ] = = NULL ? 0 : strlen ( headers [ LCR_HEADERS_CID ] ) ) ;
2010-06-19 20:08:06 -05:00
maxes - > limit = ( headers [ LCR_HEADERS_LIMIT ] = = NULL ? 0 : strlen ( headers [ LCR_HEADERS_LIMIT ] ) ) ;
2009-01-14 02:18:51 +00:00
}
2009-04-09 20:58:34 +00:00
static switch_status_t process_max_lengths ( max_obj_t * maxes , lcr_route routes , char * destination_number )
2009-01-15 21:51:15 +00:00
{
2009-01-14 02:18:51 +00:00
lcr_route current = NULL ;
if ( routes = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " no routes \n " ) ;
return SWITCH_STATUS_FALSE ;
}
if ( maxes = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " no maxes \n " ) ;
return SWITCH_STATUS_FALSE ;
}
init_max_lens ( maxes ) ;
for ( current = routes ; current ; current = current - > next ) {
size_t this_len ;
2010-06-19 20:08:06 -05:00
if ( current - > carrier_name ) {
2009-01-14 02:18:51 +00:00
this_len = strlen ( current - > carrier_name ) ;
if ( this_len > maxes - > carrier_name ) {
maxes - > carrier_name = this_len ;
}
}
2010-06-19 20:08:06 -05:00
if ( current - > dialstring ) {
2009-01-14 02:18:51 +00:00
this_len = strlen ( current - > dialstring ) ;
if ( this_len > maxes - > dialstring ) {
maxes - > dialstring = this_len ;
}
}
2010-06-19 20:08:06 -05:00
if ( current - > digit_str ) {
2009-01-14 02:18:51 +00:00
if ( current - > digit_len > maxes - > digit_str ) {
maxes - > digit_str = current - > digit_len ;
2010-06-19 20:08:06 -05:00
}
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
if ( current - > rate_str ) {
2009-01-14 02:18:51 +00:00
this_len = strlen ( current - > rate_str ) ;
if ( this_len > maxes - > rate ) {
maxes - > rate = this_len ;
}
}
2010-06-19 20:08:06 -05:00
if ( current - > codec ) {
this_len = strlen ( current - > codec ) ;
2009-03-27 20:01:54 +00:00
if ( this_len > maxes - > codec ) {
maxes - > codec = this_len ;
}
}
2010-06-19 20:08:06 -05:00
if ( current - > cid ) {
2009-03-27 20:01:54 +00:00
this_len = strlen ( current - > cid ) ;
if ( this_len > maxes - > cid ) {
maxes - > cid = this_len ;
}
}
2010-06-19 20:08:06 -05:00
if ( current - > limit_realm & & current - > limit_id ) {
this_len = strlen ( current - > limit_realm ) + strlen ( current - > limit_id ) + 5 ;
if ( this_len > maxes - > limit ) {
maxes - > limit = this_len ;
}
}
2009-01-14 02:18:51 +00:00
}
return SWITCH_STATUS_SUCCESS ;
}
2009-11-26 05:38:43 +00:00
static switch_cache_db_handle_t * lcr_get_db_handle ( void )
{
switch_cache_db_connection_options_t options = { { 0 } } ;
switch_cache_db_handle_t * dbh = NULL ;
2010-06-19 20:08:06 -05:00
2010-01-13 18:02:42 +00:00
if ( ! zstr ( globals . odbc_dsn ) ) {
2009-11-26 05:38:43 +00:00
options . odbc_options . dsn = globals . odbc_dsn ;
options . odbc_options . user = globals . odbc_user ;
options . odbc_options . pass = globals . odbc_pass ;
2010-06-19 20:08:06 -05:00
if ( switch_cache_db_get_db_handle ( & dbh , SCDB_TYPE_ODBC , & options ) ! = SWITCH_STATUS_SUCCESS ) dbh = NULL ;
2009-11-26 05:38:43 +00:00
}
return dbh ;
}
2009-03-20 20:15:39 +00:00
static switch_bool_t db_check ( char * sql )
2009-01-15 21:51:15 +00:00
{
2009-11-26 05:38:43 +00:00
switch_bool_t ret = SWITCH_FALSE ;
switch_cache_db_handle_t * dbh = NULL ;
if ( globals . odbc_dsn & & ( dbh = lcr_get_db_handle ( ) ) ) {
2010-06-19 08:08:42 -05:00
if ( switch_cache_db_execute_sql ( dbh , sql , NULL ) = = SWITCH_STATUS_SUCCESS ) {
2009-11-26 05:38:43 +00:00
ret = SWITCH_TRUE ;
2009-01-14 02:18:51 +00:00
}
}
2009-11-26 05:38:43 +00:00
2010-07-05 11:11:07 -05:00
switch_cache_db_release_db_handle ( & dbh ) ;
2009-11-26 05:38:43 +00:00
return ret ;
2009-03-20 20:15:39 +00:00
}
/* try each type of random until we suceed */
static switch_bool_t set_db_random ( )
{
if ( db_check ( " SELECT rand(); " ) = = SWITCH_TRUE ) {
db_random = " rand() " ;
return SWITCH_TRUE ;
}
2009-12-11 01:20:26 +00:00
if ( db_check ( " SELECT random(); " ) = = SWITCH_TRUE ) {
2009-03-20 20:15:39 +00:00
db_random = " random() " ;
return SWITCH_TRUE ;
}
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
return SWITCH_FALSE ;
}
2009-01-15 20:32:25 +00:00
/* make a new string with digits only */
2010-06-19 20:08:06 -05:00
static char * string_digitsonly ( switch_memory_pool_t * pool , const char * str )
2009-01-15 21:51:15 +00:00
{
2009-01-15 20:32:25 +00:00
char * p , * np , * newstr ;
size_t len ;
2010-06-19 20:08:06 -05:00
p = ( char * ) str ;
2009-01-15 20:32:25 +00:00
len = strlen ( str ) ;
2010-06-19 20:08:06 -05:00
newstr = switch_core_alloc ( pool , len + 1 ) ;
2009-01-15 20:32:25 +00:00
np = newstr ;
2010-06-19 20:08:06 -05:00
while ( * p ) {
2009-02-13 21:45:54 +00:00
if ( switch_isdigit ( * p ) ) {
2009-01-15 20:32:25 +00:00
* np = * p ;
np + + ;
}
p + + ;
}
* np = ' \0 ' ;
return newstr ;
}
2009-02-20 20:36:04 +00:00
/* escape sql */
# ifdef _WAITING_FOR_ESCAPE
static char * escape_sql ( const char * sql )
{
return switch_string_replace ( sql , " ' " , " '' " ) ;
}
# endif
/* expand the digits */
2009-03-16 15:54:44 +00:00
static char * expand_digits ( switch_memory_pool_t * pool , char * digits , switch_bool_t quote )
2009-02-20 20:36:04 +00:00
{
switch_stream_handle_t dig_stream = { 0 } ;
char * ret ;
char * digits_copy ;
int n ;
int digit_len ;
SWITCH_STANDARD_STREAM ( dig_stream ) ;
2009-03-16 15:54:44 +00:00
2009-02-20 20:36:04 +00:00
digit_len = strlen ( digits ) ;
digits_copy = switch_core_strdup ( pool , digits ) ;
2010-06-19 20:08:06 -05:00
2009-02-20 20:36:04 +00:00
for ( n = digit_len ; n > 0 ; n - - ) {
digits_copy [ n ] = ' \0 ' ;
2010-06-19 20:08:06 -05:00
dig_stream . write_function ( & dig_stream , " %s%s%s%s " ,
( n = = digit_len ? " " : " , " ) ,
( quote ? " ' " : " " ) ,
digits_copy ,
( quote ? " ' " : " " ) ) ;
2009-02-20 20:36:04 +00:00
}
ret = switch_core_strdup ( pool , dig_stream . data ) ;
switch_safe_free ( dig_stream . data ) ;
return ret ;
}
/* format the custom sql */
static char * format_custom_sql ( const char * custom_sql , callback_t * cb_struct , const char * digits )
{
2010-06-19 20:08:06 -05:00
char * tmpSQL = NULL ;
char * newSQL = NULL ;
2009-02-20 20:36:04 +00:00
switch_channel_t * channel ;
2010-06-19 20:08:06 -05:00
2009-02-20 20:36:04 +00:00
/* first replace %s with digits to maintain backward compat */
2009-03-05 04:08:31 +00:00
if ( cb_struct - > profile - > custom_sql_has_percent = = SWITCH_TRUE ) {
2009-02-20 20:36:04 +00:00
tmpSQL = switch_string_replace ( custom_sql , " %q " , digits ) ;
newSQL = tmpSQL ;
}
2010-06-19 20:08:06 -05:00
2009-02-20 20:36:04 +00:00
/* expand the vars */
2009-03-05 04:08:31 +00:00
if ( cb_struct - > profile - > custom_sql_has_vars = = SWITCH_TRUE ) {
if ( cb_struct - > session ) {
2009-02-20 20:36:04 +00:00
channel = switch_core_session_get_channel ( cb_struct - > session ) ;
switch_assert ( channel ) ;
/*
2010-06-19 20:08:06 -05:00
newSQL = switch_channel_expand_variables_escape ( channel ,
tmpSQL ? tmpSQL : custom_sql ,
escape_sql ) ;
*/
newSQL = switch_channel_expand_variables ( channel ,
tmpSQL ? tmpSQL : custom_sql ) ;
2009-03-20 20:15:39 +00:00
} else if ( cb_struct - > event ) {
/* use event system to expand vars */
newSQL = switch_event_expand_headers ( cb_struct - > event , tmpSQL ? tmpSQL : custom_sql ) ;
2010-06-19 20:08:06 -05:00
2009-02-20 20:36:04 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_CRIT ,
2010-06-19 20:08:06 -05:00
" mod_lcr called without a valid session while using a custom_sql that has channel variables. \n " ) ;
2009-02-20 20:36:04 +00:00
}
}
2010-06-19 20:08:06 -05:00
2009-03-05 04:08:31 +00:00
if ( tmpSQL ! = newSQL ) {
2009-02-20 20:36:04 +00:00
switch_safe_free ( tmpSQL ) ;
}
2010-06-19 20:08:06 -05:00
2009-03-05 04:08:31 +00:00
if ( newSQL = = NULL ) {
2009-02-20 22:00:24 +00:00
return ( char * ) custom_sql ;
} else {
return newSQL ;
}
2009-02-20 20:36:04 +00:00
}
2009-01-15 21:51:15 +00:00
static switch_bool_t lcr_execute_sql_callback ( char * sql , switch_core_db_callback_func_t callback , void * pdata )
{
2009-02-03 15:59:46 +00:00
switch_bool_t retval = SWITCH_FALSE ;
2009-11-26 05:38:43 +00:00
switch_cache_db_handle_t * dbh = NULL ;
2010-06-19 20:08:06 -05:00
2009-11-26 05:38:43 +00:00
if ( globals . odbc_dsn & & ( dbh = lcr_get_db_handle ( ) ) ) {
2010-06-19 08:08:42 -05:00
if ( switch_cache_db_execute_sql_callback ( dbh , sql , callback , pdata , NULL ) ! = SWITCH_STATUS_SUCCESS ) {
2009-02-03 15:59:46 +00:00
retval = SWITCH_FALSE ;
2009-01-14 02:18:51 +00:00
} else {
2009-02-03 15:59:46 +00:00
retval = SWITCH_TRUE ;
2009-01-14 02:18:51 +00:00
}
}
2010-07-05 11:11:07 -05:00
switch_cache_db_release_db_handle ( & dbh ) ;
2009-02-03 15:59:46 +00:00
return retval ;
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
/* CF = compare field */
# define CF(x) !strcmp(x, columnNames[i])
2009-04-09 20:58:34 +00:00
static int route_add_callback ( void * pArg , int argc , char * * argv , char * * columnNames )
2009-01-15 21:51:15 +00:00
{
2009-01-14 02:18:51 +00:00
lcr_route additional = NULL ;
lcr_route current = NULL ;
callback_t * cbt = ( callback_t * ) pArg ;
2009-02-12 01:18:43 +00:00
char * key = NULL ;
2010-06-19 20:08:06 -05:00
int i = 0 ;
2010-02-06 03:38:24 +00:00
2009-02-03 21:20:09 +00:00
switch_memory_pool_t * pool = cbt - > pool ;
2010-06-19 20:08:06 -05:00
2009-02-03 21:20:09 +00:00
additional = switch_core_alloc ( pool , sizeof ( lcr_obj_t ) ) ;
2010-06-19 20:08:06 -05:00
additional - > fields = switch_core_alloc ( pool , sizeof ( switch_event_t ) ) ;
for ( i = 0 ; i < argc ; i + + ) {
if ( CF ( " lcr_digits " ) ) {
additional - > digit_len = strlen ( argv [ i ] ) ;
additional - > digit_str = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_prefix " ) ) {
additional - > prefix = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_suffix " ) ) {
additional - > suffix = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_carrier_name " ) ) {
additional - > carrier_name = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_rate_field " ) ) {
additional - > rate = ( float ) atof ( switch_str_nil ( argv [ i ] ) ) ;
additional - > rate_str = switch_core_sprintf ( pool , " %0.5f " , additional - > rate ) ;
} else if ( CF ( " lcr_gw_prefix " ) ) {
additional - > gw_prefix = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_gw_suffix " ) ) {
additional - > gw_suffix = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_lead_strip " ) ) {
additional - > lstrip = atoi ( switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_trail_strip " ) ) {
additional - > tstrip = atoi ( switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_codec " ) ) {
additional - > codec = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_cid " ) ) {
additional - > cid = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_user_rate " ) ) {
additional - > user_rate = ( float ) atof ( switch_str_nil ( argv [ i ] ) ) ;
additional - > user_rate_str = switch_core_sprintf ( pool , " %0.5f " , additional - > user_rate ) ;
} else if ( CF ( " lcr_limit_realm " ) ) {
additional - > limit_realm = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_limit_id " ) ) {
additional - > limit_id = switch_core_strdup ( pool , switch_str_nil ( argv [ i ] ) ) ;
} else if ( CF ( " lcr_limit_max " ) ) {
additional - > limit_max = ( float ) atof ( switch_str_nil ( argv [ i ] ) ) ;
}
/* add all fields to the fields event */
switch_event_add_header_string ( additional - > fields , SWITCH_STACK_BOTTOM , columnNames [ i ] , argv [ i ] ) ;
2009-09-30 14:52:19 +00:00
}
2010-06-19 20:08:06 -05:00
cbt - > matches + + ;
2009-07-17 22:41:40 +00:00
additional - > dialstring = get_bridge_data ( pool , cbt - > lookup_number , cbt - > cid , additional , cbt - > profile , cbt - > session ) ;
2009-01-14 02:18:51 +00:00
if ( cbt - > head = = NULL ) {
2009-02-12 01:18:43 +00:00
key = switch_core_sprintf ( pool , " %s:%s " , additional - > gw_prefix , additional - > gw_suffix ) ;
2009-01-14 02:18:51 +00:00
additional - > next = cbt - > head ;
cbt - > head = additional ;
2009-02-11 21:33:22 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Adding %s to head of list \n " , additional - > carrier_name ) ;
2009-02-13 21:45:54 +00:00
if ( switch_core_hash_insert ( cbt - > dedup_hash , key , additional ) ! = SWITCH_STATUS_SUCCESS ) {
2009-02-12 01:18:43 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error inserting into dedup hash \n " ) ;
return SWITCH_STATUS_GENERR ;
}
2009-01-14 02:18:51 +00:00
return SWITCH_STATUS_SUCCESS ;
}
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
for ( current = cbt - > head ; current ; current = current - > next ) {
2010-06-19 20:08:06 -05:00
2009-02-12 01:18:43 +00:00
key = switch_core_sprintf ( pool , " %s:%s " , additional - > gw_prefix , additional - > gw_suffix ) ;
2009-02-13 21:45:54 +00:00
if ( switch_core_hash_find ( cbt - > dedup_hash , key ) ) {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG ,
" Ignoring Duplicate route for termination point (%s) \n " ,
key ) ;
2009-01-14 02:18:51 +00:00
break ;
}
2009-02-11 21:33:22 +00:00
2009-02-13 21:45:54 +00:00
if ( ! cbt - > profile - > reorder_by_rate ) {
2009-02-11 21:33:22 +00:00
/* use db order */
if ( current - > next = = NULL ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Adding %s to end of list \n " , additional - > carrier_name ) ;
current - > next = additional ;
additional - > prev = current ;
2009-02-13 21:45:54 +00:00
if ( switch_core_hash_insert ( cbt - > dedup_hash , key , additional ) ! = SWITCH_STATUS_SUCCESS ) {
2009-02-12 01:18:43 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error inserting into dedup hash \n " ) ;
return SWITCH_STATUS_GENERR ;
}
2009-02-11 21:33:22 +00:00
break ;
}
} else {
2009-02-13 21:45:54 +00:00
if ( current - > rate > additional - > rate ) {
2009-02-11 21:33:22 +00:00
/* insert myself here */
2009-02-13 21:45:54 +00:00
if ( current - > prev ! = NULL ) {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Adding %s before %s \n " ,
additional - > carrier_name , current - > carrier_name ) ;
2009-02-11 21:33:22 +00:00
current - > prev - > next = additional ;
} else {
/* put this one at the head */
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Inserting %s to list head before %s \n " ,
additional - > carrier_name , current - > carrier_name ) ;
2009-02-11 21:33:22 +00:00
cbt - > head = additional ;
}
additional - > next = current ;
current - > prev = additional ;
2009-02-13 21:45:54 +00:00
if ( switch_core_hash_insert ( cbt - > dedup_hash , key , additional ) ! = SWITCH_STATUS_SUCCESS ) {
2009-02-12 01:18:43 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error inserting into dedup hash \n " ) ;
return SWITCH_STATUS_GENERR ;
}
2009-02-11 21:33:22 +00:00
break ;
2009-02-13 21:45:54 +00:00
} else if ( current - > next = = NULL ) {
2009-02-11 21:33:22 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " adding %s to end of list after %s \n " ,
2010-06-19 20:08:06 -05:00
additional - > carrier_name , current - > carrier_name ) ;
2009-02-11 21:33:22 +00:00
current - > next = additional ;
additional - > prev = current ;
2009-02-13 21:45:54 +00:00
if ( switch_core_hash_insert ( cbt - > dedup_hash , key , additional ) ! = SWITCH_STATUS_SUCCESS ) {
2009-02-12 01:18:43 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Error inserting into dedup hash \n " ) ;
return SWITCH_STATUS_GENERR ;
}
2009-02-11 21:33:22 +00:00
break ;
}
2009-01-14 02:18:51 +00:00
}
}
return SWITCH_STATUS_SUCCESS ;
}
2009-07-16 15:38:16 +00:00
static int intrastatelata_callback ( void * pArg , int argc , char * * argv , char * * columnNames )
{
int count = 0 ;
callback_t * cbt = ( callback_t * ) pArg ;
2010-06-19 20:08:06 -05:00
2009-07-16 15:38:16 +00:00
count = atoi ( argv [ 1 ] ) ;
if ( count = = 1 ) {
if ( ! strcmp ( argv [ 0 ] , " state " ) ) {
cbt - > intrastate = SWITCH_TRUE ;
} else if ( ! strcmp ( argv [ 0 ] , " lata " ) ) {
cbt - > intralata = SWITCH_TRUE ;
}
}
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Type: %s, Count: %d \n " , argv [ 0 ] , count ) ;
2009-07-16 15:38:16 +00:00
return SWITCH_STATUS_SUCCESS ;
}
static switch_status_t is_intrastatelata ( callback_t * cb_struct )
{
char * sql = NULL ;
2010-06-19 20:08:06 -05:00
2009-07-16 15:38:16 +00:00
/* extract npa nxx - make some assumptions about format:
2010-02-06 03:38:24 +00:00
e164 format without the +
NANP only ( so 11 digits starting with 1 )
*/
2010-06-19 20:08:06 -05:00
if ( ! cb_struct - > lookup_number | | strlen ( cb_struct - > lookup_number ) ! = 11 | | * cb_struct - > lookup_number ! = ' 1 ' | |
2010-03-19 23:23:04 +00:00
! switch_is_number ( cb_struct - > lookup_number ) ) {
2009-07-16 15:38:16 +00:00
/* dest doesn't appear to be NANP number */
return SWITCH_STATUS_GENERR ;
}
2010-06-19 20:08:06 -05:00
if ( ! cb_struct - > cid | | strlen ( cb_struct - > cid ) ! = 11 | | * cb_struct - > cid ! = ' 1 ' | | ! switch_is_number ( cb_struct - > cid ) ) {
2009-07-16 15:38:16 +00:00
/* cid not NANP */
return SWITCH_STATUS_GENERR ;
}
2010-06-19 20:08:06 -05:00
2009-07-16 15:38:16 +00:00
/* assume that if the area code (plus leading 1) are the same we're intrastate */
/* probably a bad assumption */
/*
2010-06-19 20:08:06 -05:00
if ( ! strncmp ( cb_struct - > lookup_number , cb_struct - > cid , 4 ) ) {
cb_struct - > intrastate = SWITCH_TRUE ;
return SWITCH_STATUS_SUCCESS ;
}
*/
2009-07-16 15:38:16 +00:00
sql = switch_core_sprintf ( cb_struct - > pool ,
2010-06-19 20:08:06 -05:00
" SELECT 'state', count(DISTINCT state) FROM npa_nxx_company_ocn WHERE (npa=%3.3s AND nxx=%3.3s) OR (npa=%3.3s AND nxx=%3.3s) "
" UNION "
" SELECT 'lata', count(DISTINCT lata) FROM npa_nxx_company_ocn WHERE (npa=%3.3s AND nxx=%3.3s) OR (npa=%3.3s AND nxx=%3.3s) " ,
cb_struct - > lookup_number + 1 , cb_struct - > lookup_number + 4 ,
cb_struct - > cid + 1 , cb_struct - > cid + 4 ,
cb_struct - > lookup_number + 1 , cb_struct - > lookup_number + 4 ,
cb_struct - > cid + 1 , cb_struct - > cid + 4 ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_DEBUG , " SQL: %s \n " , sql ) ;
return ( lcr_execute_sql_callback ( sql , intrastatelata_callback , cb_struct ) ) ;
2009-07-16 15:38:16 +00:00
}
2009-04-09 20:58:34 +00:00
static switch_status_t lcr_do_lookup ( callback_t * cb_struct )
2009-01-15 21:51:15 +00:00
{
2009-01-14 02:18:51 +00:00
switch_stream_handle_t sql_stream = { 0 } ;
2009-03-27 20:01:54 +00:00
char * digits = cb_struct - > lookup_number ;
2009-01-14 02:18:51 +00:00
char * digits_copy ;
2009-02-20 20:36:04 +00:00
char * digits_expanded ;
2009-02-11 21:33:22 +00:00
profile_t * profile = cb_struct - > profile ;
2009-01-14 02:18:51 +00:00
switch_bool_t lookup_status ;
2009-02-20 20:36:04 +00:00
switch_channel_t * channel ;
char * id_str ;
2009-06-19 14:46:51 +00:00
char * safe_sql = NULL ;
char * rate_field = NULL ;
2009-09-30 14:52:19 +00:00
char * user_rate_field = NULL ;
2010-06-19 20:08:06 -05:00
2009-03-27 20:01:54 +00:00
switch_assert ( cb_struct - > lookup_number ! = NULL ) ;
2009-01-14 02:18:51 +00:00
2009-02-11 00:18:50 +00:00
digits_copy = string_digitsonly ( cb_struct - > pool , digits ) ;
2009-10-23 16:03:42 +00:00
if ( zstr ( digits_copy ) ) {
2009-03-20 20:23:32 +00:00
return SWITCH_STATUS_GENERR ;
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
2009-02-12 01:18:43 +00:00
/* allocate the dedup hash */
2009-02-13 21:45:54 +00:00
if ( switch_core_hash_init ( & cb_struct - > dedup_hash , cb_struct - > pool ) ! = SWITCH_STATUS_SUCCESS ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_ERROR , " Error initializing the dedup hash \n " ) ;
2009-03-20 20:23:32 +00:00
return SWITCH_STATUS_GENERR ;
2009-02-12 01:18:43 +00:00
}
2010-06-19 20:08:06 -05:00
2009-03-16 15:54:44 +00:00
digits_expanded = expand_digits ( cb_struct - > pool , digits_copy , cb_struct - > profile - > quote_in_list ) ;
2010-06-19 20:08:06 -05:00
2009-07-16 15:38:16 +00:00
if ( profile - > profile_has_npanxx = = SWITCH_TRUE ) {
is_intrastatelata ( cb_struct ) ;
}
2010-06-19 20:08:06 -05:00
2009-06-19 17:48:49 +00:00
/* set our rate field based on env and profile */
2009-07-16 15:38:16 +00:00
if ( cb_struct - > intralata = = SWITCH_TRUE & & profile - > profile_has_intralata = = SWITCH_TRUE ) {
rate_field = switch_core_strdup ( cb_struct - > pool , " intralata_rate " ) ;
2009-09-30 14:52:19 +00:00
user_rate_field = switch_core_strdup ( cb_struct - > pool , " user_intralata_rate " ) ;
2009-07-16 15:38:16 +00:00
} else if ( cb_struct - > intrastate = = SWITCH_TRUE & & profile - > profile_has_intrastate = = SWITCH_TRUE ) {
rate_field = switch_core_strdup ( cb_struct - > pool , " intrastate_rate " ) ;
2009-09-30 14:52:19 +00:00
user_rate_field = switch_core_strdup ( cb_struct - > pool , " user_intrastate_rate " ) ;
2009-06-19 17:48:49 +00:00
} else {
rate_field = switch_core_strdup ( cb_struct - > pool , " rate " ) ;
2009-09-30 14:52:19 +00:00
user_rate_field = switch_core_strdup ( cb_struct - > pool , " user_rate " ) ;
2009-06-19 17:48:49 +00:00
}
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_DEBUG , " intra routing [state:%d lata:%d] so rate field is [%s] \n " ,
2009-07-16 15:38:16 +00:00
cb_struct - > intrastate , cb_struct - > intralata , rate_field ) ;
2010-06-19 20:08:06 -05:00
2009-02-20 20:36:04 +00:00
/* set some channel vars if we have a session */
2009-03-05 04:08:31 +00:00
if ( cb_struct - > session ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_DEBUG , " we have a session \n " ) ;
2009-03-05 04:08:31 +00:00
if ( ( channel = switch_core_session_get_channel ( cb_struct - > session ) ) ) {
2009-06-19 14:46:51 +00:00
switch_channel_set_variable_var_check ( channel , " lcr_rate_field " , rate_field , SWITCH_FALSE ) ;
2009-09-30 14:52:19 +00:00
switch_channel_set_variable_var_check ( channel , " lcr_user_rate_field " , user_rate_field , SWITCH_FALSE ) ;
2009-02-20 20:36:04 +00:00
switch_channel_set_variable_var_check ( channel , " lcr_query_digits " , digits_copy , SWITCH_FALSE ) ;
id_str = switch_core_sprintf ( cb_struct - > pool , " %d " , cb_struct - > profile - > id ) ;
switch_channel_set_variable_var_check ( channel , " lcr_query_profile " , id_str , SWITCH_FALSE ) ;
switch_channel_set_variable_var_check ( channel , " lcr_query_expanded_digits " , digits_expanded , SWITCH_FALSE ) ;
}
}
2009-03-20 20:15:39 +00:00
if ( cb_struct - > event ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_DEBUG , " we have an event \n " ) ;
2009-06-19 14:46:51 +00:00
switch_event_add_header_string ( cb_struct - > event , SWITCH_STACK_BOTTOM , " lcr_rate_field " , rate_field ) ;
2009-09-30 14:52:19 +00:00
switch_event_add_header_string ( cb_struct - > event , SWITCH_STACK_BOTTOM , " lcr_user_rate_field " , user_rate_field ) ;
2009-03-20 20:15:39 +00:00
switch_event_add_header_string ( cb_struct - > event , SWITCH_STACK_BOTTOM , " lcr_query_digits " , digits_copy ) ;
id_str = switch_core_sprintf ( cb_struct - > pool , " %d " , cb_struct - > profile - > id ) ;
switch_event_add_header_string ( cb_struct - > event , SWITCH_STACK_BOTTOM , " lcr_query_profile " , id_str ) ;
switch_event_add_header_string ( cb_struct - > event , SWITCH_STACK_BOTTOM , " lcr_query_expanded_digits " , digits_expanded ) ;
}
2009-01-14 02:18:51 +00:00
/* set up the query to be executed */
2009-03-20 20:15:39 +00:00
/* format the custom_sql */
safe_sql = format_custom_sql ( profile - > custom_sql , cb_struct , digits_copy ) ;
if ( ! safe_sql ) {
2009-03-23 15:34:46 +00:00
switch_core_hash_destroy ( & cb_struct - > dedup_hash ) ;
2009-03-20 20:15:39 +00:00
return SWITCH_STATUS_GENERR ;
}
SWITCH_STANDARD_STREAM ( sql_stream ) ;
sql_stream . write_function ( & sql_stream , safe_sql ) ;
if ( safe_sql ! = profile - > custom_sql ) {
/* channel_expand_variables returned the same string to us, no need to free */
switch_safe_free ( safe_sql ) ;
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( cb_struct - > session ) , SWITCH_LOG_DEBUG , " SQL: %s \n " , ( char * ) sql_stream . data ) ;
lookup_status = lcr_execute_sql_callback ( ( char * ) sql_stream . data , route_add_callback , cb_struct ) ;
2009-02-12 01:18:43 +00:00
2009-01-14 02:18:51 +00:00
switch_safe_free ( sql_stream . data ) ;
2009-02-12 01:18:43 +00:00
switch_core_hash_destroy ( & cb_struct - > dedup_hash ) ;
2009-02-13 21:45:54 +00:00
if ( lookup_status ) {
2009-01-14 02:18:51 +00:00
return SWITCH_STATUS_SUCCESS ;
} else {
return SWITCH_STATUS_GENERR ;
}
}
2009-04-09 20:58:34 +00:00
static switch_bool_t test_profile ( char * lcr_profile )
2009-03-20 20:15:39 +00:00
{
callback_t routes = { 0 } ;
switch_memory_pool_t * pool = NULL ;
switch_event_t * event = NULL ;
switch_core_new_memory_pool ( & pool ) ;
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
routes . event = event ;
routes . pool = pool ;
2010-06-19 20:08:06 -05:00
2009-03-20 20:15:39 +00:00
if ( ! ( routes . profile = locate_profile ( lcr_profile ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unknown profile: %s \n " , lcr_profile ) ;
return SWITCH_FALSE ;
}
2010-06-19 20:08:06 -05:00
2009-03-20 20:15:39 +00:00
routes . lookup_number = " 15555551212 " ;
2009-03-27 20:01:54 +00:00
routes . cid = " 18005551212 " ;
2010-06-19 20:08:06 -05:00
return ( lcr_do_lookup ( & routes ) = = SWITCH_STATUS_SUCCESS ) ?
SWITCH_TRUE : SWITCH_FALSE ;
2009-03-20 20:15:39 +00:00
}
2009-01-15 21:51:15 +00:00
static switch_status_t lcr_load_config ( )
{
2009-01-14 02:18:51 +00:00
char * cf = " lcr.conf " ;
2009-03-20 20:15:39 +00:00
switch_stream_handle_t sql_stream = { 0 } ;
2009-01-14 02:18:51 +00:00
switch_xml_t cfg , xml , settings , param , x_profile , x_profiles ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
profile_t * profile = NULL ;
2009-11-26 05:38:43 +00:00
switch_cache_db_handle_t * dbh = NULL ;
2009-01-14 02:18:51 +00:00
if ( ! ( xml = switch_xml_open_cfg ( cf , & cfg , NULL ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " open of %s failed \n " , cf ) ;
return SWITCH_STATUS_TERM ;
}
if ( ( settings = switch_xml_child ( cfg , " settings " ) ) ) {
for ( param = switch_xml_child ( settings , " param " ) ; param ; param = param - > next ) {
char * var = NULL ;
char * val = NULL ;
var = ( char * ) switch_xml_attr_soft ( param , " name " ) ;
val = ( char * ) switch_xml_attr_soft ( param , " value " ) ;
2009-10-23 16:03:42 +00:00
if ( ! strcasecmp ( var , " odbc-dsn " ) & & ! zstr ( val ) ) {
2009-01-14 02:18:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " odbc_dsn is %s \n " , val ) ;
2009-11-26 05:38:43 +00:00
switch_safe_free ( globals . odbc_dsn ) ;
globals . odbc_dsn = strdup ( val ) ;
if ( ( globals . odbc_user = strchr ( globals . odbc_dsn , ' : ' ) ) ) {
* globals . odbc_user + + = ' \0 ' ;
if ( ( globals . odbc_pass = strchr ( globals . odbc_user , ' : ' ) ) ) {
* globals . odbc_pass + + = ' \0 ' ;
2009-01-14 02:18:51 +00:00
}
}
}
}
}
2010-06-19 20:08:06 -05:00
2009-02-11 00:18:50 +00:00
/* initialize sql here, 'cause we need to verify custom_sql for each profile below */
if ( globals . odbc_dsn ) {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG
, " dsn is \" %s \" , user is \" %s \" \n "
, globals . odbc_dsn , globals . odbc_user
) ;
2009-11-26 05:38:43 +00:00
if ( ! ( dbh = lcr_get_db_handle ( ) ) ) {
2009-02-11 00:18:50 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open ODBC Database! \n " ) ;
2009-11-26 05:38:43 +00:00
switch_goto_status ( SWITCH_STATUS_FALSE , done ) ;
2009-02-11 00:18:50 +00:00
}
}
2010-06-19 20:08:06 -05:00
2009-03-20 20:15:39 +00:00
if ( set_db_random ( ) = = SWITCH_TRUE ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Database RANDOM function set to %s \n " , db_random ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unable to determine database RANDOM function \n " ) ;
} ;
2009-01-14 02:18:51 +00:00
switch_core_hash_init ( & globals . profile_hash , globals . pool ) ;
2009-02-13 21:45:54 +00:00
if ( ( x_profiles = switch_xml_child ( cfg , " profiles " ) ) ) {
2009-01-14 02:18:51 +00:00
for ( x_profile = switch_xml_child ( x_profiles , " profile " ) ; x_profile ; x_profile = x_profile - > next ) {
char * name = ( char * ) switch_xml_attr_soft ( x_profile , " name " ) ;
2009-02-11 16:52:29 +00:00
char * comma = " , " ;
2009-01-14 02:18:51 +00:00
switch_stream_handle_t order_by = { 0 } ;
2009-02-11 16:52:29 +00:00
switch_stream_handle_t * thisorder = NULL ;
2009-02-15 04:10:31 +00:00
char * reorder_by_rate = NULL ;
2009-03-16 15:54:44 +00:00
char * quote_in_list = NULL ;
2009-06-02 16:38:29 +00:00
char * info_in_headers = NULL ;
2010-06-19 08:08:42 -05:00
char * enable_sip_redir = NULL ;
2009-01-14 02:18:51 +00:00
char * id_s = NULL ;
2009-02-11 00:18:50 +00:00
char * custom_sql = NULL ;
2010-06-19 20:08:06 -05:00
char * export_fields = NULL ;
char * limit_type = NULL ;
2009-01-14 02:18:51 +00:00
int argc , x = 0 ;
char * argv [ 4 ] = { 0 } ;
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
SWITCH_STANDARD_STREAM ( order_by ) ;
2009-02-11 16:52:29 +00:00
2009-01-14 02:18:51 +00:00
for ( param = switch_xml_child ( x_profile , " param " ) ; param ; param = param - > next ) {
char * var , * val ;
var = ( char * ) switch_xml_attr_soft ( param , " name " ) ;
val = ( char * ) switch_xml_attr_soft ( param , " value " ) ;
2010-06-19 20:08:06 -05:00
if ( ! strcasecmp ( var , " order_by " ) & & ! zstr ( val ) ) {
2009-06-11 21:20:42 +00:00
thisorder = & order_by ;
2009-01-14 02:18:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " param val is %s \n " , val ) ;
if ( ( argc = switch_separate_string ( val , ' , ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2010-06-19 20:08:06 -05:00
for ( x = 0 ; x < argc ; x + + ) {
2009-01-14 02:18:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " arg #%d/%d is %s \n " , x , argc , argv [ x ] ) ;
2009-10-23 16:03:42 +00:00
if ( ! zstr ( argv [ x ] ) ) {
2009-01-14 02:18:51 +00:00
if ( ! strcasecmp ( argv [ x ] , " quality " ) ) {
2009-02-11 16:52:29 +00:00
thisorder - > write_function ( thisorder , " %s quality DESC " , comma ) ;
2009-02-13 21:45:54 +00:00
} else if ( ! strcasecmp ( argv [ x ] , " reliability " ) ) {
2009-02-11 16:52:29 +00:00
thisorder - > write_function ( thisorder , " %s reliability DESC " , comma ) ;
2009-06-19 14:46:51 +00:00
} else if ( ! strcasecmp ( argv [ x ] , " rate " ) ) {
thisorder - > write_function ( thisorder , " %s ${lcr_rate_field} " , comma ) ;
2009-01-14 02:18:51 +00:00
} else {
2009-02-11 16:52:29 +00:00
thisorder - > write_function ( thisorder , " %s %s " , comma , argv [ x ] ) ;
2009-01-14 02:18:51 +00:00
}
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " arg #%d is empty \n " , x ) ;
}
}
} else {
if ( ! strcasecmp ( val , " quality " ) ) {
2009-02-11 16:52:29 +00:00
thisorder - > write_function ( thisorder , " %s quality DESC " , comma ) ;
2009-02-13 21:45:54 +00:00
} else if ( ! strcasecmp ( val , " reliability " ) ) {
2009-02-11 16:52:29 +00:00
thisorder - > write_function ( thisorder , " %s reliability DESC " , comma ) ;
2009-01-14 02:18:51 +00:00
} else {
2009-02-11 16:52:29 +00:00
thisorder - > write_function ( thisorder , " %s %s " , comma , val ) ;
2009-01-14 02:18:51 +00:00
}
}
2009-10-23 16:03:42 +00:00
} else if ( ! strcasecmp ( var , " id " ) & & ! zstr ( val ) ) {
2009-01-14 02:18:51 +00:00
id_s = val ;
2009-10-23 16:03:42 +00:00
} else if ( ! strcasecmp ( var , " custom_sql " ) & & ! zstr ( val ) ) {
2009-02-11 00:18:50 +00:00
custom_sql = val ;
2009-10-23 16:03:42 +00:00
} else if ( ! strcasecmp ( var , " reorder_by_rate " ) & & ! zstr ( val ) ) {
2009-02-11 21:33:22 +00:00
reorder_by_rate = val ;
2009-10-23 16:03:42 +00:00
} else if ( ! strcasecmp ( var , " info_in_headers " ) & & ! zstr ( val ) ) {
2009-06-02 16:38:29 +00:00
info_in_headers = val ;
2009-10-23 16:03:42 +00:00
} else if ( ! strcasecmp ( var , " quote_in_list " ) & & ! zstr ( val ) ) {
2009-03-16 15:54:44 +00:00
quote_in_list = val ;
2010-06-19 20:08:06 -05:00
} else if ( ! strcasecmp ( var , " export_fields " ) & & ! zstr ( val ) ) {
export_fields = val ;
} else if ( ! strcasecmp ( var , " limit_type " ) & & ! zstr ( val ) ) {
limit_type = val ;
2010-06-19 08:08:42 -05:00
} else if ( ! strcasecmp ( var , " enable_sip_redir " ) & & ! zstr ( val ) ) {
enable_sip_redir = val ;
2009-01-14 02:18:51 +00:00
}
}
2010-06-19 20:08:06 -05:00
2009-10-23 16:03:42 +00:00
if ( zstr ( name ) ) {
2009-01-14 02:18:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " No name specified. \n " ) ;
} else {
profile = switch_core_alloc ( globals . pool , sizeof ( * profile ) ) ;
2009-02-11 00:18:50 +00:00
memset ( profile , 0 , sizeof ( profile_t ) ) ;
2009-01-14 02:18:51 +00:00
profile - > name = switch_core_strdup ( globals . pool , name ) ;
2010-06-19 20:08:06 -05:00
if ( ! zstr ( ( char * ) order_by . data ) ) {
profile - > order_by = switch_core_strdup ( globals . pool , ( char * ) order_by . data ) ;
2009-01-14 02:18:51 +00:00
} else {
/* default to rate */
2009-06-19 14:46:51 +00:00
profile - > order_by = " , ${lcr_rate_field} " ;
2009-01-14 02:18:51 +00:00
}
2009-02-11 16:52:29 +00:00
2009-10-23 16:03:42 +00:00
if ( ! zstr ( id_s ) ) {
2010-06-19 20:08:06 -05:00
profile - > id = ( uint16_t ) atoi ( id_s ) ;
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
2009-03-20 20:15:39 +00:00
/* SWITCH_STANDARD_STREAM doesn't use pools. but we only have to free sql_stream.data */
SWITCH_STANDARD_STREAM ( sql_stream ) ;
2009-10-23 16:03:42 +00:00
if ( zstr ( custom_sql ) ) {
2009-03-20 20:15:39 +00:00
/* use default sql */
2010-06-19 20:08:06 -05:00
sql_stream . write_function ( & sql_stream ,
" SELECT l.digits AS lcr_digits, c.carrier_name AS lcr_carrier_name, l.${lcr_rate_field} AS lcr_rate_field, cg.prefix AS lcr_gw_prefix, cg.suffix AS lcr_gw_suffix, l.lead_strip AS lcr_lead_strip, l.trail_strip AS lcr_trail_strip, l.prefix AS lcr_prefix, l.suffix AS lcr_suffix "
) ;
2009-03-20 20:15:39 +00:00
if ( db_check ( " SELECT codec from carrier_gateway limit 1 " ) = = SWITCH_TRUE ) {
2010-06-19 20:08:06 -05:00
sql_stream . write_function ( & sql_stream , " , cg.codec AS lcr_codec " ) ;
2009-03-20 20:15:39 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " codec field defined. \n " ) ;
} else {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " codec field not defined, please update your lcr carrier_gateway database schema. \n " ) ;
2009-03-27 20:01:54 +00:00
}
if ( db_check ( " SELECT cid from lcr limit 1 " ) = = SWITCH_TRUE ) {
2010-06-19 20:08:06 -05:00
sql_stream . write_function ( & sql_stream , " , l.cid AS lcr_cid " ) ;
2009-03-27 20:01:54 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " cid field defined. \n " ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " cid field not defined, please update your lcr database schema. \n " ) ;
2009-03-20 20:15:39 +00:00
}
2010-06-19 20:08:06 -05:00
sql_stream . write_function ( & sql_stream , " FROM lcr l JOIN carriers c ON l.carrier_id=c.id JOIN carrier_gateway cg ON c.id=cg.carrier_id WHERE c.enabled = '1' AND cg.enabled = '1' AND l.enabled = '1' AND digits IN ( " ) ;
2009-03-20 20:15:39 +00:00
sql_stream . write_function ( & sql_stream , " ${lcr_query_expanded_digits} " ) ;
sql_stream . write_function ( & sql_stream , " ) AND CURRENT_TIMESTAMP BETWEEN date_start AND date_end " ) ;
if ( profile - > id > 0 ) {
sql_stream . write_function ( & sql_stream , " AND lcr_profile=%d " , profile - > id ) ;
2009-02-20 20:36:04 +00:00
}
2010-06-19 20:08:06 -05:00
sql_stream . write_function ( & sql_stream , " ORDER BY digits DESC%s " ,
profile - > order_by ) ;
2009-03-20 20:15:39 +00:00
if ( db_random ) {
sql_stream . write_function ( & sql_stream , " , %s " , db_random ) ;
2009-02-11 00:18:50 +00:00
}
2009-03-20 20:15:39 +00:00
sql_stream . write_function ( & sql_stream , " ; " ) ;
2010-06-19 20:08:06 -05:00
2009-03-20 20:15:39 +00:00
custom_sql = sql_stream . data ;
2009-02-11 00:18:50 +00:00
}
2010-06-19 20:08:06 -05:00
2009-07-16 15:38:16 +00:00
profile - > profile_has_intralata = db_check ( " SELECT intralata_rate FROM lcr LIMIT 1 " ) ;
if ( profile - > profile_has_intralata ! = SWITCH_TRUE ) {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING ,
" no \" intralata_rate \" field found in the \" lcr \" table, routing by intralata rates will be disabled until the field is added and mod_lcr is reloaded \n "
) ;
2009-07-16 15:38:16 +00:00
}
profile - > profile_has_intrastate = db_check ( " SELECT intrastate_rate FROM lcr LIMIT 1 " ) ;
if ( profile - > profile_has_intrastate ! = SWITCH_TRUE ) {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING ,
" no \" intrastate_rate \" field found in the \" lcr \" table, routing by intrastate rates will be disabled until the field is added and mod_lcr is reloaded \n "
) ;
2009-07-16 15:38:16 +00:00
}
2010-06-19 20:08:06 -05:00
2009-07-16 15:38:16 +00:00
profile - > profile_has_npanxx = db_check ( " SELECT npa, nxx, state FROM npa_nxx_company_ocn LIMIT 1 " ) ;
if ( profile - > profile_has_npanxx ! = SWITCH_TRUE ) {
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING ,
" no \" npa_nxx_company_ocn \" table found in the \" lcr \" database, automatic intrastate detection will be disabled until the table is added and mod_lcr is reloaded \n "
) ;
2009-06-19 14:46:51 +00:00
}
2009-04-30 17:22:24 +00:00
if ( switch_string_var_check_const ( custom_sql ) | | switch_string_has_escaped_data ( custom_sql ) ) {
2009-03-20 20:15:39 +00:00
profile - > custom_sql_has_vars = SWITCH_TRUE ;
}
if ( strstr ( custom_sql , " % " ) ) {
profile - > custom_sql_has_percent = SWITCH_TRUE ;
}
2010-06-19 20:08:06 -05:00
profile - > custom_sql = switch_core_strdup ( globals . pool , ( char * ) custom_sql ) ;
2009-10-23 16:03:42 +00:00
if ( ! zstr ( reorder_by_rate ) ) {
2009-02-11 21:33:22 +00:00
profile - > reorder_by_rate = switch_true ( reorder_by_rate ) ;
}
2010-06-19 20:08:06 -05:00
2009-10-23 16:03:42 +00:00
if ( ! zstr ( info_in_headers ) ) {
2009-06-02 16:38:29 +00:00
profile - > info_in_headers = switch_true ( info_in_headers ) ;
}
2010-02-06 03:38:24 +00:00
2010-06-19 08:08:42 -05:00
if ( ! zstr ( enable_sip_redir ) ) {
profile - > enable_sip_redir = switch_true ( enable_sip_redir ) ;
}
2009-10-23 16:03:42 +00:00
if ( ! zstr ( quote_in_list ) ) {
2009-03-16 15:54:44 +00:00
profile - > quote_in_list = switch_true ( quote_in_list ) ;
}
2010-06-19 20:08:06 -05:00
if ( ! zstr ( export_fields ) ) {
int argc2 = 0 ;
char * argv2 [ 50 ] = { 0 } ;
char * * argvdup = NULL ;
char * dup = switch_core_strdup ( globals . pool , export_fields ) ;
argc2 = switch_separate_string ( dup , ' , ' , argv2 , ( sizeof ( argv2 ) / sizeof ( argv2 [ 0 ] ) ) ) ;
profile - > export_fields_str = switch_core_strdup ( globals . pool , export_fields ) ;
profile - > export_fields_cnt = argc2 ;
argvdup = switch_core_alloc ( globals . pool , sizeof ( argv2 ) ) ;
memcpy ( argvdup , argv2 , sizeof ( argv2 ) ) ;
profile - > export_fields = argvdup ;
}
if ( ! zstr ( limit_type ) ) {
if ( ! strcasecmp ( limit_type , " hash " ) ) {
profile - > limit_type = " hash " ;
} else {
profile - > limit_type = " sql " ;
}
} else {
profile - > limit_type = " sql " ;
}
2009-01-14 02:18:51 +00:00
switch_core_hash_insert ( globals . profile_hash , profile - > name , profile ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Loaded lcr profile %s. \n " , profile - > name ) ;
2009-03-20 20:15:39 +00:00
/* test the profile */
2010-07-06 23:43:56 -05:00
if ( profile - > custom_sql_has_vars ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " custom_sql has channel vars, skipping verification and assuming valid profile: %s. \n " , profile - > name ) ;
} else if ( test_profile ( profile - > name ) = = SWITCH_TRUE ) {
2009-03-20 20:15:39 +00:00
if ( ! strcasecmp ( profile - > name , " default " ) ) {
globals . default_profile = profile ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Setting user defined default profile: %s. \n " , profile - > name ) ;
}
} else {
2009-06-19 14:46:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Removing INVALID Profile %s. \n " , profile - > name ) ;
2009-03-20 20:15:39 +00:00
switch_core_hash_delete ( globals . profile_hash , profile - > name ) ;
2009-03-16 16:31:23 +00:00
}
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
}
2009-02-03 21:20:09 +00:00
switch_safe_free ( order_by . data ) ;
2009-03-20 20:15:39 +00:00
switch_safe_free ( sql_stream . data ) ;
2009-01-14 02:18:51 +00:00
}
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " No lcr profiles defined. \n " ) ;
}
2010-06-19 20:08:06 -05:00
2009-03-16 16:31:23 +00:00
/* define default profile */
if ( ! globals . default_profile ) {
profile = switch_core_alloc ( globals . pool , sizeof ( * profile ) ) ;
memset ( profile , 0 , sizeof ( profile_t ) ) ;
profile - > name = " global_default " ;
profile - > order_by = " , rate " ;
globals . default_profile = profile ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Setting system defined default profile. " ) ;
}
2010-06-19 20:08:06 -05:00
done :
2010-07-05 11:11:07 -05:00
switch_cache_db_release_db_handle ( & dbh ) ;
2009-01-14 02:18:51 +00:00
switch_xml_free ( xml ) ;
return status ;
}
2010-06-19 20:08:06 -05:00
/* fake chan_lcr */
switch_endpoint_interface_t * lcr_endpoint_interface ;
static switch_call_cause_t lcr_outgoing_channel ( switch_core_session_t * session ,
switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
switch_core_session_t * * new_session , switch_memory_pool_t * * pool , switch_originate_flag_t flags ,
switch_call_cause_t * cancel_cause ) ;
switch_io_routines_t lcr_io_routines = {
/*.outgoing_channel */ lcr_outgoing_channel
} ;
static switch_call_cause_t lcr_outgoing_channel ( switch_core_session_t * session ,
switch_event_t * var_event ,
switch_caller_profile_t * outbound_profile ,
switch_core_session_t * * new_session , switch_memory_pool_t * * new_pool , switch_originate_flag_t flags ,
switch_call_cause_t * cancel_cause )
{
switch_call_cause_t cause = SWITCH_CAUSE_NONE ;
char * dest = NULL ;
switch_originate_flag_t myflags = SOF_NONE ;
const char * cid_name_override = NULL ;
const char * cid_num_override = NULL ;
switch_channel_t * new_channel = NULL ;
unsigned int timelimit = 60 ;
const char * skip , * var ;
switch_memory_pool_t * pool = NULL ;
callback_t routes = { 0 } ;
lcr_route cur_route = { 0 } ;
char * lcr_profile = NULL ;
switch_event_t * event = NULL ;
const char * intrastate = NULL ;
const char * intralata = NULL ;
switch_core_session_t * mysession = NULL ;
switch_channel_t * channel = NULL ;
switch_caller_profile_t * caller_profile = NULL ;
dest = strdup ( outbound_profile - > destination_number ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Entering lcr endpoint for %s \n " , dest ) ;
if ( ! dest ) {
goto done ;
}
switch_core_new_memory_pool ( & pool ) ;
routes . pool = pool ;
if ( var_event & & ( skip = switch_event_get_header ( var_event , " lcr_recurse_variables " ) ) & & switch_false ( skip ) ) {
if ( ( var = switch_event_get_header ( var_event , SWITCH_CALL_TIMEOUT_VARIABLE ) ) | | ( var = switch_event_get_header ( var_event , " leg_timeout " ) ) ) {
timelimit = atoi ( var ) ;
}
var_event = NULL ;
}
if ( session ) {
mysession = session ;
channel = switch_core_session_get_channel ( session ) ;
if ( ( var = switch_channel_get_variable ( channel , SWITCH_CALL_TIMEOUT_VARIABLE ) ) | | ( var = switch_event_get_header ( var_event , " leg_timeout " ) ) ) {
timelimit = atoi ( var ) ;
}
routes . session = session ;
caller_profile = switch_channel_get_caller_profile ( channel ) ;
intrastate = switch_channel_get_variable ( channel , " intrastate " ) ;
intralata = switch_channel_get_variable ( channel , " intralata " ) ;
cid_name_override = switch_channel_get_variable ( channel , " origination_caller_id_name " ) ;
cid_num_override = switch_channel_get_variable ( channel , " origination_caller_id_number " ) ;
if ( zstr ( cid_name_override ) ) {
cid_name_override = switch_channel_get_variable ( channel , " effective_caller_id_name " ) ;
}
if ( zstr ( cid_num_override ) ) {
cid_num_override = switch_channel_get_variable ( channel , " effective_caller_id_number " ) ;
}
if ( ( var = switch_channel_get_variable ( channel , SWITCH_CALL_TIMEOUT_VARIABLE ) ) | | ( var = switch_event_get_header ( var_event , " leg_timeout " ) ) ) {
timelimit = atoi ( var ) ;
}
} else if ( var_event ) {
char * session_uuid = switch_event_get_header ( var_event , " ent_originate_aleg_uuid " ) ;
if ( session_uuid ) {
mysession = switch_core_session_locate ( session_uuid ) ;
}
cid_name_override = switch_event_get_header ( var_event , " origination_caller_id_name " ) ;
cid_num_override = switch_event_get_header ( var_event , " origination_caller_id_number " ) ;
if ( zstr ( cid_name_override ) ) {
cid_name_override = switch_event_get_header ( var_event , " effective_caller_id_name " ) ;
}
if ( zstr ( cid_num_override ) ) {
cid_num_override = switch_event_get_header ( var_event , " caller_id_number " ) ;
}
if ( ( var = switch_event_get_header ( var_event , SWITCH_CALL_TIMEOUT_VARIABLE ) ) | | ( var = switch_event_get_header ( var_event , " leg_timeout " ) ) ) {
timelimit = atoi ( var ) ;
}
intrastate = switch_event_get_header ( var_event , " intrastate " ) ;
intralata = switch_event_get_header ( var_event , " intralata " ) ;
//switch_event_dup(&event, var_event);
routes . event = var_event ;
} else {
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
routes . event = event ;
}
routes . lookup_number = dest ;
routes . cid = ( char * ) cid_num_override ;
if ( ( flags & SOF_FORKED_DIAL ) ) {
myflags | = SOF_NOBLOCK ;
}
if ( ! ( routes . profile = locate_profile ( lcr_profile ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unknown profile: %s \n " , lcr_profile ) ;
goto done ;
}
if ( ! zstr ( intralata ) & & ! strcasecmp ( ( char * ) intralata , " true " ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Select routes based on intralata rates \n " ) ;
routes . intralata = SWITCH_FALSE ;
} else if ( ! zstr ( intrastate ) & & ! strcasecmp ( ( char * ) intrastate , " true " ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Select routes based on intrastate rates \n " ) ;
routes . intrastate = SWITCH_TRUE ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Select routes based on interstate rates \n " ) ;
routes . intrastate = SWITCH_FALSE ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " LCR Lookup on %s \n " , dest ) ;
if ( lcr_do_lookup ( & routes ) = = SWITCH_STATUS_SUCCESS ) {
if ( channel ) {
if ( zstr ( switch_channel_get_variable ( channel , " import " ) ) ) {
switch_channel_set_variable ( channel , " import " , " lcr_carrier,lcr_rate " ) ;
} else {
const char * tmp = switch_channel_get_variable ( channel , " import " ) ;
if ( ! strstr ( tmp , " lcr_carrier,lcr_rate " ) ) {
switch_channel_set_variable_printf ( channel , " import " , " %s,lcr_carrier,lcr_rate " , tmp ) ;
}
}
}
for ( cur_route = routes . head ; cur_route ; cur_route = cur_route - > next ) {
switch_bool_t pop_limit = SWITCH_FALSE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Trying route: %s \n " , cur_route - > dialstring ) ;
if ( mysession & & cur_route - > limit_realm & & cur_route - > limit_id ) {
if ( switch_limit_incr ( routes . profile - > limit_type , mysession , cur_route - > limit_realm , cur_route - > limit_id , cur_route - > limit_max , 0 ) = = SWITCH_STATUS_SUCCESS ) {
pop_limit = SWITCH_TRUE ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Limit exceeded for route %s, session: %s \n " , cur_route - > dialstring , mysession ? " true " : " false " ) ;
continue ;
}
}
if ( switch_ivr_originate ( session , new_session , & cause , cur_route - > dialstring , timelimit , NULL ,
cid_name_override , cid_num_override , NULL , var_event , myflags , cancel_cause ) = = SWITCH_STATUS_SUCCESS ) {
const char * context ;
switch_caller_profile_t * cp ;
new_channel = switch_core_session_get_channel ( * new_session ) ;
if ( ( context = switch_channel_get_variable ( new_channel , " lcr_context " ) ) ) {
if ( ( cp = switch_channel_get_caller_profile ( new_channel ) ) ) {
cp - > context = switch_core_strdup ( cp - > pool , context ) ;
}
}
switch_core_session_rwunlock ( * new_session ) ;
break ;
}
/* did not connect, release limit */
if ( pop_limit ) {
switch_limit_release ( routes . profile - > limit_type , mysession , cur_route - > limit_realm , cur_route - > limit_id ) ;
}
if ( cause = = SWITCH_CAUSE_LOSE_RACE | | cause = = SWITCH_CAUSE_ORIGINATOR_CANCEL ) {
break ;
}
}
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " LCR lookup failed for %s \n " , caller_profile - > destination_number ) ;
}
done :
if ( event ) {
switch_event_destroy ( & event ) ;
}
if ( mysession ) {
switch_core_session_rwunlock ( mysession ) ;
}
switch_core_destroy_memory_pool ( & pool ) ;
switch_safe_free ( dest ) ;
if ( cause = = SWITCH_CAUSE_NONE ) {
cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER ;
}
return cause ;
}
2009-01-15 21:51:15 +00:00
SWITCH_STANDARD_DIALPLAN ( lcr_dialplan_hunt )
{
2009-01-14 02:18:51 +00:00
switch_caller_extension_t * extension = NULL ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
callback_t routes = { 0 } ;
lcr_route cur_route = { 0 } ;
char * lcr_profile = NULL ;
2009-02-03 21:20:09 +00:00
switch_memory_pool_t * pool = NULL ;
2009-03-20 20:15:39 +00:00
switch_event_t * event = NULL ;
2009-07-16 15:38:16 +00:00
const char * intrastate = NULL ;
const char * intralata = NULL ;
2009-01-14 02:18:51 +00:00
2009-02-13 21:45:54 +00:00
if ( session ) {
2009-02-03 21:20:09 +00:00
pool = switch_core_session_get_pool ( session ) ;
2009-02-20 20:36:04 +00:00
routes . session = session ;
2009-02-03 21:20:09 +00:00
} else {
switch_core_new_memory_pool ( & pool ) ;
2009-03-20 20:15:39 +00:00
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
routes . event = event ;
2009-02-03 21:20:09 +00:00
}
routes . pool = pool ;
2009-02-13 21:45:54 +00:00
if ( ! ( routes . profile = locate_profile ( lcr_profile ) ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Unknown profile: %s \n " , lcr_profile ) ;
2009-02-11 21:33:22 +00:00
goto end ;
}
2009-06-19 17:48:49 +00:00
2009-07-16 15:38:16 +00:00
intrastate = switch_channel_get_variable ( channel , " intrastate " ) ;
intralata = switch_channel_get_variable ( channel , " intralata " ) ;
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " intrastate channel var is [%s] \n " , intrastate ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " intralata channel var is [%s] \n " , intralata ) ;
2010-06-19 20:08:06 -05:00
if ( ! zstr ( intralata ) & & ! strcasecmp ( ( char * ) intralata , " true " ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Select routes based on intralata rates \n " ) ;
2009-07-16 15:38:16 +00:00
routes . intralata = SWITCH_FALSE ;
2010-06-19 20:08:06 -05:00
} else if ( ! zstr ( intrastate ) & & ! strcasecmp ( ( char * ) intrastate , " true " ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Select routes based on intrastate rates \n " ) ;
2009-06-19 17:48:49 +00:00
routes . intrastate = SWITCH_TRUE ;
2009-07-16 15:38:16 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Select routes based on interstate rates \n " ) ;
2009-07-16 15:38:16 +00:00
routes . intrastate = SWITCH_FALSE ;
2009-06-19 17:48:49 +00:00
}
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
if ( ! caller_profile ) {
caller_profile = switch_channel_get_caller_profile ( channel ) ;
}
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " LCR Lookup on %s \n " , caller_profile - > destination_number ) ;
2009-01-14 02:18:51 +00:00
routes . lookup_number = caller_profile - > destination_number ;
2009-03-27 20:01:54 +00:00
routes . cid = ( char * ) caller_profile - > caller_id_number ;
if ( lcr_do_lookup ( & routes ) = = SWITCH_STATUS_SUCCESS ) {
2009-01-14 02:18:51 +00:00
if ( ( extension = switch_caller_extension_new ( session , caller_profile - > destination_number , caller_profile - > destination_number ) ) = = 0 ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " memory error! \n " ) ;
2009-02-03 21:20:09 +00:00
goto end ;
2009-01-14 02:18:51 +00:00
}
switch_channel_set_variable ( channel , SWITCH_CONTINUE_ON_FAILURE_VARIABLE , " true " ) ;
switch_channel_set_variable ( channel , SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE , " true " ) ;
2010-06-19 20:08:06 -05:00
if ( zstr ( switch_channel_get_variable ( channel , " import " ) ) ) {
switch_channel_set_variable ( channel , " import " , " lcr_carrier,lcr_rate " ) ;
} else {
const char * tmp = switch_channel_get_variable ( channel , " import " ) ;
if ( ! strstr ( tmp , " lcr_carrier,lcr_rate " ) ) {
switch_channel_set_variable_printf ( channel , " import " , " %s,lcr_carrier,lcr_rate " , tmp ) ;
}
}
2009-01-14 02:18:51 +00:00
for ( cur_route = routes . head ; cur_route ; cur_route = cur_route - > next ) {
2010-06-19 20:08:06 -05:00
char * app = NULL ;
char * argc = NULL ;
if ( cur_route - > limit_realm & & cur_route - > limit_id ) {
app = " limit_execute " ;
argc = switch_core_sprintf ( pool , " %s %s %s %d bridge %s " ,
routes . profile - > limit_type ,
cur_route - > limit_realm ,
cur_route - > limit_id ,
cur_route - > limit_max ,
cur_route - > dialstring ) ;
} else {
app = " bridge " ;
argc = cur_route - > dialstring ;
}
switch_caller_extension_add_application ( session , extension , app , argc ) ;
2009-01-14 02:18:51 +00:00
}
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " LCR lookup failed for %s \n " , caller_profile - > destination_number ) ;
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
end :
if ( event ) {
switch_event_destroy ( & event ) ;
}
2009-02-13 21:45:54 +00:00
if ( ! session ) {
2009-02-03 21:20:09 +00:00
switch_core_destroy_memory_pool ( & pool ) ;
}
2009-01-14 02:18:51 +00:00
return extension ;
}
2009-01-15 21:51:15 +00:00
void str_repeat ( size_t how_many , char * what , switch_stream_handle_t * str_stream )
{
2009-01-14 02:18:51 +00:00
size_t i ;
2010-06-19 20:08:06 -05:00
/*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "repeating %d of '%s'\n", (int)how_many, what);*/
for ( i = 0 ; i < how_many ; i + + ) {
2009-01-14 02:18:51 +00:00
str_stream - > write_function ( str_stream , " %s " , what ) ;
}
}
SWITCH_STANDARD_APP ( lcr_app_function )
{
int argc = 0 ;
char * argv [ 4 ] = { 0 } ;
char * mydata = NULL ;
char * dest = NULL ;
char vbuf [ 1024 ] = " " ;
uint32_t cnt = 1 ;
char * lcr_profile = NULL ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
2009-03-28 08:08:48 +00:00
switch_caller_profile_t * caller_profile = NULL ;
2009-01-14 02:18:51 +00:00
callback_t routes = { 0 } ;
lcr_route cur_route = { 0 } ;
2009-02-03 21:20:09 +00:00
switch_memory_pool_t * pool ;
2009-03-20 20:15:39 +00:00
switch_event_t * event ;
2009-06-19 17:48:49 +00:00
const char * intra = NULL ;
2009-01-14 02:18:51 +00:00
if ( ! ( mydata = switch_core_session_strdup ( session , data ) ) ) {
return ;
}
2009-02-13 21:45:54 +00:00
if ( session ) {
2009-02-03 21:20:09 +00:00
pool = switch_core_session_get_pool ( session ) ;
2009-02-20 20:36:04 +00:00
routes . session = session ;
2009-02-03 21:20:09 +00:00
} else {
switch_core_new_memory_pool ( & pool ) ;
2009-03-20 20:15:39 +00:00
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
routes . event = event ;
2009-02-03 21:20:09 +00:00
}
routes . pool = pool ;
2009-06-19 17:48:49 +00:00
intra = switch_channel_get_variable ( channel , " intrastate " ) ;
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " intrastate channel var is [%s] \n " ,
zstr ( intra ) ? " undef " : intra ) ;
if ( zstr ( intra ) | | strcasecmp ( ( char * ) intra , " true " ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Select routes based on interstate rates \n " ) ;
2009-06-19 17:48:49 +00:00
routes . intrastate = SWITCH_FALSE ;
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Select routes based on intrastate rates \n " ) ;
2009-06-19 17:48:49 +00:00
routes . intrastate = SWITCH_TRUE ;
}
2009-03-28 08:08:48 +00:00
if ( ! caller_profile ) {
if ( ! ( caller_profile = switch_channel_get_caller_profile ( channel ) ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Unable to locate caller_profile \n " ) ;
2009-03-28 08:08:48 +00:00
}
}
2009-01-14 02:18:51 +00:00
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
dest = argv [ 0 ] ;
2009-02-13 21:45:54 +00:00
if ( argc > 1 ) {
2009-01-14 02:18:51 +00:00
lcr_profile = argv [ 1 ] ;
}
2010-06-19 20:08:06 -05:00
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " LCR Lookup on %s using profile %s \n " , dest , lcr_profile ) ;
2009-01-14 02:18:51 +00:00
routes . lookup_number = dest ;
2009-03-28 08:08:48 +00:00
if ( caller_profile ) {
2009-06-04 13:56:28 +00:00
routes . cid = ( char * ) switch_channel_get_variable ( channel , " effective_caller_id_number " ) ;
if ( ! routes . cid ) {
routes . cid = ( char * ) caller_profile - > caller_id_number ;
}
2009-03-28 08:08:48 +00:00
}
2009-09-30 14:52:19 +00:00
2010-06-19 20:08:06 -05:00
2009-02-20 20:28:18 +00:00
if ( ! ( routes . profile = locate_profile ( lcr_profile ) ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_ERROR , " Unknown profile: %s \n " , lcr_profile ) ;
2009-02-20 20:28:18 +00:00
goto end ;
}
2009-03-27 20:01:54 +00:00
if ( lcr_do_lookup ( & routes ) = = SWITCH_STATUS_SUCCESS ) {
2010-03-19 21:45:33 +00:00
switch_stream_handle_t dig_stream = { 0 } ;
SWITCH_STANDARD_STREAM ( dig_stream ) ;
2009-01-14 02:18:51 +00:00
for ( cur_route = routes . head ; cur_route ; cur_route = cur_route - > next ) {
2009-04-02 12:32:18 +00:00
switch_snprintf ( vbuf , sizeof ( vbuf ) , " lcr_route_%d " , cnt ) ;
2009-01-14 02:18:51 +00:00
switch_channel_set_variable ( channel , vbuf , cur_route - > dialstring ) ;
2009-04-02 12:32:18 +00:00
switch_snprintf ( vbuf , sizeof ( vbuf ) , " lcr_rate_%d " , cnt ) ;
switch_channel_set_variable ( channel , vbuf , cur_route - > rate_str ) ;
switch_snprintf ( vbuf , sizeof ( vbuf ) , " lcr_carrier_%d " , cnt ) ;
switch_channel_set_variable ( channel , vbuf , cur_route - > carrier_name ) ;
switch_snprintf ( vbuf , sizeof ( vbuf ) , " lcr_codec_%d " , cnt ) ;
switch_channel_set_variable ( channel , vbuf , cur_route - > codec ) ;
cnt + + ;
2010-03-19 21:45:33 +00:00
if ( cur_route - > next ) {
2010-06-19 08:08:42 -05:00
if ( routes . profile - > enable_sip_redir ) {
dig_stream . write_function ( & dig_stream , " %s, " , cur_route - > dialstring ) ;
} else {
dig_stream . write_function ( & dig_stream , " %s| " , cur_route - > dialstring ) ;
}
2010-03-19 21:45:33 +00:00
} else {
dig_stream . write_function ( & dig_stream , " %s " , cur_route - > dialstring ) ;
}
2010-06-19 20:08:06 -05:00
cnt + + ;
2009-01-14 02:18:51 +00:00
}
2010-03-19 21:45:33 +00:00
2009-01-14 02:18:51 +00:00
switch_snprintf ( vbuf , sizeof ( vbuf ) , " %d " , cnt - 1 ) ;
switch_channel_set_variable ( channel , " lcr_route_count " , vbuf ) ;
2010-03-19 21:45:33 +00:00
switch_channel_set_variable ( channel , " lcr_auto_route " , ( char * ) dig_stream . data ) ;
2010-06-19 20:08:06 -05:00
if ( zstr ( switch_channel_get_variable ( channel , " import " ) ) ) {
switch_channel_set_variable ( channel , " import " , " lcr_carrier,lcr_rate " ) ;
} else {
const char * tmp = switch_channel_get_variable ( channel , " import " ) ;
if ( ! strstr ( tmp , " lcr_carrier,lcr_rate " ) ) {
switch_channel_set_variable_printf ( channel , " import " , " %s,lcr_carrier,lcr_rate " , tmp ) ;
}
}
2010-03-19 21:45:33 +00:00
free ( dig_stream . data ) ;
2009-01-14 02:18:51 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " LCR lookup failed for %s \n " , dest ) ;
2009-01-14 02:18:51 +00:00
}
}
2010-06-19 20:08:06 -05:00
end :
if ( routes . event ) {
switch_event_destroy ( & event ) ;
}
2009-02-13 21:45:54 +00:00
if ( ! session ) {
2009-02-03 21:20:09 +00:00
switch_core_destroy_memory_pool ( & pool ) ;
}
2009-01-14 02:18:51 +00:00
}
2010-06-19 20:08:06 -05:00
static void write_data ( switch_stream_handle_t * stream , switch_bool_t as_xml , const char * key , const char * data , int indent , int maxlen ) {
if ( ! data ) {
data = " " ;
}
2009-07-21 18:43:00 +00:00
if ( as_xml ) {
2010-06-19 20:08:06 -05:00
str_repeat ( indent * 2 , " " , stream ) ;
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " <%s>%s</%s> \n " , key , data , key ) ;
} else {
stream - > write_function ( stream , " | %s " , data ) ;
str_repeat ( ( maxlen - strlen ( data ) ) , " " , stream ) ;
}
}
2009-01-15 21:51:15 +00:00
SWITCH_STANDARD_API ( dialplan_lcr_function )
{
2009-01-14 02:18:51 +00:00
char * argv [ 4 ] = { 0 } ;
int argc ;
char * mydata = NULL ;
char * dialstring = NULL ;
char * lcr_profile = NULL ;
lcr_route current = NULL ;
max_obj_t maximum_lengths = { 0 } ;
callback_t cb_struct = { 0 } ;
2009-07-29 21:30:05 +00:00
switch_memory_pool_t * pool = NULL ;
2009-03-20 20:15:39 +00:00
switch_event_t * event ;
2009-01-14 02:18:51 +00:00
switch_status_t lookup_status = SWITCH_STATUS_SUCCESS ;
2009-07-21 18:43:00 +00:00
switch_bool_t as_xml = SWITCH_FALSE ;
2010-06-19 20:08:06 -05:00
char * event_str = NULL ;
switch_xml_t event_xml = NULL ;
int rowcount = 0 ;
2009-01-14 02:18:51 +00:00
2009-10-23 16:03:42 +00:00
if ( zstr ( cmd ) ) {
2009-01-14 02:18:51 +00:00
goto usage ;
}
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG
, " data passed to lcr is [%s] \n " , cmd
) ;
2009-06-19 14:46:51 +00:00
2009-02-20 20:36:04 +00:00
if ( session ) {
pool = switch_core_session_get_pool ( session ) ;
cb_struct . session = session ;
} else {
switch_core_new_memory_pool ( & pool ) ;
2009-03-20 20:15:39 +00:00
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
cb_struct . event = event ;
2009-02-20 20:36:04 +00:00
}
cb_struct . pool = pool ;
2010-06-19 20:08:06 -05:00
2009-02-03 21:20:09 +00:00
mydata = switch_core_strdup ( pool , cmd ) ;
2009-01-14 02:18:51 +00:00
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2009-02-03 22:19:31 +00:00
switch_assert ( argv [ 0 ] ! = NULL ) ;
2009-03-27 20:01:54 +00:00
cb_struct . lookup_number = switch_core_strdup ( pool , argv [ 0 ] ) ;
2009-02-13 21:45:54 +00:00
if ( argc > 1 ) {
2009-01-14 02:18:51 +00:00
lcr_profile = argv [ 1 ] ;
}
2009-03-27 20:01:54 +00:00
if ( argc > 2 ) {
2009-06-19 14:46:51 +00:00
int i ;
2010-06-19 20:08:06 -05:00
for ( i = 2 ; i < argc ; i + + ) {
2009-06-19 14:46:51 +00:00
if ( ! strcasecmp ( argv [ i ] , " intrastate " ) ) {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Select routes based on intrastate rates \n " ) ;
2009-06-19 14:46:51 +00:00
cb_struct . intrastate = SWITCH_TRUE ;
2009-12-11 01:20:26 +00:00
} else if ( ! strcasecmp ( argv [ i ] , " as " ) ) {
2009-07-21 18:43:00 +00:00
i + + ;
2009-12-11 01:20:26 +00:00
if ( argv [ i ] & & ! strcasecmp ( argv [ i ] , " xml " ) ) {
2010-06-19 20:08:06 -05:00
as_xml = SWITCH_TRUE ;
} else {
goto usage ;
}
2009-06-19 14:46:51 +00:00
} else {
2009-08-13 21:24:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Set Caller ID to [%s] \n " , argv [ i ] ) ;
2009-06-19 14:46:51 +00:00
/* the only other option we have right now is caller id */
cb_struct . cid = switch_core_strdup ( pool , argv [ i ] ) ;
}
}
2010-06-19 20:08:06 -05:00
}
2009-10-23 16:03:42 +00:00
if ( zstr ( cb_struct . cid ) ) {
2009-03-27 20:01:54 +00:00
cb_struct . cid = " 18005551212 " ;
2010-06-19 20:08:06 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING
, " Using default CID [%s] \n " , cb_struct . cid
) ;
2009-03-27 20:01:54 +00:00
}
2009-06-19 14:46:51 +00:00
2009-02-13 21:45:54 +00:00
if ( ! ( cb_struct . profile = locate_profile ( lcr_profile ) ) ) {
2009-02-11 21:33:22 +00:00
stream - > write_function ( stream , " -ERR Unknown profile: %s \n " , lcr_profile ) ;
goto end ;
}
2009-01-14 02:18:51 +00:00
2009-03-27 20:01:54 +00:00
lookup_status = lcr_do_lookup ( & cb_struct ) ;
2009-06-19 14:46:51 +00:00
2009-01-14 02:18:51 +00:00
if ( cb_struct . head ! = NULL ) {
size_t len ;
2009-07-21 18:43:00 +00:00
if ( as_xml ) {
stream - > write_function ( stream , " <result> \n " ) ;
} else {
process_max_lengths ( & maximum_lengths , cb_struct . head , cb_struct . lookup_number ) ;
2009-03-27 20:01:54 +00:00
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_DIGITS ] ) ;
if ( ( len = ( maximum_lengths . digit_str - strlen ( headers [ LCR_HEADERS_DIGITS ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_CARRIER ] ) ;
if ( ( len = ( maximum_lengths . carrier_name - strlen ( headers [ LCR_HEADERS_CARRIER ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_RATE ] ) ;
if ( ( len = ( maximum_lengths . rate - strlen ( headers [ LCR_HEADERS_RATE ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_CODEC ] ) ;
if ( ( len = ( maximum_lengths . codec - strlen ( headers [ LCR_HEADERS_CODEC ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_CID ] ) ;
if ( ( len = ( maximum_lengths . cid - strlen ( headers [ LCR_HEADERS_CID ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
2010-06-19 20:08:06 -05:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_LIMIT ] ) ;
if ( ( len = ( maximum_lengths . limit - strlen ( headers [ LCR_HEADERS_LIMIT ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_DIALSTRING ] ) ;
if ( ( len = ( maximum_lengths . dialstring - strlen ( headers [ LCR_HEADERS_DIALSTRING ] ) ) ) > 0 ) {
str_repeat ( len , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " | \n " ) ;
}
2009-01-14 02:18:51 +00:00
current = cb_struct . head ;
while ( current ) {
2009-07-17 22:41:40 +00:00
dialstring = get_bridge_data ( pool , cb_struct . lookup_number , cb_struct . cid , current , cb_struct . profile , cb_struct . session ) ;
2009-07-21 18:43:00 +00:00
rowcount + + ;
2009-01-14 02:18:51 +00:00
2009-07-21 18:43:00 +00:00
if ( as_xml ) {
stream - > write_function ( stream , " <row id= \" %d \" > \n " , rowcount ) ;
}
2010-06-19 20:08:06 -05:00
2009-07-21 18:43:00 +00:00
write_data ( stream , as_xml , " prefix " , current - > digit_str , 2 , maximum_lengths . digit_str ) ;
write_data ( stream , as_xml , " carrier_name " , current - > carrier_name , 2 , maximum_lengths . carrier_name ) ;
write_data ( stream , as_xml , " rate " , current - > rate_str , 2 , maximum_lengths . rate ) ;
2009-03-27 20:01:54 +00:00
if ( current - > codec ) {
2009-07-21 18:43:00 +00:00
write_data ( stream , as_xml , " codec " , current - > codec , 2 , maximum_lengths . codec ) ;
2009-03-27 20:01:54 +00:00
} else {
2009-07-21 18:43:00 +00:00
write_data ( stream , as_xml , " codec " , " " , 2 , maximum_lengths . codec ) ;
2009-03-27 20:01:54 +00:00
}
if ( current - > cid ) {
2009-07-21 18:43:00 +00:00
write_data ( stream , as_xml , " cid " , current - > cid , 2 , maximum_lengths . cid ) ;
2009-03-27 20:01:54 +00:00
} else {
2009-07-21 18:43:00 +00:00
write_data ( stream , as_xml , " cid " , " " , 2 , maximum_lengths . cid ) ;
2009-03-27 20:01:54 +00:00
}
2010-06-19 20:08:06 -05:00
if ( current - > limit_realm & & current - > limit_id ) {
char * str = NULL ;
str = switch_core_sprintf ( pool , " %s %s %d " , current - > limit_realm , current - > limit_id , current - > limit_max ) ;
write_data ( stream , as_xml , " limit " , str , 2 , maximum_lengths . limit ) ;
} else {
write_data ( stream , as_xml , " limit " , " " , 2 , maximum_lengths . limit ) ;
}
2009-07-21 18:43:00 +00:00
write_data ( stream , as_xml , " dialstring " , current - > dialstring , 2 , maximum_lengths . dialstring ) ;
2010-06-19 20:08:06 -05:00
if ( as_xml ) {
event_xml = switch_event_xmlize ( current - > fields , NULL ) ;
event_str = switch_xml_toxml ( event_xml , SWITCH_FALSE ) ;
stream - > write_function ( stream , event_str ) ;
switch_xml_free ( event_xml ) ;
switch_safe_free ( event_str ) ;
}
2009-07-21 18:43:00 +00:00
if ( as_xml ) {
stream - > write_function ( stream , " </row> \n " ) ;
} else {
stream - > write_function ( stream , " | \n " ) ;
}
2009-01-14 02:18:51 +00:00
current = current - > next ;
}
2009-07-21 18:43:00 +00:00
if ( as_xml ) {
stream - > write_function ( stream , " </result> \n " ) ;
}
2009-01-14 02:18:51 +00:00
} else {
2009-02-13 21:45:54 +00:00
if ( lookup_status = = SWITCH_STATUS_SUCCESS ) {
2009-07-21 18:43:00 +00:00
if ( as_xml ) {
stream - > write_function ( stream , " <result row_count= \" 0 \" > \n </results> \n " ) ;
} else {
stream - > write_function ( stream , " No Routes To Display \n " ) ;
}
2009-01-14 02:18:51 +00:00
} else {
2009-07-21 18:43:00 +00:00
stream - > write_function ( stream , " -ERR Error looking up routes \n " ) ;
2009-01-14 02:18:51 +00:00
}
}
}
2010-06-19 20:08:06 -05:00
end :
2009-02-20 20:36:04 +00:00
if ( ! session ) {
2009-07-21 18:43:00 +00:00
if ( pool ) {
switch_core_destroy_memory_pool ( & pool ) ;
}
2009-02-20 20:36:04 +00:00
}
2009-01-14 02:18:51 +00:00
return SWITCH_STATUS_SUCCESS ;
2010-06-19 20:08:06 -05:00
usage :
2009-01-14 02:18:51 +00:00
stream - > write_function ( stream , " USAGE: %s \n " , LCR_SYNTAX ) ;
2009-07-21 18:43:00 +00:00
goto end ;
2009-01-14 02:18:51 +00:00
}
2009-02-11 05:07:37 +00:00
SWITCH_STANDARD_API ( dialplan_lcr_admin_function )
{
char * argv [ 4 ] = { 0 } ;
int argc ;
char * mydata = NULL ;
switch_hash_index_t * hi ;
void * val ;
profile_t * profile ;
2009-10-23 16:03:42 +00:00
if ( zstr ( cmd ) ) {
2009-02-11 05:07:37 +00:00
goto usage ;
}
mydata = strdup ( cmd ) ;
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2009-02-13 21:45:54 +00:00
if ( argc < 2 ) {
2009-02-11 05:07:37 +00:00
goto usage ;
}
2009-02-11 18:08:04 +00:00
switch_assert ( argv [ 0 ] ) ;
2009-02-13 21:45:54 +00:00
if ( ! strcasecmp ( argv [ 0 ] , " show " ) & & ! strcasecmp ( argv [ 1 ] , " profiles " ) ) {
2009-02-11 05:07:37 +00:00
for ( hi = switch_hash_first ( NULL , globals . profile_hash ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , NULL , NULL , & val ) ;
profile = ( profile_t * ) val ;
2010-06-19 20:08:06 -05:00
2009-02-11 05:07:37 +00:00
stream - > write_function ( stream , " Name: \t \t %s \n " , profile - > name ) ;
2009-10-23 16:03:42 +00:00
if ( zstr ( profile - > custom_sql ) ) {
2009-02-11 21:33:22 +00:00
stream - > write_function ( stream , " ID: \t \t %d \n " , profile - > id ) ;
stream - > write_function ( stream , " order by: \t %s \n " , profile - > order_by ) ;
2009-02-11 16:52:29 +00:00
} else {
2009-02-11 21:33:22 +00:00
stream - > write_function ( stream , " custom sql: \t %s \n " , profile - > custom_sql ) ;
2009-02-20 20:36:04 +00:00
stream - > write_function ( stream , " has %%: \t \t %s \n " , profile - > custom_sql_has_percent ? " true " : " false " ) ;
stream - > write_function ( stream , " has vars: \t %s \n " , profile - > custom_sql_has_vars ? " true " : " false " ) ;
2009-02-11 05:07:37 +00:00
}
2009-07-16 15:38:16 +00:00
stream - > write_function ( stream , " has intrastate: \t %s \n " , profile - > profile_has_intrastate ? " true " : " false " ) ;
stream - > write_function ( stream , " has intralata: \t %s \n " , profile - > profile_has_intralata ? " true " : " false " ) ;
stream - > write_function ( stream , " has npanxx: \t %s \n " , profile - > profile_has_npanxx ? " true " : " false " ) ;
2010-06-19 20:08:06 -05:00
stream - > write_function ( stream , " Reorder rate: \t %s \n " ,
profile - > reorder_by_rate ? " enabled " : " disabled " ) ;
stream - > write_function ( stream , " Info in headers: \t %s \n " ,
profile - > info_in_headers ? " enabled " : " disabled " ) ;
stream - > write_function ( stream , " Quote IN() List: \t %s \n " ,
profile - > quote_in_list ? " enabled " : " disabled " ) ;
stream - > write_function ( stream , " Sip Redirection Mode: \t %s \n " ,
profile - > enable_sip_redir ? " enabled " : " disabled " ) ;
stream - > write_function ( stream , " Import fields: \t %s \n " ,
profile - > export_fields_str ? profile - > export_fields_str : " (null) " ) ;
stream - > write_function ( stream , " Limit type: \t %s \n " , profile - > limit_type ) ;
2009-02-11 05:07:37 +00:00
stream - > write_function ( stream , " \n " ) ;
}
} else {
goto usage ;
}
}
switch_safe_free ( mydata ) ;
return SWITCH_STATUS_SUCCESS ;
2010-06-19 20:08:06 -05:00
usage :
2009-02-11 05:07:37 +00:00
switch_safe_free ( mydata ) ;
stream - > write_function ( stream , " -ERR %s \n " , LCR_ADMIN_SYNTAX ) ;
return SWITCH_STATUS_SUCCESS ;
2010-06-19 20:08:06 -05:00
2009-02-11 05:07:37 +00:00
}
2010-06-19 20:08:06 -05:00
2009-01-15 21:51:15 +00:00
SWITCH_MODULE_LOAD_FUNCTION ( mod_lcr_load )
{
2009-01-14 02:18:51 +00:00
switch_api_interface_t * dialplan_lcr_api_interface ;
2009-02-11 05:07:37 +00:00
switch_api_interface_t * dialplan_lcr_api_admin_interface ;
2009-01-14 02:18:51 +00:00
switch_application_interface_t * app_interface ;
switch_dialplan_interface_t * dp_interface ;
2010-06-19 20:08:06 -05:00
2009-01-14 02:18:51 +00:00
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
2009-06-24 16:02:43 +00:00
if ( ! switch_odbc_available ( ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " You must have ODBC support in FreeSWITCH to use this module \n " ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " \t ./configure --enable-core-odbc-support \n " ) ;
return SWITCH_STATUS_FALSE ;
}
2009-01-14 02:18:51 +00:00
2009-02-23 20:46:46 +00:00
globals . pool = pool ;
2009-01-14 02:18:51 +00:00
if ( switch_mutex_init ( & globals . mutex , SWITCH_MUTEX_NESTED , globals . pool ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " failed to initialize mutex \n " ) ;
}
2009-03-20 20:15:39 +00:00
if ( lcr_load_config ( ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unable to load lcr config file \n " ) ;
return SWITCH_STATUS_FALSE ;
}
2009-01-14 02:18:51 +00:00
SWITCH_ADD_API ( dialplan_lcr_api_interface , " lcr " , " Least Cost Routing Module " , dialplan_lcr_function , LCR_SYNTAX ) ;
2009-02-11 05:07:37 +00:00
SWITCH_ADD_API ( dialplan_lcr_api_admin_interface , " lcr_admin " , " Least Cost Routing Module Admin " , dialplan_lcr_admin_function , LCR_ADMIN_SYNTAX ) ;
2009-01-14 02:18:51 +00:00
SWITCH_ADD_APP ( app_interface , " lcr " , " Perform an LCR lookup " , " Perform an LCR lookup " ,
2009-09-18 22:55:33 +00:00
lcr_app_function , " <number> " , SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC ) ;
2009-01-14 02:18:51 +00:00
SWITCH_ADD_DIALPLAN ( dp_interface , " lcr " , lcr_dialplan_hunt ) ;
2010-02-06 03:38:24 +00:00
2010-06-19 20:08:06 -05:00
lcr_endpoint_interface = switch_loadable_module_create_interface ( * module_interface , SWITCH_ENDPOINT_INTERFACE ) ;
lcr_endpoint_interface - > interface_name = " lcr " ;
lcr_endpoint_interface - > io_routines = & lcr_io_routines ;
2009-01-14 02:18:51 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
2009-01-15 21:51:15 +00:00
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_lcr_shutdown )
{
2009-02-20 20:36:04 +00:00
2009-02-03 21:20:09 +00:00
switch_core_hash_destroy ( & globals . profile_hash ) ;
2009-02-23 20:46:46 +00:00
2009-01-14 02:18:51 +00:00
return SWITCH_STATUS_SUCCESS ;
}
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2009-09-14 22:03:37 +00:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 :
2009-01-14 02:18:51 +00:00
*/