2009-04-10 22:01:23 +00:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 - 2009 , Anthony Minessale II < anthm @ freeswitch . org >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthm @ freeswitch . org >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Rupa Schomaker < rupa @ rupa . com >
*
* mod_cidlookup . c - - API for querying cid - > name services
*
*/
2009-04-11 03:49:42 +00:00
2009-04-10 22:01:23 +00:00
# include <switch.h>
2009-04-11 02:45:22 +00:00
# include <curl/curl.h>
2009-04-10 22:01:23 +00:00
2009-11-03 21:07:59 +00:00
# define SWITCH_REWIND_STREAM(s) s.end = s.data
2009-04-10 22:01:23 +00:00
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_cidlookup_shutdown ) ;
SWITCH_MODULE_RUNTIME_FUNCTION ( mod_cidlookup_runtime ) ;
SWITCH_MODULE_LOAD_FUNCTION ( mod_cidlookup_load ) ;
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
* Defines a switch_loadable_module_function_table_t and a static const char [ ] modname
*/
SWITCH_MODULE_DEFINITION ( mod_cidlookup , mod_cidlookup_load , mod_cidlookup_shutdown , NULL ) ;
2009-11-03 21:07:59 +00:00
static char * SYNTAX = " cidlookup status|number [skipurl] [skipcitystate] [verbose] " ;
2009-04-10 22:01:23 +00:00
static struct {
char * url ;
2009-11-26 06:13:10 +00:00
int curl_timeout ;
int curl_warnduration ;
2009-09-30 17:23:01 +00:00
char * whitepages_apikey ;
2009-04-11 03:12:52 +00:00
2009-04-10 22:01:23 +00:00
switch_bool_t cache ;
int cache_expire ;
char * odbc_dsn ;
2009-11-26 03:54:04 +00:00
char * odbc_user ;
char * odbc_pass ;
2009-04-10 22:01:23 +00:00
char * sql ;
2009-07-08 02:40:15 +00:00
char * citystate_sql ;
2009-04-10 22:01:23 +00:00
switch_memory_pool_t * pool ;
} globals ;
2009-04-11 02:45:22 +00:00
struct http_data {
switch_stream_handle_t stream ;
switch_size_t bytes ;
switch_size_t max_bytes ;
int err ;
} ;
2009-11-03 21:07:59 +00:00
struct cid_data_obj {
char * name ;
char * area ;
char * src ;
} ;
typedef struct cid_data_obj cid_data_t ;
2009-04-11 02:45:22 +00:00
2009-04-10 22:01:23 +00:00
struct callback_obj {
switch_memory_pool_t * pool ;
char * name ;
} ;
typedef struct callback_obj callback_t ;
static switch_event_node_t * reload_xml_event = NULL ;
2009-11-26 03:54:04 +00:00
static switch_cache_db_handle_t * cidlookup_get_db_handle ( void )
{
switch_cache_db_connection_options_t options = { { 0 } } ;
switch_cache_db_handle_t * dbh = NULL ;
if ( globals . odbc_dsn & & globals . odbc_user & & globals . odbc_pass ) {
options . odbc_options . dsn = globals . odbc_dsn ;
options . odbc_options . user = globals . odbc_user ;
options . odbc_options . pass = globals . odbc_pass ;
if ( switch_cache_db_get_db_handle ( & dbh , SCDB_TYPE_ODBC , & options ) ! = SWITCH_STATUS_SUCCESS ) dbh = NULL ;
}
return dbh ;
}
2009-06-20 14:09:35 +00:00
static switch_status_t config_callback_dsn ( switch_xml_config_item_t * data , const char * newvalue , switch_config_callback_type_t callback_type , switch_bool_t changed )
2009-04-10 22:01:23 +00:00
{
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2009-11-26 03:54:04 +00:00
switch_cache_db_handle_t * dbh = NULL ;
2009-04-10 22:01:23 +00:00
2009-06-24 16:02:43 +00:00
if ( ! switch_odbc_available ( ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " ODBC is not compiled in. Do not configure odbc-dsn parameter! \n " ) ;
return SWITCH_STATUS_FALSE ;
}
2009-04-16 01:54:15 +00:00
if ( ( callback_type = = CONFIG_LOAD | | callback_type = = CONFIG_RELOAD ) & & changed ) {
2009-10-23 16:03:42 +00:00
if ( zstr ( newvalue ) ) {
2009-04-16 01:54:15 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " No local database defined. \n " ) ;
} else {
2009-11-26 03:54:04 +00:00
switch_safe_free ( globals . odbc_dsn ) ;
globals . odbc_dsn = strdup ( newvalue ) ;
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-04-16 01:54:15 +00:00
}
}
2009-11-26 06:13:10 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Connecting to dsn: %s \n " , globals . odbc_dsn ) ;
2009-11-26 03:54:04 +00:00
if ( ! ( dbh = cidlookup_get_db_handle ( ) ) ) {
2009-04-16 01:54:15 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " Cannot Open ODBC Database! \n " ) ;
switch_goto_status ( SWITCH_STATUS_FALSE , done ) ;
2009-04-10 22:01:23 +00:00
}
}
}
2009-04-11 03:49:42 +00:00
2009-04-10 22:01:23 +00:00
switch_goto_status ( SWITCH_STATUS_SUCCESS , done ) ;
done :
2009-11-26 03:54:04 +00:00
switch_cache_db_release_db_handle ( & dbh ) ;
2009-04-10 22:01:23 +00:00
return status ;
}
static switch_xml_config_string_options_t config_opt_dsn = { NULL , 0 , NULL } ; /* anything is ok here */
static switch_xml_config_item_t instructions [ ] = {
/* parameter name type reloadable pointer default value options structure */
2009-04-11 03:12:52 +00:00
SWITCH_CONFIG_ITEM_STRING_STRDUP ( " url " , CONFIG_RELOAD , & globals . url , NULL , " http://server.example.com/app?number=${caller_id_number} " , " URL for the CID lookup service " ) ,
2009-09-30 17:23:01 +00:00
SWITCH_CONFIG_ITEM_STRING_STRDUP ( " whitepages-apikey " , CONFIG_RELOAD , & globals . whitepages_apikey , NULL , " api key for whitepages.com " , " api key for whitepages.com " ) ,
2009-04-10 22:01:23 +00:00
SWITCH_CONFIG_ITEM ( " cache " , SWITCH_CONFIG_BOOL , CONFIG_RELOAD , & globals . cache , SWITCH_FALSE , NULL , " true|false " , " whether to cache via cidlookup " ) ,
SWITCH_CONFIG_ITEM ( " cache-expire " , SWITCH_CONFIG_INT , CONFIG_RELOAD , & globals . cache_expire , ( void * ) 300 , NULL , " expire " , " seconds to preserve num->name cache " ) ,
2009-11-26 06:13:10 +00:00
SWITCH_CONFIG_ITEM ( " curl-timeout " , SWITCH_CONFIG_INT , CONFIG_RELOAD , & globals . curl_timeout , ( void * ) 1500 , NULL , " timeout for curl " , " milliseconds to timeout " ) ,
SWITCH_CONFIG_ITEM ( " curl-warning-duration " , SWITCH_CONFIG_INT , CONFIG_RELOAD , & globals . curl_warnduration , ( void * ) 1000 , NULL , " warning when curl queries are longer than specified time " , " milliseconds " ) ,
2009-11-04 04:20:09 +00:00
SWITCH_CONFIG_ITEM_STRING_STRDUP ( " sql " , CONFIG_RELOAD , & globals . sql , NULL , " sql whre number=${caller_id_number} " , " SQL to run if overriding CID " ) ,
2009-11-03 17:57:44 +00:00
SWITCH_CONFIG_ITEM_STRING_STRDUP ( " citystate-sql " , CONFIG_RELOAD , & globals . citystate_sql , NULL , " sql to look up city/state info " , " SQL to run if overriding CID " ) ,
2009-04-16 01:54:15 +00:00
SWITCH_CONFIG_ITEM_CALLBACK ( " odbc-dsn " , SWITCH_CONFIG_STRING , CONFIG_RELOAD , & globals . odbc_dsn , " " , config_callback_dsn , & config_opt_dsn ,
2009-04-10 22:01:23 +00:00
" db:user:passwd " , " Database to use. " ) ,
SWITCH_CONFIG_ITEM_END ( )
} ;
static switch_status_t do_config ( switch_bool_t reload )
{
if ( switch_xml_config_parse_module_settings ( " cidlookup.conf " , reload , instructions ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_GENERR ;
}
return SWITCH_STATUS_SUCCESS ;
}
static void event_handler ( switch_event_t * event )
{
do_config ( SWITCH_TRUE ) ;
}
2009-11-26 03:54:04 +00:00
static switch_bool_t cidlookup_execute_sql_callback ( char * sql , switch_core_db_callback_func_t callback , callback_t * cbt , char * * err )
2009-04-10 22:01:23 +00:00
{
switch_bool_t retval = SWITCH_FALSE ;
2009-11-26 03:54:04 +00:00
switch_cache_db_handle_t * dbh = NULL ;
2009-04-10 22:01:23 +00:00
2009-11-26 03:54:04 +00:00
if ( globals . odbc_dsn & & ( dbh = cidlookup_get_db_handle ( ) ) ) {
if ( switch_cache_db_execute_sql_callback ( dbh , sql , callback , ( void * ) cbt , err )
2009-04-10 22:01:23 +00:00
= = SWITCH_ODBC_FAIL ) {
retval = SWITCH_FALSE ;
} else {
retval = SWITCH_TRUE ;
}
2009-11-26 03:54:04 +00:00
} else {
* err = switch_core_sprintf ( cbt - > pool , " Unable to get ODBC handle. dsn: %s, dbh is %s \n " , globals . odbc_dsn , dbh ? " not null " : " null " ) ;
2009-04-10 22:01:23 +00:00
}
2009-11-26 03:54:04 +00:00
switch_cache_db_release_db_handle ( & dbh ) ;
2009-04-10 22:01:23 +00:00
return retval ;
}
static int cidlookup_callback ( void * pArg , int argc , char * * argv , char * * columnNames )
{
callback_t * cbt = ( callback_t * ) pArg ;
switch_memory_pool_t * pool = cbt - > pool ;
if ( argc < 1 ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR ,
" Unexpected number of columns returned for SQL. Returned column count: %d. " ,
argc ) ;
return SWITCH_STATUS_GENERR ;
}
cbt - > name = switch_core_strdup ( pool , switch_str_nil ( argv [ 0 ] ) ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Name: %s \n " , cbt - > name ) ;
return SWITCH_STATUS_SUCCESS ;
}
/* make a new string with digits only */
static char * string_digitsonly ( switch_memory_pool_t * pool , const char * str )
{
char * p , * np , * newstr ;
size_t len ;
p = ( char * ) str ;
len = strlen ( str ) ;
newstr = switch_core_alloc ( pool , len + 1 ) ;
2009-11-03 21:07:59 +00:00
switch_assert ( newstr ) ;
2009-04-10 22:01:23 +00:00
np = newstr ;
while ( * p ) {
if ( switch_isdigit ( * p ) ) {
* np = * p ;
np + + ;
}
p + + ;
}
* np = ' \0 ' ;
return newstr ;
}
2009-11-03 21:07:59 +00:00
static cid_data_t * check_cache ( switch_memory_pool_t * pool , const char * number ) {
2009-04-10 22:01:23 +00:00
char * cmd ;
2009-05-29 00:14:34 +00:00
char * name = NULL ;
2009-11-03 21:07:59 +00:00
char * area = NULL ;
char * src = NULL ;
cid_data_t * cid = NULL ;
2009-04-10 22:01:23 +00:00
switch_stream_handle_t stream = { 0 } ;
SWITCH_STANDARD_STREAM ( stream ) ;
2009-11-03 21:07:59 +00:00
cmd = switch_core_sprintf ( pool , " get fs:cidlookup:name:%s " , number ) ;
2009-04-10 22:01:23 +00:00
if ( switch_api_execute ( " memcache " , cmd , NULL , & stream ) = = SWITCH_STATUS_SUCCESS ) {
if ( strncmp ( " -ERR " , stream . data , 4 ) ) {
name = switch_core_strdup ( pool , stream . data ) ;
} else {
name = NULL ;
}
}
2009-11-03 21:07:59 +00:00
SWITCH_REWIND_STREAM ( stream ) ;
cmd = switch_core_sprintf ( pool , " get fs:cidlookup:area:%s " , number ) ;
if ( switch_api_execute ( " memcache " , cmd , NULL , & stream ) = = SWITCH_STATUS_SUCCESS ) {
if ( strncmp ( " -ERR " , stream . data , 4 ) ) {
area = switch_core_strdup ( pool , stream . data ) ;
} else {
area = NULL ;
}
}
SWITCH_REWIND_STREAM ( stream ) ;
cmd = switch_core_sprintf ( pool , " get fs:cidlookup:src:%s " , number ) ;
if ( switch_api_execute ( " memcache " , cmd , NULL , & stream ) = = SWITCH_STATUS_SUCCESS ) {
if ( strncmp ( " -ERR " , stream . data , 4 ) ) {
src = switch_core_strdup ( pool , stream . data ) ;
} else {
src = NULL ;
}
}
if ( name | | area | | src ) {
cid = switch_core_alloc ( pool , sizeof ( cid_data_t ) ) ;
switch_assert ( cid ) ;
cid - > name = name ;
cid - > area = area ;
cid - > src = src ;
}
2009-04-10 22:01:23 +00:00
2009-11-03 21:07:59 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " memcache: k:'%s', vn:'%s', va:'%s', vs:'%s' \n " ,
cmd ,
( name ) ? name : " (null) " ,
( area ) ? area : " (null) " ,
( src ) ? src : " (null) "
) ;
2009-04-10 22:01:23 +00:00
switch_safe_free ( stream . data ) ;
2009-11-03 21:07:59 +00:00
return cid ;
2009-04-10 22:01:23 +00:00
}
2009-11-03 21:07:59 +00:00
switch_bool_t set_cache ( switch_memory_pool_t * pool , char * number , cid_data_t * cid ) {
2009-04-10 22:01:23 +00:00
char * cmd ;
2009-04-15 15:10:20 +00:00
switch_bool_t success = SWITCH_TRUE ;
2009-04-10 22:01:23 +00:00
switch_stream_handle_t stream = { 0 } ;
SWITCH_STANDARD_STREAM ( stream ) ;
2009-11-03 21:07:59 +00:00
cmd = switch_core_sprintf ( pool , " set fs:cidlookup:name:%s '%s' %d " , number , cid - > name , globals . cache_expire ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " memcache: %s \n " , cmd ) ;
2009-04-10 22:01:23 +00:00
if ( switch_api_execute ( " memcache " , cmd , NULL , & stream ) = = SWITCH_STATUS_SUCCESS ) {
if ( strncmp ( " -ERR " , stream . data , 4 ) ) {
success = SWITCH_TRUE ;
} else {
success = SWITCH_FALSE ;
2009-11-03 21:07:59 +00:00
goto done ;
2009-04-10 22:01:23 +00:00
}
}
2009-11-03 21:07:59 +00:00
SWITCH_REWIND_STREAM ( stream ) ;
cmd = switch_core_sprintf ( pool , " set fs:cidlookup:area:%s '%s' %d " , number , cid - > area , globals . cache_expire ) ;
if ( switch_api_execute ( " memcache " , cmd , NULL , & stream ) = = SWITCH_STATUS_SUCCESS ) {
if ( strncmp ( " -ERR " , stream . data , 4 ) ) {
success = SWITCH_TRUE ;
} else {
success = SWITCH_FALSE ;
goto done ;
}
}
SWITCH_REWIND_STREAM ( stream ) ;
cmd = switch_core_sprintf ( pool , " set fs:cidlookup:src:%s '%s' %d " , number , cid - > src , globals . cache_expire ) ;
if ( switch_api_execute ( " memcache " , cmd , NULL , & stream ) = = SWITCH_STATUS_SUCCESS ) {
if ( strncmp ( " -ERR " , stream . data , 4 ) ) {
success = SWITCH_TRUE ;
} else {
success = SWITCH_FALSE ;
goto done ;
}
}
done :
2009-04-10 22:01:23 +00:00
switch_safe_free ( stream . data ) ;
return success ;
}
2009-04-11 02:45:22 +00:00
static size_t file_callback ( void * ptr , size_t size , size_t nmemb , void * data )
{
register unsigned int realsize = ( unsigned int ) ( size * nmemb ) ;
struct http_data * http_data = data ;
http_data - > bytes + = realsize ;
if ( http_data - > bytes > http_data - > max_bytes ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Oversized file detected [%d bytes] \n " , ( int ) http_data - > bytes ) ;
http_data - > err = 1 ;
return 0 ;
}
http_data - > stream . write_function (
& http_data - > stream , " %.*s " , realsize , ptr ) ;
return realsize ;
}
2009-09-30 17:23:01 +00:00
static char * do_lookup_url ( switch_memory_pool_t * pool , switch_event_t * event , const char * query ) {
2009-04-10 22:01:23 +00:00
char * name = NULL ;
2009-11-26 06:13:10 +00:00
switch_time_t start_time = switch_micro_time_now ( ) ;
switch_time_t time_diff = 0 ;
2009-04-11 02:45:22 +00:00
CURL * curl_handle = NULL ;
long httpRes = 0 ;
char hostname [ 256 ] = " " ;
struct http_data http_data ;
2009-04-10 22:01:23 +00:00
2009-04-11 02:45:22 +00:00
memset ( & http_data , 0 , sizeof ( http_data ) ) ;
2009-04-10 22:01:23 +00:00
2009-09-30 17:23:01 +00:00
http_data . max_bytes = 10240 ;
2009-04-11 02:45:22 +00:00
SWITCH_STANDARD_STREAM ( http_data . stream ) ;
2009-04-10 22:01:23 +00:00
2009-04-11 02:45:22 +00:00
gethostname ( hostname , sizeof ( hostname ) ) ;
2009-09-30 17:23:01 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " url: %s \n " , query ) ;
2009-04-11 02:45:22 +00:00
curl_handle = curl_easy_init ( ) ;
2009-04-10 22:01:23 +00:00
2009-09-30 17:23:01 +00:00
if ( ! strncasecmp ( query , " https " , 5 ) ) {
2009-04-11 02:45:22 +00:00
curl_easy_setopt ( curl_handle , CURLOPT_SSL_VERIFYPEER , 0 ) ;
curl_easy_setopt ( curl_handle , CURLOPT_SSL_VERIFYHOST , 0 ) ;
}
curl_easy_setopt ( curl_handle , CURLOPT_POST , SWITCH_FALSE ) ;
curl_easy_setopt ( curl_handle , CURLOPT_FOLLOWLOCATION , 1 ) ;
curl_easy_setopt ( curl_handle , CURLOPT_MAXREDIRS , 10 ) ;
2009-11-26 06:13:10 +00:00
curl_easy_setopt ( curl_handle , CURLOPT_TIMEOUT_MS , globals . curl_timeout ) ;
2009-09-30 17:23:01 +00:00
curl_easy_setopt ( curl_handle , CURLOPT_URL , query ) ;
2009-04-11 02:45:22 +00:00
curl_easy_setopt ( curl_handle , CURLOPT_WRITEFUNCTION , file_callback ) ;
curl_easy_setopt ( curl_handle , CURLOPT_WRITEDATA , ( void * ) & http_data ) ;
curl_easy_setopt ( curl_handle , CURLOPT_USERAGENT , " freeswitch-cidlookup/1.0 " ) ;
curl_easy_perform ( curl_handle ) ;
curl_easy_getinfo ( curl_handle , CURLINFO_RESPONSE_CODE , & httpRes ) ;
curl_easy_cleanup ( curl_handle ) ;
if ( http_data . stream . data & &
2009-10-23 16:03:42 +00:00
! zstr ( ( char * ) http_data . stream . data ) & &
2009-04-11 02:45:22 +00:00
strcmp ( " " , http_data . stream . data ) ) {
2009-11-03 17:57:44 +00:00
/* don't return UNKNOWN */
if ( strcmp ( " UNKNOWN " , http_data . stream . data ) | |
strcmp ( " UNAVAILABLE " , http_data . stream . data ) ) {
name = switch_core_strdup ( pool , http_data . stream . data ) ;
}
2009-04-10 22:01:23 +00:00
}
2009-11-26 06:13:10 +00:00
time_diff = ( switch_micro_time_now ( ) - start_time ) ; /* convert to milli from micro */
if ( ( time_diff / 1000 ) > = globals . curl_warnduration ) {
switch_core_time_duration_t duration ;
switch_core_measure_time ( time_diff , & duration ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " SLOW LOOKUP ( "
" %um, "
" %us, "
" %ums "
" ): url: %s \n " ,
duration . min ,
duration . sec ,
duration . ms ,
query ) ;
}
2009-04-11 02:45:22 +00:00
switch_safe_free ( http_data . stream . data ) ;
2009-04-10 22:01:23 +00:00
return name ;
}
2009-11-03 21:07:59 +00:00
static cid_data_t * do_whitepages_lookup ( switch_memory_pool_t * pool , switch_event_t * event , const char * num )
2009-09-30 17:23:01 +00:00
{
char * xml_s = NULL ;
char * query = NULL ;
char * name = NULL ;
char * city = NULL ;
char * state = NULL ;
2009-11-03 21:07:59 +00:00
char * area = NULL ;
2009-09-30 17:23:01 +00:00
switch_xml_t xml = NULL ;
switch_xml_t node = NULL ;
2009-11-03 21:07:59 +00:00
cid_data_t * cid = NULL ;
2009-09-30 17:23:01 +00:00
/* NANPA check */
if ( strlen ( num ) = = 11 & & num [ 0 ] = = ' 1 ' ) {
num + + ; /* skip past leading 1 */
} else {
goto done ;
}
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " whitepages-cid " , num ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " whitepages-api-key " , globals . whitepages_apikey ) ;
query = switch_event_expand_headers ( event , " http://api.whitepages.com/reverse_phone/1.0/?phone=${whitepages-cid};api_key=${whitepages-api-key} " ) ;
xml_s = do_lookup_url ( pool , event , query ) ;
xml = switch_xml_parse_str_dup ( xml_s ) ;
if ( ! xml ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unable to parse XML: %s \n " , xml_s ) ;
goto done ;
}
/* try for bizname first */
node = switch_xml_get ( xml , " wp:listings " , 0 , " wp:listing " , 0 , " wp:business " , 0 , " wp:businessname " , - 1 ) ;
if ( node ) {
name = switch_core_strdup ( pool , switch_xml_txt ( node ) ) ;
2009-11-03 17:57:44 +00:00
goto area ;
2009-09-30 17:23:01 +00:00
}
node = switch_xml_get ( xml , " wp:listings " , 0 , " wp:listing " , 0 , " wp:displayname " , - 1 ) ;
if ( node ) {
name = switch_core_strdup ( pool , switch_xml_txt ( node ) ) ;
}
2009-11-03 17:57:44 +00:00
area :
2009-09-30 17:23:01 +00:00
node = switch_xml_get ( xml , " wp:listings " , 0 , " wp:listing " , 0 , " wp:address " , 0 , " wp:city " , - 1 ) ;
if ( node ) {
city = switch_xml_txt ( node ) ;
}
node = switch_xml_get ( xml , " wp:listings " , 0 , " wp:listing " , 0 , " wp:address " , 0 , " wp:state " , - 1 ) ;
if ( node ) {
state = switch_xml_txt ( node ) ;
}
if ( city | | state ) {
2009-11-03 21:07:59 +00:00
area = switch_core_sprintf ( pool , " %s %s " , city ? city : " " , state ? state : " " ) ;
2009-09-30 17:23:01 +00:00
}
done :
if ( query ) {
switch_safe_free ( query ) ;
}
if ( xml ) {
switch_xml_free ( xml ) ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " whitepages XML: %s \n " , xml_s ) ;
2009-11-03 21:07:59 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " whitepages name: %s, area: %s \n " , name ? name : " (null) " , area ? area : " (null) " ) ;
cid = switch_core_alloc ( pool , sizeof ( cid_data_t ) ) ;
switch_assert ( cid ) ;
cid - > name = name ;
cid - > area = area ;
2009-11-03 21:35:23 +00:00
cid - > src = " whitepages " ;
2009-11-03 21:07:59 +00:00
return cid ;
2009-09-30 17:23:01 +00:00
}
2009-07-08 02:40:15 +00:00
static char * do_db_lookup ( switch_memory_pool_t * pool , switch_event_t * event , const char * num , const char * sql ) {
2009-04-10 22:01:23 +00:00
char * name = NULL ;
char * newsql = NULL ;
2009-11-26 03:54:04 +00:00
char * err = NULL ;
2009-04-10 22:01:23 +00:00
callback_t cbt = { 0 } ;
cbt . pool = pool ;
2009-11-26 03:54:04 +00:00
if ( globals . odbc_dsn ) {
2009-07-08 02:40:15 +00:00
newsql = switch_event_expand_headers ( event , sql ) ;
2009-04-10 22:01:23 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " SQL: %s \n " , newsql ) ;
2009-11-26 03:54:04 +00:00
if ( cidlookup_execute_sql_callback ( newsql , cidlookup_callback , & cbt , & err ) ) {
2009-04-10 22:01:23 +00:00
name = cbt . name ;
} else {
2009-11-26 03:54:04 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Unable to lookup cid: %s \n " , err ? err : " (null) " ) ;
2009-04-10 22:01:23 +00:00
}
}
if ( newsql ! = globals . sql ) {
switch_safe_free ( newsql ) ;
}
return name ;
}
2009-11-03 21:07:59 +00:00
static cid_data_t * do_lookup ( switch_memory_pool_t * pool , switch_event_t * event , const char * num , switch_bool_t skipurl , switch_bool_t skipcitystate ) {
2009-04-10 22:01:23 +00:00
char * number = NULL ;
char * name = NULL ;
2009-09-30 17:23:01 +00:00
char * url_query = NULL ;
2009-11-03 21:07:59 +00:00
cid_data_t * cid = NULL ;
switch_bool_t save_cache = SWITCH_FALSE ;
cid = switch_core_alloc ( pool , sizeof ( cid_data_t ) ) ;
switch_assert ( cid ) ;
2009-11-03 17:57:44 +00:00
2009-04-10 22:01:23 +00:00
number = string_digitsonly ( pool , num ) ;
switch_event_add_header_string ( event , SWITCH_STACK_BOTTOM , " caller_id_number " , number ) ;
2009-04-11 06:37:45 +00:00
/* database always wins */
2009-11-26 03:54:04 +00:00
if ( switch_odbc_available ( ) & & globals . odbc_dsn & & globals . sql ) {
2009-07-08 02:40:15 +00:00
name = do_db_lookup ( pool , event , number , globals . sql ) ;
2009-11-03 17:57:44 +00:00
if ( name ) {
2009-11-03 21:07:59 +00:00
cid - > name = name ;
cid - > src = " phone_database " ;
goto done ;
2009-11-03 17:57:44 +00:00
}
2009-04-10 22:01:23 +00:00
}
2009-06-24 16:02:43 +00:00
2009-11-03 21:07:59 +00:00
if ( globals . cache ) {
cid = check_cache ( pool , number ) ;
if ( cid ) {
cid - > src = switch_core_sprintf ( pool , " %s (cache) " , cid - > src ) ;
goto done ;
2009-04-11 06:37:45 +00:00
}
2009-11-03 21:07:59 +00:00
}
if ( ! skipurl & & globals . whitepages_apikey ) {
cid = do_whitepages_lookup ( pool , event , number ) ;
if ( cid & & cid - > name ) { /* only cache if we have a name */
save_cache = SWITCH_TRUE ;
goto done ;
2009-09-30 17:23:01 +00:00
}
2009-11-03 21:07:59 +00:00
}
if ( ! skipurl & & globals . url ) {
url_query = switch_event_expand_headers ( event , globals . url ) ;
name = do_lookup_url ( pool , event , url_query ) ;
if ( name ) {
cid - > name = name ;
cid - > src = " url " ;
2009-09-30 17:23:01 +00:00
2009-11-03 21:07:59 +00:00
save_cache = SWITCH_TRUE ;
}
if ( url_query ! = globals . url ) {
switch_safe_free ( url_query ) ;
2009-04-10 22:01:23 +00:00
}
}
2009-11-03 21:07:59 +00:00
2009-11-06 08:45:58 +00:00
done :
if ( ! cid ) {
cid = switch_core_alloc ( pool , sizeof ( cid_data_t ) ) ;
switch_assert ( cid ) ;
}
2009-11-03 21:07:59 +00:00
/* append area if we can */
if ( ! cid - > area & &
2009-11-03 17:57:44 +00:00
! skipcitystate & &
strlen ( number ) = = 11 & & number [ 0 ] = = ' 1 ' & &
2009-11-26 03:54:04 +00:00
switch_odbc_available ( ) & & globals . odbc_dsn & & globals . citystate_sql ) {
2009-07-08 02:40:15 +00:00
2009-11-04 04:20:09 +00:00
/* yes, this is really area */
2009-11-03 21:07:59 +00:00
name = do_db_lookup ( pool , event , number , globals . citystate_sql ) ;
if ( name ) {
2009-11-04 04:20:09 +00:00
cid - > area = name ;
2009-11-03 21:07:59 +00:00
if ( cid - > src ) {
cid - > src = switch_core_sprintf ( pool , " %s,%s " , cid - > src , " npanxx_database " ) ;
} else {
cid - > src = " npanxx_database " ;
}
}
2009-07-08 02:40:15 +00:00
}
2009-11-03 17:57:44 +00:00
2009-11-03 21:07:59 +00:00
if ( ! cid - > area ) {
cid - > area = " UNKNOWN " ;
}
2009-11-04 04:20:09 +00:00
if ( ! cid - > name ) {
cid - > name = cid - > area ;
}
2009-11-03 21:07:59 +00:00
if ( ! cid - > src ) {
cid - > src = " UNKNOWN " ;
2009-11-03 17:57:44 +00:00
}
2009-11-03 21:07:59 +00:00
if ( globals . cache & & save_cache ) {
set_cache ( pool , number , cid ) ;
2009-11-03 17:57:44 +00:00
}
2009-11-03 21:07:59 +00:00
2009-10-29 13:55:09 +00:00
2009-11-03 21:07:59 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " cidlookup source: %s \n " , cid - > src ) ;
return cid ;
2009-04-10 22:01:23 +00:00
}
2009-04-11 06:25:05 +00:00
SWITCH_STANDARD_APP ( cidlookup_app_function )
{
switch_status_t status = SWITCH_STATUS_SUCCESS ;
2009-07-09 17:28:43 +00:00
char * argv [ 4 ] = { 0 } ;
2009-04-11 06:25:05 +00:00
int argc ;
char * mydata = NULL ;
2009-07-09 17:28:43 +00:00
int i ;
2009-04-11 06:25:05 +00:00
switch_memory_pool_t * pool = NULL ;
switch_event_t * event = NULL ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_caller_profile_t * profile = switch_channel_get_caller_profile ( channel ) ;
2009-11-03 21:07:59 +00:00
cid_data_t * cid = NULL ;
2009-04-11 06:25:05 +00:00
const char * number = NULL ;
switch_bool_t skipurl = SWITCH_FALSE ;
2009-07-09 17:28:43 +00:00
switch_bool_t skipcitystate = SWITCH_FALSE ;
2009-04-11 06:25:05 +00:00
if ( session ) {
pool = switch_core_session_get_pool ( session ) ;
} else {
switch_core_new_memory_pool ( & pool ) ;
}
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
2009-04-10 22:01:23 +00:00
2009-04-11 06:25:05 +00:00
if ( ! ( mydata = switch_core_session_strdup ( session , data ) ) ) {
return ;
}
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
2009-04-11 18:04:48 +00:00
if ( argc > 0 ) {
number = switch_core_session_strdup ( session , argv [ 0 ] ) ;
}
2009-07-09 17:28:43 +00:00
for ( i = 1 ; i < argc ; i + + ) {
if ( ! strcasecmp ( argv [ i ] , " skipurl " ) ) {
skipurl = SWITCH_TRUE ;
} else if ( ! strcasecmp ( argv [ i ] , " skipcitystate " ) ) {
skipcitystate = SWITCH_TRUE ;
}
2009-04-11 06:25:05 +00:00
}
}
2009-04-11 18:04:48 +00:00
if ( ! number & & profile ) {
2009-04-11 06:25:05 +00:00
number = switch_caller_get_field_by_name ( profile , " caller_id_number " ) ;
}
if ( number ) {
2009-11-03 21:07:59 +00:00
cid = do_lookup ( pool , event , number , skipurl , skipcitystate ) ;
2009-04-11 06:25:05 +00:00
}
2009-11-03 21:07:59 +00:00
if ( cid & & channel ) {
2009-04-11 16:31:55 +00:00
switch_channel_set_variable ( channel , " original_caller_id_name " , switch_core_strdup ( pool , profile - > caller_id_name ) ) ;
2009-11-03 21:07:59 +00:00
if ( ! zstr ( cid - > src ) ) {
switch_channel_set_variable ( channel , " cidlookup_source " , cid - > src ) ;
2009-10-29 13:55:09 +00:00
}
2009-11-03 21:07:59 +00:00
if ( ! zstr ( cid - > area ) ) {
switch_channel_set_variable ( channel , " cidlookup_area " , cid - > area ) ;
2009-11-03 17:57:44 +00:00
}
2009-11-03 21:07:59 +00:00
profile - > caller_id_name = switch_core_strdup ( profile - > pool , cid - > name ) ; ;
2009-04-11 06:25:05 +00:00
}
switch_goto_status ( SWITCH_STATUS_SUCCESS , done ) ;
done :
2009-07-09 16:41:49 +00:00
if ( event ) {
switch_event_destroy ( & event ) ;
}
if ( ! session & & pool ) {
2009-04-11 06:25:05 +00:00
switch_core_destroy_memory_pool ( & pool ) ;
}
}
2009-04-10 22:01:23 +00:00
SWITCH_STANDARD_API ( cidlookup_function )
{
switch_status_t status ;
2009-07-09 17:28:43 +00:00
char * argv [ 4 ] = { 0 } ;
2009-04-10 22:01:23 +00:00
int argc ;
2009-07-09 17:28:43 +00:00
int i ;
2009-11-03 21:07:59 +00:00
cid_data_t * cid = NULL ;
2009-04-10 22:01:23 +00:00
char * mydata = NULL ;
switch_memory_pool_t * pool = NULL ;
switch_event_t * event = NULL ;
2009-04-11 06:25:05 +00:00
switch_bool_t skipurl = SWITCH_FALSE ;
2009-07-09 17:28:43 +00:00
switch_bool_t skipcitystate = SWITCH_FALSE ;
2009-11-03 21:07:59 +00:00
switch_bool_t verbose = SWITCH_FALSE ;
2009-04-10 22:01:23 +00:00
2009-10-23 16:03:42 +00:00
if ( zstr ( cmd ) ) {
2009-04-10 22:01:23 +00:00
switch_goto_status ( SWITCH_STATUS_SUCCESS , usage ) ;
}
if ( session ) {
pool = switch_core_session_get_pool ( session ) ;
} else {
switch_core_new_memory_pool ( & pool ) ;
}
switch_event_create ( & event , SWITCH_EVENT_MESSAGE ) ;
mydata = strdup ( cmd ) ;
if ( ( argc = switch_separate_string ( mydata , ' ' , argv , ( sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) ) {
if ( argc < 1 ) {
switch_goto_status ( SWITCH_STATUS_SUCCESS , usage ) ;
}
if ( ! strcmp ( " status " , argv [ 0 ] ) ) {
stream - > write_function ( stream , " +OK \n url: %s \n cache: %s \n cache-expire: %d \n " ,
2009-11-03 17:57:44 +00:00
globals . url ? globals . url : " (null) " ,
2009-04-10 22:01:23 +00:00
( globals . cache ) ? " true " : " false " ,
globals . cache_expire ) ;
2009-11-26 06:13:10 +00:00
stream - > write_function ( stream , " curl-timeout: % " SWITCH_TIME_T_FMT " \n curl-warn-duration: % " SWITCH_TIME_T_FMT " \n " ,
globals . curl_timeout ,
globals . curl_warnduration ) ;
2009-04-10 22:01:23 +00:00
2009-07-08 02:40:15 +00:00
stream - > write_function ( stream , " odbc-dsn: %s \n sql: %s \n citystate-sql: %s \n " ,
2009-11-03 17:57:44 +00:00
globals . odbc_dsn ? globals . odbc_dsn : " (null) " ,
globals . sql ? globals . sql : " (null) " ,
globals . citystate_sql ? globals . citystate_sql : " (null) " ) ;
2009-06-24 16:02:43 +00:00
stream - > write_function ( stream , " ODBC Compiled: %s \n " , switch_odbc_available ( ) ? " true " : " false " ) ;
2009-04-10 22:01:23 +00:00
switch_goto_status ( SWITCH_STATUS_SUCCESS , done ) ;
}
2009-07-09 17:28:43 +00:00
for ( i = 1 ; i < argc ; i + + ) {
if ( ! strcasecmp ( argv [ i ] , " skipurl " ) ) {
skipurl = SWITCH_TRUE ;
} else if ( ! strcasecmp ( argv [ i ] , " skipcitystate " ) ) {
skipcitystate = SWITCH_TRUE ;
2009-11-03 21:07:59 +00:00
} else if ( ! strcasecmp ( argv [ i ] , " verbose " ) ) {
verbose = SWITCH_TRUE ;
2009-07-09 17:28:43 +00:00
}
2009-04-11 06:25:05 +00:00
}
2009-04-10 22:01:23 +00:00
2009-11-03 21:07:59 +00:00
cid = do_lookup ( pool , event , argv [ 0 ] , skipurl , skipcitystate ) ;
if ( cid ) {
stream - > write_function ( stream , cid - > name ) ;
if ( verbose ) {
stream - > write_function ( stream , " (%s) [%s] " , cid - > area , cid - > src ) ;
}
2009-04-10 22:01:23 +00:00
} else {
2009-07-13 19:07:05 +00:00
stream - > write_function ( stream , " UNKNOWN " ) ;
2009-04-10 22:01:23 +00:00
}
}
switch_goto_status ( SWITCH_STATUS_SUCCESS , done ) ;
usage :
stream - > write_function ( stream , " -ERR \n %s \n " , SYNTAX ) ;
switch_goto_status ( status , done ) ;
done :
switch_safe_free ( mydata ) ;
2009-07-09 16:41:49 +00:00
if ( event ) {
switch_event_destroy ( & event ) ;
}
if ( ! session & & pool ) {
2009-04-10 22:01:23 +00:00
switch_core_destroy_memory_pool ( & pool ) ;
}
return status ;
}
/* Macro expands to: switch_status_t mod_cidlookup_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION ( mod_cidlookup_load )
{
switch_api_interface_t * api_interface ;
2009-04-11 06:25:05 +00:00
switch_application_interface_t * app_interface ;
2009-04-10 22:01:23 +00:00
/* connect my internal structure to the blank pointer passed to me */
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
memset ( & globals , 0 , sizeof ( globals ) ) ;
globals . pool = pool ;
do_config ( SWITCH_FALSE ) ;
if ( ( switch_event_bind_removable ( modname , SWITCH_EVENT_RELOADXML , NULL , event_handler , NULL , & reload_xml_event ) ! = SWITCH_STATUS_SUCCESS ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Couldn't bind event! \n " ) ;
return SWITCH_STATUS_TERM ;
}
2009-04-11 05:06:05 +00:00
SWITCH_ADD_API ( api_interface , " cidlookup " , " cidlookup API " , cidlookup_function , SYNTAX ) ;
2009-04-11 06:25:05 +00:00
SWITCH_ADD_APP ( app_interface , " cidlookup " , " Perform a CID lookup " , " Perform a CID lookup " ,
2009-09-18 22:55:33 +00:00
cidlookup_app_function , " [number [skipurl]] " , SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC ) ;
2009-04-10 22:01:23 +00:00
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS ;
}
/*
Called when the system shuts down
Macro expands to : switch_status_t mod_cidlookup_shutdown ( ) */
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_cidlookup_shutdown )
{
2009-06-24 16:02:43 +00:00
2009-04-10 22:01:23 +00:00
switch_event_unbind ( & reload_xml_event ) ;
return SWITCH_STATUS_SUCCESS ;
}
/*
If it exists , this is called in it ' s own thread when the module - load completes
If it returns anything but SWITCH_STATUS_TERM it will be called again automatically
Macro expands to : switch_status_t mod_cidlookup_runtime ( )
SWITCH_MODULE_RUNTIME_FUNCTION ( mod_cidlookup_runtime )
{
while ( looping )
{
switch_cond_next ( ) ;
}
return SWITCH_STATUS_TERM ;
}
*/
/* 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
*/