2009-01-14 02:18:51 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
2009-02-13 23:37:37 +00:00
* Copyright ( C ) 2005 - 2009 , 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>
# include <switch_odbc.h>
2009-03-27 20:01:54 +00:00
# define LCR_SYNTAX "lcr <digits> [<lcr profile>] [caller_id]"
2009-02-11 05:07:37 +00:00
# define LCR_ADMIN_SYNTAX "lcr_admin show profiles"
2009-01-14 02:18:51 +00:00
/* SQL Query places */
# define LCR_DIGITS_PLACE 0
# define LCR_CARRIER_PLACE 1
# define LCR_RATE_PLACE 2
# define LCR_GW_PREFIX_PLACE 3
# define LCR_GW_SUFFIX_PLACE 4
# define LCR_LSTRIP_PLACE 5
# define LCR_TSTRIP_PLACE 6
# define LCR_PREFIX_PLACE 7
# define LCR_SUFFIX_PLACE 8
2009-03-20 20:15:39 +00:00
# define LCR_CODEC_PLACE 9
2009-03-27 20:01:54 +00:00
# define LCR_CID_PLACE 10
2009-01-14 02:18:51 +00:00
2009-03-20 20:15:39 +00:00
# define LCR_QUERY_COLS_REQUIRED 9
2009-03-27 20:01:54 +00:00
# define LCR_QUERY_COLS 11
2009-01-14 02:18:51 +00:00
2009-03-27 20:01:54 +00:00
# define LCR_HEADERS_COUNT 6
# 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
# define LCR_
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 " ,
" CID Regexp "
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 odbc_obj {
switch_odbc_handle_t * handle ;
SQLHSTMT stmt ;
SQLCHAR * colbuf ;
int32_t cblen ;
SQLCHAR * code ;
int32_t codelen ;
} ;
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 ;
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 ;
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 ;
} ;
typedef struct odbc_obj odbc_obj_t ;
typedef odbc_obj_t * odbc_handle ;
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 16:52:29 +00:00
char * pre_order ;
2009-02-11 00:18:50 +00:00
char * custom_sql ;
2009-02-20 20:36:04 +00:00
switch_bool_t custom_sql_has_percent ;
switch_bool_t custom_sql_has_vars ;
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-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-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 ;
switch_mutex_t * mutex ;
2009-02-03 15:59:46 +00:00
switch_mutex_t * db_mutex ;
2009-01-14 02:18:51 +00:00
switch_odbc_handle_t * master_odbc ;
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-03-27 20:01:54 +00:00
static const char * do_cid ( switch_memory_pool_t * pool , const char * cid , const char * number )
{
switch_regex_t * re = NULL ;
int proceed = 0 , ovector [ 30 ] ;
char * substituted = NULL ;
uint32_t len = 0 ;
char * src = NULL ;
char * dst = NULL ;
if ( ! switch_strlen_zero ( cid ) ) {
len = strlen ( cid ) ;
} else {
goto done ;
}
src = switch_core_strdup ( pool , cid ) ;
/* check that this is a valid regexp and split the string */
if ( ( src [ 0 ] = = ' / ' ) & & src [ len - 1 ] = = ' / ' ) {
/* strip leading / trailing slashes */
src [ len - 1 ] = ' \0 ' ;
src + + ;
/* break on first / */
dst = strchr ( src , ' / ' ) ;
* dst = ' \0 ' ;
dst + + ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " src: %s, dst: %s \n " , src , dst ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Not a valid regexp: %s \n " , src ) ;
goto done ;
}
if ( ( proceed = switch_regex_perform ( number , src , & re , ovector , sizeof ( ovector ) / sizeof ( ovector [ 0 ] ) ) ) ) {
len = ( uint32_t ) ( strlen ( src ) + strlen ( dst ) + 10 ) * proceed ; /* guestimate size */
if ( ! ( substituted = switch_core_alloc ( pool , len ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Memory Error! \n " ) ;
goto done ;
}
memset ( substituted , 0 , len ) ;
switch_perform_substitution ( re , proceed , dst , number , substituted , len , ovector ) ;
} else {
goto done ;
}
switch_regex_safe_free ( re ) ;
return substituted ;
done :
switch_regex_safe_free ( re ) ;
return number ;
}
static char * get_bridge_data ( switch_memory_pool_t * pool , char * dialed_number , char * caller_id , lcr_route cur_route )
2009-01-15 21:51:15 +00:00
{
2009-01-14 02:18:51 +00:00
size_t lstrip ;
size_t tstrip ;
char * data = NULL ;
char * destination_number = NULL ;
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-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 ) ;
2009-01-14 02:18:51 +00:00
tstrip = ( ( cur_route - > digit_len - cur_route - > tstrip ) + 1 ) ;
lstrip = cur_route - > lstrip ;
if ( strlen ( destination_number ) > tstrip & & cur_route - > tstrip > 0 ) {
destination_number [ tstrip ] = ' \0 ' ;
}
if ( strlen ( destination_number ) > lstrip & & cur_route - > lstrip > 0 ) {
destination_number + = lstrip ;
}
2009-03-20 20:15:39 +00:00
codec = " " ;
if ( ! switch_strlen_zero ( cur_route - > codec ) ) {
codec = switch_core_sprintf ( pool , " ,absolute_codec_string=%s " , cur_route - > codec ) ;
}
2009-03-27 20:01:54 +00:00
cid = " " ;
if ( ! switch_strlen_zero ( cur_route - > cid ) ) {
cid = switch_core_sprintf ( pool , " ,effective_caller_id_number=%s " ,
do_cid ( pool , cur_route - > cid , caller_id ) ) ;
}
data = switch_core_sprintf ( pool , " [lcr_carrier=%s,lcr_rate=%s%s%s]%s%s%s%s%s "
2009-02-12 23:52:03 +00:00
, cur_route - > carrier_name , cur_route - > rate_str
2009-03-27 20:01:54 +00:00
, codec , cid
2009-02-12 23:52:03 +00:00
, cur_route - > gw_prefix , cur_route - > prefix
2009-02-03 21:31:41 +00:00
, destination_number , cur_route - > suffix , cur_route - > gw_suffix ) ;
2009-01-14 02:18:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Returning Dialstring %s \n " , data ) ;
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 ;
2009-02-13 21:45:54 +00:00
if ( switch_strlen_zero ( 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 ) ;
}
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 ] ) ) ;
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 ;
if ( current - > carrier_name ! = NULL ) {
this_len = strlen ( current - > carrier_name ) ;
if ( this_len > maxes - > carrier_name ) {
maxes - > carrier_name = this_len ;
}
}
if ( current - > dialstring ! = NULL ) {
this_len = strlen ( current - > dialstring ) ;
if ( this_len > maxes - > dialstring ) {
maxes - > dialstring = this_len ;
}
}
if ( current - > digit_str ! = NULL ) {
if ( current - > digit_len > maxes - > digit_str ) {
maxes - > digit_str = current - > digit_len ;
}
}
if ( current - > rate_str ! = NULL ) {
this_len = strlen ( current - > rate_str ) ;
if ( this_len > maxes - > rate ) {
maxes - > rate = this_len ;
}
}
2009-03-27 20:01:54 +00:00
if ( current - > codec ! = NULL ) {
this_len = strlen ( current - > codec ) ;
if ( this_len > maxes - > codec ) {
maxes - > codec = this_len ;
}
}
if ( current - > cid ! = NULL ) {
this_len = strlen ( current - > cid ) ;
if ( this_len > maxes - > cid ) {
maxes - > cid = this_len ;
}
}
2009-01-14 02:18:51 +00:00
}
return SWITCH_STATUS_SUCCESS ;
}
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-01-14 02:18:51 +00:00
if ( globals . odbc_dsn ) {
2009-03-20 20:15:39 +00:00
if ( switch_odbc_handle_exec ( globals . master_odbc , sql , NULL ) = = SWITCH_ODBC_SUCCESS ) {
2009-01-14 02:18:51 +00:00
return SWITCH_TRUE ;
}
}
2009-03-20 20:15:39 +00:00
return SWITCH_FALSE ;
}
/* 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 ;
}
if ( db_check ( " SELECT random(); " ) = = SWITCH_TRUE ) {
db_random = " random() " ;
return SWITCH_TRUE ;
}
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 */
2009-02-03 21:20:09 +00: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 ;
p = ( char * ) str ;
len = strlen ( str ) ;
2009-02-03 21:20:09 +00:00
newstr = switch_core_alloc ( pool , len + 1 ) ;
2009-01-15 20:32:25 +00:00
np = newstr ;
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 ) ;
for ( n = digit_len ; n > 0 ; n - - ) {
digits_copy [ n ] = ' \0 ' ;
2009-03-16 15:54:44 +00: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 )
{
2009-02-20 22:00:24 +00:00
char * tmpSQL = NULL ;
char * newSQL = NULL ;
2009-02-20 20:36:04 +00:00
switch_channel_t * channel ;
/* 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 ;
}
/* 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 ) ;
/*
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 ) ;
2009-02-20 20:36:04 +00:00
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT ,
" mod_lcr called without a valid session while using a custom_sql that has channel variables. \n " ) ;
}
}
2009-03-05 04:08:31 +00:00
if ( tmpSQL ! = newSQL ) {
2009-02-20 20:36:04 +00:00
switch_safe_free ( tmpSQL ) ;
}
2009-02-20 22:00:24 +00: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 ;
switch_mutex_lock ( globals . db_mutex ) ;
2009-01-14 02:18:51 +00:00
if ( globals . odbc_dsn ) {
2009-02-13 21:45:54 +00:00
if ( switch_odbc_handle_callback_exec ( globals . master_odbc , sql , callback , pdata )
2009-01-14 02:18:51 +00:00
= = SWITCH_ODBC_FAIL ) {
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
}
}
2009-02-03 15:59:46 +00:00
switch_mutex_unlock ( globals . db_mutex ) ;
return retval ;
2009-01-14 02:18:51 +00:00
}
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 ;
2009-02-11 21:33:22 +00:00
2009-02-03 21:20:09 +00:00
switch_memory_pool_t * pool = cbt - > pool ;
2009-01-14 02:18:51 +00:00
2009-02-11 00:18:50 +00:00
2009-03-20 20:15:39 +00:00
if ( argc < LCR_QUERY_COLS_REQUIRED ) {
2009-02-11 00:18:50 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT ,
2009-03-20 20:15:39 +00:00
" Unexpected number of columns returned for SQL. Returned column count: %d. "
2009-02-11 00:18:50 +00:00
" If using a custom sql for this profile, verify it is correct. Otherwise file a bug report. \n " ,
argc ) ;
return SWITCH_STATUS_GENERR ;
}
2009-01-14 02:18:51 +00:00
2009-01-28 01:50:45 +00:00
if ( switch_strlen_zero ( argv [ LCR_GW_PREFIX_PLACE ] ) & & switch_strlen_zero ( argv [ LCR_GW_SUFFIX_PLACE ] ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING ,
" There's no way to dial this Gateway: Carrier: \" %s \" Prefix: \" %s \" , Suffix \" %s \" \n " ,
switch_str_nil ( argv [ LCR_CARRIER_PLACE ] ) ,
switch_str_nil ( argv [ LCR_GW_PREFIX_PLACE ] ) , switch_str_nil ( argv [ LCR_GW_SUFFIX_PLACE ] ) ) ;
return SWITCH_STATUS_SUCCESS ;
}
2009-02-11 21:33:22 +00:00
cbt - > matches + + ;
2009-02-03 21:20:09 +00:00
additional = switch_core_alloc ( pool , sizeof ( lcr_obj_t ) ) ;
2009-01-14 02:18:51 +00:00
additional - > digit_len = strlen ( argv [ LCR_DIGITS_PLACE ] ) ;
2009-02-03 21:41:48 +00:00
additional - > digit_str = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_DIGITS_PLACE ] ) ) ;
additional - > suffix = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_SUFFIX_PLACE ] ) ) ;
additional - > prefix = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_PREFIX_PLACE ] ) ) ;
additional - > carrier_name = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_CARRIER_PLACE ] ) ) ;
additional - > rate = ( float ) atof ( switch_str_nil ( argv [ LCR_RATE_PLACE ] ) ) ;
2009-02-03 21:20:09 +00:00
additional - > rate_str = switch_core_sprintf ( pool , " %0.5f " , additional - > rate ) ;
2009-02-03 21:41:48 +00:00
additional - > gw_prefix = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_GW_PREFIX_PLACE ] ) ) ;
additional - > gw_suffix = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_GW_SUFFIX_PLACE ] ) ) ;
additional - > lstrip = atoi ( switch_str_nil ( argv [ LCR_LSTRIP_PLACE ] ) ) ;
additional - > tstrip = atoi ( switch_str_nil ( argv [ LCR_TSTRIP_PLACE ] ) ) ;
2009-03-20 20:15:39 +00:00
if ( argc > LCR_CODEC_PLACE ) {
additional - > codec = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_CODEC_PLACE ] ) ) ;
}
2009-03-27 20:01:54 +00:00
if ( argc > LCR_CID_PLACE ) {
additional - > cid = switch_core_strdup ( pool , switch_str_nil ( argv [ LCR_CID_PLACE ] ) ) ;
}
additional - > dialstring = get_bridge_data ( pool , cbt - > lookup_number , cbt - > cid , additional ) ;
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 ;
}
2009-02-12 01:18:43 +00:00
2009-01-14 02:18:51 +00:00
for ( current = cbt - > head ; current ; current = current - > next ) {
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 ) ) {
2009-01-28 01:50:45 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG ,
2009-02-12 01:18:43 +00:00
" 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 ) {
2009-02-11 21:33:22 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Adding %s before %s \n " ,
additional - > carrier_name , current - > carrier_name ) ;
current - > prev - > next = additional ;
} else {
/* put this one at the head */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Inserting %s to list head before %s \n " ,
additional - > carrier_name , current - > carrier_name ) ;
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 " ,
additional - > carrier_name , current - > 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 ;
}
2009-01-14 02:18:51 +00:00
}
}
return SWITCH_STATUS_SUCCESS ;
}
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-03-20 22:38:38 +00:00
char * safe_sql ;
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 ) ;
if ( switch_strlen_zero ( digits_copy ) ) {
2009-03-20 20:23:32 +00:00
return SWITCH_STATUS_GENERR ;
2009-01-14 02:18:51 +00: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-02-12 01:18:43 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , 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
}
2009-03-16 15:54:44 +00:00
digits_expanded = expand_digits ( cb_struct - > pool , digits_copy , cb_struct - > profile - > quote_in_list ) ;
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 ) {
if ( ( channel = switch_core_session_get_channel ( cb_struct - > session ) ) ) {
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 ) {
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-02-20 20:36:04 +00:00
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_event_safe_destroy ( & cb_struct - > event ) ;
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
}
2009-02-20 20:36:04 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " SQL: %s \n " , ( char * ) sql_stream . data ) ;
2009-01-14 02:18:51 +00:00
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-03-23 15:34:46 +00:00
switch_event_safe_destroy ( & cb_struct - > event ) ;
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 ;
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 ;
}
routes . lookup_number = " 15555551212 " ;
2009-03-27 20:01:54 +00:00
routes . cid = " 18005551212 " ;
return ( lcr_do_lookup ( & routes ) = = SWITCH_STATUS_SUCCESS ) ?
2009-03-20 20:23:32 +00:00
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 ;
char * odbc_user = NULL ;
char * odbc_pass = NULL ;
profile_t * profile = NULL ;
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 " ) ;
if ( ! strcasecmp ( var , " odbc-dsn " ) & & ! switch_strlen_zero ( val ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " odbc_dsn is %s \n " , val ) ;
globals . odbc_dsn = switch_core_strdup ( globals . pool , val ) ;
if ( ( odbc_user = strchr ( globals . odbc_dsn , ' : ' ) ) ) {
* odbc_user + + = ' \0 ' ;
if ( ( odbc_pass = strchr ( odbc_user , ' : ' ) ) ) {
* odbc_pass + + = ' \0 ' ;
}
}
}
}
}
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 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO
, " dsn is \" %s \" , user is \" %s \" , and password is \" %s \" \n "
, globals . odbc_dsn , odbc_user , odbc_pass
) ;
if ( ! ( globals . master_odbc = switch_odbc_handle_new ( globals . odbc_dsn , odbc_user , odbc_pass ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open ODBC Database! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( switch_odbc_handle_connect ( globals . master_odbc ) ! = SWITCH_ODBC_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open ODBC Database! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
}
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 pre_order = { 0 } ;
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-01-14 02:18:51 +00:00
char * id_s = NULL ;
2009-02-11 00:18:50 +00:00
char * custom_sql = NULL ;
2009-01-14 02:18:51 +00:00
int argc , x = 0 ;
char * argv [ 4 ] = { 0 } ;
SWITCH_STANDARD_STREAM ( order_by ) ;
2009-02-11 16:52:29 +00:00
SWITCH_STANDARD_STREAM ( pre_order ) ;
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 " ) ;
2009-02-11 16:52:29 +00:00
if ( ( ! strcasecmp ( var , " order_by " ) | | ! strcasecmp ( var , " pre_order " ) ) & & ! switch_strlen_zero ( val ) ) {
2009-02-13 21:45:54 +00:00
if ( ! strcasecmp ( var , " order_by " ) ) {
2009-02-11 16:52:29 +00:00
thisorder = & order_by ;
2009-02-13 21:45:54 +00:00
} else if ( ! strcasecmp ( var , " pre_order " ) ) {
2009-02-11 16:52:29 +00:00
thisorder = & pre_order ;
comma = " " ; /* don't want leading comma */
}
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 ] ) ) ) ) ) {
for ( x = 0 ; x < argc ; x + + ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " arg #%d/%d is %s \n " , x , argc , argv [ x ] ) ;
2009-02-13 21:45:54 +00:00
if ( ! switch_strlen_zero ( 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-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
}
}
} else if ( ! strcasecmp ( var , " id " ) & & ! switch_strlen_zero ( val ) ) {
id_s = val ;
2009-02-11 00:18:50 +00:00
} else if ( ! strcasecmp ( var , " custom_sql " ) & & ! switch_strlen_zero ( val ) ) {
custom_sql = val ;
2009-02-11 21:33:22 +00:00
} else if ( ! strcasecmp ( var , " reorder_by_rate " ) & & ! switch_strlen_zero ( val ) ) {
reorder_by_rate = val ;
2009-03-16 15:54:44 +00:00
} else if ( ! strcasecmp ( var , " quote_in_list " ) & & ! switch_strlen_zero ( val ) ) {
quote_in_list = val ;
2009-01-14 02:18:51 +00:00
}
}
2009-02-13 21:45:54 +00:00
if ( switch_strlen_zero ( 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 ) ;
2009-02-13 21:45:54 +00:00
if ( ! switch_strlen_zero ( ( char * ) order_by . data ) ) {
2009-01-14 02:18:51 +00:00
profile - > order_by = switch_core_strdup ( globals . pool , ( char * ) order_by . data ) ;
} else {
/* default to rate */
profile - > order_by = " , rate " ;
}
2009-02-13 21:45:54 +00:00
if ( ! switch_strlen_zero ( ( char * ) pre_order . data ) ) {
2009-02-11 16:52:29 +00:00
profile - > pre_order = switch_core_strdup ( globals . pool , ( char * ) pre_order . data ) ;
} else {
/* default to rate */
2009-02-11 21:33:22 +00:00
profile - > pre_order = " " ;
2009-02-11 16:52:29 +00:00
}
2009-02-13 21:45:54 +00:00
if ( ! switch_strlen_zero ( id_s ) ) {
2009-01-28 01:50:45 +00:00
profile - > id = ( uint16_t ) atoi ( id_s ) ;
2009-01-14 02:18:51 +00: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 ) ;
if ( switch_strlen_zero ( custom_sql ) ) {
/* use default sql */
sql_stream . write_function ( & sql_stream ,
" SELECT l.digits, c.carrier_name, l.rate, cg.prefix AS gw_prefix, cg.suffix AS gw_suffix, l.lead_strip, l.trail_strip, l.prefix, l.suffix "
) ;
if ( db_check ( " SELECT codec from carrier_gateway limit 1 " ) = = SWITCH_TRUE ) {
sql_stream . write_function ( & sql_stream , " , cg.codec " ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " codec field defined. \n " ) ;
} else {
2009-03-27 20:01:54 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " codec field not defined, please update your lcr carrier_gateway database schema. \n " ) ;
}
if ( db_check ( " SELECT cid from lcr limit 1 " ) = = SWITCH_TRUE ) {
sql_stream . write_function ( & sql_stream , " , l.cid " ) ;
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
}
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 ( " ) ;
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
}
2009-03-20 20:15:39 +00:00
sql_stream . write_function ( & sql_stream , " ORDER BY %s%s digits DESC%s " ,
profile - > pre_order ,
switch_strlen_zero ( profile - > pre_order ) ? " " : " , " ,
profile - > order_by ) ;
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 , " ; " ) ;
custom_sql = sql_stream . data ;
2009-02-11 00:18:50 +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 ;
}
profile - > custom_sql = switch_core_strdup ( globals . pool , ( char * ) custom_sql ) ;
2009-02-15 04:10:31 +00:00
if ( ! switch_strlen_zero ( reorder_by_rate ) ) {
2009-02-11 21:33:22 +00:00
profile - > reorder_by_rate = switch_true ( reorder_by_rate ) ;
}
2009-03-16 15:54:44 +00:00
if ( ! switch_strlen_zero ( quote_in_list ) ) {
profile - > quote_in_list = switch_true ( quote_in_list ) ;
}
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 */
2009-03-20 20:23:32 +00:00
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-03-20 20:23:32 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Removing INAVLID 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
}
2009-03-20 20:15:39 +00:00
2009-01-14 02:18:51 +00:00
}
2009-02-03 21:20:09 +00:00
switch_safe_free ( order_by . data ) ;
2009-02-11 16:52:29 +00:00
switch_safe_free ( pre_order . 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 " ) ;
}
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 " ;
profile - > pre_order = " " ;
globals . default_profile = profile ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Setting system defined default profile. " ) ;
}
done :
2009-01-14 02:18:51 +00:00
switch_xml_free ( xml ) ;
return status ;
}
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-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-02-11 21:33:22 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unknown profile: %s \n " , lcr_profile ) ;
goto end ;
}
2009-02-03 21:20:09 +00:00
2009-01-14 02:18:51 +00:00
if ( ! caller_profile ) {
caller_profile = switch_channel_get_caller_profile ( channel ) ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " LCR Lookup on %s \n " , caller_profile - > destination_number ) ;
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 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , 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 " ) ;
2009-02-12 23:52:03 +00:00
switch_channel_set_variable ( channel , " import " , " lcr_carrier,lcr_rate " ) ;
2009-01-14 02:18:51 +00:00
for ( cur_route = routes . head ; cur_route ; cur_route = cur_route - > next ) {
switch_caller_extension_add_application ( session , extension , " bridge " , cur_route - > dialstring ) ;
}
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " LCR lookup failed for %s \n " , caller_profile - > destination_number ) ;
}
2009-02-03 21:20:09 +00:00
end :
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 ;
2009-01-15 22:00:43 +00:00
/*//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "repeating %d of '%s'\n", how_many, what);*/
2009-01-14 02:18:51 +00:00
for ( i = 0 ; i < how_many ; i + + ) {
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 rbuf [ 1024 ] = " " ;
char vbuf [ 1024 ] = " " ;
char * rbp = rbuf ;
switch_size_t l = 0 , rbl = sizeof ( rbuf ) ;
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
char * last_delim = " | " ;
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-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-03-28 08:08:48 +00:00
if ( ! caller_profile ) {
if ( ! ( caller_profile = switch_channel_get_caller_profile ( channel ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Unable to locate caller_profile \n " ) ;
}
}
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 ] ;
}
2009-02-20 20:28:18 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , 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 ) {
routes . cid = ( char * ) caller_profile - > caller_id_number ;
}
2009-02-20 20:28:18 +00:00
if ( ! ( routes . profile = locate_profile ( lcr_profile ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unknown profile: %s \n " , lcr_profile ) ;
goto end ;
}
2009-03-27 20:01:54 +00:00
if ( lcr_do_lookup ( & routes ) = = SWITCH_STATUS_SUCCESS ) {
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 + + ;
2009-01-14 02:18:51 +00:00
switch_snprintf ( rbp , rbl , " %s| " , cur_route - > dialstring ) ;
last_delim = end_of_p ( rbp ) ;
l = strlen ( cur_route - > dialstring ) + 1 ;
rbp + = l ;
rbl - = l ;
}
switch_snprintf ( vbuf , sizeof ( vbuf ) , " %d " , cnt - 1 ) ;
switch_channel_set_variable ( channel , " lcr_route_count " , vbuf ) ;
* ( rbuf + strlen ( rbuf ) - 1 ) = ' \0 ' ;
switch_channel_set_variable ( channel , " lcr_auto_route " , rbuf ) ;
2009-02-12 23:52:03 +00:00
switch_channel_set_variable ( channel , " import " , " lcr_carrier,lcr_rate " ) ;
2009-01-14 02:18:51 +00:00
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " LCR lookup failed for %s \n " , dest ) ;
}
}
2009-02-11 21:33:22 +00:00
end :
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
}
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-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-01-14 02:18:51 +00:00
switch_status_t lookup_status = SWITCH_STATUS_SUCCESS ;
if ( switch_strlen_zero ( cmd ) ) {
goto usage ;
}
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 ;
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 ) {
cb_struct . cid = switch_core_strdup ( pool , argv [ 2 ] ) ;
} else {
cb_struct . cid = " 18005551212 " ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING
, " Using default CID [%s] \n " , cb_struct . cid
) ;
}
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
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO
, " data passed to lcr is [%s] \n " , cmd
) ;
2009-03-27 20:01:54 +00:00
lookup_status = lcr_do_lookup ( & cb_struct ) ;
2009-01-14 02:18:51 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO
, " lcr lookup returned [%d] \n "
, lookup_status
) ;
if ( cb_struct . head ! = NULL ) {
size_t len ;
2009-03-27 20:01:54 +00:00
process_max_lengths ( & maximum_lengths , cb_struct . head , cb_struct . lookup_number ) ;
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 ) ;
}
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-03-27 20:01:54 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_RATE ] ) ;
if ( ( len = ( maximum_lengths . rate - strlen ( headers [ LCR_HEADERS_RATE ] ) ) ) > 0 ) {
2009-01-14 02:18:51 +00:00
str_repeat ( len , " " , stream ) ;
}
2009-03-27 20:01:54 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_CODEC ] ) ;
if ( ( len = ( maximum_lengths . codec - strlen ( headers [ LCR_HEADERS_CODEC ] ) ) ) > 0 ) {
2009-01-14 02:18:51 +00:00
str_repeat ( len , " " , stream ) ;
}
2009-03-27 20:01:54 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_CID ] ) ;
if ( ( len = ( maximum_lengths . cid - strlen ( headers [ LCR_HEADERS_CID ] ) ) ) > 0 ) {
2009-01-14 02:18:51 +00:00
str_repeat ( len , " " , stream ) ;
}
2009-03-27 20:01:54 +00:00
stream - > write_function ( stream , " | %s " , headers [ LCR_HEADERS_DIALSTRING ] ) ;
if ( ( len = ( maximum_lengths . dialstring - strlen ( headers [ LCR_HEADERS_DIALSTRING ] ) ) ) > 0 ) {
2009-01-14 02:18:51 +00:00
str_repeat ( len , " " , stream ) ;
}
stream - > write_function ( stream , " | \n " ) ;
current = cb_struct . head ;
while ( current ) {
2009-03-27 20:01:54 +00:00
dialstring = get_bridge_data ( pool , cb_struct . lookup_number , cb_struct . cid , current ) ;
2009-01-14 02:18:51 +00:00
stream - > write_function ( stream , " | %s " , current - > digit_str ) ;
str_repeat ( ( maximum_lengths . digit_str - current - > digit_len ) , " " , stream ) ;
stream - > write_function ( stream , " | %s " , current - > carrier_name ) ;
str_repeat ( ( maximum_lengths . carrier_name - strlen ( current - > carrier_name ) ) , " " , stream ) ;
stream - > write_function ( stream , " | %s " , current - > rate_str ) ;
str_repeat ( ( maximum_lengths . rate - strlen ( current - > rate_str ) ) , " " , stream ) ;
2009-03-27 20:01:54 +00:00
if ( current - > codec ) {
stream - > write_function ( stream , " | %s " , current - > codec ) ;
str_repeat ( ( maximum_lengths . codec - strlen ( current - > codec ) ) , " " , stream ) ;
} else {
stream - > write_function ( stream , " | " ) ;
str_repeat ( ( maximum_lengths . codec ) , " " , stream ) ;
}
if ( current - > cid ) {
stream - > write_function ( stream , " | %s " , current - > cid ) ;
str_repeat ( ( maximum_lengths . cid - strlen ( current - > cid ) ) , " " , stream ) ;
} else {
stream - > write_function ( stream , " | " ) ;
str_repeat ( ( maximum_lengths . cid ) , " " , stream ) ;
}
2009-01-14 02:18:51 +00:00
stream - > write_function ( stream , " | %s " , dialstring ) ;
str_repeat ( ( maximum_lengths . dialstring - strlen ( dialstring ) ) , " " , stream ) ;
stream - > write_function ( stream , " | \n " ) ;
current = current - > next ;
}
} else {
2009-02-13 21:45:54 +00:00
if ( lookup_status = = SWITCH_STATUS_SUCCESS ) {
2009-01-14 02:18:51 +00:00
stream - > write_function ( stream , " No Routes To Display \n " ) ;
} else {
stream - > write_function ( stream , " Error looking up routes \n " ) ;
}
}
}
2009-02-11 21:33:22 +00:00
end :
2009-02-20 20:36:04 +00:00
if ( ! session ) {
switch_core_destroy_memory_pool ( & pool ) ;
}
2009-01-14 02:18:51 +00:00
return SWITCH_STATUS_SUCCESS ;
usage :
stream - > write_function ( stream , " USAGE: %s \n " , LCR_SYNTAX ) ;
return SWITCH_STATUS_SUCCESS ;
}
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 ;
if ( switch_strlen_zero ( cmd ) ) {
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 ;
stream - > write_function ( stream , " Name: \t \t %s \n " , profile - > name ) ;
2009-02-13 21:45:54 +00:00
if ( switch_strlen_zero ( 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-13 21:45:54 +00:00
if ( ! switch_strlen_zero ( profile - > pre_order ) ) {
2009-02-11 21:33:22 +00:00
stream - > write_function ( stream , " pre_order: \t %s \n " , profile - > pre_order ) ;
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-02-11 21:33:22 +00:00
stream - > write_function ( stream , " Reorder rate: \t %s \n " ,
profile - > reorder_by_rate ? " enabled " : " disabled " ) ;
2009-03-16 15:54:44 +00:00
stream - > write_function ( stream , " Quote IN() List: \t %s \n " ,
profile - > quote_in_list ? " enabled " : " disabled " ) ;
2009-02-11 05:07:37 +00:00
stream - > write_function ( stream , " \n " ) ;
}
} else {
goto usage ;
}
}
switch_safe_free ( mydata ) ;
return SWITCH_STATUS_SUCCESS ;
usage :
switch_safe_free ( mydata ) ;
stream - > write_function ( stream , " -ERR %s \n " , LCR_ADMIN_SYNTAX ) ;
return SWITCH_STATUS_SUCCESS ;
}
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 ;
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
# ifndef SWITCH_HAVE_ODBC
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 ;
# endif
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-02-03 15:59:46 +00:00
if ( switch_mutex_init ( & globals . db_mutex , SWITCH_MUTEX_UNNESTED , globals . pool ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " failed to initialize db_mutex \n " ) ;
}
2009-02-20 20:36:04 +00:00
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 " ,
lcr_app_function , " <number> " , SAF_SUPPORT_NOMEDIA ) ;
SWITCH_ADD_DIALPLAN ( dp_interface , " lcr " , lcr_dialplan_hunt ) ;
/* 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-05-09 16:51:12 +00:00
# ifdef SWITCH_HAVE_ODBC
2009-02-03 21:20:09 +00:00
switch_odbc_handle_disconnect ( globals . master_odbc ) ;
switch_odbc_handle_destroy ( & globals . master_odbc ) ;
2009-05-09 16:51:12 +00:00
# endif
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 :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 expandtab :
*/