2005-10-31 22:51:12 +00:00
/*
2005-11-06 15:09:47 +00:00
* Asterisk - - An open source telephony toolkit .
*
2006-02-23 17:13:57 +00:00
* Copyright ( C ) 2004 - 2006 , Christian Richter
2005-10-31 22:51:12 +00:00
*
* Christian Richter < crich @ beronet . com >
*
2005-11-06 15:09:47 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2005-10-31 22:51:12 +00:00
* This program is free software , distributed under the terms of
2005-11-06 15:09:47 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*
*/
/*!
* \ file
*
* \ brief the chan_misdn channel driver for Asterisk
* \ author Christian Richter < crich @ beronet . com >
*
* \ ingroup channel_drivers
2005-10-31 22:51:12 +00:00
*/
2006-08-21 02:11:39 +00:00
/*** MODULEINFO
< depend > isdnnet < / depend >
< depend > misdn < / depend >
< depend > suppserv < / depend >
* * */
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-10-31 22:51:12 +00:00
# include <stdio.h>
# include <pthread.h>
# include <string.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <errno.h>
# include <unistd.h>
# include <stdlib.h>
# include <arpa/inet.h>
# include <fcntl.h>
# include <sys/ioctl.h>
2006-07-11 19:30:35 +00:00
# include <signal.h>
2005-10-31 22:51:12 +00:00
# include <sys/file.h>
2006-08-08 18:13:40 +00:00
# include <semaphore.h>
2005-10-31 22:51:12 +00:00
2006-06-07 18:54:56 +00:00
# include "asterisk/channel.h"
# include "asterisk/config.h"
# include "asterisk/logger.h"
# include "asterisk/module.h"
# include "asterisk/pbx.h"
# include "asterisk/options.h"
# include "asterisk/io.h"
# include "asterisk/frame.h"
# include "asterisk/translate.h"
# include "asterisk/cli.h"
# include "asterisk/musiconhold.h"
# include "asterisk/dsp.h"
# include "asterisk/translate.h"
# include "asterisk/config.h"
# include "asterisk/file.h"
# include "asterisk/callerid.h"
# include "asterisk/indications.h"
# include "asterisk/app.h"
# include "asterisk/features.h"
2006-07-03 16:41:43 +00:00
# include "asterisk/term.h"
2006-07-11 19:30:35 +00:00
# include "asterisk/sched.h"
2006-06-07 18:54:56 +00:00
# include "asterisk/stringfields.h"
2005-10-31 22:51:12 +00:00
2006-06-07 18:54:56 +00:00
# include "chan_misdn_config.h"
# include "isdn_lib.h"
2005-10-31 22:51:12 +00:00
2006-02-22 21:59:46 +00:00
char global_tracefile [ BUFFERSIZE + 1 ] ;
2005-12-09 11:01:18 +00:00
struct misdn_jb {
int size ;
int upper_threshold ;
char * samples , * ok ;
int wp , rp ;
int state_empty ;
int state_full ;
int state_buffer ;
int bytes_wrote ;
ast_mutex_t mutexjb ;
} ;
2006-02-22 21:59:46 +00:00
2005-12-09 11:01:18 +00:00
/* allocates the jb-structure and initialise the elements*/
struct misdn_jb * misdn_jb_init ( int size , int upper_threshold ) ;
/* frees the data and destroys the given jitterbuffer struct */
void misdn_jb_destroy ( struct misdn_jb * jb ) ;
/* fills the jitterbuffer with len data returns < 0 if there was an
error ( bufferoverun ) . */
int misdn_jb_fill ( struct misdn_jb * jb , const char * data , int len ) ;
/* gets len bytes out of the jitterbuffer if available, else only the
available data is returned and the return value indicates the number
of data . */
int misdn_jb_empty ( struct misdn_jb * jb , char * data , int len ) ;
2005-10-31 22:51:12 +00:00
enum misdn_chan_state {
2005-11-06 15:09:47 +00:00
MISDN_NOTHING , /*!< at beginning */
MISDN_WAITING4DIGS , /*!< when waiting for infos */
MISDN_EXTCANTMATCH , /*!< when asterisk couldnt match our ext */
MISDN_DIALING , /*!< when pbx_start */
MISDN_PROGRESS , /*!< we got a progress */
2006-02-10 10:10:58 +00:00
MISDN_PROCEEDING , /*!< we got a progress */
2005-11-06 15:09:47 +00:00
MISDN_CALLING , /*!< when misdn_call is called */
MISDN_CALLING_ACKNOWLEDGE , /*!< when we get SETUP_ACK */
MISDN_ALERTING , /*!< when Alerting */
MISDN_BUSY , /*!< when BUSY */
MISDN_CONNECTED , /*!< when connected */
2006-05-24 07:58:52 +00:00
MISDN_PRECONNECTED , /*!< when connected */
2006-03-07 12:17:35 +00:00
MISDN_DISCONNECTED , /*!< when connected */
2006-06-21 15:21:46 +00:00
MISDN_RELEASED , /*!< when connected */
2005-11-06 15:09:47 +00:00
MISDN_BRIDGED , /*!< when bridged */
MISDN_CLEANING , /*!< when hangup from * but we were connected before */
MISDN_HUNGUP_FROM_MISDN , /*!< when DISCONNECT/RELEASE/REL_COMP cam from misdn */
MISDN_HUNGUP_FROM_AST , /*!< when DISCONNECT/RELEASE/REL_COMP came out of */
2005-10-31 22:51:12 +00:00
/* misdn_hangup */
2005-11-06 15:09:47 +00:00
MISDN_HOLDED , /*!< if this chan is holded */
MISDN_HOLD_DISCONNECT /*!< if this chan is holded */
2005-10-31 22:51:12 +00:00
} ;
# define ORG_AST 1
# define ORG_MISDN 2
struct chan_list {
2006-06-01 12:51:41 +00:00
char allowed_bearers [ BUFFERSIZE + 1 ] ;
2005-10-31 22:51:12 +00:00
enum misdn_chan_state state ;
2006-07-06 15:11:40 +00:00
int need_queue_hangup ;
int need_hangup ;
2006-08-03 16:38:00 +00:00
int need_busy ;
2006-07-06 15:11:40 +00:00
2005-10-31 22:51:12 +00:00
int orginator ;
int norxtone ;
int notxtone ;
2006-08-08 09:19:06 +00:00
int toggle_ec ;
2006-06-08 09:51:13 +00:00
2006-02-15 19:51:33 +00:00
int incoming_early_audio ;
2006-06-08 09:51:13 +00:00
int ignore_dtmf ;
2005-10-31 22:51:12 +00:00
int pipe [ 2 ] ;
char ast_rd_buf [ 4096 ] ;
struct ast_frame frame ;
2006-08-08 18:13:40 +00:00
int faxdetect ; /* 0:no 1:yes 2:yes+nojump */
int faxdetect_timeout ;
struct timeval faxdetect_tv ;
2005-10-31 22:51:12 +00:00
int faxhandled ;
int ast_dsp ;
2005-12-09 11:01:18 +00:00
2006-02-10 14:17:28 +00:00
int jb_len ;
int jb_upper_threshold ;
2005-12-09 11:01:18 +00:00
struct misdn_jb * jb ;
2005-10-31 22:51:12 +00:00
struct ast_dsp * dsp ;
struct ast_trans_pvt * trans ;
struct ast_channel * ast ;
2006-06-17 10:37:35 +00:00
int dummy ;
2005-10-31 22:51:12 +00:00
struct misdn_bchannel * bc ;
struct misdn_bchannel * holded_bc ;
unsigned int l3id ;
int addr ;
2005-12-09 11:01:18 +00:00
char context [ BUFFERSIZE ] ;
2006-02-02 21:15:34 +00:00
2006-04-29 22:56:00 +00:00
int zero_read_cnt ;
int dropped_frame_cnt ;
2006-05-05 16:38:15 +00:00
int far_alerting ;
2006-06-17 10:37:35 +00:00
int other_pid ;
struct chan_list * other_ch ;
2006-05-05 16:38:15 +00:00
2006-02-02 21:15:34 +00:00
const struct tone_zone_sound * ts ;
2005-10-31 22:51:12 +00:00
2006-07-11 19:30:35 +00:00
int overlap_dial ;
int overlap_dial_task ;
ast_mutex_t overlap_tv_lock ;
struct timeval overlap_tv ;
2005-10-31 22:51:12 +00:00
struct chan_list * peer ;
struct chan_list * next ;
struct chan_list * prev ;
struct chan_list * first ;
} ;
2006-06-17 10:37:35 +00:00
void export_ch ( struct ast_channel * chan , struct misdn_bchannel * bc , struct chan_list * ch ) ;
void import_ch ( struct ast_channel * chan , struct misdn_bchannel * bc , struct chan_list * ch ) ;
2005-10-31 22:51:12 +00:00
struct robin_list {
char * group ;
int port ;
int channel ;
struct robin_list * next ;
struct robin_list * prev ;
} ;
static struct robin_list * robin = NULL ;
2006-05-16 14:34:21 +00:00
2006-09-20 05:13:03 +00:00
static struct ast_frame * process_ast_dsp ( struct chan_list * tmp , struct ast_frame * frame ) ;
2006-05-16 14:34:21 +00:00
2005-10-31 22:51:12 +00:00
static inline void free_robin_list_r ( struct robin_list * r )
{
2005-12-09 11:01:18 +00:00
if ( r ) {
if ( r - > next ) free_robin_list_r ( r - > next ) ;
if ( r - > group ) free ( r - > group ) ;
free ( r ) ;
}
2005-10-31 22:51:12 +00:00
}
2005-11-11 00:35:21 +00:00
static void free_robin_list ( void )
2005-10-31 22:51:12 +00:00
{
free_robin_list_r ( robin ) ;
2005-11-15 20:20:45 +00:00
robin = NULL ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
static struct robin_list * get_robin_position ( char * group )
2005-10-31 22:51:12 +00:00
{
struct robin_list * iter = robin ;
for ( ; iter ; iter = iter - > next ) {
if ( ! strcasecmp ( iter - > group , group ) )
return iter ;
}
struct robin_list * new = ( struct robin_list * ) calloc ( 1 , sizeof ( struct robin_list ) ) ;
new - > group = strndup ( group , strlen ( group ) ) ;
new - > channel = 1 ;
if ( robin ) {
new - > next = robin ;
robin - > prev = new ;
}
robin = new ;
return robin ;
}
2005-12-09 11:01:18 +00:00
2006-07-11 19:30:35 +00:00
/* the main schedule context for stuff like l1 watcher, overlap dial, ... */
static struct sched_context * misdn_tasks = NULL ;
static pthread_t misdn_tasks_thread ;
2006-08-17 09:14:01 +00:00
static int * misdn_ports ;
2005-12-09 11:01:18 +00:00
static void chan_misdn_log ( int level , int port , char * tmpl , . . . ) ;
static struct ast_channel * misdn_new ( struct chan_list * cl , int state , char * exten , char * callerid , int format , int port , int c ) ;
static void send_digit_to_chan ( struct chan_list * cl , char digit ) ;
2005-10-31 22:51:12 +00:00
2006-07-06 15:11:40 +00:00
static void hangup_chan ( struct chan_list * ch ) ;
static int pbx_start_chan ( struct chan_list * ch ) ;
2005-10-31 22:51:12 +00:00
# define AST_CID_P(ast) ast->cid.cid_num
# define AST_BRIDGED_P(ast) ast_bridged_channel(ast)
# define AST_LOAD_CFG ast_config_load
# define AST_DESTROY_CFG ast_config_destroy
2005-11-01 22:04:14 +00:00
# define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
# define MISDN_ASTERISK_PVT(ast) 1
2005-10-31 22:51:12 +00:00
# include <asterisk/strings.h>
/* #define MISDN_DEBUG 1 */
2006-02-22 21:59:46 +00:00
static const char misdn_type [ ] = " mISDN " ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
static int tracing = 0 ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
static char * * misdn_key_vector = NULL ;
static int misdn_key_vector_size = 0 ;
2005-10-31 22:51:12 +00:00
/* Only alaw and mulaw is allowed for now */
static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */
2005-12-09 11:01:18 +00:00
static int * misdn_debug ;
static int * misdn_debug_only ;
static int max_ports ;
2005-10-31 22:51:12 +00:00
2006-05-22 15:02:03 +00:00
static int * misdn_in_calls ;
static int * misdn_out_calls ;
2005-10-31 22:51:12 +00:00
struct chan_list dummy_cl ;
struct chan_list * cl_te = NULL ;
2005-11-01 22:04:14 +00:00
ast_mutex_t cl_te_lock ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
static enum event_response_e
2005-10-31 22:51:12 +00:00
cb_events ( enum event_e event , struct misdn_bchannel * bc , void * user_data ) ;
2006-06-26 17:37:11 +00:00
static void send_cause2ast ( struct ast_channel * ast , struct misdn_bchannel * bc , struct chan_list * ch ) ;
2005-12-09 11:01:18 +00:00
static void cl_queue_chan ( struct chan_list * * list , struct chan_list * chan ) ;
static void cl_dequeue_chan ( struct chan_list * * list , struct chan_list * chan ) ;
static struct chan_list * find_chan_by_bc ( struct chan_list * list , struct misdn_bchannel * bc ) ;
2006-06-17 10:37:35 +00:00
static struct chan_list * find_chan_by_pid ( struct chan_list * list , int pid ) ;
2005-12-09 11:01:18 +00:00
2006-07-06 15:11:40 +00:00
static int dialtone_indicate ( struct chan_list * cl ) ;
static int hanguptone_indicate ( struct chan_list * cl ) ;
static int stop_indicate ( struct chan_list * cl ) ;
2005-10-31 22:51:12 +00:00
static int start_bc_tones ( struct chan_list * cl ) ;
static int stop_bc_tones ( struct chan_list * cl ) ;
static void release_chan ( struct misdn_bchannel * bc ) ;
static int misdn_set_opt_exec ( struct ast_channel * chan , void * data ) ;
static int misdn_facility_exec ( struct ast_channel * chan , void * data ) ;
2005-12-09 11:01:18 +00:00
int chan_misdn_jb_empty ( struct misdn_bchannel * bc , char * buf , int len ) ;
2006-05-16 14:34:21 +00:00
void debug_numplan ( int port , int numplan , char * type ) ;
2006-05-22 15:02:03 +00:00
int add_out_calls ( int port ) ;
int add_in_calls ( int port ) ;
2006-08-08 09:19:06 +00:00
static int update_ec_config ( struct misdn_bchannel * bc ) ;
2005-10-31 22:51:12 +00:00
/*************** Helpers *****************/
static struct chan_list * get_chan_by_ast ( struct ast_channel * ast )
{
struct chan_list * tmp ;
for ( tmp = cl_te ; tmp ; tmp = tmp - > next ) {
if ( tmp - > ast = = ast ) return tmp ;
}
return NULL ;
}
static struct chan_list * get_chan_by_ast_name ( char * name )
{
struct chan_list * tmp ;
for ( tmp = cl_te ; tmp ; tmp = tmp - > next ) {
if ( tmp - > ast & & strcmp ( tmp - > ast - > name , name ) = = 0 ) return tmp ;
}
return NULL ;
}
2006-06-01 12:51:41 +00:00
struct allowed_bearers {
int cap ;
int val ;
char * name ;
} ;
struct allowed_bearers allowed_bearers_array [ ] = {
{ INFO_CAPABILITY_SPEECH , 1 , " speech " } ,
{ INFO_CAPABILITY_AUDIO_3_1K , 2 , " 3_1khz " } ,
{ INFO_CAPABILITY_DIGITAL_UNRESTRICTED , 4 , " digital_unrestricted " } ,
{ INFO_CAPABILITY_DIGITAL_RESTRICTED , 8 , " digital_restriced " } ,
{ INFO_CAPABILITY_VIDEO , 16 , " video " }
} ;
2005-10-31 22:51:12 +00:00
static char * bearer2str ( int cap ) {
static char * bearers [ ] = {
" Speech " ,
" Audio 3.1k " ,
" Unres Digital " ,
" Res Digital " ,
2006-06-01 12:51:41 +00:00
" Video " ,
2005-10-31 22:51:12 +00:00
" Unknown Bearer "
} ;
switch ( cap ) {
case INFO_CAPABILITY_SPEECH :
return bearers [ 0 ] ;
break ;
case INFO_CAPABILITY_AUDIO_3_1K :
return bearers [ 1 ] ;
break ;
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED :
return bearers [ 2 ] ;
break ;
case INFO_CAPABILITY_DIGITAL_RESTRICTED :
return bearers [ 3 ] ;
break ;
2006-06-01 12:51:41 +00:00
case INFO_CAPABILITY_VIDEO :
2005-10-31 22:51:12 +00:00
return bearers [ 4 ] ;
break ;
2006-06-01 12:51:41 +00:00
default :
return bearers [ 5 ] ;
break ;
2005-10-31 22:51:12 +00:00
}
}
2005-12-09 11:01:18 +00:00
2006-08-16 13:19:54 +00:00
static void print_facility ( struct FacParm * fac , struct misdn_bchannel * bc )
2005-12-09 11:01:18 +00:00
{
2006-08-15 16:49:26 +00:00
switch ( fac - > Function ) {
2006-08-16 13:19:54 +00:00
case Fac_CD :
2006-08-15 16:49:26 +00:00
chan_misdn_log ( 0 , bc - > port , " --> calldeflect to: %s, screened: %s \n " , fac - > u . CDeflection . DeflectedToNumber ,
fac - > u . CDeflection . PresentationAllowed ? " yes " : " no " ) ;
2005-12-09 11:01:18 +00:00
break ;
2006-08-16 13:19:54 +00:00
case Fac_AOCDCurrency :
if ( fac - > u . AOCDcur . chargeNotAvailable )
chan_misdn_log ( 0 , bc - > port , " --> AOCD currency: charge not available \n " ) ;
else if ( fac - > u . AOCDcur . freeOfCharge )
chan_misdn_log ( 0 , bc - > port , " --> AOCD currency: free of charge \n " ) ;
else if ( fac - > u . AOCDchu . billingId > = 0 )
chan_misdn_log ( 0 , bc - > port , " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%d billingId:%d \n " ,
fac - > u . AOCDcur . currency , fac - > u . AOCDcur . currencyAmount , fac - > u . AOCDcur . multiplier ,
( fac - > u . AOCDcur . typeOfChargingInfo = = 0 ) ? " subTotal " : " total " , fac - > u . AOCDcur . billingId ) ;
else
chan_misdn_log ( 0 , bc - > port , " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%d \n " ,
fac - > u . AOCDcur . currency , fac - > u . AOCDcur . currencyAmount , fac - > u . AOCDcur . multiplier ,
( fac - > u . AOCDcur . typeOfChargingInfo = = 0 ) ? " subTotal " : " total " ) ;
break ;
case Fac_AOCDChargingUnit :
if ( fac - > u . AOCDchu . chargeNotAvailable )
chan_misdn_log ( 0 , bc - > port , " --> AOCD charging unit: charge not available \n " ) ;
else if ( fac - > u . AOCDchu . freeOfCharge )
chan_misdn_log ( 0 , bc - > port , " --> AOCD charging unit: free of charge \n " ) ;
else if ( fac - > u . AOCDchu . billingId > = 0 )
chan_misdn_log ( 0 , bc - > port , " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d \n " ,
fac - > u . AOCDchu . recordedUnits , ( fac - > u . AOCDchu . typeOfChargingInfo = = 0 ) ? " subTotal " : " total " , fac - > u . AOCDchu . billingId ) ;
else
chan_misdn_log ( 0 , bc - > port , " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s \n " ,
fac - > u . AOCDchu . recordedUnits , ( fac - > u . AOCDchu . typeOfChargingInfo = = 0 ) ? " subTotal " : " total " ) ;
break ;
2005-12-09 11:01:18 +00:00
default :
2006-08-08 18:13:40 +00:00
chan_misdn_log ( 0 , bc - > port , " --> unknown \n " ) ;
2005-12-09 11:01:18 +00:00
}
}
2005-10-31 22:51:12 +00:00
static void print_bearer ( struct misdn_bchannel * bc )
{
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 2 , bc - > port , " --> Bearer: %s \n " , bearer2str ( bc - > capability ) ) ;
2005-10-31 22:51:12 +00:00
switch ( bc - > law ) {
case INFO_CODEC_ALAW :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 2 , bc - > port , " --> Codec: Alaw \n " ) ;
2005-10-31 22:51:12 +00:00
break ;
case INFO_CODEC_ULAW :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 2 , bc - > port , " --> Codec: Ulaw \n " ) ;
2005-10-31 22:51:12 +00:00
break ;
}
}
/*************** Helpers END *************/
2006-07-11 19:30:35 +00:00
static void sighandler ( int sig )
{ }
static void * misdn_tasks_thread_func ( void * data )
{
int wait ;
struct sigaction sa ;
sa . sa_handler = sighandler ;
sa . sa_flags = SA_NODEFER ;
sigemptyset ( & sa . sa_mask ) ;
sigaddset ( & sa . sa_mask , SIGUSR1 ) ;
sigaction ( SIGUSR1 , & sa , NULL ) ;
2006-08-08 18:13:40 +00:00
sem_post ( ( sem_t * ) data ) ;
2006-07-11 19:30:35 +00:00
while ( 1 ) {
wait = ast_sched_wait ( misdn_tasks ) ;
if ( wait < 0 )
wait = 8000 ;
if ( poll ( NULL , 0 , wait ) < 0 )
chan_misdn_log ( 4 , 0 , " Waking up misdn_tasks thread \n " ) ;
ast_sched_runq ( misdn_tasks ) ;
}
return NULL ;
}
static void misdn_tasks_init ( void )
{
2006-08-08 18:13:40 +00:00
sem_t blocker ;
int i = 5 ;
2006-07-11 19:30:35 +00:00
2006-08-08 18:13:40 +00:00
if ( sem_init ( & blocker , 0 , 0 ) ) {
2006-07-11 19:30:35 +00:00
perror ( " chan_misdn: Failed to initialize semaphore! " ) ;
exit ( 1 ) ;
}
2006-08-08 18:13:40 +00:00
chan_misdn_log ( 4 , 0 , " Starting misdn_tasks thread \n " ) ;
2006-07-11 19:30:35 +00:00
misdn_tasks = sched_context_create ( ) ;
2006-08-08 18:13:40 +00:00
pthread_create ( & misdn_tasks_thread , NULL , misdn_tasks_thread_func , & blocker ) ;
2006-07-11 19:30:35 +00:00
2006-08-08 18:13:40 +00:00
while ( sem_wait ( & blocker ) & & - - i ) ;
sem_destroy ( & blocker ) ;
2006-07-11 19:30:35 +00:00
}
static void misdn_tasks_destroy ( void )
{
if ( misdn_tasks ) {
chan_misdn_log ( 4 , 0 , " Killing misdn_tasks thread \n " ) ;
if ( pthread_cancel ( misdn_tasks_thread ) = = 0 ) {
cb_log ( 4 , 0 , " Joining misdn_tasks thread \n " ) ;
pthread_join ( misdn_tasks_thread , NULL ) ;
}
sched_context_destroy ( misdn_tasks ) ;
}
}
static inline void misdn_tasks_wakeup ( void )
{
pthread_kill ( misdn_tasks_thread , SIGUSR1 ) ;
}
static inline int _misdn_tasks_add_variable ( int timeout , ast_sched_cb callback , void * data , int variable )
{
int task_id ;
if ( ! misdn_tasks ) {
misdn_tasks_init ( ) ;
}
task_id = ast_sched_add_variable ( misdn_tasks , timeout , callback , data , variable ) ;
misdn_tasks_wakeup ( ) ;
return task_id ;
}
static int misdn_tasks_add ( int timeout , ast_sched_cb callback , void * data )
{
return _misdn_tasks_add_variable ( timeout , callback , data , 0 ) ;
}
static int misdn_tasks_add_variable ( int timeout , ast_sched_cb callback , void * data )
{
return _misdn_tasks_add_variable ( timeout , callback , data , 1 ) ;
}
static void misdn_tasks_remove ( int task_id )
{
ast_sched_del ( misdn_tasks , task_id ) ;
}
static int misdn_l1_task ( void * data )
{
2006-08-17 09:14:01 +00:00
misdn_lib_isdn_l1watcher ( * ( int * ) data ) ;
chan_misdn_log ( 5 , * ( int * ) data , " L1watcher timeout \n " ) ;
2006-07-11 19:30:35 +00:00
return 1 ;
}
static int misdn_overlap_dial_task ( void * data )
{
struct timeval tv_end , tv_now ;
int diff ;
struct chan_list * ch = ( struct chan_list * ) data ;
chan_misdn_log ( 4 , ch - > bc - > port , " overlap dial task, chan_state: %d \n " , ch - > state ) ;
if ( ch - > state ! = MISDN_WAITING4DIGS ) {
ch - > overlap_dial_task = - 1 ;
return 0 ;
}
ast_mutex_lock ( & ch - > overlap_tv_lock ) ;
tv_end = ch - > overlap_tv ;
ast_mutex_unlock ( & ch - > overlap_tv_lock ) ;
tv_end . tv_sec + = ch - > overlap_dial ;
tv_now = ast_tvnow ( ) ;
diff = ast_tvdiff_ms ( tv_end , tv_now ) ;
if ( diff < = 100 ) {
/* if we are 100ms near the timeout, we are satisfied.. */
stop_indicate ( ch ) ;
if ( ast_exists_extension ( ch - > ast , ch - > context , ch - > bc - > dad , 1 , ch - > bc - > oad ) ) {
ch - > state = MISDN_DIALING ;
if ( pbx_start_chan ( ch ) < 0 ) {
chan_misdn_log ( - 1 , ch - > bc - > port , " ast_pbx_start returned < 0 in misdn_overlap_dial_task \n " ) ;
goto misdn_overlap_dial_task_disconnect ;
}
} else {
misdn_overlap_dial_task_disconnect :
hanguptone_indicate ( ch ) ;
if ( ch - > bc - > nt )
misdn_lib_send_event ( ch - > bc , EVENT_RELEASE_COMPLETE ) ;
else
misdn_lib_send_event ( ch - > bc , EVENT_RELEASE ) ;
}
ch - > overlap_dial_task = - 1 ;
return 0 ;
} else
return diff ;
}
2005-12-09 11:01:18 +00:00
static void send_digit_to_chan ( struct chan_list * cl , char digit )
2005-10-31 22:51:12 +00:00
{
static const char * dtmf_tones [ ] = {
" !941+1336/100,!0/100 " , /* 0 */
" !697+1209/100,!0/100 " , /* 1 */
" !697+1336/100,!0/100 " , /* 2 */
" !697+1477/100,!0/100 " , /* 3 */
" !770+1209/100,!0/100 " , /* 4 */
" !770+1336/100,!0/100 " , /* 5 */
" !770+1477/100,!0/100 " , /* 6 */
" !852+1209/100,!0/100 " , /* 7 */
" !852+1336/100,!0/100 " , /* 8 */
" !852+1477/100,!0/100 " , /* 9 */
" !697+1633/100,!0/100 " , /* A */
" !770+1633/100,!0/100 " , /* B */
" !852+1633/100,!0/100 " , /* C */
" !941+1633/100,!0/100 " , /* D */
" !941+1209/100,!0/100 " , /* * */
" !941+1477/100,!0/100 " } ; /* # */
struct ast_channel * chan = cl - > ast ;
if ( digit > = ' 0 ' & & digit < = ' 9 ' )
ast_playtones_start ( chan , 0 , dtmf_tones [ digit - ' 0 ' ] , 0 ) ;
else if ( digit > = ' A ' & & digit < = ' D ' )
ast_playtones_start ( chan , 0 , dtmf_tones [ digit - ' A ' + 10 ] , 0 ) ;
else if ( digit = = ' * ' )
ast_playtones_start ( chan , 0 , dtmf_tones [ 14 ] , 0 ) ;
else if ( digit = = ' # ' )
ast_playtones_start ( chan , 0 , dtmf_tones [ 15 ] , 0 ) ;
else {
/* not handled */
ast_log ( LOG_DEBUG , " Unable to handle DTMF tone '%c' for '%s' \n " , digit , chan - > name ) ;
}
}
/*** CLI HANDLING ***/
static int misdn_set_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 4 & & argc ! = 5 & & argc ! = 6 & & argc ! = 7 )
return RESULT_SHOWUSAGE ;
int level = atoi ( argv [ 3 ] ) ;
switch ( argc ) {
case 4 :
case 5 : {
int only = 0 ;
if ( argc = = 5 ) {
if ( strncasecmp ( argv [ 4 ] , " only " , strlen ( argv [ 4 ] ) ) )
return RESULT_SHOWUSAGE ;
else
only = 1 ;
}
int i ;
for ( i = 0 ; i < = max_ports ; i + + ) {
misdn_debug [ i ] = level ;
misdn_debug_only [ i ] = only ;
}
ast_cli ( fd , " changing debug level for all ports to %d%s \n " , misdn_debug [ 0 ] , only ? " (only) " : " " ) ;
}
break ;
case 6 :
case 7 : {
if ( strncasecmp ( argv [ 4 ] , " port " , strlen ( argv [ 4 ] ) ) )
return RESULT_SHOWUSAGE ;
int port = atoi ( argv [ 5 ] ) ;
if ( port < = 0 | | port > max_ports ) {
switch ( max_ports ) {
case 0 :
ast_cli ( fd , " port number not valid! no ports available so you won't get lucky with any number here... \n " ) ;
break ;
case 1 :
ast_cli ( fd , " port number not valid! only port 1 is availble. \n " ) ;
break ;
default :
ast_cli ( fd , " port number not valid! only ports 1 to %d are available. \n " , max_ports ) ;
}
return 0 ;
}
if ( argc = = 7 ) {
if ( strncasecmp ( argv [ 6 ] , " only " , strlen ( argv [ 6 ] ) ) )
return RESULT_SHOWUSAGE ;
else
misdn_debug_only [ port ] = 1 ;
} else
misdn_debug_only [ port ] = 0 ;
misdn_debug [ port ] = level ;
ast_cli ( fd , " changing debug level to %d%s for port %d \n " , misdn_debug [ port ] , misdn_debug_only [ port ] ? " (only) " : " " , port ) ;
}
}
return 0 ;
}
static int misdn_set_crypt_debug ( int fd , int argc , char * argv [ ] )
{
2005-12-09 11:01:18 +00:00
if ( argc ! = 5 ) return RESULT_SHOWUSAGE ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2006-08-03 16:38:00 +00:00
static int misdn_port_block ( int fd , int argc , char * argv [ ] )
{
int port ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
port = atoi ( argv [ 3 ] ) ;
misdn_lib_port_block ( port ) ;
return 0 ;
}
static int misdn_port_unblock ( int fd , int argc , char * argv [ ] )
{
int port ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
port = atoi ( argv [ 3 ] ) ;
misdn_lib_port_unblock ( port ) ;
return 0 ;
}
2005-10-31 22:51:12 +00:00
static int misdn_restart_port ( int fd , int argc , char * argv [ ] )
{
int port ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
port = atoi ( argv [ 3 ] ) ;
misdn_lib_port_restart ( port ) ;
return 0 ;
}
static int misdn_port_up ( int fd , int argc , char * argv [ ] )
{
int port ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
port = atoi ( argv [ 3 ] ) ;
misdn_lib_get_port_up ( port ) ;
return 0 ;
}
2006-03-07 11:16:56 +00:00
static int misdn_port_down ( int fd , int argc , char * argv [ ] )
{
int port ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
port = atoi ( argv [ 3 ] ) ;
misdn_lib_get_port_down ( port ) ;
return 0 ;
}
2006-07-03 16:41:43 +00:00
static inline void show_config_description ( int fd , enum misdn_cfg_elements elem )
{
char section [ BUFFERSIZE ] ;
char name [ BUFFERSIZE ] ;
char desc [ BUFFERSIZE ] ;
char def [ BUFFERSIZE ] ;
char tmp [ BUFFERSIZE ] ;
misdn_cfg_get_name ( elem , tmp , sizeof ( tmp ) ) ;
term_color ( name , tmp , COLOR_BRWHITE , 0 , sizeof ( tmp ) ) ;
misdn_cfg_get_desc ( elem , desc , sizeof ( desc ) , def , sizeof ( def ) ) ;
if ( elem < MISDN_CFG_LAST )
term_color ( section , " PORTS SECTION " , COLOR_YELLOW , 0 , sizeof ( section ) ) ;
else
term_color ( section , " GENERAL SECTION " , COLOR_YELLOW , 0 , sizeof ( section ) ) ;
if ( * def )
ast_cli ( fd , " [%s] %s (Default: %s) \n \t %s \n " , section , name , def , desc ) ;
else
ast_cli ( fd , " [%s] %s \n \t %s \n " , section , name , desc ) ;
}
2005-10-31 22:51:12 +00:00
static int misdn_show_config ( int fd , int argc , char * argv [ ] )
{
char buffer [ BUFFERSIZE ] ;
enum misdn_cfg_elements elem ;
int linebreak ;
int onlyport = - 1 ;
2006-07-03 16:41:43 +00:00
int ok = 0 ;
2005-10-31 22:51:12 +00:00
if ( argc > = 4 ) {
2006-07-03 16:41:43 +00:00
if ( ! strcmp ( argv [ 3 ] , " description " ) ) {
if ( argc = = 5 ) {
enum misdn_cfg_elements elem = misdn_cfg_get_elem ( argv [ 4 ] ) ;
if ( elem = = MISDN_CFG_FIRST )
ast_cli ( fd , " Unknown element: %s \n " , argv [ 4 ] ) ;
else
show_config_description ( fd , elem ) ;
return 0 ;
}
return RESULT_SHOWUSAGE ;
}
if ( ! strcmp ( argv [ 3 ] , " descriptions " ) ) {
if ( ( argc = = 4 ) | | ( ( argc = = 5 ) & & ! strcmp ( argv [ 4 ] , " general " ) ) ) {
for ( elem = MISDN_GEN_FIRST + 1 ; elem < MISDN_GEN_LAST ; + + elem ) {
show_config_description ( fd , elem ) ;
ast_cli ( fd , " \n " ) ;
}
ok = 1 ;
}
if ( ( argc = = 4 ) | | ( ( argc = = 5 ) & & ! strcmp ( argv [ 4 ] , " ports " ) ) ) {
2006-07-11 19:30:35 +00:00
for ( elem = MISDN_CFG_FIRST + 1 ; elem < MISDN_CFG_LAST - 1 /* the ptp hack, remove the -1 when ptp is gone */ ; + + elem ) {
2006-07-03 16:41:43 +00:00
show_config_description ( fd , elem ) ;
ast_cli ( fd , " \n " ) ;
}
ok = 1 ;
}
return ok ? 0 : RESULT_SHOWUSAGE ;
}
2005-10-31 22:51:12 +00:00
if ( ! sscanf ( argv [ 3 ] , " %d " , & onlyport ) | | onlyport < 0 ) {
ast_cli ( fd , " Unknown option: %s \n " , argv [ 3 ] ) ;
return RESULT_SHOWUSAGE ;
}
}
if ( argc = = 3 | | onlyport = = 0 ) {
ast_cli ( fd , " Misdn General-Config: \n " ) ;
2006-02-02 21:15:34 +00:00
ast_cli ( fd , " -> Version: chan_misdn- " CHAN_MISDN_VERSION " \n " ) ;
2005-10-31 22:51:12 +00:00
for ( elem = MISDN_GEN_FIRST + 1 , linebreak = 1 ; elem < MISDN_GEN_LAST ; elem + + , linebreak + + ) {
misdn_cfg_get_config_string ( 0 , elem , buffer , BUFFERSIZE ) ;
ast_cli ( fd , " %-36s%s " , buffer , ! ( linebreak % 2 ) ? " \n " : " " ) ;
}
2006-02-02 21:15:34 +00:00
ast_cli ( fd , " \n " ) ;
2005-10-31 22:51:12 +00:00
}
if ( onlyport < 0 ) {
int port = misdn_cfg_get_next_port ( 0 ) ;
for ( ; port > 0 ; port = misdn_cfg_get_next_port ( port ) ) {
ast_cli ( fd , " \n [PORT %d] \n " , port ) ;
for ( elem = MISDN_CFG_FIRST + 1 , linebreak = 1 ; elem < MISDN_CFG_LAST ; elem + + , linebreak + + ) {
misdn_cfg_get_config_string ( port , elem , buffer , BUFFERSIZE ) ;
ast_cli ( fd , " %-36s%s " , buffer , ! ( linebreak % 2 ) ? " \n " : " " ) ;
}
ast_cli ( fd , " \n " ) ;
}
}
if ( onlyport > 0 ) {
if ( misdn_cfg_is_port_valid ( onlyport ) ) {
ast_cli ( fd , " [PORT %d] \n " , onlyport ) ;
for ( elem = MISDN_CFG_FIRST + 1 , linebreak = 1 ; elem < MISDN_CFG_LAST ; elem + + , linebreak + + ) {
2006-07-03 16:41:43 +00:00
misdn_cfg_get_config_string ( onlyport , elem , buffer , BUFFERSIZE ) ;
2005-10-31 22:51:12 +00:00
ast_cli ( fd , " %-36s%s " , buffer , ! ( linebreak % 2 ) ? " \n " : " " ) ;
}
ast_cli ( fd , " \n " ) ;
} else {
ast_cli ( fd , " Port %d is not active! \n " , onlyport ) ;
}
}
return 0 ;
}
struct state_struct {
enum misdn_chan_state state ;
char txt [ 255 ] ;
} ;
2005-12-09 11:01:18 +00:00
static struct state_struct state_array [ ] = {
2005-10-31 22:51:12 +00:00
{ MISDN_NOTHING , " NOTHING " } , /* at beginning */
{ MISDN_WAITING4DIGS , " WAITING4DIGS " } , /* when waiting for infos */
{ MISDN_EXTCANTMATCH , " EXTCANTMATCH " } , /* when asterisk couldnt match our ext */
{ MISDN_DIALING , " DIALING " } , /* when pbx_start */
{ MISDN_PROGRESS , " PROGRESS " } , /* when pbx_start */
2006-06-26 17:37:11 +00:00
{ MISDN_PROCEEDING , " PROCEEDING " } , /* when pbx_start */
2005-10-31 22:51:12 +00:00
{ MISDN_CALLING , " CALLING " } , /* when misdn_call is called */
2006-06-26 17:37:11 +00:00
{ MISDN_CALLING_ACKNOWLEDGE , " CALLING_ACKNOWLEDGE " } , /* when misdn_call is called */
2005-10-31 22:51:12 +00:00
{ MISDN_ALERTING , " ALERTING " } , /* when Alerting */
{ MISDN_BUSY , " BUSY " } , /* when BUSY */
{ MISDN_CONNECTED , " CONNECTED " } , /* when connected */
2006-08-03 16:38:00 +00:00
{ MISDN_PRECONNECTED , " PRECONNECTED " } , /* when connected */
2006-06-21 15:21:46 +00:00
{ MISDN_DISCONNECTED , " DISCONNECTED " } , /* when connected */
{ MISDN_RELEASED , " RELEASED " } , /* when connected */
2005-10-31 22:51:12 +00:00
{ MISDN_BRIDGED , " BRIDGED " } , /* when bridged */
{ MISDN_CLEANING , " CLEANING " } , /* when hangup from * but we were connected before */
{ MISDN_HUNGUP_FROM_MISDN , " HUNGUP_FROM_MISDN " } , /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */
{ MISDN_HOLDED , " HOLDED " } , /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */
{ MISDN_HOLD_DISCONNECT , " HOLD_DISCONNECT " } , /* when DISCONNECT/RELEASE/REL_COMP cam from misdn */
{ MISDN_HUNGUP_FROM_AST , " HUNGUP_FROM_AST " } /* when DISCONNECT/RELEASE/REL_COMP came out of */
/* misdn_hangup */
} ;
2005-12-09 11:01:18 +00:00
static char * misdn_get_ch_state ( struct chan_list * p )
2005-10-31 22:51:12 +00:00
{
int i ;
2006-06-26 17:37:11 +00:00
static char state [ 8 ] ;
2005-10-31 22:51:12 +00:00
if ( ! p ) return NULL ;
for ( i = 0 ; i < sizeof ( state_array ) / sizeof ( struct state_struct ) ; i + + ) {
if ( state_array [ i ] . state = = p - > state ) return state_array [ i ] . txt ;
}
2006-06-26 17:37:11 +00:00
sprintf ( state , " %d " , p - > state ) ;
return state ;
2005-10-31 22:51:12 +00:00
}
2006-02-10 14:17:28 +00:00
2006-04-24 17:11:45 +00:00
static void reload_config ( void )
2005-10-31 22:51:12 +00:00
{
int i , cfg_debug ;
free_robin_list ( ) ;
misdn_cfg_reload ( ) ;
2006-02-02 21:15:34 +00:00
misdn_cfg_update_ptp ( ) ;
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_TRACEFILE , global_tracefile , BUFFERSIZE ) ;
2005-10-31 22:51:12 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_DEBUG , & cfg_debug , sizeof ( int ) ) ;
2006-02-10 14:17:28 +00:00
2005-10-31 22:51:12 +00:00
for ( i = 0 ; i < = max_ports ; i + + ) {
misdn_debug [ i ] = cfg_debug ;
misdn_debug_only [ i ] = 0 ;
}
2006-02-10 14:17:28 +00:00
}
static int misdn_reload ( int fd , int argc , char * argv [ ] )
{
ast_cli ( fd , " Reloading mISDN Config \n " ) ;
reload_config ( ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
static void print_bc_info ( int fd , struct chan_list * help , struct misdn_bchannel * bc )
{
struct ast_channel * ast = help - > ast ;
ast_cli ( fd ,
2006-03-09 18:01:27 +00:00
" * Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s \n " ,
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
bc - > pid , bc - > port , bc - > channel ,
bc - > nt ? " NT " : " TE " ,
2005-10-31 22:51:12 +00:00
help - > orginator = = ORG_AST ? " * " : " I " ,
ast ? ast - > exten : NULL ,
ast ? AST_CID_P ( ast ) : NULL ,
2006-03-09 18:01:27 +00:00
bc - > rad ,
2005-10-31 22:51:12 +00:00
ast ? ast - > context : NULL ,
misdn_get_ch_state ( help )
) ;
2005-11-01 22:04:14 +00:00
if ( misdn_debug [ bc - > port ] > 0 )
2005-10-31 22:51:12 +00:00
ast_cli ( fd ,
" --> astname: %s \n "
" --> ch_l3id: %x \n "
" --> ch_addr: %x \n "
" --> bc_addr: %x \n "
" --> bc_l3id: %x \n "
" --> display: %s \n "
" --> activated: %d \n "
2006-04-03 19:17:59 +00:00
" --> state: %s \n "
2005-10-31 22:51:12 +00:00
" --> capability: %s \n "
" --> echo_cancel: %d \n "
" --> notone : rx %d tx:%d \n "
" --> bc_hold: %d holded_bc :%d \n " ,
help - > ast - > name ,
help - > l3id ,
help - > addr ,
bc - > addr ,
bc ? bc - > l3_id : - 1 ,
bc - > display ,
bc - > active ,
2006-04-03 19:17:59 +00:00
bc_state2str ( bc - > bc_state ) ,
2005-10-31 22:51:12 +00:00
bearer2str ( bc - > capability ) ,
bc - > ec_enable ,
2006-08-08 09:19:06 +00:00
2005-10-31 22:51:12 +00:00
help - > norxtone , help - > notxtone ,
bc - > holded , help - > holded_bc ? 1 : 0
) ;
}
static int misdn_show_cls ( int fd , int argc , char * argv [ ] )
{
struct chan_list * help = cl_te ;
ast_cli ( fd , " Chan List: %p \n " , cl_te ) ;
for ( ; help ; help = help - > next ) {
struct misdn_bchannel * bc = help - > bc ;
struct ast_channel * ast = help - > ast ;
if ( misdn_debug [ 0 ] > 2 ) ast_cli ( fd , " Bc:%p Ast:%p \n " , bc , ast ) ;
if ( bc ) {
print_bc_info ( fd , help , bc ) ;
} else if ( ( bc = help - > holded_bc ) ) {
chan_misdn_log ( 0 , 0 , " ITS A HOLDED BC: \n " ) ;
print_bc_info ( fd , help , bc ) ;
} else {
ast_cli ( fd , " * Channel in unknown STATE !!! Exten:%s, Callerid:%s \n " , ast - > exten , AST_CID_P ( ast ) ) ;
}
}
return 0 ;
}
static int misdn_show_cl ( int fd , int argc , char * argv [ ] )
{
struct chan_list * help = cl_te ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
for ( ; help ; help = help - > next ) {
struct misdn_bchannel * bc = help - > bc ;
struct ast_channel * ast = help - > ast ;
if ( bc & & ast ) {
if ( ! strcasecmp ( ast - > name , argv [ 3 ] ) ) {
print_bc_info ( fd , help , bc ) ;
break ;
}
}
}
return 0 ;
}
2005-11-01 22:04:14 +00:00
ast_mutex_t lock ;
2005-10-31 22:51:12 +00:00
int MAXTICS = 8 ;
static int misdn_set_tics ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
MAXTICS = atoi ( argv [ 3 ] ) ;
return 0 ;
}
static int misdn_show_stacks ( int fd , int argc , char * argv [ ] )
{
2005-11-01 22:04:14 +00:00
int port ;
2006-04-29 22:56:00 +00:00
2005-10-31 22:51:12 +00:00
ast_cli ( fd , " BEGIN STACK_LIST: \n " ) ;
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
for ( port = misdn_cfg_get_next_port ( 0 ) ; port > 0 ;
port = misdn_cfg_get_next_port ( port ) ) {
char buf [ 128 ] ;
get_show_stack_details ( port , buf ) ;
ast_cli ( fd , " %s Debug:%d%s \n " , buf , misdn_debug [ port ] , misdn_debug_only [ port ] ? " (only) " : " " ) ;
2005-10-31 22:51:12 +00:00
}
2005-11-01 22:04:14 +00:00
2005-10-31 22:51:12 +00:00
return 0 ;
}
2006-05-22 15:02:03 +00:00
static int misdn_show_ports_stats ( int fd , int argc , char * argv [ ] )
{
int port ;
ast_cli ( fd , " Port \t in_calls \t out_calls \n " ) ;
for ( port = misdn_cfg_get_next_port ( 0 ) ; port > 0 ;
port = misdn_cfg_get_next_port ( port ) ) {
ast_cli ( fd , " %d \t %d \t \t %d \n " , port , misdn_in_calls [ port ] , misdn_out_calls [ port ] ) ;
}
ast_cli ( fd , " \n " ) ;
return 0 ;
}
2005-10-31 22:51:12 +00:00
static int misdn_show_port ( int fd , int argc , char * argv [ ] )
{
int port ;
2005-11-01 22:04:14 +00:00
2005-10-31 22:51:12 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
port = atoi ( argv [ 3 ] ) ;
ast_cli ( fd , " BEGIN STACK_LIST: \n " ) ;
2005-11-01 22:04:14 +00:00
char buf [ 128 ] ;
get_show_stack_details ( port , buf ) ;
ast_cli ( fd , " %s Debug:%d%s \n " , buf , misdn_debug [ port ] , misdn_debug_only [ port ] ? " (only) " : " " ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
static int misdn_send_cd ( int fd , int argc , char * argv [ ] )
{
char * channame ;
char * nr ;
if ( argc ! = 5 )
return RESULT_SHOWUSAGE ;
channame = argv [ 3 ] ;
nr = argv [ 4 ] ;
2006-08-15 16:49:26 +00:00
2005-10-31 22:51:12 +00:00
ast_cli ( fd , " Sending Calldeflection (%s) to %s \n " , nr , channame ) ;
{
struct chan_list * tmp = get_chan_by_ast_name ( channame ) ;
if ( ! tmp ) {
2006-08-15 16:49:26 +00:00
ast_cli ( fd , " Sending CD with nr %s to %s failed: Channel does not exist. \n " , nr , channame ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
} else {
2006-08-15 16:49:26 +00:00
if ( strlen ( nr ) > = 15 ) {
ast_cli ( fd , " Sending CD with nr %s to %s failed: Number too long (up to 15 digits are allowed). \n " , nr , channame ) ;
return 0 ;
}
2006-08-16 13:19:54 +00:00
tmp - > bc - > fac_out . Function = Fac_CD ;
2006-08-15 16:49:26 +00:00
strncpy ( ( char * ) tmp - > bc - > fac_out . u . CDeflection . DeflectedToNumber , nr , sizeof ( tmp - > bc - > fac_out . u . CDeflection . DeflectedToNumber ) ) ;
misdn_lib_send_event ( tmp - > bc , EVENT_FACILITY ) ;
2005-10-31 22:51:12 +00:00
}
}
return 0 ;
}
static int misdn_send_digit ( int fd , int argc , char * argv [ ] )
{
char * channame ;
char * msg ;
if ( argc ! = 5 )
return RESULT_SHOWUSAGE ;
channame = argv [ 3 ] ;
msg = argv [ 4 ] ;
ast_cli ( fd , " Sending %s to %s \n " , msg , channame ) ;
{
struct chan_list * tmp = get_chan_by_ast_name ( channame ) ;
if ( ! tmp ) {
ast_cli ( fd , " Sending %s to %s failed Channel does not exist \n " , msg , channame ) ;
return 0 ;
} else {
# if 1
int i ;
int msglen = strlen ( msg ) ;
for ( i = 0 ; i < msglen ; i + + ) {
ast_cli ( fd , " Sending: %c \n " , msg [ i ] ) ;
send_digit_to_chan ( tmp , msg [ i ] ) ;
/* res = ast_safe_sleep(tmp->ast, 250); */
usleep ( 250000 ) ;
/* res = ast_waitfor(tmp->ast,100); */
}
# else
int res ;
res = ast_dtmf_stream ( tmp - > ast , NULL , msg , 250 ) ;
# endif
}
}
return 0 ;
}
static int misdn_toggle_echocancel ( int fd , int argc , char * argv [ ] )
{
char * channame ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
channame = argv [ 3 ] ;
ast_cli ( fd , " Toggling EchoCancel on %s \n " , channame ) ;
{
struct chan_list * tmp = get_chan_by_ast_name ( channame ) ;
if ( ! tmp ) {
ast_cli ( fd , " Toggling EchoCancel %s failed Channel does not exist \n " , channame ) ;
return 0 ;
} else {
2006-08-08 09:19:06 +00:00
tmp - > toggle_ec = tmp - > toggle_ec ? 0 : 1 ;
2005-10-31 22:51:12 +00:00
2006-08-08 09:19:06 +00:00
if ( tmp - > toggle_ec ) {
update_ec_config ( tmp - > bc ) ;
2005-10-31 22:51:12 +00:00
manager_ec_enable ( tmp - > bc ) ;
} else {
manager_ec_disable ( tmp - > bc ) ;
}
}
}
return 0 ;
}
static int misdn_send_display ( int fd , int argc , char * argv [ ] )
{
char * channame ;
char * msg ;
if ( argc ! = 5 )
return RESULT_SHOWUSAGE ;
channame = argv [ 3 ] ;
msg = argv [ 4 ] ;
ast_cli ( fd , " Sending %s to %s \n " , msg , channame ) ;
{
struct chan_list * tmp ;
tmp = get_chan_by_ast_name ( channame ) ;
if ( tmp & & tmp - > bc ) {
2006-02-22 21:59:46 +00:00
ast_copy_string ( tmp - > bc - > display , msg , sizeof ( tmp - > bc - > display ) ) ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( tmp - > bc , EVENT_INFORMATION ) ;
} else {
ast_cli ( fd , " No such channel %s \n " , channame ) ;
return RESULT_FAILURE ;
}
}
return RESULT_SUCCESS ;
}
2006-02-08 16:10:21 +00:00
static char * complete_ch_helper ( const char * line , const char * word , int pos , int state , int rpos )
2005-10-31 22:51:12 +00:00
{
struct ast_channel * c ;
int which = 0 ;
char * ret ;
if ( pos ! = rpos )
return NULL ;
c = ast_channel_walk_locked ( NULL ) ;
while ( c ) {
if ( ! strncasecmp ( word , c - > name , strlen ( word ) ) ) {
if ( + + which > state )
break ;
}
ast_mutex_unlock ( & c - > lock ) ;
c = ast_channel_walk_locked ( c ) ;
}
if ( c ) {
2006-05-01 03:58:13 +00:00
ret = strdup ( c - > name ) ;
2005-10-31 22:51:12 +00:00
ast_mutex_unlock ( & c - > lock ) ;
} else
ret = NULL ;
return ret ;
}
2006-02-08 16:10:21 +00:00
static char * complete_ch ( const char * line , const char * word , int pos , int state )
2005-10-31 22:51:12 +00:00
{
return complete_ch_helper ( line , word , pos , state , 3 ) ;
}
2006-02-08 16:10:21 +00:00
static char * complete_debug_port ( const char * line , const char * word , int pos , int state )
2005-10-31 22:51:12 +00:00
{
if ( state )
return NULL ;
switch ( pos ) {
case 4 : if ( * word = = ' p ' )
2006-05-01 03:58:13 +00:00
return strdup ( " port " ) ;
2005-10-31 22:51:12 +00:00
else if ( * word = = ' o ' )
2006-05-01 03:58:13 +00:00
return strdup ( " only " ) ;
2005-10-31 22:51:12 +00:00
break ;
case 6 : if ( * word = = ' o ' )
2006-05-01 03:58:13 +00:00
return strdup ( " only " ) ;
2005-10-31 22:51:12 +00:00
break ;
}
return NULL ;
}
2006-07-03 16:41:43 +00:00
static char * complete_show_config ( const char * line , const char * word , int pos , int state )
{
char buffer [ BUFFERSIZE ] ;
enum misdn_cfg_elements elem ;
int wordlen = strlen ( word ) ;
int which = 0 ;
int port = 0 ;
switch ( pos ) {
case 3 : if ( ( ! strncmp ( word , " description " , wordlen ) ) & & ( + + which > state ) )
return strdup ( " description " ) ;
if ( ( ! strncmp ( word , " descriptions " , wordlen ) ) & & ( + + which > state ) )
return strdup ( " descriptions " ) ;
if ( ( ! strncmp ( word , " 0 " , wordlen ) ) & & ( + + which > state ) )
return strdup ( " 0 " ) ;
while ( ( port = misdn_cfg_get_next_port ( port ) ) ! = - 1 ) {
snprintf ( buffer , sizeof ( buffer ) , " %d " , port ) ;
if ( ( ! strncmp ( word , buffer , wordlen ) ) & & ( + + which > state ) ) {
return strdup ( buffer ) ;
}
}
break ;
case 4 :
if ( strstr ( line , " description " ) ) {
for ( elem = MISDN_CFG_FIRST + 1 ; elem < MISDN_GEN_LAST ; + + elem ) {
if ( ( elem = = MISDN_CFG_LAST ) | | ( elem = = MISDN_GEN_FIRST ) )
continue ;
misdn_cfg_get_name ( elem , buffer , BUFFERSIZE ) ;
if ( ! wordlen | | ! strncmp ( word , buffer , wordlen ) ) {
if ( + + which > state )
return strdup ( buffer ) ;
}
}
} else if ( strstr ( line , " descriptions " ) ) {
if ( ( ! wordlen | | ! strncmp ( word , " general " , wordlen ) ) & & ( + + which > state ) )
return strdup ( " general " ) ;
if ( ( ! wordlen | | ! strncmp ( word , " ports " , wordlen ) ) & & ( + + which > state ) )
return strdup ( " ports " ) ;
}
break ;
}
return NULL ;
}
2006-08-16 15:03:09 +00:00
static struct ast_cli_entry chan_misdn_clis [ ] = {
{ { " misdn " , " send " , " calldeflect " , NULL } , misdn_send_cd , " Sends CallDeflection to mISDN Channel " ,
" Usage: misdn send calldeflect <channel> \" <nr> \" \n " , complete_ch } ,
{ { " misdn " , " send " , " digit " , NULL } , misdn_send_digit , " Sends DTMF Digit to mISDN Channel " ,
" Usage: misdn send digit <channel> \" <msg> \" \n "
" Send <digit> to <channel> as DTMF Tone \n "
" when channel is a mISDN channel \n " , complete_ch } ,
{ { " misdn " , " toggle " , " echocancel " , NULL } , misdn_toggle_echocancel , " Toggles EchoCancel on mISDN Channel " ,
" Usage: misdn toggle echocancel <channel> \n " , complete_ch } ,
{ { " misdn " , " send " , " display " , NULL } , misdn_send_display , " Sends Text to mISDN Channel " ,
" Usage: misdn send display <channel> \" <msg> \" \n "
" Send <msg> to <channel> as Display Message \n "
" when channel is a mISDN channel \n " , complete_ch } ,
{ { " misdn " , " show " , " config " , NULL } , misdn_show_config , " Shows internal mISDN config, read from cfg-file " ,
" Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]] \n "
" Use 0 for <port> to only print the general config. \n " , complete_show_config } ,
{ { " misdn " , " reload " , NULL } , misdn_reload , " Reloads internal mISDN config, read from cfg-file " ,
" Usage: misdn reload \n " } ,
{ { " misdn " , " set " , " tics " , NULL } , misdn_set_tics , " " ,
" \n " } ,
{ { " misdn " , " show " , " channels " , NULL } , misdn_show_cls , " Shows internal mISDN chan_list " ,
" Usage: misdn show channels \n " } ,
{ { " misdn " , " show " , " channel " , NULL } , misdn_show_cl , " Shows internal mISDN chan_list " ,
" Usage: misdn show channels \n " , complete_ch } ,
{ { " misdn " , " port " , " block " , NULL } , misdn_port_block , " Blocks the given port " ,
" Usage: misdn port block \n " } ,
{ { " misdn " , " port " , " unblock " , NULL } , misdn_port_unblock , " Unblocks the given port " ,
" Usage: misdn port unblock \n " } ,
{ { " misdn " , " restart " , " port " , NULL } , misdn_restart_port , " Restarts the given port " ,
" Usage: misdn restart port \n " } ,
{ { " misdn " , " port " , " up " , NULL } , misdn_port_up , " Tries to establish L1 on the given port " ,
" Usage: misdn port up <port> \n " } ,
{ { " misdn " , " port " , " down " , NULL } , misdn_port_down , " Tries to deacivate the L1 on the given port " ,
" Usage: misdn port down <port> \n " } ,
{ { " misdn " , " show " , " stacks " , NULL } , misdn_show_stacks , " Shows internal mISDN stack_list " ,
" Usage: misdn show stacks \n " } ,
{ { " misdn " , " show " , " ports " , " stats " , NULL } , misdn_show_ports_stats , " Shows chan_misdns call statistics per port " ,
" Usage: misdn show port stats \n " } ,
{ { " misdn " , " show " , " port " , NULL } , misdn_show_port , " Shows detailed information for given port " ,
" Usage: misdn show port <port> \n " } ,
{ { " misdn " , " set " , " debug " , NULL } , misdn_set_debug , " Sets Debuglevel of chan_misdn " ,
" Usage: misdn set debug <level> [only] | [port <port> [only]] \n " , complete_debug_port } ,
{ { " misdn " , " set " , " crypt " , " debug " , NULL } , misdn_set_crypt_debug , " Sets CryptDebuglevel of chan_misdn, at the moment, level={1,2} " ,
" Usage: misdn set crypt debug <level> \n " }
2005-10-31 22:51:12 +00:00
} ;
2006-02-02 21:15:34 +00:00
static int update_config ( struct chan_list * ch , int orig )
{
if ( ! ch ) {
ast_log ( LOG_WARNING , " Cannot configure without chanlist \n " ) ;
return - 1 ;
}
struct ast_channel * ast = ch - > ast ;
struct misdn_bchannel * bc = ch - > bc ;
if ( ! ast | | ! bc ) {
ast_log ( LOG_WARNING , " Cannot configure without ast || bc \n " ) ;
return - 1 ;
}
int port = bc - > port ;
2006-06-01 12:51:41 +00:00
chan_misdn_log ( 5 , port , " update_config: Getting Config \n " ) ;
2006-02-02 21:15:34 +00:00
2006-03-20 18:04:05 +00:00
int hdlc = 0 ;
misdn_cfg_get ( port , MISDN_CFG_HDLC , & hdlc , sizeof ( int ) ) ;
if ( hdlc ) {
switch ( bc - > capability ) {
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED :
case INFO_CAPABILITY_DIGITAL_RESTRICTED :
chan_misdn_log ( 1 , bc - > port , " --> CONF HDLC \n " ) ;
bc - > hdlc = 1 ;
break ;
}
}
2006-02-02 21:15:34 +00:00
int pres , screen ;
misdn_cfg_get ( port , MISDN_CFG_PRES , & pres , sizeof ( int ) ) ;
misdn_cfg_get ( port , MISDN_CFG_SCREEN , & screen , sizeof ( int ) ) ;
chan_misdn_log ( 2 , port , " --> pres: %d screen: %d \n " , pres , screen ) ;
if ( ( pres + screen ) < 0 ) {
chan_misdn_log ( 2 , port , " --> pres: %x \n " , ast - > cid . cid_pres ) ;
switch ( ast - > cid . cid_pres & 0x60 ) {
case AST_PRES_RESTRICTED :
bc - > pres = 1 ;
chan_misdn_log ( 2 , port , " --> PRES: Restricted (0x1) \n " ) ;
break ;
case AST_PRES_UNAVAILABLE :
bc - > pres = 2 ;
chan_misdn_log ( 2 , port , " --> PRES: Unavailable (0x2) \n " ) ;
break ;
default :
bc - > pres = 0 ;
chan_misdn_log ( 2 , port , " --> PRES: Allowed (0x0) \n " ) ;
}
switch ( ast - > cid . cid_pres & 0x3 ) {
case AST_PRES_USER_NUMBER_UNSCREENED :
bc - > screen = 0 ;
chan_misdn_log ( 2 , port , " --> SCREEN: Unscreened (0x0) \n " ) ;
break ;
case AST_PRES_USER_NUMBER_PASSED_SCREEN :
bc - > screen = 1 ;
chan_misdn_log ( 2 , port , " --> SCREEN: Passed Screen (0x1) \n " ) ;
break ;
case AST_PRES_USER_NUMBER_FAILED_SCREEN :
bc - > screen = 2 ;
chan_misdn_log ( 2 , port , " --> SCREEN: Failed Screen (0x2) \n " ) ;
break ;
case AST_PRES_NETWORK_NUMBER :
bc - > screen = 3 ;
chan_misdn_log ( 2 , port , " --> SCREEN: Network Nr. (0x3) \n " ) ;
break ;
default :
bc - > screen = 0 ;
chan_misdn_log ( 2 , port , " --> SCREEN: Unscreened (0x0) \n " ) ;
}
} else {
bc - > screen = screen ;
bc - > pres = pres ;
}
return 0 ;
}
2005-10-31 22:51:12 +00:00
2006-02-10 14:17:28 +00:00
2006-04-24 17:11:45 +00:00
static void config_jitterbuffer ( struct chan_list * ch )
2006-02-10 14:17:28 +00:00
{
struct misdn_bchannel * bc = ch - > bc ;
int len = ch - > jb_len , threshold = ch - > jb_upper_threshold ;
2006-06-01 12:51:41 +00:00
chan_misdn_log ( 5 , bc - > port , " config_jb: Called \n " ) ;
2006-02-10 14:17:28 +00:00
if ( ! len ) {
chan_misdn_log ( 1 , bc - > port , " config_jb: Deactivating Jitterbuffer \n " ) ;
bc - > nojitter = 1 ;
} else {
if ( len < = 100 | | len > 8000 ) {
2006-08-03 16:38:00 +00:00
chan_misdn_log ( 0 , bc - > port , " config_jb: Jitterbuffer out of Bounds, setting to 1000 \n " ) ;
2006-02-10 14:17:28 +00:00
len = 1000 ;
}
if ( threshold > len ) {
2006-08-03 16:38:00 +00:00
chan_misdn_log ( 0 , bc - > port , " config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1 \n " ) ;
2006-02-10 14:17:28 +00:00
}
if ( ch - > jb ) {
cb_log ( 0 , bc - > port , " config_jb: We've got a Jitterbuffer Already on this port. \n " ) ;
misdn_jb_destroy ( ch - > jb ) ;
ch - > jb = NULL ;
}
ch - > jb = misdn_jb_init ( len , threshold ) ;
2006-04-04 19:09:26 +00:00
if ( ! ch - > jb )
bc - > nojitter = 1 ;
2006-02-10 14:17:28 +00:00
}
}
2006-05-16 14:34:21 +00:00
void debug_numplan ( int port , int numplan , char * type )
{
switch ( numplan ) {
case NUMPLAN_INTERNATIONAL :
chan_misdn_log ( 2 , port , " --> %s: International \n " , type ) ;
break ;
case NUMPLAN_NATIONAL :
chan_misdn_log ( 2 , port , " --> %s: National \n " , type ) ;
break ;
case NUMPLAN_SUBSCRIBER :
chan_misdn_log ( 2 , port , " --> %s: Subscriber \n " , type ) ;
break ;
case NUMPLAN_UNKNOWN :
chan_misdn_log ( 2 , port , " --> %s: Unknown \n " , type ) ;
break ;
/* Maybe we should cut off the prefix if present ? */
default :
chan_misdn_log ( 0 , port , " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file \n " ) ;
break ;
}
}
2006-06-01 12:51:41 +00:00
2006-08-08 09:19:06 +00:00
static int update_ec_config ( struct misdn_bchannel * bc )
{
int ec ;
int port = bc - > port ;
misdn_cfg_get ( port , MISDN_CFG_ECHOCANCEL , & ec , sizeof ( int ) ) ;
if ( ec = = 1 ) {
bc - > ec_enable = 1 ;
} else if ( ec > 1 ) {
bc - > ec_enable = 1 ;
bc - > ec_deftaps = ec ;
}
# ifdef WITH_ECHOTRAINING
int ectr ;
misdn_cfg_get ( port , MISDN_CFG_ECHOTRAINING , & ectr , sizeof ( int ) ) ;
if ( ectr > = 0 ) {
bc - > ec_training = ectr ;
}
# endif
return 0 ;
}
2006-06-01 12:51:41 +00:00
2005-12-09 11:01:18 +00:00
static int read_config ( struct chan_list * ch , int orig ) {
2005-11-15 20:20:45 +00:00
2005-12-09 11:01:18 +00:00
if ( ! ch ) {
ast_log ( LOG_WARNING , " Cannot configure without chanlist \n " ) ;
2005-10-31 22:51:12 +00:00
return - 1 ;
}
2005-12-09 11:01:18 +00:00
struct ast_channel * ast = ch - > ast ;
struct misdn_bchannel * bc = ch - > bc ;
if ( ! ast | | ! bc ) {
ast_log ( LOG_WARNING , " Cannot configure without ast || bc \n " ) ;
2005-10-31 22:51:12 +00:00
return - 1 ;
}
2005-12-09 11:01:18 +00:00
int port = bc - > port ;
chan_misdn_log ( 1 , port , " read_config: Getting Config \n " ) ;
2005-10-31 22:51:12 +00:00
2006-02-22 21:59:46 +00:00
char lang [ BUFFERSIZE + 1 ] ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( port , MISDN_CFG_LANGUAGE , lang , BUFFERSIZE ) ;
2006-02-02 18:33:23 +00:00
ast_string_field_set ( ast , language , lang ) ;
2005-12-09 11:01:18 +00:00
2006-02-22 21:59:46 +00:00
char localmusicclass [ BUFFERSIZE + 1 ] ;
2005-10-31 22:51:12 +00:00
2006-02-02 18:33:23 +00:00
misdn_cfg_get ( port , MISDN_CFG_MUSICCLASS , localmusicclass , BUFFERSIZE ) ;
ast_string_field_set ( ast , musicclass , localmusicclass ) ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( port , MISDN_CFG_TXGAIN , & bc - > txgain , sizeof ( int ) ) ;
misdn_cfg_get ( port , MISDN_CFG_RXGAIN , & bc - > rxgain , sizeof ( int ) ) ;
2006-02-15 19:51:33 +00:00
misdn_cfg_get ( port , MISDN_CFG_INCOMING_EARLY_AUDIO , & ch - > incoming_early_audio , sizeof ( int ) ) ;
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( port , MISDN_CFG_SENDDTMF , & bc - > send_dtmf , sizeof ( int ) ) ;
2006-02-02 21:15:34 +00:00
misdn_cfg_get ( port , MISDN_CFG_NEED_MORE_INFOS , & bc - > need_more_infos , sizeof ( int ) ) ;
2005-12-09 11:01:18 +00:00
2006-05-05 16:38:15 +00:00
misdn_cfg_get ( port , MISDN_CFG_FAR_ALERTING , & ch - > far_alerting , sizeof ( int ) ) ;
2006-06-01 12:51:41 +00:00
misdn_cfg_get ( port , MISDN_CFG_ALLOWED_BEARERS , & ch - > allowed_bearers , BUFFERSIZE ) ;
2006-08-08 18:13:40 +00:00
char faxdetect [ BUFFERSIZE + 1 ] ;
misdn_cfg_get ( port , MISDN_CFG_FAXDETECT , faxdetect , BUFFERSIZE ) ;
2006-05-05 16:38:15 +00:00
2006-03-20 18:04:05 +00:00
int hdlc = 0 ;
misdn_cfg_get ( port , MISDN_CFG_HDLC , & hdlc , sizeof ( int ) ) ;
if ( hdlc ) {
switch ( bc - > capability ) {
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED :
case INFO_CAPABILITY_DIGITAL_RESTRICTED :
chan_misdn_log ( 1 , bc - > port , " --> CONF HDLC \n " ) ;
bc - > hdlc = 1 ;
break ;
}
}
2005-12-09 11:01:18 +00:00
/*Initialize new Jitterbuffer*/
{
2006-02-10 14:17:28 +00:00
misdn_cfg_get ( port , MISDN_CFG_JITTERBUFFER , & ch - > jb_len , sizeof ( int ) ) ;
misdn_cfg_get ( port , MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD , & ch - > jb_upper_threshold , sizeof ( int ) ) ;
2005-12-09 11:01:18 +00:00
2006-02-10 14:17:28 +00:00
config_jitterbuffer ( ch ) ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( bc - > port , MISDN_CFG_CONTEXT , ch - > context , sizeof ( ch - > context ) ) ;
2006-02-02 21:15:34 +00:00
2006-05-16 14:34:21 +00:00
ast_copy_string ( ast - > context , ch - > context , sizeof ( ast - > context ) ) ;
2006-08-03 16:38:00 +00:00
2006-08-08 09:19:06 +00:00
update_ec_config ( bc ) ;
2005-12-09 11:01:18 +00:00
{
int eb3 ;
misdn_cfg_get ( bc - > port , MISDN_CFG_EARLY_BCONNECT , & eb3 , sizeof ( int ) ) ;
bc - > early_bconnect = eb3 ;
}
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
port = bc - > port ;
2005-10-31 22:51:12 +00:00
{
2005-12-09 11:01:18 +00:00
char buf [ 256 ] ;
ast_group_t pg , cg ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( port , MISDN_CFG_PICKUPGROUP , & pg , sizeof ( pg ) ) ;
misdn_cfg_get ( port , MISDN_CFG_CALLGROUP , & cg , sizeof ( cg ) ) ;
2005-10-31 22:51:12 +00:00
2006-06-01 12:51:41 +00:00
chan_misdn_log ( 5 , port , " --> * CallGrp:%s PickupGrp:%s \n " , ast_print_group ( buf , sizeof ( buf ) , cg ) , ast_print_group ( buf , sizeof ( buf ) , pg ) ) ;
2005-12-09 11:01:18 +00:00
ast - > pickupgroup = pg ;
ast - > callgroup = cg ;
}
if ( orig = = ORG_AST ) {
misdn_cfg_get ( port , MISDN_CFG_TE_CHOOSE_CHANNEL , & ( bc - > te_choose_channel ) , sizeof ( int ) ) ;
2005-10-31 22:51:12 +00:00
2006-08-08 18:13:40 +00:00
if ( strstr ( faxdetect , " outgoing " ) | | strstr ( faxdetect , " both " ) ) {
if ( strstr ( faxdetect , " nojump " ) )
ch - > faxdetect = 2 ;
else
ch - > faxdetect = 1 ;
}
2005-10-31 22:51:12 +00:00
{
2006-02-22 21:59:46 +00:00
char callerid [ BUFFERSIZE + 1 ] ;
2005-10-31 22:51:12 +00:00
misdn_cfg_get ( port , MISDN_CFG_CALLERID , callerid , BUFFERSIZE ) ;
if ( ! ast_strlen_zero ( callerid ) ) {
chan_misdn_log ( 1 , port , " --> * Setting Cid to %s \n " , callerid ) ;
{
2005-12-09 11:01:18 +00:00
int l = sizeof ( bc - > oad ) ;
strncpy ( bc - > oad , callerid , l ) ;
bc - > oad [ l - 1 ] = 0 ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
}
misdn_cfg_get ( port , MISDN_CFG_DIALPLAN , & bc - > dnumplan , sizeof ( int ) ) ;
misdn_cfg_get ( port , MISDN_CFG_LOCALDIALPLAN , & bc - > onumplan , sizeof ( int ) ) ;
2006-03-09 18:01:27 +00:00
misdn_cfg_get ( port , MISDN_CFG_CPNDIALPLAN , & bc - > cpnnumplan , sizeof ( int ) ) ;
2006-05-16 14:34:21 +00:00
debug_numplan ( port , bc - > dnumplan , " TON " ) ;
debug_numplan ( port , bc - > onumplan , " LTON " ) ;
debug_numplan ( port , bc - > cpnnumplan , " CTON " ) ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
2006-07-11 19:30:35 +00:00
ch - > overlap_dial = 0 ;
2005-12-09 11:01:18 +00:00
} else { /** ORIGINATOR MISDN **/
2006-08-08 18:13:40 +00:00
if ( strstr ( faxdetect , " incoming " ) | | strstr ( faxdetect , " both " ) ) {
if ( strstr ( faxdetect , " nojump " ) )
ch - > faxdetect = 2 ;
else
ch - > faxdetect = 1 ;
}
2006-04-05 15:54:15 +00:00
misdn_cfg_get ( port , MISDN_CFG_CPNDIALPLAN , & bc - > cpnnumplan , sizeof ( int ) ) ;
2006-05-16 14:34:21 +00:00
debug_numplan ( port , bc - > cpnnumplan , " CTON " ) ;
2005-12-09 11:01:18 +00:00
2006-02-22 21:59:46 +00:00
char prefix [ BUFFERSIZE + 1 ] = " " ;
2005-12-09 11:01:18 +00:00
switch ( bc - > onumplan ) {
case NUMPLAN_INTERNATIONAL :
misdn_cfg_get ( bc - > port , MISDN_CFG_INTERNATPREFIX , prefix , BUFFERSIZE ) ;
break ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
case NUMPLAN_NATIONAL :
misdn_cfg_get ( bc - > port , MISDN_CFG_NATPREFIX , prefix , BUFFERSIZE ) ;
break ;
default :
break ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
{
int l = strlen ( prefix ) + strlen ( bc - > oad ) ;
char tmp [ l + 1 ] ;
strcpy ( tmp , prefix ) ;
strcat ( tmp , bc - > oad ) ;
strcpy ( bc - > oad , tmp ) ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
if ( ! ast_strlen_zero ( bc - > dad ) ) {
2006-02-22 21:59:46 +00:00
ast_copy_string ( bc - > orig_dad , bc - > dad , sizeof ( bc - > orig_dad ) ) ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
if ( ast_strlen_zero ( bc - > dad ) & & ! ast_strlen_zero ( bc - > keypad ) ) {
2006-02-22 21:59:46 +00:00
ast_copy_string ( bc - > dad , bc - > keypad , sizeof ( bc - > dad ) ) ;
2005-12-09 11:01:18 +00:00
}
2006-05-16 14:34:21 +00:00
2005-12-09 11:01:18 +00:00
prefix [ 0 ] = 0 ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
switch ( bc - > dnumplan ) {
case NUMPLAN_INTERNATIONAL :
misdn_cfg_get ( bc - > port , MISDN_CFG_INTERNATPREFIX , prefix , BUFFERSIZE ) ;
break ;
2006-05-16 14:34:21 +00:00
case NUMPLAN_NATIONAL :
misdn_cfg_get ( bc - > port , MISDN_CFG_NATPREFIX , prefix , BUFFERSIZE ) ;
2005-12-09 11:01:18 +00:00
break ;
default :
break ;
}
{
int l = strlen ( prefix ) + strlen ( bc - > dad ) ;
char tmp [ l + 1 ] ;
strcpy ( tmp , prefix ) ;
strcat ( tmp , bc - > dad ) ;
strcpy ( bc - > dad , tmp ) ;
}
2006-02-02 21:15:34 +00:00
if ( strcmp ( bc - > dad , ast - > exten ) ) {
ast_copy_string ( ast - > exten , bc - > dad , sizeof ( ast - > exten ) ) ;
}
2006-04-29 22:56:00 +00:00
2006-05-02 14:26:40 +00:00
ast_set_callerid ( ast , bc - > oad , NULL , bc - > oad ) ;
2006-02-22 21:59:46 +00:00
2006-05-01 03:58:13 +00:00
if ( ! ast_strlen_zero ( bc - > rad ) ) {
if ( ast - > cid . cid_rdnis )
free ( ast - > cid . cid_rdnis ) ;
ast - > cid . cid_rdnis = strdup ( bc - > rad ) ;
}
2006-07-11 19:30:35 +00:00
misdn_cfg_get ( bc - > port , MISDN_CFG_OVERLAP_DIAL , & ch - > overlap_dial , sizeof ( ch - > overlap_dial ) ) ;
ast_mutex_init ( & ch - > overlap_tv_lock ) ;
2006-05-16 14:34:21 +00:00
} /* ORIG MISDN END */
2006-08-08 18:13:40 +00:00
ch - > overlap_dial_task = - 1 ;
if ( ch - > faxdetect ) {
misdn_cfg_get ( port , MISDN_CFG_FAXDETECT_TIMEOUT , & ch - > faxdetect_timeout , sizeof ( ch - > faxdetect_timeout ) ) ;
if ( ! ch - > dsp )
ch - > dsp = ast_dsp_new ( ) ;
if ( ch - > dsp )
ast_dsp_set_features ( ch - > dsp , DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT ) ;
if ( ! ch - > trans )
ch - > trans = ast_translator_build_path ( AST_FORMAT_SLINEAR , AST_FORMAT_ALAW ) ;
}
2006-08-16 13:19:54 +00:00
/* AOCD initialization */
bc - > AOCDtype = Fac_None ;
2005-12-09 11:01:18 +00:00
return 0 ;
}
/*****************************/
/*** AST Indications Start ***/
/*****************************/
static int misdn_call ( struct ast_channel * ast , char * dest , int timeout )
{
int port = 0 ;
int r ;
struct chan_list * ch = MISDN_ASTERISK_TECH_PVT ( ast ) ;
struct misdn_bchannel * newbc ;
char * opts = NULL , * ext , * tokb ;
char dest_cp [ 256 ] ;
2006-02-08 16:10:21 +00:00
2005-12-09 11:01:18 +00:00
{
strncpy ( dest_cp , dest , sizeof ( dest_cp ) - 1 ) ;
dest_cp [ sizeof ( dest_cp ) ] = 0 ;
ext = strtok_r ( dest_cp , " / " , & tokb ) ;
if ( ext ) {
ext = strtok_r ( NULL , " / " , & tokb ) ;
if ( ext ) {
opts = strtok_r ( NULL , " / " , & tokb ) ;
} else {
2006-08-03 16:38:00 +00:00
chan_misdn_log ( 0 , 0 , " misdn_call: No Extension given! \n " ) ;
2005-12-09 11:01:18 +00:00
return - 1 ;
}
}
}
if ( ! ast ) {
ast_log ( LOG_WARNING , " --> ! misdn_call called on ast_channel *ast where ast == NULL \n " ) ;
return - 1 ;
}
if ( ( ( ast - > _state ! = AST_STATE_DOWN ) & & ( ast - > _state ! = AST_STATE_RESERVED ) ) | | ! dest ) {
ast_log ( LOG_WARNING , " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL) \n " , ast - > name ) ;
ast - > hangupcause = 41 ;
ast_setstate ( ast , AST_STATE_DOWN ) ;
return - 1 ;
}
if ( ! ch ) {
ast_log ( LOG_WARNING , " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL) \n " , ast - > name ) ;
ast - > hangupcause = 41 ;
ast_setstate ( ast , AST_STATE_DOWN ) ;
return - 1 ;
}
newbc = ch - > bc ;
if ( ! newbc ) {
ast_log ( LOG_WARNING , " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL) \n " , ast - > name ) ;
ast - > hangupcause = 41 ;
ast_setstate ( ast , AST_STATE_DOWN ) ;
return - 1 ;
}
port = newbc - > port ;
strncpy ( newbc - > dad , ext , sizeof ( newbc - > dad ) ) ;
strncpy ( ast - > exten , ext , sizeof ( ast - > exten ) ) ;
2006-05-22 15:02:03 +00:00
int exceed ;
if ( ( exceed = add_out_calls ( port ) ) ) {
char tmp [ 16 ] ;
sprintf ( tmp , " %d " , exceed ) ;
pbx_builtin_setvar_helper ( ast , " MAX_OVERFLOW " , tmp ) ;
return - 1 ;
}
2005-12-09 11:01:18 +00:00
2006-02-08 16:10:21 +00:00
chan_misdn_log ( 1 , port , " * CALL: %s \n " , dest ) ;
2005-12-09 11:01:18 +00:00
chan_misdn_log ( 1 , port , " --> * dad:%s tech:%s ctx:%s \n " , ast - > exten , ast - > name , ast - > context ) ;
chan_misdn_log ( 3 , port , " --> * adding2newbc ext %s \n " , ast - > exten ) ;
if ( ast - > exten ) {
int l = sizeof ( newbc - > dad ) ;
strncpy ( newbc - > dad , ast - > exten , l ) ;
newbc - > dad [ l - 1 ] = 0 ;
}
newbc - > rad [ 0 ] = 0 ;
chan_misdn_log ( 3 , port , " --> * adding2newbc callerid %s \n " , AST_CID_P ( ast ) ) ;
if ( ast_strlen_zero ( newbc - > oad ) & & AST_CID_P ( ast ) ) {
if ( AST_CID_P ( ast ) ) {
int l = sizeof ( newbc - > oad ) ;
strncpy ( newbc - > oad , AST_CID_P ( ast ) , l ) ;
newbc - > oad [ l - 1 ] = 0 ;
}
}
{
struct chan_list * ch = MISDN_ASTERISK_TECH_PVT ( ast ) ;
if ( ! ch ) { ast_verbose ( " No chan_list in misdn_call " ) ; return - 1 ; }
newbc - > capability = ast - > transfercapability ;
pbx_builtin_setvar_helper ( ast , " TRANSFERCAPABILITY " , ast_transfercapability2str ( newbc - > capability ) ) ;
if ( ast - > transfercapability = = INFO_CAPABILITY_DIGITAL_UNRESTRICTED ) {
chan_misdn_log ( 2 , port , " --> * Call with flag Digital \n " ) ;
}
2006-02-02 21:15:34 +00:00
/* update screening and presentation */
update_config ( ch , ORG_AST ) ;
2006-03-20 18:04:05 +00:00
2006-02-22 21:59:46 +00:00
/* fill in some ies from channel vary*/
2006-06-17 10:37:35 +00:00
import_ch ( ast , newbc , ch ) ;
2006-02-22 21:59:46 +00:00
2005-12-09 11:01:18 +00:00
/* Finally The Options Override Everything */
if ( opts )
misdn_set_opt_exec ( ast , opts ) ;
else
2006-02-08 16:10:21 +00:00
chan_misdn_log ( 2 , port , " NO OPTS GIVEN \n " ) ;
2005-12-09 11:01:18 +00:00
ch - > state = MISDN_CALLING ;
r = misdn_lib_send_event ( newbc , EVENT_SETUP ) ;
/** we should have l3id after sending setup **/
ch - > l3id = newbc - > l3_id ;
}
if ( r = = - ENOCHAN ) {
2005-10-31 22:51:12 +00:00
chan_misdn_log ( 0 , port , " --> * Theres no Channel at the moment .. ! \n " ) ;
chan_misdn_log ( 1 , port , " --> * SEND: State Down pid:%d \n " , newbc ? newbc - > pid : - 1 ) ;
ast - > hangupcause = 34 ;
ast_setstate ( ast , AST_STATE_DOWN ) ;
return - 1 ;
}
chan_misdn_log ( 1 , port , " --> * SEND: State Dialing pid:%d \n " , newbc ? newbc - > pid : 1 ) ;
ast_setstate ( ast , AST_STATE_DIALING ) ;
ast - > hangupcause = 16 ;
2006-07-03 16:47:28 +00:00
if ( newbc - > nt ) stop_bc_tones ( ch ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2005-12-09 11:01:18 +00:00
static int misdn_answer ( struct ast_channel * ast )
2005-10-31 22:51:12 +00:00
{
struct chan_list * p ;
2006-02-02 21:15:34 +00:00
if ( ! ast | | ! ( p = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) return - 1 ;
2005-10-31 22:51:12 +00:00
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p ? ( p - > bc ? p - > bc - > port : 0 ) : 0 , " * ANSWER: \n " ) ;
2005-10-31 22:51:12 +00:00
if ( ! p ) {
ast_log ( LOG_WARNING , " --> Channel not connected ?? \n " ) ;
ast_queue_hangup ( ast ) ;
}
if ( ! p - > bc ) {
chan_misdn_log ( 1 , 0 , " --> Got Answer, but theres no bc obj ?? \n " ) ;
ast_queue_hangup ( ast ) ;
}
{
2005-12-09 11:01:18 +00:00
const char * tmp_key = pbx_builtin_getvar_helper ( p - > ast , " CRYPT_KEY " ) ;
2005-10-31 22:51:12 +00:00
if ( tmp_key ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> Connection will be BF crypted \n " ) ;
2005-10-31 22:51:12 +00:00
{
int l = sizeof ( p - > bc - > crypt_key ) ;
strncpy ( p - > bc - > crypt_key , tmp_key , l ) ;
p - > bc - > crypt_key [ l - 1 ] = 0 ;
}
} else {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 3 , p - > bc - > port , " --> Connection is without BF encryption \n " ) ;
2005-10-31 22:51:12 +00:00
}
}
2005-11-15 20:20:45 +00:00
{
2006-02-02 21:15:34 +00:00
const char * nodsp = pbx_builtin_getvar_helper ( ast , " MISDN_DIGITAL_TRANS " ) ;
if ( nodsp ) {
2005-11-15 20:20:45 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> Connection is transparent digital \n " ) ;
2006-02-02 21:15:34 +00:00
p - > bc - > nodsp = 1 ;
p - > bc - > hdlc = 0 ;
p - > bc - > nojitter = 1 ;
2005-11-15 20:20:45 +00:00
}
}
2005-10-31 22:51:12 +00:00
p - > state = MISDN_CONNECTED ;
2006-05-05 16:38:15 +00:00
misdn_lib_echo ( p - > bc , 0 ) ;
2006-07-06 15:11:40 +00:00
stop_indicate ( p ) ;
2006-04-05 14:51:48 +00:00
if ( ast_strlen_zero ( p - > bc - > cad ) ) {
chan_misdn_log ( 2 , p - > bc - > port , " --> empty cad using dad \n " ) ;
ast_copy_string ( p - > bc - > cad , p - > bc - > dad , sizeof ( p - > bc - > cad ) ) ;
}
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( p - > bc , EVENT_CONNECT ) ;
start_bc_tones ( p ) ;
return 0 ;
}
2006-08-31 01:59:02 +00:00
static int misdn_digit_begin ( struct ast_channel * chan , char digit )
{
/* XXX Modify this callback to support Asterisk controlling the length of DTMF */
return 0 ;
}
static int misdn_digit_end ( struct ast_channel * ast , char digit )
2005-10-31 22:51:12 +00:00
{
struct chan_list * p ;
2006-02-02 21:15:34 +00:00
if ( ! ast | | ! ( p = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) return - 1 ;
2005-10-31 22:51:12 +00:00
struct misdn_bchannel * bc = p - > bc ;
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc ? bc - > port : 0 , " * IND : Digit %c \n " , digit ) ;
2005-10-31 22:51:12 +00:00
if ( ! bc ) {
ast_log ( LOG_WARNING , " --> !! Got Digit Event withut having bchannel Object \n " ) ;
return - 1 ;
}
switch ( p - > state ) {
case MISDN_CALLING :
{
char buf [ 8 ] ;
buf [ 0 ] = digit ;
buf [ 1 ] = 0 ;
int l = sizeof ( bc - > infos_pending ) ;
strncat ( bc - > infos_pending , buf , l ) ;
bc - > infos_pending [ l - 1 ] = 0 ;
}
break ;
case MISDN_CALLING_ACKNOWLEDGE :
{
bc - > info_dad [ 0 ] = digit ;
bc - > info_dad [ 1 ] = 0 ;
{
int l = sizeof ( bc - > dad ) ;
strncat ( bc - > dad , bc - > info_dad , l - strlen ( bc - > dad ) ) ;
bc - > dad [ l - 1 ] = 0 ;
}
{
int l = sizeof ( p - > ast - > exten ) ;
strncpy ( p - > ast - > exten , bc - > dad , l ) ;
p - > ast - > exten [ l - 1 ] = 0 ;
}
misdn_lib_send_event ( bc , EVENT_INFORMATION ) ;
}
break ;
default :
if ( bc - > send_dtmf ) {
send_digit_to_chan ( p , digit ) ;
}
break ;
}
return 0 ;
}
2005-12-09 11:01:18 +00:00
static int misdn_fixup ( struct ast_channel * oldast , struct ast_channel * ast )
2005-10-31 22:51:12 +00:00
{
struct chan_list * p ;
2006-02-02 21:15:34 +00:00
if ( ! ast | | ! ( p = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) return - 1 ;
2005-10-31 22:51:12 +00:00
2006-08-08 09:19:06 +00:00
chan_misdn_log ( 1 , p - > bc ? p - > bc - > port : 0 , " * IND: Got Fixup State:%s L3id:%x \n " , misdn_get_ch_state ( p ) , p - > l3id ) ;
2005-10-31 22:51:12 +00:00
p - > ast = ast ;
p - > state = MISDN_CONNECTED ;
return 0 ;
}
2006-05-16 14:34:21 +00:00
static int misdn_indication ( struct ast_channel * ast , int cond , const void * data , size_t datalen )
2005-10-31 22:51:12 +00:00
{
struct chan_list * p ;
2006-02-02 21:15:34 +00:00
if ( ! ast | | ! ( p = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) {
2005-10-31 22:51:12 +00:00
ast_log ( LOG_WARNING , " Returnded -1 in misdn_indication \n " ) ;
return - 1 ;
}
if ( ! p - > bc ) {
chan_misdn_log ( 1 , 0 , " * IND : Indication from %s \n " , ast - > exten ) ;
ast_log ( LOG_WARNING , " Private Pointer but no bc ? \n " ) ;
return - 1 ;
}
2006-02-02 21:15:34 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " * IND : Indication [%d] from %s \n " , cond , ast - > exten ) ;
2005-10-31 22:51:12 +00:00
switch ( cond ) {
case AST_CONTROL_BUSY :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " * IND : \t busy \n " ) ;
chan_misdn_log ( 1 , p - > bc - > port , " --> * SEND: State Busy pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
ast_setstate ( ast , AST_STATE_BUSY ) ;
2006-06-26 17:37:11 +00:00
2005-10-31 22:51:12 +00:00
p - > bc - > out_cause = 17 ;
if ( p - > state ! = MISDN_CONNECTED ) {
2006-07-06 15:11:40 +00:00
start_bc_tones ( p ) ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( p - > bc , EVENT_DISCONNECT ) ;
} else {
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , p - > bc - > port , " --> !! Got Busy in Connected State !?! ast:%s \n " , ast - > name ) ;
2005-10-31 22:51:12 +00:00
}
2006-07-06 15:11:40 +00:00
return - 1 ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_RING :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t ring pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-07-06 15:11:40 +00:00
return - 1 ;
2005-10-31 22:51:12 +00:00
break ;
2006-07-06 15:11:40 +00:00
2005-10-31 22:51:12 +00:00
case AST_CONTROL_RINGING :
2006-02-02 21:15:34 +00:00
switch ( p - > state ) {
case MISDN_ALERTING :
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t ringing pid:%d but I was Ringing before, so ignoreing it \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
break ;
case MISDN_CONNECTED :
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t ringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-07-03 16:47:28 +00:00
return - 1 ;
2006-02-02 21:15:34 +00:00
break ;
default :
p - > state = MISDN_ALERTING ;
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t ringing pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
misdn_lib_send_event ( p - > bc , EVENT_ALERTING ) ;
2006-06-17 10:37:35 +00:00
2006-06-21 15:21:46 +00:00
if ( p - > other_ch & & p - > other_ch - > bc ) {
if ( misdn_inband_avail ( p - > other_ch - > bc ) ) {
chan_misdn_log ( 1 , p - > bc - > port , " --> other End is mISDN and has inband info available \n " ) ;
break ;
}
if ( ! p - > other_ch - > bc - > nt ) {
chan_misdn_log ( 1 , p - > bc - > port , " --> other End is mISDN TE so it has inband info for sure (?) \n " ) ;
break ;
}
2006-06-17 10:37:35 +00:00
}
2006-06-21 15:21:46 +00:00
2006-07-03 16:47:28 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * SEND: State Ring pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
ast_setstate ( ast , AST_STATE_RINGING ) ;
2006-06-17 10:37:35 +00:00
2006-02-15 19:51:33 +00:00
if ( ! p - > bc - > nt & & ( p - > orginator = = ORG_MISDN ) & & ! p - > incoming_early_audio )
chan_misdn_log ( 1 , p - > bc - > port , " --> incoming_early_audio off \n " ) ;
2006-06-21 15:21:46 +00:00
else
2006-07-03 16:47:28 +00:00
return - 1 ;
2005-10-31 22:51:12 +00:00
}
break ;
case AST_CONTROL_ANSWER :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t answer pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-02-02 21:15:34 +00:00
start_bc_tones ( p ) ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_TAKEOFFHOOK :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * \t takeoffhook pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-07-06 15:11:40 +00:00
return - 1 ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_OFFHOOK :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * \t offhook pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-07-06 15:11:40 +00:00
return - 1 ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_FLASH :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * \t flash pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_PROGRESS :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t progress pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-02-02 21:15:34 +00:00
misdn_lib_send_event ( p - > bc , EVENT_PROGRESS ) ;
break ;
case AST_CONTROL_PROCEEDING :
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t proceeding pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
misdn_lib_send_event ( p - > bc , EVENT_PROCEEDING ) ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_CONGESTION :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t congestion pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
p - > bc - > out_cause = 42 ;
if ( p - > state ! = MISDN_CONNECTED ) {
start_bc_tones ( p ) ;
misdn_lib_send_event ( p - > bc , EVENT_RELEASE ) ;
} else {
misdn_lib_send_event ( p - > bc , EVENT_DISCONNECT ) ;
}
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
if ( p - > bc - > nt ) {
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( p ) ;
2005-10-31 22:51:12 +00:00
}
break ;
case - 1 :
2006-02-02 21:15:34 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * IND : \t -1! (stop indication) pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2006-02-10 14:17:28 +00:00
2006-07-06 15:11:40 +00:00
stop_indicate ( p ) ;
2006-06-17 10:37:35 +00:00
if ( p - > state = = MISDN_CONNECTED )
2006-02-10 14:17:28 +00:00
start_bc_tones ( p ) ;
2006-06-17 10:37:35 +00:00
2005-10-31 22:51:12 +00:00
break ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
case AST_CONTROL_HOLD :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * \t HOLD pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
break ;
case AST_CONTROL_UNHOLD :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , p - > bc - > port , " --> * \t UNHOLD pid:%d \n " , p - > bc ? p - > bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
break ;
default :
2006-06-21 15:21:46 +00:00
ast_log ( LOG_NOTICE , " --> * Unknown Indication:%d pid:%d \n " , cond , p - > bc ? p - > bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
}
return 0 ;
}
2005-12-09 11:01:18 +00:00
static int misdn_hangup ( struct ast_channel * ast )
2005-10-31 22:51:12 +00:00
{
struct chan_list * p ;
struct misdn_bchannel * bc = NULL ;
ast_log ( LOG_DEBUG , " misdn_hangup(%s) \n " , ast - > name ) ;
2006-09-06 18:02:25 +00:00
if ( ! ast | | ! ( p = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) return - 1 ;
2005-10-31 22:51:12 +00:00
if ( ! p ) {
chan_misdn_log ( 3 , 0 , " misdn_hangup called, without chan_list obj. \n " ) ;
return 0 ;
}
2005-11-15 20:20:45 +00:00
bc = p - > bc ;
if ( ! bc ) {
ast_log ( LOG_WARNING , " Hangup with private but no bc ? \n " ) ;
return 0 ;
}
2005-10-31 22:51:12 +00:00
MISDN_ASTERISK_TECH_PVT ( ast ) = NULL ;
p - > ast = NULL ;
2005-12-09 11:01:18 +00:00
bc = p - > bc ;
2005-10-31 22:51:12 +00:00
if ( ast - > _state = = AST_STATE_RESERVED ) {
/* between request and call */
MISDN_ASTERISK_TECH_PVT ( ast ) = NULL ;
cl_dequeue_chan ( & cl_te , p ) ;
2006-09-06 18:02:25 +00:00
close ( p - > pipe [ 0 ] ) ;
close ( p - > pipe [ 1 ] ) ;
2005-10-31 22:51:12 +00:00
free ( p ) ;
2005-12-09 11:01:18 +00:00
if ( bc )
misdn_lib_release ( bc ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2006-08-03 16:38:00 +00:00
p - > need_hangup = 0 ;
p - > need_queue_hangup = 0 ;
p - > need_busy = 0 ;
2006-06-19 09:44:04 +00:00
if ( ! p - > bc - > nt )
stop_bc_tones ( p ) ;
2005-10-31 22:51:12 +00:00
{
2005-12-09 11:01:18 +00:00
const char * varcause = NULL ;
2006-06-26 17:37:11 +00:00
bc - > out_cause = ast - > hangupcause ? ast - > hangupcause : 16 ;
2005-10-31 22:51:12 +00:00
if ( ( varcause = pbx_builtin_getvar_helper ( ast , " HANGUPCAUSE " ) ) | |
( varcause = pbx_builtin_getvar_helper ( ast , " PRI_CAUSE " ) ) ) {
int tmpcause = atoi ( varcause ) ;
bc - > out_cause = tmpcause ? tmpcause : 16 ;
}
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc - > port , " * IND : HANGUP \t pid:%d ctx:%s dad:%s oad:%s State:%s \n " , p - > bc ? p - > bc - > pid : - 1 , ast - > context , ast - > exten , AST_CID_P ( ast ) , misdn_get_ch_state ( p ) ) ;
chan_misdn_log ( 2 , bc - > port , " --> l3id:%x \n " , p - > l3id ) ;
chan_misdn_log ( 1 , bc - > port , " --> cause:%d \n " , bc - > cause ) ;
chan_misdn_log ( 1 , bc - > port , " --> out_cause:%d \n " , bc - > out_cause ) ;
2006-06-21 15:21:46 +00:00
chan_misdn_log ( 1 , bc - > port , " --> state:%s \n " , misdn_get_ch_state ( p ) ) ;
2005-10-31 22:51:12 +00:00
switch ( p - > state ) {
case MISDN_CALLING :
p - > state = MISDN_CLEANING ;
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
break ;
case MISDN_HOLDED :
case MISDN_DIALING :
start_bc_tones ( p ) ;
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( p ) ;
2006-06-17 10:37:35 +00:00
2006-08-03 16:38:00 +00:00
if ( bc - > need_disconnect )
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2005-10-31 22:51:12 +00:00
break ;
2006-07-06 15:11:40 +00:00
case MISDN_CALLING_ACKNOWLEDGE :
start_bc_tones ( p ) ;
hanguptone_indicate ( p ) ;
2006-07-13 14:13:24 +00:00
if ( bc - > need_disconnect )
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2006-07-06 15:11:40 +00:00
break ;
2005-10-31 22:51:12 +00:00
case MISDN_ALERTING :
2006-02-10 10:10:58 +00:00
case MISDN_PROGRESS :
case MISDN_PROCEEDING :
2005-10-31 22:51:12 +00:00
if ( p - > orginator ! = ORG_AST )
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( p ) ;
2005-10-31 22:51:12 +00:00
2006-06-26 17:37:11 +00:00
/*p->state=MISDN_CLEANING;*/
2006-07-13 14:13:24 +00:00
if ( bc - > need_disconnect )
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2005-10-31 22:51:12 +00:00
break ;
case MISDN_CONNECTED :
2006-08-03 16:38:00 +00:00
case MISDN_PRECONNECTED :
2005-10-31 22:51:12 +00:00
/* Alerting or Disconect */
2006-06-26 17:37:11 +00:00
if ( p - > bc - > nt ) {
start_bc_tones ( p ) ;
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( p ) ;
2006-06-26 17:37:11 +00:00
p - > bc - > progress_indicator = 8 ;
}
2006-07-13 14:13:24 +00:00
if ( bc - > need_disconnect )
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2006-06-26 17:37:11 +00:00
/*p->state=MISDN_CLEANING;*/
2005-10-31 22:51:12 +00:00
break ;
2006-03-07 12:17:35 +00:00
case MISDN_DISCONNECTED :
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
p - > state = MISDN_CLEANING ; /* MISDN_HUNGUP_FROM_AST; */
break ;
2005-10-31 22:51:12 +00:00
2006-06-21 15:21:46 +00:00
case MISDN_RELEASED :
2005-10-31 22:51:12 +00:00
case MISDN_CLEANING :
2006-06-26 17:37:11 +00:00
p - > state = MISDN_CLEANING ;
break ;
case MISDN_BUSY :
2005-10-31 22:51:12 +00:00
break ;
case MISDN_HOLD_DISCONNECT :
/* need to send release here */
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc - > port , " --> cause %d \n " , bc - > cause ) ;
chan_misdn_log ( 1 , bc - > port , " --> out_cause %d \n " , bc - > out_cause ) ;
2005-10-31 22:51:12 +00:00
2006-02-22 16:48:25 +00:00
bc - > out_cause = - 1 ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
2006-06-26 17:37:11 +00:00
p - > state = MISDN_CLEANING ;
2005-10-31 22:51:12 +00:00
break ;
default :
2006-02-22 16:48:25 +00:00
if ( bc - > nt ) {
bc - > out_cause = - 1 ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
2006-06-26 17:37:11 +00:00
p - > state = MISDN_CLEANING ;
} else {
2006-07-13 14:13:24 +00:00
if ( bc - > need_disconnect )
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2006-06-26 17:37:11 +00:00
}
2005-10-31 22:51:12 +00:00
}
2006-06-28 14:15:29 +00:00
p - > state = MISDN_CLEANING ;
2005-10-31 22:51:12 +00:00
}
2006-04-04 19:09:26 +00:00
2006-06-26 17:37:11 +00:00
chan_misdn_log ( 1 , bc - > port , " Channel: %s hanguped new state:%s \n " , ast - > name , misdn_get_ch_state ( p ) ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2006-05-16 14:34:21 +00:00
2006-09-20 05:13:03 +00:00
static struct ast_frame * process_ast_dsp ( struct chan_list * tmp , struct ast_frame * frame )
2006-05-16 14:34:21 +00:00
{
struct ast_frame * f , * f2 ;
2006-08-08 18:13:40 +00:00
if ( tmp - > trans ) {
f2 = ast_translate ( tmp - > trans , frame , 0 ) ;
f = ast_dsp_process ( tmp - > ast , tmp - > dsp , f2 ) ;
} else {
2006-05-16 14:34:21 +00:00
chan_misdn_log ( 0 , tmp - > bc - > port , " No T-Path found \n " ) ;
return NULL ;
}
2006-08-08 18:13:40 +00:00
if ( ! f | | ( f - > frametype ! = AST_FRAME_DTMF ) )
return frame ;
ast_log ( LOG_DEBUG , " Detected inband DTMF digit: %c " , f - > subclass ) ;
if ( tmp - > faxdetect & & ( f - > subclass = = ' f ' ) ) {
/* Fax tone -- Handle and return NULL */
if ( ! tmp - > faxhandled ) {
struct ast_channel * ast = tmp - > ast ;
tmp - > faxhandled + + ;
chan_misdn_log ( 0 , tmp - > bc - > port , " Fax detected, preparing %s for fax transfer. \n " , ast - > name ) ;
tmp - > bc - > rxgain = 0 ;
isdn_lib_update_rxgain ( tmp - > bc ) ;
tmp - > bc - > txgain = 0 ;
isdn_lib_update_txgain ( tmp - > bc ) ;
tmp - > bc - > ec_enable = 0 ;
isdn_lib_update_ec ( tmp - > bc ) ;
isdn_lib_stop_dtmf ( tmp - > bc ) ;
switch ( tmp - > faxdetect ) {
case 1 :
if ( strcmp ( ast - > exten , " fax " ) ) {
char * context ;
char context_tmp [ BUFFERSIZE ] ;
misdn_cfg_get ( tmp - > bc - > port , MISDN_CFG_FAXDETECT_CONTEXT , & context_tmp , sizeof ( context_tmp ) ) ;
context = ast_strlen_zero ( context_tmp ) ? ( ast_strlen_zero ( ast - > macrocontext ) ? ast - > context : ast - > macrocontext ) : context_tmp ;
if ( ast_exists_extension ( ast , context , " fax " , 1 , AST_CID_P ( ast ) ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Redirecting %s to fax extension (context:%s) \n " , ast - > name , context ) ;
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
pbx_builtin_setvar_helper ( ast , " FAXEXTEN " , ast - > exten ) ;
if ( ast_async_goto ( ast , context , " fax " , 1 ) )
ast_log ( LOG_WARNING , " Failed to async goto '%s' into fax of '%s' \n " , ast - > name , context ) ;
} else
ast_log ( LOG_NOTICE , " Fax detected, but no fax extension ctx:%s exten:%s \n " , context , ast - > exten ) ;
} else
ast_log ( LOG_DEBUG , " Already in a fax extension, not redirecting \n " ) ;
break ;
case 2 :
ast_verbose ( VERBOSE_PREFIX_3 " Not redirecting %s to fax extension, nojump is set. \n " , ast - > name ) ;
break ;
}
} else
ast_log ( LOG_DEBUG , " Fax already handled \n " ) ;
}
if ( tmp - > ast_dsp & & ( f - > subclass ! = ' f ' ) ) {
chan_misdn_log ( 2 , tmp - > bc - > port , " --> * SEND: DTMF (AST_DSP) :%c \n " , f - > subclass ) ;
}
2006-05-16 14:34:21 +00:00
return frame ;
}
2005-12-09 11:01:18 +00:00
static struct ast_frame * misdn_read ( struct ast_channel * ast )
2005-10-31 22:51:12 +00:00
{
struct chan_list * tmp ;
2006-05-16 14:34:21 +00:00
int len ;
2005-10-31 22:51:12 +00:00
2006-07-06 15:11:40 +00:00
if ( ! ast ) {
chan_misdn_log ( 1 , 0 , " misdn_read called without ast \n " ) ;
return NULL ;
}
2006-08-08 18:13:40 +00:00
if ( ! ( tmp = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) {
2006-07-06 15:11:40 +00:00
chan_misdn_log ( 1 , 0 , " misdn_read called without ast->pvt \n " ) ;
return NULL ;
}
if ( ! tmp - > bc ) {
chan_misdn_log ( 1 , 0 , " misdn_read called without bc \n " ) ;
return NULL ;
}
2006-06-18 19:09:32 +00:00
2006-05-16 14:34:21 +00:00
len = read ( tmp - > pipe [ 0 ] , tmp - > ast_rd_buf , sizeof ( tmp - > ast_rd_buf ) ) ;
2006-04-29 22:56:00 +00:00
2006-05-16 14:34:21 +00:00
if ( len < = 0 ) {
/* we hangup here, since our pipe is closed */
chan_misdn_log ( 2 , tmp - > bc - > port , " misdn_read: Pipe closed, hanging up \n " ) ;
return NULL ;
2006-04-03 19:17:59 +00:00
}
2005-10-31 22:51:12 +00:00
tmp - > frame . frametype = AST_FRAME_VOICE ;
tmp - > frame . subclass = AST_FORMAT_ALAW ;
tmp - > frame . datalen = len ;
2006-08-08 18:13:40 +00:00
tmp - > frame . samples = len ;
tmp - > frame . mallocd = 0 ;
tmp - > frame . offset = 0 ;
2005-10-31 22:51:12 +00:00
tmp - > frame . src = NULL ;
2006-08-08 18:13:40 +00:00
tmp - > frame . data = tmp - > ast_rd_buf ;
if ( tmp - > faxdetect & & ! tmp - > faxhandled ) {
if ( tmp - > faxdetect_timeout ) {
if ( ast_tvzero ( tmp - > faxdetect_tv ) ) {
tmp - > faxdetect_tv = ast_tvnow ( ) ;
chan_misdn_log ( 2 , tmp - > bc - > port , " faxdetect: starting detection with timeout: %ds ... \n " , tmp - > faxdetect_timeout ) ;
return process_ast_dsp ( tmp , & tmp - > frame ) ;
} else {
struct timeval tv_now = ast_tvnow ( ) ;
int diff = ast_tvdiff_ms ( tv_now , tmp - > faxdetect_tv ) ;
if ( diff < = ( tmp - > faxdetect_timeout * 1000 ) ) {
chan_misdn_log ( 5 , tmp - > bc - > port , " faxdetect: detecting ... \n " ) ;
return process_ast_dsp ( tmp , & tmp - > frame ) ;
} else {
chan_misdn_log ( 2 , tmp - > bc - > port , " faxdetect: stopping detection (time ran out) ... \n " ) ;
tmp - > faxdetect = 0 ;
return & tmp - > frame ;
}
}
} else {
chan_misdn_log ( 5 , tmp - > bc - > port , " faxdetect: detecting ... (no timeout) \n " ) ;
return process_ast_dsp ( tmp , & tmp - > frame ) ;
}
} else {
if ( tmp - > ast_dsp )
return process_ast_dsp ( tmp , & tmp - > frame ) ;
else
return & tmp - > frame ;
2006-05-16 14:34:21 +00:00
}
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
static int misdn_write ( struct ast_channel * ast , struct ast_frame * frame )
2005-10-31 22:51:12 +00:00
{
2005-12-09 11:01:18 +00:00
struct chan_list * ch ;
2005-10-31 22:51:12 +00:00
int i = 0 ;
2005-12-09 11:01:18 +00:00
if ( ! ast | | ! ( ch = MISDN_ASTERISK_TECH_PVT ( ast ) ) ) return - 1 ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
if ( ! ch - > bc ) {
2005-10-31 22:51:12 +00:00
ast_log ( LOG_WARNING , " private but no bc \n " ) ;
return - 1 ;
}
2006-08-08 09:19:06 +00:00
if ( ch - > state = = MISDN_HOLDED ) {
2006-07-11 19:30:35 +00:00
chan_misdn_log ( 7 , ch - > bc - > port , " misdn_write: Returning because holded \n " ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2005-12-09 11:01:18 +00:00
if ( ch - > notxtone ) {
2006-07-11 19:30:35 +00:00
chan_misdn_log ( 7 , ch - > bc - > port , " misdn_write: Returning because notxone \n " ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2006-02-02 21:15:34 +00:00
if ( ! frame - > subclass ) {
2006-04-03 19:17:59 +00:00
chan_misdn_log ( 4 , ch - > bc - > port , " misdn_write: * prods us \n " ) ;
2006-02-02 21:15:34 +00:00
return 0 ;
}
2005-10-31 22:51:12 +00:00
if ( ! ( frame - > subclass & prefformat ) ) {
2006-02-02 21:15:34 +00:00
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , ch - > bc - > port , " Got Unsupported Frame with Format:%d \n " , frame - > subclass ) ;
2006-05-05 16:38:15 +00:00
return 0 ;
2005-10-31 22:51:12 +00:00
}
2006-04-03 19:17:59 +00:00
if ( ! frame - > samples ) {
chan_misdn_log ( 4 , ch - > bc - > port , " misdn_write: zero write \n " ) ;
return 0 ;
}
if ( ! ch - > bc - > addr ) {
2006-04-04 19:09:26 +00:00
chan_misdn_log ( 8 , ch - > bc - > port , " misdn_write: no addr for bc dropping:%d \n " , frame - > samples ) ;
2006-04-03 19:17:59 +00:00
return 0 ;
}
2005-10-31 22:51:12 +00:00
# if MISDN_DEBUG
{
int i , max = 5 > frame - > samples ? frame - > samples : 5 ;
printf ( " write2mISDN %p %d bytes: " , p , frame - > samples ) ;
for ( i = 0 ; i < max ; i + + ) printf ( " %2.2x " , ( ( char * ) frame - > data ) [ i ] ) ;
printf ( " \n " ) ;
}
# endif
2005-12-09 11:01:18 +00:00
2006-04-03 19:17:59 +00:00
switch ( ch - > bc - > bc_state ) {
case BCHAN_ACTIVATED :
case BCHAN_BRIDGED :
break ;
default :
2006-04-29 22:56:00 +00:00
if ( ! ch - > dropped_frame_cnt )
chan_misdn_log ( 5 , ch - > bc - > port , " BC not active (nor bridged) droping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d \n " , frame - > samples , ch - > bc - > addr , ast - > exten , ast - > cid . cid_num , misdn_get_ch_state ( ch ) , ch - > bc - > bc_state ) ;
ch - > dropped_frame_cnt + + ;
if ( ch - > dropped_frame_cnt > 100 ) {
ch - > dropped_frame_cnt = 0 ;
chan_misdn_log ( 5 , ch - > bc - > port , " BC not active (nor bridged) droping: %d frames addr:%x dropped > 100 frames! \n " , frame - > samples , ch - > bc - > addr ) ;
}
2006-02-02 21:15:34 +00:00
return 0 ;
}
2006-05-05 16:38:15 +00:00
2006-02-02 21:15:34 +00:00
chan_misdn_log ( 9 , ch - > bc - > port , " Sending :%d bytes 2 MISDN \n " , frame - > samples ) ;
2005-12-09 11:01:18 +00:00
if ( ! ch - > bc - > nojitter & & misdn_cap_is_speech ( ch - > bc - > capability ) ) {
/* Buffered Transmit (triggert by read from isdn side)*/
if ( misdn_jb_fill ( ch - > jb , frame - > data , frame - > samples ) < 0 ) {
if ( ch - > bc - > active )
cb_log ( 0 , ch - > bc - > port , " Misdn Jitterbuffer Overflow. \n " ) ;
}
} else {
/*transmit without jitterbuffer*/
i = misdn_lib_tx2misdn_frm ( ch - > bc , frame - > data , frame - > samples ) ;
}
2005-10-31 22:51:12 +00:00
return 0 ;
}
2005-12-09 11:01:18 +00:00
2006-04-24 17:11:45 +00:00
static enum ast_bridge_result misdn_bridge ( struct ast_channel * c0 ,
2005-11-01 22:04:14 +00:00
struct ast_channel * c1 , int flags ,
struct ast_frame * * fo ,
struct ast_channel * * rc ,
int timeoutms )
2005-10-31 22:51:12 +00:00
{
struct chan_list * ch1 , * ch2 ;
struct ast_channel * carr [ 2 ] , * who ;
int to = - 1 ;
struct ast_frame * f ;
ch1 = get_chan_by_ast ( c0 ) ;
ch2 = get_chan_by_ast ( c1 ) ;
carr [ 0 ] = c0 ;
carr [ 1 ] = c1 ;
if ( ch1 & & ch2 ) ;
else
return - 1 ;
int bridging ;
misdn_cfg_get ( 0 , MISDN_GEN_BRIDGING , & bridging , sizeof ( int ) ) ;
if ( bridging ) {
2006-06-01 12:51:41 +00:00
int ecwb , ec ;
2005-11-01 22:04:14 +00:00
misdn_cfg_get ( ch1 - > bc - > port , MISDN_CFG_ECHOCANCELWHENBRIDGED , & ecwb , sizeof ( int ) ) ;
2006-06-01 12:51:41 +00:00
misdn_cfg_get ( ch1 - > bc - > port , MISDN_CFG_ECHOCANCEL , & ec , sizeof ( int ) ) ;
if ( ! ecwb & & ec ) {
2006-03-21 09:47:51 +00:00
chan_misdn_log ( 2 , ch1 - > bc - > port , " Disabling Echo Cancellor when Bridged \n " ) ;
2005-10-31 22:51:12 +00:00
ch1 - > bc - > ec_enable = 0 ;
2006-06-01 12:51:41 +00:00
manager_ec_disable ( ch1 - > bc ) ;
2005-10-31 22:51:12 +00:00
}
2005-11-01 22:04:14 +00:00
misdn_cfg_get ( ch2 - > bc - > port , MISDN_CFG_ECHOCANCELWHENBRIDGED , & ecwb , sizeof ( int ) ) ;
2006-06-01 12:51:41 +00:00
misdn_cfg_get ( ch2 - > bc - > port , MISDN_CFG_ECHOCANCEL , & ec , sizeof ( int ) ) ;
if ( ! ecwb & & ec ) {
2006-03-21 09:47:51 +00:00
chan_misdn_log ( 2 , ch2 - > bc - > port , " Disabling Echo Cancellor when Bridged \n " ) ;
2005-10-31 22:51:12 +00:00
ch2 - > bc - > ec_enable = 0 ;
2006-06-01 12:51:41 +00:00
manager_ec_disable ( ch2 - > bc ) ;
2005-10-31 22:51:12 +00:00
}
/* trying to make a mISDN_dsp conference */
2006-06-07 13:01:02 +00:00
chan_misdn_log ( 1 , ch1 - > bc - > port , " I SEND: Making conference with Number:%d \n " , ch1 - > bc - > pid + 1 ) ;
2005-10-31 22:51:12 +00:00
2005-11-01 22:04:14 +00:00
misdn_lib_bridge ( ch1 - > bc , ch2 - > bc ) ;
2005-10-31 22:51:12 +00:00
}
2005-11-01 22:04:14 +00:00
2006-01-17 05:15:33 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Native bridging %s and %s \n " , c0 - > name , c1 - > name ) ;
2006-06-07 13:01:02 +00:00
chan_misdn_log ( 1 , ch1 - > bc - > port , " * Making Native Bridge between %s and %s \n " , ch1 - > bc - > oad , ch2 - > bc - > oad ) ;
2006-06-08 09:51:13 +00:00
if ( ! ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) )
ch1 - > ignore_dtmf = 1 ;
if ( ! ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) )
ch2 - > ignore_dtmf = 1 ;
2005-10-31 22:51:12 +00:00
while ( 1 ) {
to = - 1 ;
who = ast_waitfor_n ( carr , 2 , & to ) ;
2005-11-08 00:02:53 +00:00
if ( ! who ) {
2006-04-07 09:46:38 +00:00
ast_log ( LOG_NOTICE , " misdn_bridge: empty read, breaking out \n " ) ;
2006-04-07 09:31:27 +00:00
break ;
2005-11-08 00:02:53 +00:00
}
2005-10-31 22:51:12 +00:00
f = ast_read ( who ) ;
if ( ! f | | f - > frametype = = AST_FRAME_CONTROL ) {
/* got hangup .. */
2006-06-30 14:09:52 +00:00
if ( ! f )
chan_misdn_log ( 1 , ch1 - > bc - > port , " Read Null Frame \n " ) ;
else
chan_misdn_log ( 1 , ch1 - > bc - > port , " Read Frame Controll class:%d \n " , f - > subclass ) ;
2005-10-31 22:51:12 +00:00
* fo = f ;
* rc = who ;
break ;
}
2006-06-08 09:51:13 +00:00
if ( f - > frametype = = AST_FRAME_DTMF ) {
chan_misdn_log ( 1 , 0 , " Read DTMF %d from %s \n " , f - > subclass , who - > exten ) ;
* fo = f ;
* rc = who ;
break ;
}
2005-10-31 22:51:12 +00:00
if ( who = = c0 ) {
ast_write ( c1 , f ) ;
}
else {
ast_write ( c0 , f ) ;
}
}
2006-06-08 09:51:13 +00:00
chan_misdn_log ( 1 , ch1 - > bc - > port , " I SEND: Splitting conference with Number:%d \n " , ch1 - > bc - > pid + 1 ) ;
misdn_lib_split_bridge ( ch1 - > bc , ch2 - > bc ) ;
return AST_BRIDGE_COMPLETE ;
2005-10-31 22:51:12 +00:00
}
/** AST INDICATIONS END **/
2006-07-06 15:11:40 +00:00
static int dialtone_indicate ( struct chan_list * cl )
2006-02-02 21:15:34 +00:00
{
const struct tone_zone_sound * ts = NULL ;
struct ast_channel * ast = cl - > ast ;
2006-07-13 14:13:24 +00:00
int nd = 0 ;
misdn_cfg_get ( cl - > bc - > port , MISDN_CFG_NODIALTONE , & nd , sizeof ( nd ) ) ;
if ( nd ) {
chan_misdn_log ( 1 , cl - > bc - > port , " Not sending Dialtone, because config wants it \n " ) ;
return 0 ;
}
2006-07-06 15:11:40 +00:00
chan_misdn_log ( 3 , cl - > bc - > port , " --> Dial \n " ) ;
ts = ast_get_indication_tone ( ast - > zone , " dial " ) ;
2006-02-02 21:15:34 +00:00
cl - > ts = ts ;
2006-06-26 17:37:11 +00:00
if ( ts ) {
cl - > notxtone = 0 ;
cl - > norxtone = 0 ;
ast_playtones_start ( ast , 0 , ts - > data , 0 ) ;
chan_misdn_log ( 4 , cl - > bc - > port , " Starting Playtones \n " ) ;
misdn_lib_tone_generator_start ( cl - > bc ) ;
}
2006-07-06 15:11:40 +00:00
return 0 ;
}
static int hanguptone_indicate ( struct chan_list * cl )
{
misdn_lib_send_tone ( cl - > bc , TONE_HANGUP ) ;
return 0 ;
}
static int stop_indicate ( struct chan_list * cl )
{
struct ast_channel * ast = cl - > ast ;
chan_misdn_log ( 3 , cl - > bc - > port , " --> None \n " ) ;
misdn_lib_tone_generator_stop ( cl - > bc ) ;
ast_playtones_stop ( ast ) ;
/*ast_deactivate_generator(ast);*/
2006-02-02 21:15:34 +00:00
return 0 ;
}
2006-07-06 15:11:40 +00:00
2005-10-31 22:51:12 +00:00
static int start_bc_tones ( struct chan_list * cl )
{
2006-02-02 21:15:34 +00:00
misdn_lib_tone_generator_stop ( cl - > bc ) ;
2005-10-31 22:51:12 +00:00
cl - > notxtone = 0 ;
cl - > norxtone = 0 ;
return 0 ;
}
static int stop_bc_tones ( struct chan_list * cl )
{
2006-07-06 15:11:40 +00:00
if ( ! cl ) return - 1 ;
2005-10-31 22:51:12 +00:00
cl - > notxtone = 1 ;
cl - > norxtone = 1 ;
return 0 ;
}
2006-05-17 15:29:01 +00:00
static struct chan_list * init_chan_list ( int orig )
2005-10-31 22:51:12 +00:00
{
struct chan_list * cl = malloc ( sizeof ( struct chan_list ) ) ;
if ( ! cl ) {
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , 0 , " misdn_request: malloc failed! " ) ;
2005-10-31 22:51:12 +00:00
return NULL ;
}
memset ( cl , 0 , sizeof ( struct chan_list ) ) ;
2006-05-17 15:29:01 +00:00
cl - > orginator = orig ;
2006-07-06 15:11:40 +00:00
cl - > need_queue_hangup = 1 ;
cl - > need_hangup = 1 ;
2006-08-03 16:38:00 +00:00
cl - > need_busy = 1 ;
2006-07-11 19:30:35 +00:00
cl - > overlap_dial_task = - 1 ;
2005-10-31 22:51:12 +00:00
return cl ;
}
static struct ast_channel * misdn_request ( const char * type , int format , void * data , int * cause )
{
struct ast_channel * tmp = NULL ;
2006-02-22 21:59:46 +00:00
char group [ BUFFERSIZE + 1 ] = " " ;
2005-10-31 22:51:12 +00:00
char buf [ 128 ] ;
char buf2 [ 128 ] , * ext = NULL , * port_str ;
char * tokb = NULL , * p = NULL ;
int channel = 0 , port = 0 ;
struct misdn_bchannel * newbc = NULL ;
2006-05-17 15:29:01 +00:00
struct chan_list * cl = init_chan_list ( ORG_AST ) ;
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
sprintf ( buf , " %s/%s " , misdn_type , ( char * ) data ) ;
2006-02-22 21:59:46 +00:00
ast_copy_string ( buf2 , data , 128 ) ;
2005-10-31 22:51:12 +00:00
port_str = strtok_r ( buf2 , " / " , & tokb ) ;
ext = strtok_r ( NULL , " / " , & tokb ) ;
2005-11-15 20:20:45 +00:00
2005-10-31 22:51:12 +00:00
if ( port_str ) {
if ( port_str [ 0 ] = = ' g ' & & port_str [ 1 ] = = ' : ' ) {
/* We make a group call lets checkout which ports are in my group */
port_str + = 2 ;
strncpy ( group , port_str , BUFFERSIZE ) ;
group [ 127 ] = 0 ;
chan_misdn_log ( 2 , 0 , " --> Group Call group: %s \n " , group ) ;
}
else if ( ( p = strchr ( port_str , ' : ' ) ) ) {
2006-06-17 10:37:35 +00:00
/* we have a preselected channel */
2005-10-31 22:51:12 +00:00
* p = 0 ;
channel = atoi ( + + p ) ;
port = atoi ( port_str ) ;
2005-12-09 11:01:18 +00:00
chan_misdn_log ( 2 , port , " --> Call on preselected Channel (%d). \n " , channel ) ;
2005-10-31 22:51:12 +00:00
}
else {
port = atoi ( port_str ) ;
}
} else {
ast_log ( LOG_WARNING , " --> ! IND : CALL dad:%s WITHOUT PORT/Group, check extension.conf \n " , ext ) ;
return NULL ;
}
if ( ! ast_strlen_zero ( group ) ) {
2006-02-22 21:59:46 +00:00
char cfg_group [ BUFFERSIZE + 1 ] ;
2005-10-31 22:51:12 +00:00
struct robin_list * rr = NULL ;
if ( misdn_cfg_is_group_method ( group , METHOD_ROUND_ROBIN ) ) {
chan_misdn_log ( 4 , port , " --> STARTING ROUND ROBIN... " ) ;
rr = get_robin_position ( group ) ;
}
if ( rr ) {
int robin_channel = rr - > channel ;
int port_start ;
int next_chan = 1 ;
do {
port_start = 0 ;
for ( port = misdn_cfg_get_next_port_spin ( rr - > port ) ; port > 0 & & port ! = port_start ;
port = misdn_cfg_get_next_port_spin ( port ) ) {
if ( ! port_start )
port_start = port ;
if ( port > = port_start )
next_chan = 1 ;
2006-06-21 15:21:46 +00:00
if ( port < = port_start & & next_chan ) {
2006-06-26 17:37:11 +00:00
int maxbchans = misdn_lib_get_maxchans ( port ) ;
if ( + + robin_channel > = maxbchans ) {
2005-10-31 22:51:12 +00:00
robin_channel = 1 ;
}
next_chan = 0 ;
}
misdn_cfg_get ( port , MISDN_CFG_GROUPNAME , cfg_group , BUFFERSIZE ) ;
if ( ! strcasecmp ( cfg_group , group ) ) {
2006-02-02 21:15:34 +00:00
int port_up ;
2006-08-03 16:38:00 +00:00
int check ;
2006-02-15 19:32:45 +00:00
misdn_cfg_get ( port , MISDN_CFG_PMP_L1_CHECK , & check , sizeof ( int ) ) ;
port_up = misdn_lib_port_up ( port , check ) ;
2006-06-21 15:21:46 +00:00
if ( check & & ! port_up )
chan_misdn_log ( 1 , port , " L1 is not Up on this Port \n " ) ;
2006-08-03 16:38:00 +00:00
if ( check & & port_up < 0 ) {
ast_log ( LOG_WARNING , " This port (%d) is blocked \n " , port ) ;
}
2005-10-31 22:51:12 +00:00
2006-08-03 16:38:00 +00:00
if ( port_up > 0 ) {
2005-10-31 22:51:12 +00:00
newbc = misdn_lib_get_free_bc ( port , robin_channel ) ;
if ( newbc ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 4 , port , " Success! Found port:%d channel:%d \n " , newbc - > port , newbc - > channel ) ;
2005-10-31 22:51:12 +00:00
if ( port_up )
2006-06-21 15:21:46 +00:00
chan_misdn_log ( 4 , port , " portup:%d \n " , port_up ) ;
2005-11-01 22:04:14 +00:00
rr - > port = newbc - > port ;
2005-10-31 22:51:12 +00:00
rr - > channel = newbc - > channel ;
break ;
}
}
}
}
} while ( ! newbc & & robin_channel ! = rr - > channel ) ;
if ( ! newbc )
2006-08-03 16:38:00 +00:00
chan_misdn_log ( - 1 , port , " Failed! No free channel in group %d! " , group ) ;
2005-10-31 22:51:12 +00:00
}
else {
for ( port = misdn_cfg_get_next_port ( 0 ) ; port > 0 ;
port = misdn_cfg_get_next_port ( port ) ) {
misdn_cfg_get ( port , MISDN_CFG_GROUPNAME , cfg_group , BUFFERSIZE ) ;
2006-02-15 19:32:45 +00:00
chan_misdn_log ( 3 , port , " Group [%s] Port [%d] \n " , group , port ) ;
2005-10-31 22:51:12 +00:00
if ( ! strcasecmp ( cfg_group , group ) ) {
2006-02-02 21:15:34 +00:00
int port_up ;
2006-08-03 16:38:00 +00:00
int check ;
2006-02-15 19:32:45 +00:00
misdn_cfg_get ( port , MISDN_CFG_PMP_L1_CHECK , & check , sizeof ( int ) ) ;
port_up = misdn_lib_port_up ( port , check ) ;
2005-10-31 22:51:12 +00:00
2006-02-02 21:15:34 +00:00
chan_misdn_log ( 4 , port , " portup:%d \n " , port_up ) ;
2005-10-31 22:51:12 +00:00
2006-08-03 16:38:00 +00:00
if ( port_up > 0 ) {
2005-10-31 22:51:12 +00:00
newbc = misdn_lib_get_free_bc ( port , 0 ) ;
if ( newbc )
break ;
}
}
}
}
} else {
if ( channel )
chan_misdn_log ( 1 , port , " --> preselected_channel: %d \n " , channel ) ;
newbc = misdn_lib_get_free_bc ( port , channel ) ;
}
if ( ! newbc ) {
2006-06-21 15:21:46 +00:00
chan_misdn_log ( - 1 , 0 , " Could not create channel on port:%d with extensions:%s \n " , port , ext ) ;
2005-10-31 22:51:12 +00:00
return NULL ;
}
2005-12-09 11:01:18 +00:00
/* create ast_channel and link all the objects together */
2005-10-31 22:51:12 +00:00
cl - > bc = newbc ;
2005-12-09 11:01:18 +00:00
tmp = misdn_new ( cl , AST_STATE_RESERVED , ext , NULL , format , port , channel ) ;
cl - > ast = tmp ;
/* register chan in local list */
cl_queue_chan ( & cl_te , cl ) ;
/* fill in the config into the objects */
read_config ( cl , ORG_AST ) ;
2006-07-06 15:11:40 +00:00
/* important */
cl - > need_hangup = 0 ;
2005-10-31 22:51:12 +00:00
return tmp ;
}
2006-04-24 17:11:45 +00:00
static int misdn_send_text ( struct ast_channel * chan , const char * text )
2006-02-02 21:15:34 +00:00
{
struct chan_list * tmp = chan - > tech_pvt ;
if ( tmp & & tmp - > bc ) {
ast_copy_string ( tmp - > bc - > display , text , sizeof ( tmp - > bc - > display ) ) ;
misdn_lib_send_event ( tmp - > bc , EVENT_INFORMATION ) ;
} else {
ast_log ( LOG_WARNING , " No chan_list but send_text request? \n " ) ;
return - 1 ;
}
return 0 ;
}
2005-12-09 11:01:18 +00:00
static struct ast_channel_tech misdn_tech = {
2005-10-31 22:51:12 +00:00
. type = " mISDN " ,
. description = " Channel driver for mISDN Support (Bri/Pri) " ,
. capabilities = AST_FORMAT_ALAW ,
. requester = misdn_request ,
2006-08-31 01:59:02 +00:00
. send_digit_begin = misdn_digit_begin ,
. send_digit_end = misdn_digit_end ,
2005-10-31 22:51:12 +00:00
. call = misdn_call ,
. bridge = misdn_bridge ,
. hangup = misdn_hangup ,
. answer = misdn_answer ,
. read = misdn_read ,
. write = misdn_write ,
. indicate = misdn_indication ,
. fixup = misdn_fixup ,
2006-02-02 21:15:34 +00:00
. send_text = misdn_send_text ,
2005-10-31 22:51:12 +00:00
. properties = 0
} ;
2005-12-09 11:01:18 +00:00
static struct ast_channel_tech misdn_tech_wo_bridge = {
2005-10-31 22:51:12 +00:00
. type = " mISDN " ,
. description = " Channel driver for mISDN Support (Bri/Pri) " ,
. capabilities = AST_FORMAT_ALAW ,
. requester = misdn_request ,
2006-08-31 01:59:02 +00:00
. send_digit_begin = misdn_digit_begin ,
. send_digit_end = misdn_digit_end ,
2005-10-31 22:51:12 +00:00
. call = misdn_call ,
. hangup = misdn_hangup ,
. answer = misdn_answer ,
. read = misdn_read ,
. write = misdn_write ,
. indicate = misdn_indication ,
. fixup = misdn_fixup ,
2006-02-02 21:15:34 +00:00
. send_text = misdn_send_text ,
2005-10-31 22:51:12 +00:00
. properties = 0
} ;
2006-08-07 09:09:17 +00:00
static int glob_channel = 0 ;
2005-10-31 22:51:12 +00:00
2006-05-24 23:21:03 +00:00
static void update_name ( struct ast_channel * tmp , int port , int c )
{
2006-08-07 09:09:17 +00:00
int chan_offset = 0 ;
int tmp_port = misdn_cfg_get_next_port ( 0 ) ;
for ( ; tmp_port > 0 ; tmp_port = misdn_cfg_get_next_port ( tmp_port ) ) {
if ( tmp_port = = port ) break ;
chan_offset + = misdn_lib_port_is_pri ( tmp_port ) ? 30 : 2 ;
2006-05-24 23:21:03 +00:00
}
2006-08-07 09:09:17 +00:00
if ( c < 0 ) c = 0 ;
ast_string_field_build ( tmp , name , " %s/%d-u%d " ,
misdn_type , chan_offset + c , glob_channel + + ) ;
2006-05-24 23:21:03 +00:00
chan_misdn_log ( 3 , port , " --> updating channel name to [%s] \n " , tmp - > name ) ;
}
2005-12-09 11:01:18 +00:00
static struct ast_channel * misdn_new ( struct chan_list * chlist , int state , char * exten , char * callerid , int format , int port , int c )
2005-10-31 22:51:12 +00:00
{
struct ast_channel * tmp ;
2005-11-15 20:20:45 +00:00
tmp = ast_channel_alloc ( 1 ) ;
2005-10-31 22:51:12 +00:00
if ( tmp ) {
2005-12-09 11:01:18 +00:00
chan_misdn_log ( 2 , 0 , " --> * NEW CHANNEL dad:%s oad:%s \n " , exten , callerid ) ;
2005-10-31 22:51:12 +00:00
2006-05-24 23:21:03 +00:00
update_name ( tmp , port , c ) ;
2005-10-31 22:51:12 +00:00
tmp - > nativeformats = prefformat ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
tmp - > readformat = format ;
2006-05-05 16:38:15 +00:00
tmp - > rawreadformat = format ;
2005-10-31 22:51:12 +00:00
tmp - > writeformat = format ;
2006-05-05 16:38:15 +00:00
tmp - > rawwriteformat = format ;
2005-10-31 22:51:12 +00:00
tmp - > tech_pvt = chlist ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
int bridging ;
misdn_cfg_get ( 0 , MISDN_GEN_BRIDGING , & bridging , sizeof ( int ) ) ;
if ( bridging )
tmp - > tech = & misdn_tech ;
else
tmp - > tech = & misdn_tech_wo_bridge ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
tmp - > writeformat = format ;
tmp - > readformat = format ;
tmp - > priority = 1 ;
2005-11-15 20:20:45 +00:00
if ( exten )
2005-12-09 11:01:18 +00:00
ast_copy_string ( tmp - > exten , exten , sizeof ( tmp - > exten ) ) ;
2005-11-15 20:20:45 +00:00
else
chan_misdn_log ( 1 , 0 , " misdn_new: no exten given. \n " ) ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
if ( callerid ) {
char * cid_name , * cid_num ;
ast_callerid_parse ( callerid , & cid_name , & cid_num ) ;
2006-08-05 05:26:29 +00:00
/* Don't use ast_set_callerid() here because it will
* generate a NewCallerID event before the NewChannel event */
tmp - > cid . cid_num = ast_strdup ( cid_num ) ;
tmp - > cid . cid_ani = ast_strdup ( cid_num ) ;
tmp - > cid . cid_name = ast_strdup ( cid_name ) ;
2005-10-31 22:51:12 +00:00
}
{
if ( pipe ( chlist - > pipe ) < 0 )
perror ( " Pipe failed \n " ) ;
tmp - > fds [ 0 ] = chlist - > pipe [ 0 ] ;
}
2005-11-01 22:04:14 +00:00
2005-10-31 22:51:12 +00:00
ast_setstate ( tmp , state ) ;
if ( state = = AST_STATE_RING )
tmp - > rings = 1 ;
else
tmp - > rings = 0 ;
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
} else {
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , 0 , " Unable to allocate channel structure \n " ) ;
2005-11-01 22:04:14 +00:00
}
2005-10-31 22:51:12 +00:00
return tmp ;
}
2005-12-09 11:01:18 +00:00
static struct chan_list * find_chan_by_bc ( struct chan_list * list , struct misdn_bchannel * bc )
2005-10-31 22:51:12 +00:00
{
struct chan_list * help = list ;
for ( ; help ; help = help - > next ) {
if ( help - > bc = = bc ) return help ;
}
2006-04-03 19:17:59 +00:00
chan_misdn_log ( 6 , bc - > port , " $$$ find_chan: No channel found for oad:%s dad:%s \n " , bc - > oad , bc - > dad ) ;
2005-10-31 22:51:12 +00:00
return NULL ;
}
2006-06-17 10:37:35 +00:00
static struct chan_list * find_chan_by_pid ( struct chan_list * list , int pid )
{
struct chan_list * help = list ;
for ( ; help ; help = help - > next ) {
if ( help - > bc - > pid = = pid ) return help ;
}
chan_misdn_log ( 6 , 0 , " $$$ find_chan: No channel found for pid:%d \n " , pid ) ;
return NULL ;
}
2005-10-31 22:51:12 +00:00
2005-12-09 11:01:18 +00:00
static struct chan_list * find_holded ( struct chan_list * list , struct misdn_bchannel * bc )
2005-10-31 22:51:12 +00:00
{
struct chan_list * help = list ;
2006-04-03 19:17:59 +00:00
chan_misdn_log ( 6 , bc - > port , " $$$ find_holded: channel:%d oad:%s dad:%s \n " , bc - > channel , bc - > oad , bc - > dad ) ;
2005-10-31 22:51:12 +00:00
for ( ; help ; help = help - > next ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 4 , bc - > port , " $$$ find_holded: --> holded:%d channel:%d \n " , help - > bc - > holded , help - > bc - > channel ) ;
if ( help - > bc - > port = = bc - > port
2005-10-31 22:51:12 +00:00
& & help - > bc - > holded ) return help ;
}
2006-04-03 19:17:59 +00:00
chan_misdn_log ( 6 , bc - > port , " $$$ find_chan: No channel found for oad:%s dad:%s \n " , bc - > oad , bc - > dad ) ;
2005-10-31 22:51:12 +00:00
return NULL ;
}
2005-12-09 11:01:18 +00:00
static void cl_queue_chan ( struct chan_list * * list , struct chan_list * chan )
2005-10-31 22:51:12 +00:00
{
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 4 , chan - > bc ? chan - > bc - > port : 0 , " * Queuing chan %p \n " , chan ) ;
2005-10-31 22:51:12 +00:00
2005-11-01 22:04:14 +00:00
ast_mutex_lock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
if ( ! * list ) {
* list = chan ;
} else {
struct chan_list * help = * list ;
for ( ; help - > next ; help = help - > next ) ;
help - > next = chan ;
}
chan - > next = NULL ;
2005-11-01 22:04:14 +00:00
ast_mutex_unlock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
}
2005-12-09 11:01:18 +00:00
static void cl_dequeue_chan ( struct chan_list * * list , struct chan_list * chan )
2005-10-31 22:51:12 +00:00
{
if ( chan - > dsp )
ast_dsp_free ( chan - > dsp ) ;
if ( chan - > trans )
ast_translator_free_path ( chan - > trans ) ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
2005-11-01 22:04:14 +00:00
ast_mutex_lock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
if ( ! * list ) {
2005-11-01 22:04:14 +00:00
ast_mutex_unlock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
return ;
}
if ( * list = = chan ) {
* list = ( * list ) - > next ;
2005-11-01 22:04:14 +00:00
ast_mutex_unlock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
return ;
}
{
struct chan_list * help = * list ;
for ( ; help - > next ; help = help - > next ) {
if ( help - > next = = chan ) {
help - > next = help - > next - > next ;
2005-11-01 22:04:14 +00:00
ast_mutex_unlock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
return ;
}
}
}
2005-11-01 22:04:14 +00:00
ast_mutex_unlock ( & cl_te_lock ) ;
2005-10-31 22:51:12 +00:00
}
/** Channel Queue End **/
2006-07-06 15:11:40 +00:00
int pbx_start_chan ( struct chan_list * ch )
{
int ret = ast_pbx_start ( ch - > ast ) ;
if ( ret > = 0 )
ch - > need_hangup = 0 ;
else
ch - > need_hangup = 1 ;
return ret ;
}
static void hangup_chan ( struct chan_list * ch )
{
if ( ! ch ) {
cb_log ( 1 , 0 , " Cannot hangup chan, no ch \n " ) ;
return ;
}
2006-08-03 16:38:00 +00:00
cb_log ( 1 , ch - > bc ? ch - > bc - > port : 0 , " hangup_chan \n " ) ;
2006-07-06 15:11:40 +00:00
if ( ch - > need_hangup )
{
2006-08-03 16:38:00 +00:00
cb_log ( 1 , ch - > bc - > port , " -> hangup \n " ) ;
2006-07-06 15:11:40 +00:00
send_cause2ast ( ch - > ast , ch - > bc , ch ) ;
ch - > need_hangup = 0 ;
ch - > need_queue_hangup = 0 ;
if ( ch - > ast )
ast_hangup ( ch - > ast ) ;
return ;
}
if ( ! ch - > need_queue_hangup ) {
cb_log ( 1 , ch - > bc - > port , " No need to queue hangup \n " ) ;
}
ch - > need_queue_hangup = 0 ;
if ( ch - > ast ) {
send_cause2ast ( ch - > ast , ch - > bc , ch ) ;
2006-08-03 16:38:00 +00:00
if ( ch - > ast )
ast_queue_hangup ( ch - > ast ) ;
cb_log ( 1 , ch - > bc - > port , " -> queue_hangup \n " ) ;
2006-07-06 15:11:40 +00:00
} else {
cb_log ( 1 , ch - > bc - > port , " Cannot hangup chan, no ast \n " ) ;
}
}
2005-10-31 22:51:12 +00:00
/** Isdn asks us to release channel, pendant to misdn_hangup **/
static void release_chan ( struct misdn_bchannel * bc ) {
struct ast_channel * ast = NULL ;
{
struct chan_list * ch = find_chan_by_bc ( cl_te , bc ) ;
2006-02-02 21:15:34 +00:00
if ( ! ch ) {
chan_misdn_log ( 0 , bc - > port , " release_chan: Ch not found! \n " ) ;
return ;
}
2005-10-31 22:51:12 +00:00
if ( ch - > ast ) {
ast = ch - > ast ;
}
2006-06-01 12:51:41 +00:00
chan_misdn_log ( 1 , bc - > port , " release_chan: bc with l3id: %x \n " , bc - > l3_id ) ;
2006-06-17 10:37:35 +00:00
/*releaseing jitterbuffer*/
2005-12-09 11:01:18 +00:00
if ( ch - > jb ) {
misdn_jb_destroy ( ch - > jb ) ;
ch - > jb = NULL ;
} else {
if ( ! bc - > nojitter )
chan_misdn_log ( 5 , bc - > port , " Jitterbuffer already destroyed. \n " ) ;
}
2006-05-22 15:02:03 +00:00
2006-07-11 19:30:35 +00:00
if ( ch - > overlap_dial ) {
if ( ch - > overlap_dial_task ! = - 1 ) {
misdn_tasks_remove ( ch - > overlap_dial_task ) ;
ch - > overlap_dial_task = - 1 ;
}
ast_mutex_destroy ( & ch - > overlap_tv_lock ) ;
}
2006-05-22 15:02:03 +00:00
if ( ch - > orginator = = ORG_AST ) {
misdn_out_calls [ bc - > port ] - - ;
} else {
misdn_in_calls [ bc - > port ] - - ;
}
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
if ( ch ) {
close ( ch - > pipe [ 0 ] ) ;
close ( ch - > pipe [ 1 ] ) ;
2006-06-28 14:15:29 +00:00
2005-10-31 22:51:12 +00:00
2006-04-10 16:50:20 +00:00
if ( ast & & MISDN_ASTERISK_TECH_PVT ( ast ) ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc - > port , " * RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s state: %s \n " , bc ? bc - > pid : - 1 , ast - > context , ast - > exten , AST_CID_P ( ast ) , misdn_get_ch_state ( ch ) ) ;
chan_misdn_log ( 3 , bc - > port , " --> * State Down \n " ) ;
2005-10-31 22:51:12 +00:00
MISDN_ASTERISK_TECH_PVT ( ast ) = NULL ;
if ( ast - > _state ! = AST_STATE_RESERVED ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 3 , bc - > port , " --> Setting AST State to down \n " ) ;
2005-10-31 22:51:12 +00:00
ast_setstate ( ast , AST_STATE_DOWN ) ;
}
}
2006-07-06 15:11:40 +00:00
2006-06-28 14:15:29 +00:00
ch - > state = MISDN_CLEANING ;
2005-10-31 22:51:12 +00:00
cl_dequeue_chan ( & cl_te , ch ) ;
free ( ch ) ;
} else {
/* chan is already cleaned, so exiting */
}
}
}
/*** release end **/
2005-12-09 11:01:18 +00:00
static void misdn_transfer_bc ( struct chan_list * tmp_ch , struct chan_list * holded_chan )
2005-10-31 22:51:12 +00:00
{
chan_misdn_log ( 4 , 0 , " TRANSFERING %s to %s \n " , holded_chan - > ast - > name , tmp_ch - > ast - > name ) ;
tmp_ch - > state = MISDN_HOLD_DISCONNECT ;
ast_moh_stop ( AST_BRIDGED_P ( holded_chan - > ast ) ) ;
holded_chan - > state = MISDN_CONNECTED ;
misdn_lib_transfer ( holded_chan - > bc ? holded_chan - > bc : holded_chan - > holded_bc ) ;
ast_channel_masquerade ( holded_chan - > ast , AST_BRIDGED_P ( tmp_ch - > ast ) ) ;
}
2005-12-09 11:01:18 +00:00
static void do_immediate_setup ( struct misdn_bchannel * bc , struct chan_list * ch , struct ast_channel * ast )
2005-10-31 22:51:12 +00:00
{
char predial [ 256 ] = " " ;
char * p = predial ;
struct ast_frame fr ;
strncpy ( predial , ast - > exten , sizeof ( predial ) - 1 ) ;
ch - > state = MISDN_DIALING ;
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
if ( bc - > nt ) {
2005-10-31 22:51:12 +00:00
int ret ;
ret = misdn_lib_send_event ( bc , EVENT_SETUP_ACKNOWLEDGE ) ;
} else {
int ret ;
2005-11-01 22:04:14 +00:00
if ( misdn_lib_is_ptp ( bc - > port ) ) {
2005-10-31 22:51:12 +00:00
ret = misdn_lib_send_event ( bc , EVENT_SETUP_ACKNOWLEDGE ) ;
} else {
ret = misdn_lib_send_event ( bc , EVENT_PROCEEDING ) ;
}
}
2006-02-15 19:51:33 +00:00
if ( ! bc - > nt & & ( ch - > orginator = = ORG_MISDN ) & & ! ch - > incoming_early_audio )
chan_misdn_log ( 1 , bc - > port , " --> incoming_early_audio off \n " ) ;
2006-07-06 15:11:40 +00:00
else
dialtone_indicate ( ch ) ;
2005-10-31 22:51:12 +00:00
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc - > port , " * Starting Ast ctx:%s dad:%s oad:%s with 's' extension \n " , ast - > context , ast - > exten , AST_CID_P ( ast ) ) ;
2005-10-31 22:51:12 +00:00
strncpy ( ast - > exten , " s " , 2 ) ;
2006-07-06 15:11:40 +00:00
if ( pbx_start_chan ( ch ) < 0 ) {
2005-10-31 22:51:12 +00:00
ast = NULL ;
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
hanguptone_indicate ( ch ) ;
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
if ( bc - > nt )
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
else
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
}
while ( ! ast_strlen_zero ( p ) ) {
fr . frametype = AST_FRAME_DTMF ;
fr . subclass = * p ;
fr . src = NULL ;
fr . data = NULL ;
fr . datalen = 0 ;
fr . samples = 0 ;
fr . mallocd = 0 ;
fr . offset = 0 ;
if ( ch - > ast & & MISDN_ASTERISK_PVT ( ch - > ast ) & & MISDN_ASTERISK_TECH_PVT ( ch - > ast ) ) {
ast_queue_frame ( ch - > ast , & fr ) ;
}
p + + ;
}
}
2006-06-26 17:37:11 +00:00
static void send_cause2ast ( struct ast_channel * ast , struct misdn_bchannel * bc , struct chan_list * ch ) {
2006-07-06 15:11:40 +00:00
if ( ! ast ) {
chan_misdn_log ( 1 , 0 , " send_cause2ast: No Ast \n " ) ;
return ;
}
if ( ! bc ) {
chan_misdn_log ( 1 , 0 , " send_cause2ast: No BC \n " ) ;
return ;
}
if ( ! ch ) {
chan_misdn_log ( 1 , 0 , " send_cause2ast: No Ch \n " ) ;
return ;
}
2005-10-31 22:51:12 +00:00
ast - > hangupcause = bc - > cause ;
switch ( bc - > cause ) {
case 1 : /** Congestion Cases **/
case 2 :
case 3 :
case 4 :
case 22 :
case 27 :
2006-03-07 12:17:35 +00:00
/*
* Not Queueing the Congestion anymore , since we want to hear
* the inband message
*
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc ? bc - > port : 0 , " --> * SEND: Queue Congestion pid:%d \n " , bc ? bc - > pid : - 1 ) ;
2006-06-26 17:37:11 +00:00
ch - > state = MISDN_BUSY ;
2005-10-31 22:51:12 +00:00
ast_queue_control ( ast , AST_CONTROL_CONGESTION ) ;
2006-03-07 12:17:35 +00:00
*/
2005-10-31 22:51:12 +00:00
break ;
case 21 :
case 17 : /* user busy */
2006-06-26 17:37:11 +00:00
ch - > state = MISDN_BUSY ;
2006-08-03 16:38:00 +00:00
if ( ! ch - > need_busy ) {
chan_misdn_log ( 1 , bc ? bc - > port : 0 , " Queued busy already \n " ) ;
break ;
}
chan_misdn_log ( 1 , bc ? bc - > port : 0 , " --> * SEND: Queue Busy pid:%d \n " , bc ? bc - > pid : - 1 ) ;
2005-10-31 22:51:12 +00:00
ast_queue_control ( ast , AST_CONTROL_BUSY ) ;
2006-08-03 16:38:00 +00:00
ch - > need_busy = 0 ;
2005-10-31 22:51:12 +00:00
break ;
}
}
2006-02-22 21:59:46 +00:00
2006-06-17 10:37:35 +00:00
void import_ch ( struct ast_channel * chan , struct misdn_bchannel * bc , struct chan_list * ch )
{
2006-07-03 16:41:43 +00:00
const char * tmp ;
2006-06-17 10:37:35 +00:00
tmp = pbx_builtin_getvar_helper ( chan , " MISDN_PID " ) ;
if ( tmp ) {
ch - > other_pid = atoi ( tmp ) ;
chan_misdn_log ( 1 , bc - > port , " IMPORT_PID: importing pid:%s \n " , tmp ) ;
if ( ch - > other_pid > 0 ) {
ch - > other_ch = find_chan_by_pid ( cl_te , ch - > other_pid ) ;
if ( ch - > other_ch ) ch - > other_ch - > other_ch = ch ;
}
}
2006-02-22 21:59:46 +00:00
}
2006-06-17 10:37:35 +00:00
void export_ch ( struct ast_channel * chan , struct misdn_bchannel * bc , struct chan_list * ch )
2006-02-22 21:59:46 +00:00
{
char tmp [ 32 ] ;
2006-06-17 10:37:35 +00:00
chan_misdn_log ( 1 , bc - > port , " EXPORT_PID: pid:%d \n " , bc - > pid ) ;
sprintf ( tmp , " %d " , bc - > pid ) ;
pbx_builtin_setvar_helper ( chan , " _MISDN_PID " , tmp ) ;
2006-02-22 21:59:46 +00:00
}
2006-05-22 15:02:03 +00:00
int add_in_calls ( int port )
{
int max_in_calls ;
misdn_cfg_get ( port , MISDN_CFG_MAX_IN , & max_in_calls , sizeof ( max_in_calls ) ) ;
misdn_in_calls [ port ] + + ;
if ( max_in_calls > = 0 & & max_in_calls < misdn_in_calls [ port ] ) {
ast_log ( LOG_NOTICE , " Marking Incoming Call on port[%d] \n " , port ) ;
return misdn_in_calls [ port ] - max_in_calls ;
}
return 0 ;
}
int add_out_calls ( int port )
{
int max_out_calls ;
misdn_cfg_get ( port , MISDN_CFG_MAX_OUT , & max_out_calls , sizeof ( max_out_calls ) ) ;
if ( max_out_calls > = 0 & & max_out_calls < = misdn_out_calls [ port ] ) {
ast_log ( LOG_NOTICE , " Rejecting Outgoing Call on port[%d] \n " , port ) ;
return ( misdn_out_calls [ port ] + 1 ) - max_out_calls ;
}
misdn_out_calls [ port ] + + ;
return 0 ;
}
2006-02-22 21:59:46 +00:00
2005-10-31 22:51:12 +00:00
/************************************************************/
/* Receive Events from isdn_lib here */
/************************************************************/
2005-12-09 11:01:18 +00:00
static enum event_response_e
2005-10-31 22:51:12 +00:00
cb_events ( enum event_e event , struct misdn_bchannel * bc , void * user_data )
{
struct chan_list * ch = find_chan_by_bc ( cl_te , bc ) ;
2006-02-02 21:15:34 +00:00
if ( event ! = EVENT_BCHAN_DATA & & event ! = EVENT_TONE_GENERATE ) { /* Debug Only Non-Bchan */
2006-08-03 16:38:00 +00:00
int debuglevel = 1 ;
if ( event = = EVENT_CLEANUP & & ! user_data )
debuglevel = 5 ;
chan_misdn_log ( debuglevel , bc - > port , " I IND :%s oad:%s dad:%s pid:%d state:%s \n " , manager_isdn_get_info ( event ) , bc - > oad , bc - > dad , bc - > pid , ch ? misdn_get_ch_state ( ch ) : " none " ) ;
if ( debuglevel = = 1 ) {
misdn_lib_log_ies ( bc ) ;
chan_misdn_log ( 4 , bc - > port , " --> bc_state:%s \n " , bc_state2str ( bc - > bc_state ) ) ;
}
2005-10-31 22:51:12 +00:00
}
2006-07-06 15:11:40 +00:00
if ( ! ch ) {
switch ( event ) {
case EVENT_SETUP :
case EVENT_DISCONNECT :
2006-08-03 16:38:00 +00:00
case EVENT_PORT_ALARM :
2006-08-08 09:19:06 +00:00
case EVENT_RETRIEVE :
case EVENT_NEW_BC :
2006-08-08 18:13:40 +00:00
case EVENT_FACILITY :
2006-07-06 15:11:40 +00:00
break ;
case EVENT_RELEASE_COMPLETE :
2006-06-28 14:24:18 +00:00
chan_misdn_log ( 1 , bc - > port , " --> no Ch, so we've already released. \n " ) ;
2006-07-06 15:11:40 +00:00
break ;
case EVENT_CLEANUP :
case EVENT_TONE_GENERATE :
case EVENT_BCHAN_DATA :
return - 1 ;
default :
chan_misdn_log ( 1 , bc - > port , " Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d \n " , bc - > l3_id , bc , manager_isdn_get_info ( event ) , bc - > port , bc - > channel ) ;
return - 1 ;
2005-10-31 22:51:12 +00:00
}
}
if ( ch ) {
switch ( event ) {
2006-06-26 17:37:11 +00:00
case EVENT_TONE_GENERATE :
break ;
2006-06-17 10:37:35 +00:00
case EVENT_DISCONNECT :
2005-10-31 22:51:12 +00:00
case EVENT_RELEASE :
case EVENT_RELEASE_COMPLETE :
case EVENT_CLEANUP :
2006-06-17 10:37:35 +00:00
case EVENT_TIMEOUT :
2006-06-21 15:21:46 +00:00
if ( ! ch - > ast )
chan_misdn_log ( 3 , bc - > port , " ast_hangup already called, so we have no ast ptr anymore in event(%s) \n " , manager_isdn_get_info ( event ) ) ;
2005-10-31 22:51:12 +00:00
break ;
default :
if ( ! ch - > ast | | ! MISDN_ASTERISK_PVT ( ch - > ast ) | | ! MISDN_ASTERISK_TECH_PVT ( ch - > ast ) ) {
if ( event ! = EVENT_BCHAN_DATA )
2006-06-21 15:21:46 +00:00
ast_log ( LOG_NOTICE , " No Ast or No private Pointer in Event (%d:%s) \n " , event , manager_isdn_get_info ( event ) ) ;
2005-10-31 22:51:12 +00:00
return - 1 ;
}
}
}
switch ( event ) {
2006-08-03 16:38:00 +00:00
case EVENT_PORT_ALARM :
{
int boa = 0 ;
misdn_cfg_get ( bc - > port , MISDN_CFG_ALARM_BLOCK , & boa , sizeof ( int ) ) ;
if ( boa ) {
cb_log ( 1 , bc - > port , " --> blocking \n " ) ;
misdn_lib_port_block ( bc - > port ) ;
}
}
break ;
2006-02-02 21:15:34 +00:00
case EVENT_BCHAN_ACTIVATED :
break ;
2006-05-24 23:21:03 +00:00
case EVENT_NEW_CHANNEL :
update_name ( ch - > ast , bc - > port , bc - > channel ) ;
break ;
2006-02-02 21:15:34 +00:00
2005-10-31 22:51:12 +00:00
case EVENT_NEW_L3ID :
ch - > l3id = bc - > l3_id ;
2006-05-23 12:38:06 +00:00
ch - > addr = bc - > addr ;
2005-10-31 22:51:12 +00:00
break ;
case EVENT_NEW_BC :
2006-08-08 09:19:06 +00:00
if ( ! ch ) {
ch = find_holded ( cl_te , bc ) ;
}
if ( ! ch ) {
ast_log ( LOG_WARNING , " NEW_BC without chan_list? \n " ) ;
break ;
}
2005-10-31 22:51:12 +00:00
if ( bc )
2006-08-03 16:38:00 +00:00
ch - > bc = ( struct misdn_bchannel * ) user_data ;
2005-10-31 22:51:12 +00:00
break ;
case EVENT_DTMF_TONE :
{
/* sending INFOS as DTMF-Frames :) */
struct ast_frame fr ;
memset ( & fr , 0 , sizeof ( fr ) ) ;
fr . frametype = AST_FRAME_DTMF ;
fr . subclass = bc - > dtmf ;
fr . src = NULL ;
fr . data = NULL ;
fr . datalen = 0 ;
fr . samples = 0 ;
fr . mallocd = 0 ;
fr . offset = 0 ;
2006-06-08 09:51:13 +00:00
if ( ! ch - > ignore_dtmf ) {
chan_misdn_log ( 2 , bc - > port , " --> DTMF:%c \n " , bc - > dtmf ) ;
ast_queue_frame ( ch - > ast , & fr ) ;
} else {
chan_misdn_log ( 2 , bc - > port , " --> Ingoring DTMF:%c due to bridge flags \n " , bc - > dtmf ) ;
}
2005-10-31 22:51:12 +00:00
}
break ;
case EVENT_STATUS :
break ;
case EVENT_INFORMATION :
{
int stop_tone ;
misdn_cfg_get ( 0 , MISDN_GEN_STOP_TONE , & stop_tone , sizeof ( int ) ) ;
2006-02-02 21:15:34 +00:00
if ( stop_tone ) {
2006-07-06 15:11:40 +00:00
stop_indicate ( ch ) ;
2005-10-31 22:51:12 +00:00
}
if ( ch - > state = = MISDN_WAITING4DIGS ) {
/* Ok, incomplete Setup, waiting till extension exists */
{
int l = sizeof ( bc - > dad ) ;
strncat ( bc - > dad , bc - > info_dad , l ) ;
bc - > dad [ l - 1 ] = 0 ;
}
{
int l = sizeof ( ch - > ast - > exten ) ;
strncpy ( ch - > ast - > exten , bc - > dad , l ) ;
ch - > ast - > exten [ l - 1 ] = 0 ;
}
2005-11-01 22:04:14 +00:00
/* chan_misdn_log(5, bc->port, "Can Match Extension: dad:%s oad:%s\n",bc->dad,bc->oad);*/
2005-10-31 22:51:12 +00:00
2006-02-08 16:10:21 +00:00
/* Check for Pickup Request first */
if ( ! strcmp ( ch - > ast - > exten , ast_pickup_ext ( ) ) ) {
int ret ; /** Sending SETUP_ACK**/
ret = misdn_lib_send_event ( bc , EVENT_SETUP_ACKNOWLEDGE ) ;
if ( ast_pickup_call ( ch - > ast ) ) {
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
2006-02-08 16:10:21 +00:00
} else {
struct ast_channel * chan = ch - > ast ;
ch - > state = MISDN_CALLING_ACKNOWLEDGE ;
ast_setstate ( chan , AST_STATE_DOWN ) ;
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
ch - > ast = NULL ;
2006-02-08 16:10:21 +00:00
break ;
}
}
2005-12-09 11:01:18 +00:00
if ( ! ast_canmatch_extension ( ch - > ast , ch - > context , bc - > dad , 1 , bc - > oad ) ) {
chan_misdn_log ( - 1 , bc - > port , " Extension can never match, so disconnecting \n " ) ;
2006-07-04 17:04:21 +00:00
if ( bc - > nt )
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( ch ) ;
2005-10-31 22:51:12 +00:00
ch - > state = MISDN_EXTCANTMATCH ;
bc - > out_cause = 1 ;
2005-12-09 11:01:18 +00:00
2006-06-26 17:37:11 +00:00
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2005-10-31 22:51:12 +00:00
break ;
}
2006-07-11 19:30:35 +00:00
if ( ch - > overlap_dial ) {
ast_mutex_lock ( & ch - > overlap_tv_lock ) ;
ch - > overlap_tv = ast_tvnow ( ) ;
ast_mutex_unlock ( & ch - > overlap_tv_lock ) ;
if ( ch - > overlap_dial_task = = - 1 ) {
ch - > overlap_dial_task =
misdn_tasks_add_variable ( ch - > overlap_dial , misdn_overlap_dial_task , ch ) ;
}
break ;
}
2005-12-09 11:01:18 +00:00
if ( ast_exists_extension ( ch - > ast , ch - > context , bc - > dad , 1 , bc - > oad ) ) {
2005-10-31 22:51:12 +00:00
ch - > state = MISDN_DIALING ;
2006-07-06 15:11:40 +00:00
stop_indicate ( ch ) ;
2005-12-09 11:01:18 +00:00
/* chan_misdn_log(1, bc->port, " --> * Starting Ast ctx:%s\n", ch->context);*/
2006-07-06 15:11:40 +00:00
if ( pbx_start_chan ( ch ) < 0 ) {
hangup_chan ( ch ) ;
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , bc - > port , " ast_pbx_start returned < 0 in INFO \n " ) ;
2006-07-06 15:11:40 +00:00
if ( bc - > nt ) hanguptone_indicate ( ch ) ;
2005-12-09 11:01:18 +00:00
2006-06-26 17:37:11 +00:00
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
2005-10-31 22:51:12 +00:00
}
}
} else {
/* sending INFOS as DTMF-Frames :) */
struct ast_frame fr ;
fr . frametype = AST_FRAME_DTMF ;
fr . subclass = bc - > info_dad [ 0 ] ;
fr . src = NULL ;
fr . data = NULL ;
fr . datalen = 0 ;
fr . samples = 0 ;
fr . mallocd = 0 ;
fr . offset = 0 ;
int digits ;
misdn_cfg_get ( 0 , MISDN_GEN_APPEND_DIGITS2EXTEN , & digits , sizeof ( int ) ) ;
2005-11-08 00:02:53 +00:00
if ( ch - > state ! = MISDN_CONNECTED ) {
if ( digits ) {
2005-10-31 22:51:12 +00:00
int l = sizeof ( bc - > dad ) ;
strncat ( bc - > dad , bc - > info_dad , l ) ;
bc - > dad [ l - 1 ] = 0 ;
2005-11-08 00:02:53 +00:00
l = sizeof ( ch - > ast - > exten ) ;
2005-10-31 22:51:12 +00:00
strncpy ( ch - > ast - > exten , bc - > dad , l ) ;
ch - > ast - > exten [ l - 1 ] = 0 ;
2005-11-08 00:02:53 +00:00
ast_cdr_update ( ch - > ast ) ;
2005-10-31 22:51:12 +00:00
}
ast_queue_frame ( ch - > ast , & fr ) ;
}
}
}
break ;
case EVENT_SETUP :
{
struct chan_list * ch = find_chan_by_bc ( cl_te , bc ) ;
if ( ch & & ch - > state ! = MISDN_NOTHING ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , bc - > port , " --> Ignoring Call we have already one \n " ) ;
2006-07-11 19:30:35 +00:00
return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE ;
2005-10-31 22:51:12 +00:00
}
}
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
int msn_valid = misdn_cfg_is_msn_valid ( bc - > port , bc - > dad ) ;
if ( ! bc - > nt & & ! msn_valid ) {
chan_misdn_log ( 1 , bc - > port , " --> Ignoring Call, its not in our MSN List \n " ) ;
2005-10-31 22:51:12 +00:00
return RESPONSE_IGNORE_SETUP ; /* Ignore MSNs which are not in our List */
}
2006-05-22 15:02:03 +00:00
2005-10-31 22:51:12 +00:00
print_bearer ( bc ) ;
{
2006-05-17 15:29:01 +00:00
struct chan_list * ch = init_chan_list ( ORG_MISDN ) ;
2005-10-31 22:51:12 +00:00
struct ast_channel * chan ;
2006-05-22 15:02:03 +00:00
int exceed ;
2005-12-09 11:01:18 +00:00
if ( ! ch ) { chan_misdn_log ( - 1 , bc - > port , " cb_events: malloc for chan_list failed! \n " ) ; return 0 ; }
2005-10-31 22:51:12 +00:00
ch - > bc = bc ;
ch - > l3id = bc - > l3_id ;
ch - > addr = bc - > addr ;
ch - > orginator = ORG_MISDN ;
2006-02-22 21:59:46 +00:00
2005-12-09 11:01:18 +00:00
chan = misdn_new ( ch , AST_STATE_RESERVED , bc - > dad , bc - > oad , AST_FORMAT_ALAW , bc - > port , bc - > channel ) ;
2006-02-22 21:59:46 +00:00
ch - > ast = chan ;
2006-05-22 15:02:03 +00:00
if ( ( exceed = add_in_calls ( bc - > port ) ) ) {
char tmp [ 16 ] ;
sprintf ( tmp , " %d " , exceed ) ;
pbx_builtin_setvar_helper ( chan , " MAX_OVERFLOW " , tmp ) ;
}
2005-12-09 11:01:18 +00:00
read_config ( ch , ORG_MISDN ) ;
2006-06-17 10:37:35 +00:00
export_ch ( chan , bc , ch ) ;
2005-12-09 11:01:18 +00:00
ch - > ast - > rings = 1 ;
ast_setstate ( ch - > ast , AST_STATE_RINGING ) ;
2005-10-31 22:51:12 +00:00
2006-07-13 14:13:24 +00:00
int pres , screen ;
switch ( bc - > pres ) {
case 1 :
pres = AST_PRES_RESTRICTED ; chan_misdn_log ( 2 , bc - > port , " --> PRES: Restricted (1) \n " ) ;
break ;
case 2 :
pres = AST_PRES_UNAVAILABLE ; chan_misdn_log ( 2 , bc - > port , " --> PRES: Restricted (2) \n " ) ;
break ;
default :
pres = AST_PRES_ALLOWED ; chan_misdn_log ( 2 , bc - > port , " --> PRES: Restricted (%d) \n " , bc - > pres ) ;
}
switch ( bc - > screen ) {
case 0 :
screen = AST_PRES_USER_NUMBER_UNSCREENED ; chan_misdn_log ( 2 , bc - > port , " --> SCREEN: Unscreened (0) \n " ) ;
break ;
case 1 :
screen = AST_PRES_USER_NUMBER_PASSED_SCREEN ; chan_misdn_log ( 2 , bc - > port , " --> SCREEN: Passed screen (1) \n " ) ;
break ;
case 2 :
screen = AST_PRES_USER_NUMBER_FAILED_SCREEN ; chan_misdn_log ( 2 , bc - > port , " --> SCREEN: failed screen (2) \n " ) ;
break ;
case 3 :
screen = AST_PRES_NETWORK_NUMBER ; chan_misdn_log ( 2 , bc - > port , " --> SCREEN: Network Number (3) \n " ) ;
break ;
default :
screen = AST_PRES_USER_NUMBER_UNSCREENED ; chan_misdn_log ( 2 , bc - > port , " --> SCREEN: Unscreened (%d) \n " , bc - > screen ) ;
2005-10-31 22:51:12 +00:00
}
2006-07-13 14:13:24 +00:00
chan - > cid . cid_pres = pres + screen ;
2005-10-31 22:51:12 +00:00
pbx_builtin_setvar_helper ( chan , " TRANSFERCAPABILITY " , ast_transfercapability2str ( bc - > capability ) ) ;
chan - > transfercapability = bc - > capability ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
switch ( bc - > capability ) {
case INFO_CAPABILITY_DIGITAL_UNRESTRICTED :
pbx_builtin_setvar_helper ( chan , " CALLTYPE " , " DIGITAL " ) ;
break ;
default :
pbx_builtin_setvar_helper ( chan , " CALLTYPE " , " SPEECH " ) ;
}
/** queue new chan **/
cl_queue_chan ( & cl_te , ch ) ;
2006-06-01 12:51:41 +00:00
if ( ! strstr ( ch - > allowed_bearers , " all " ) ) {
int i ;
for ( i = 0 ; i < sizeof ( allowed_bearers_array ) / sizeof ( struct allowed_bearers ) ; i + + ) {
if ( allowed_bearers_array [ i ] . cap = = bc - > capability ) {
if ( ! strstr ( ch - > allowed_bearers , allowed_bearers_array [ i ] . name ) ) {
chan_misdn_log ( 0 , bc - > port , " Bearer Not allowed \b " ) ;
bc - > out_cause = 88 ;
ch - > state = MISDN_EXTCANTMATCH ;
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
return RESPONSE_OK ;
}
}
}
}
2006-02-08 16:10:21 +00:00
/* Check for Pickup Request first */
if ( ! strcmp ( chan - > exten , ast_pickup_ext ( ) ) ) {
int ret ; /** Sending SETUP_ACK**/
ret = misdn_lib_send_event ( bc , EVENT_SETUP_ACKNOWLEDGE ) ;
if ( ast_pickup_call ( chan ) ) {
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
2006-02-08 16:10:21 +00:00
} else {
ch - > state = MISDN_CALLING_ACKNOWLEDGE ;
ast_setstate ( chan , AST_STATE_DOWN ) ;
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
ch - > ast = NULL ;
2006-02-08 16:10:21 +00:00
break ;
}
}
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
/*
added support for s extension hope it will help those poor cretains
which haven ' t overlap dial .
*/
{
int ai ;
2005-11-01 22:04:14 +00:00
misdn_cfg_get ( bc - > port , MISDN_CFG_ALWAYS_IMMEDIATE , & ai , sizeof ( ai ) ) ;
2005-10-31 22:51:12 +00:00
if ( ai ) {
do_immediate_setup ( bc , ch , chan ) ;
break ;
}
2005-11-15 20:20:45 +00:00
2006-03-27 10:13:11 +00:00
}
/* check if we should jump into s when we have no dad */
{
int im ;
misdn_cfg_get ( bc - > port , MISDN_CFG_IMMEDIATE , & im , sizeof ( im ) ) ;
if ( im & & ast_strlen_zero ( bc - > dad ) ) {
do_immediate_setup ( bc , ch , chan ) ;
break ;
}
2005-11-15 20:20:45 +00:00
}
2006-03-21 09:47:51 +00:00
chan_misdn_log ( 5 , bc - > port , " CONTEXT:%s \n " , ch - > context ) ;
2005-12-09 11:01:18 +00:00
if ( ! ast_canmatch_extension ( ch - > ast , ch - > context , bc - > dad , 1 , bc - > oad ) ) {
chan_misdn_log ( - 1 , bc - > port , " Extension can never match, so disconnecting \n " ) ;
2006-07-04 17:04:21 +00:00
if ( bc - > nt )
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( ch ) ;
2005-10-31 22:51:12 +00:00
ch - > state = MISDN_EXTCANTMATCH ;
bc - > out_cause = 1 ;
2005-12-09 11:01:18 +00:00
2005-11-01 22:04:14 +00:00
if ( bc - > nt )
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
else
2006-06-01 12:51:41 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
2005-10-31 22:51:12 +00:00
break ;
}
2006-07-11 19:30:35 +00:00
if ( ! ch - > overlap_dial & & ast_exists_extension ( ch - > ast , ch - > context , bc - > dad , 1 , bc - > oad ) ) {
2005-10-31 22:51:12 +00:00
ch - > state = MISDN_DIALING ;
2005-12-09 11:01:18 +00:00
2006-02-02 21:15:34 +00:00
if ( bc - > nt | | ( bc - > need_more_infos & & misdn_lib_is_ptp ( bc - > port ) ) ) {
2005-10-31 22:51:12 +00:00
int ret ;
ret = misdn_lib_send_event ( bc , EVENT_SETUP_ACKNOWLEDGE ) ;
} else {
int ret ;
ret = misdn_lib_send_event ( bc , EVENT_PROCEEDING ) ;
}
2006-07-06 15:11:40 +00:00
if ( pbx_start_chan ( ch ) < 0 ) {
hangup_chan ( ch ) ;
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , bc - > port , " ast_pbx_start returned <0 in SETUP \n " ) ;
2005-10-31 22:51:12 +00:00
chan = NULL ;
2005-12-09 11:01:18 +00:00
2006-07-04 17:04:21 +00:00
if ( bc - > nt ) {
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( ch ) ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
2006-07-04 17:04:21 +00:00
} else
2006-06-01 12:51:41 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
2005-10-31 22:51:12 +00:00
}
} else {
2005-12-09 11:01:18 +00:00
2006-06-01 12:51:41 +00:00
if ( bc - > sending_complete ) {
2006-06-17 10:37:35 +00:00
ch - > state = MISDN_EXTCANTMATCH ;
2006-06-01 12:51:41 +00:00
bc - > out_cause = 1 ;
2006-06-17 10:37:35 +00:00
if ( bc - > nt ) {
chan_misdn_log ( 0 , bc - > port , " --> sending_complete so we never match .. \n " ) ;
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
} else {
chan_misdn_log ( 0 , bc - > port , " --> sending_complete so we never match .. \n " ) ;
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
}
2006-06-01 12:51:41 +00:00
} else {
2006-07-11 19:30:35 +00:00
2006-06-01 12:51:41 +00:00
int ret = misdn_lib_send_event ( bc , EVENT_SETUP_ACKNOWLEDGE ) ;
if ( ret = = - ENOCHAN ) {
ast_log ( LOG_WARNING , " Channel was catched, before we could Acknowledge \n " ) ;
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
}
/* send tone to phone :) */
/** ADD IGNOREPAT **/
2006-07-11 19:30:35 +00:00
int stop_tone , dad_len ;
2006-06-01 12:51:41 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_STOP_TONE , & stop_tone , sizeof ( int ) ) ;
2006-07-11 19:30:35 +00:00
dad_len = ast_strlen_zero ( bc - > dad ) ;
if ( ! dad_len & & stop_tone )
2006-07-06 15:11:40 +00:00
stop_indicate ( ch ) ;
2006-07-11 19:30:35 +00:00
else
2006-07-06 15:11:40 +00:00
dialtone_indicate ( ch ) ;
2006-06-01 12:51:41 +00:00
ch - > state = MISDN_WAITING4DIGS ;
2006-07-11 19:30:35 +00:00
if ( ch - > overlap_dial & & ! dad_len ) {
ast_mutex_lock ( & ch - > overlap_tv_lock ) ;
ch - > overlap_tv = ast_tvnow ( ) ;
ast_mutex_unlock ( & ch - > overlap_tv_lock ) ;
if ( ch - > overlap_dial_task = = - 1 ) {
ch - > overlap_dial_task =
misdn_tasks_add_variable ( ch - > overlap_dial , misdn_overlap_dial_task , ch ) ;
}
}
2006-06-01 12:51:41 +00:00
}
2005-10-31 22:51:12 +00:00
}
2006-07-11 19:30:35 +00:00
2005-10-31 22:51:12 +00:00
}
break ;
case EVENT_SETUP_ACKNOWLEDGE :
{
ch - > state = MISDN_CALLING_ACKNOWLEDGE ;
2006-05-24 23:21:03 +00:00
if ( bc - > channel )
update_name ( ch - > ast , bc - > port , bc - > channel ) ;
2005-10-31 22:51:12 +00:00
if ( ! ast_strlen_zero ( bc - > infos_pending ) ) {
/* TX Pending Infos */
{
int l = sizeof ( bc - > dad ) ;
strncat ( bc - > dad , bc - > infos_pending , l - strlen ( bc - > dad ) ) ;
bc - > dad [ l - 1 ] = 0 ;
}
{
int l = sizeof ( ch - > ast - > exten ) ;
strncpy ( ch - > ast - > exten , bc - > dad , l ) ;
ch - > ast - > exten [ l - 1 ] = 0 ;
}
{
int l = sizeof ( bc - > info_dad ) ;
strncpy ( bc - > info_dad , bc - > infos_pending , l ) ;
bc - > info_dad [ l - 1 ] = 0 ;
}
strncpy ( bc - > infos_pending , " " , 1 ) ;
misdn_lib_send_event ( bc , EVENT_INFORMATION ) ;
}
}
break ;
case EVENT_PROCEEDING :
{
if ( misdn_cap_is_speech ( bc - > capability ) & &
misdn_inband_avail ( bc ) ) {
start_bc_tones ( ch ) ;
}
2006-02-02 21:15:34 +00:00
2006-02-10 10:10:58 +00:00
ch - > state = MISDN_PROCEEDING ;
2006-02-02 21:15:34 +00:00
ast_queue_control ( ch - > ast , AST_CONTROL_PROCEEDING ) ;
2005-10-31 22:51:12 +00:00
}
break ;
case EVENT_PROGRESS :
2005-11-01 22:04:14 +00:00
if ( ! bc - > nt ) {
2005-10-31 22:51:12 +00:00
if ( misdn_cap_is_speech ( bc - > capability ) & &
misdn_inband_avail ( bc )
) {
start_bc_tones ( ch ) ;
}
ast_queue_control ( ch - > ast , AST_CONTROL_PROGRESS ) ;
ch - > state = MISDN_PROGRESS ;
}
break ;
case EVENT_ALERTING :
{
ch - > state = MISDN_ALERTING ;
2005-11-15 20:20:45 +00:00
ast_queue_control ( ch - > ast , AST_CONTROL_RINGING ) ;
ast_setstate ( ch - > ast , AST_STATE_RINGING ) ;
cb_log ( 1 , bc - > port , " Set State Ringing \n " ) ;
if ( misdn_cap_is_speech ( bc - > capability ) & & misdn_inband_avail ( bc ) ) {
2006-05-05 16:38:15 +00:00
cb_log ( 1 , bc - > port , " Starting Tones, we have inband Data \n " ) ;
2006-02-02 21:15:34 +00:00
start_bc_tones ( ch ) ;
2006-05-05 16:38:15 +00:00
} else {
cb_log ( 1 , bc - > port , " We have no inband Data, the other end must create ringing \n " ) ;
if ( ch - > far_alerting ) {
cb_log ( 1 , bc - > port , " The other end can not do ringing eh ?.. we must do all ourself.. " ) ;
start_bc_tones ( ch ) ;
2006-07-06 15:11:40 +00:00
/*tone_indicate(ch, TONE_FAR_ALERTING);*/
2006-05-05 16:38:15 +00:00
}
2006-02-02 21:15:34 +00:00
}
2005-10-31 22:51:12 +00:00
}
break ;
case EVENT_CONNECT :
2006-04-05 14:51:48 +00:00
{
2006-08-03 16:38:00 +00:00
/*we answer when we've got our very new L3 ID from the NT stack */
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_CONNECT_ACKNOWLEDGE ) ;
2006-04-05 14:51:48 +00:00
struct ast_channel * bridged = AST_BRIDGED_P ( ch - > ast ) ;
2006-05-05 16:38:15 +00:00
misdn_lib_echo ( bc , 0 ) ;
2006-07-06 15:11:40 +00:00
stop_indicate ( ch ) ;
2006-05-05 16:38:15 +00:00
2006-05-23 12:38:06 +00:00
if ( bridged & & ! strcasecmp ( bridged - > tech - > type , " mISDN " ) ) {
2006-04-05 14:51:48 +00:00
struct chan_list * bridged_ch = MISDN_ASTERISK_TECH_PVT ( bridged ) ;
chan_misdn_log ( 1 , bc - > port , " --> copying cpndialplan:%d and cad:%s to the A-Channel \n " , bc - > cpnnumplan , bc - > cad ) ;
2006-05-23 12:38:06 +00:00
if ( bridged_ch ) {
bridged_ch - > bc - > cpnnumplan = bc - > cpnnumplan ;
ast_copy_string ( bridged_ch - > bc - > cad , bc - > cad , sizeof ( bc - > cad ) ) ;
}
2006-04-05 14:51:48 +00:00
}
}
2006-05-23 12:38:06 +00:00
/* notice that we don't break here!*/
2006-04-05 14:51:48 +00:00
2005-10-31 22:51:12 +00:00
case EVENT_CONNECT_ACKNOWLEDGE :
{
ch - > l3id = bc - > l3_id ;
ch - > addr = bc - > addr ;
start_bc_tones ( ch ) ;
ch - > state = MISDN_CONNECTED ;
ast_queue_control ( ch - > ast , AST_CONTROL_ANSWER ) ;
}
break ;
case EVENT_DISCONNECT :
2006-06-17 10:37:35 +00:00
/*we might not have an ch->ast ptr here anymore*/
2006-07-06 15:11:40 +00:00
if ( ch ) {
2005-10-31 22:51:12 +00:00
struct chan_list * holded_ch = find_holded ( cl_te , bc ) ;
2006-07-06 15:11:40 +00:00
2006-05-23 12:38:06 +00:00
chan_misdn_log ( 3 , bc - > port , " --> org:%d nt:%d, inbandavail:%d state:%d \n " , ch - > orginator , bc - > nt , misdn_inband_avail ( bc ) , ch - > state ) ;
2006-04-10 14:09:17 +00:00
if ( ch - > orginator = = ORG_AST & & ! bc - > nt & & misdn_inband_avail ( bc ) & & ch - > state ! = MISDN_CONNECTED ) {
2005-11-15 20:20:45 +00:00
/* If there's inband information available (e.g. a
recorded message saying what was wrong with the
dialled number , or perhaps even giving an
alternative number , then play it instead of
immediately releasing the call */
2006-06-28 14:15:29 +00:00
chan_misdn_log ( 1 , bc - > port , " --> Inband Info Avail, not sending RELEASE \n " ) ;
2006-06-21 15:21:46 +00:00
ch - > state = MISDN_DISCONNECTED ;
2005-11-15 20:20:45 +00:00
start_bc_tones ( ch ) ;
break ;
}
/*Check for holded channel, to implement transfer*/
2006-06-17 10:37:35 +00:00
if ( holded_ch & & ch - > ast ) {
2006-08-03 16:38:00 +00:00
cb_log ( 1 , bc - > port , " --> found holded ch \n " ) ;
2005-10-31 22:51:12 +00:00
if ( ch - > state = = MISDN_CONNECTED ) {
misdn_transfer_bc ( ch , holded_ch ) ;
}
2006-08-08 09:19:06 +00:00
hangup_chan ( ch ) ;
release_chan ( bc ) ;
2006-08-03 16:38:00 +00:00
break ;
2005-10-31 22:51:12 +00:00
}
2005-11-15 20:20:45 +00:00
stop_bc_tones ( ch ) ;
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
2005-10-31 22:51:12 +00:00
}
2006-07-06 15:11:40 +00:00
bc - > out_cause = - 1 ;
if ( bc - > need_release ) misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
2005-10-31 22:51:12 +00:00
break ;
case EVENT_RELEASE :
{
bc - > out_cause = 16 ;
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
release_chan ( bc ) ;
2006-08-03 16:38:00 +00:00
if ( bc - > need_release_complete )
2006-07-06 15:11:40 +00:00
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
2005-10-31 22:51:12 +00:00
}
break ;
case EVENT_RELEASE_COMPLETE :
{
stop_bc_tones ( ch ) ;
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
release_chan ( bc ) ;
if ( ch )
ch - > state = MISDN_CLEANING ;
}
break ;
case EVENT_CLEANUP :
{
stop_bc_tones ( ch ) ;
2006-08-03 16:38:00 +00:00
switch ( ch - > state ) {
case MISDN_CALLING :
bc - > cause = 27 ; /* Destination out of order */
break ;
default :
break ;
}
2006-07-06 15:11:40 +00:00
hangup_chan ( ch ) ;
2005-10-31 22:51:12 +00:00
release_chan ( bc ) ;
}
break ;
2006-02-02 21:15:34 +00:00
case EVENT_TONE_GENERATE :
2005-10-31 22:51:12 +00:00
{
2006-02-02 21:15:34 +00:00
int tone_len = bc - > tone_cnt ;
struct ast_channel * ast = ch - > ast ;
void * tmp ;
int res ;
int ( * generate ) ( struct ast_channel * chan , void * tmp , int datalen , int samples ) ;
2006-02-08 16:10:21 +00:00
chan_misdn_log ( 9 , bc - > port , " TONE_GEN: len:%d \n " ) ;
2006-06-06 09:40:41 +00:00
2006-06-26 17:37:11 +00:00
if ( ! ast ) break ;
2006-02-02 21:15:34 +00:00
if ( ! ast - > generator ) break ;
2006-06-17 10:37:35 +00:00
2006-02-02 21:15:34 +00:00
2006-06-17 10:37:35 +00:00
2006-02-02 21:15:34 +00:00
tmp = ast - > generatordata ;
ast - > generatordata = NULL ;
generate = ast - > generator - > generate ;
2006-06-17 10:37:35 +00:00
if ( tone_len < 0 | | tone_len > 512 ) {
2006-06-21 15:21:46 +00:00
ast_log ( LOG_NOTICE , " TONE_GEN: len was %d, set to 128 \n " , tone_len ) ;
2006-06-17 10:37:35 +00:00
tone_len = 128 ;
}
2006-02-02 21:15:34 +00:00
res = generate ( ast , tmp , tone_len , tone_len ) ;
ast - > generatordata = tmp ;
2006-06-06 09:40:41 +00:00
2006-02-02 21:15:34 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Auto-deactivating generator \n " ) ;
ast_deactivate_generator ( ast ) ;
} else {
bc - > tone_cnt = 0 ;
}
}
break ;
2005-10-31 22:51:12 +00:00
2006-02-02 21:15:34 +00:00
case EVENT_BCHAN_DATA :
{
2006-05-16 14:34:21 +00:00
if ( ! misdn_cap_is_speech ( ch - > bc - > capability ) ) {
struct ast_frame frame ;
/*In Data Modes we queue frames*/
frame . frametype = AST_FRAME_VOICE ; /*we have no data frames yet*/
frame . subclass = AST_FORMAT_ALAW ;
frame . datalen = bc - > bframe_len ;
frame . samples = bc - > bframe_len ;
frame . mallocd = 0 ;
frame . offset = 0 ;
frame . src = NULL ;
frame . data = bc - > bframe ;
ast_queue_frame ( ch - > ast , & frame ) ;
2005-10-31 22:51:12 +00:00
} else {
2006-06-06 09:40:41 +00:00
fd_set wrfs ;
struct timeval tv ;
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
FD_ZERO ( & wrfs ) ;
FD_SET ( ch - > pipe [ 1 ] , & wrfs ) ;
int t = select ( FD_SETSIZE , NULL , & wrfs , NULL , & tv ) ;
2005-11-08 00:02:53 +00:00
2006-06-06 09:40:41 +00:00
if ( ! t ) {
chan_misdn_log ( 9 , bc - > port , " Select Timed out \n " ) ;
break ;
}
if ( t < 0 ) {
chan_misdn_log ( - 1 , bc - > port , " Select Error (err=%s) \n " , strerror ( errno ) ) ;
break ;
}
if ( FD_ISSET ( ch - > pipe [ 1 ] , & wrfs ) ) {
2006-07-06 15:11:40 +00:00
chan_misdn_log ( 9 , bc - > port , " writing %d bytes 2 asterisk \n " , bc - > bframe_len ) ;
2006-06-06 09:40:41 +00:00
int ret = write ( ch - > pipe [ 1 ] , bc - > bframe , bc - > bframe_len ) ;
if ( ret < = 0 ) {
chan_misdn_log ( - 1 , bc - > port , " Write returned <=0 (err=%s) \n " , strerror ( errno ) ) ;
}
} else {
chan_misdn_log ( 1 , bc - > port , " Wripe Pipe full! \n " ) ;
2005-10-31 22:51:12 +00:00
}
}
}
break ;
case EVENT_TIMEOUT :
{
2006-06-26 17:37:11 +00:00
if ( ch & & bc )
chan_misdn_log ( 1 , bc - > port , " --> state: %s \n " , misdn_get_ch_state ( ch ) ) ;
2006-06-17 10:37:35 +00:00
switch ( ch - > state ) {
2005-10-31 22:51:12 +00:00
case MISDN_CALLING :
case MISDN_DIALING :
case MISDN_PROGRESS :
2006-06-19 07:36:18 +00:00
case MISDN_ALERTING :
case MISDN_PROCEEDING :
case MISDN_CALLING_ACKNOWLEDGE :
2006-06-17 10:37:35 +00:00
if ( bc - > nt ) {
bc - > progress_indicator = 8 ;
2006-07-06 15:11:40 +00:00
hanguptone_indicate ( ch ) ;
2006-06-17 10:37:35 +00:00
}
bc - > out_cause = 1 ;
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
break ;
2006-07-06 15:11:40 +00:00
case MISDN_WAITING4DIGS :
if ( bc - > nt ) {
bc - > progress_indicator = 8 ;
bc - > out_cause = 1 ;
hanguptone_indicate ( ch ) ;
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
} else {
bc - > out_cause = 16 ;
misdn_lib_send_event ( bc , EVENT_RELEASE ) ;
}
break ;
2006-06-17 10:37:35 +00:00
case MISDN_CLEANING :
chan_misdn_log ( 1 , bc - > port , " --> in state cleaning .. so ingoring, the stack should clean it for us \n " ) ;
break ;
2005-10-31 22:51:12 +00:00
default :
misdn_lib_send_event ( bc , EVENT_RELEASE_COMPLETE ) ;
}
}
break ;
2006-07-06 15:11:40 +00:00
2005-10-31 22:51:12 +00:00
/***************************/
/** Suplementary Services **/
/***************************/
case EVENT_RETRIEVE :
{
2006-08-08 09:19:06 +00:00
ch = find_holded ( cl_te , bc ) ;
if ( ! ch ) {
ast_log ( LOG_WARNING , " Found no Holded channel, cannot Retrieve \n " ) ;
misdn_lib_send_event ( bc , EVENT_RETRIEVE_REJECT ) ;
break ;
}
2005-10-31 22:51:12 +00:00
struct ast_channel * hold_ast = AST_BRIDGED_P ( ch - > ast ) ;
ch - > state = MISDN_CONNECTED ;
if ( hold_ast ) {
ast_moh_stop ( hold_ast ) ;
}
if ( misdn_lib_send_event ( bc , EVENT_RETRIEVE_ACKNOWLEDGE ) < 0 )
misdn_lib_send_event ( bc , EVENT_RETRIEVE_REJECT ) ;
}
break ;
case EVENT_HOLD :
{
int hold_allowed ;
2005-11-01 22:04:14 +00:00
misdn_cfg_get ( bc - > port , MISDN_CFG_HOLD_ALLOWED , & hold_allowed , sizeof ( int ) ) ;
2005-10-31 22:51:12 +00:00
if ( ! hold_allowed ) {
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , bc - > port , " Hold not allowed this port. \n " ) ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_HOLD_REJECT ) ;
break ;
}
2006-02-02 21:15:34 +00:00
#if 0
2005-10-31 22:51:12 +00:00
{
struct chan_list * holded_ch = find_holded ( cl_te , bc ) ;
if ( holded_ch ) {
misdn_lib_send_event ( bc , EVENT_HOLD_REJECT ) ;
2005-12-09 11:01:18 +00:00
chan_misdn_log ( - 1 , bc - > port , " We can't use RETRIEVE at the moment due to mISDN bug! \n " ) ;
2005-10-31 22:51:12 +00:00
break ;
}
}
2006-02-02 21:15:34 +00:00
# endif
2006-04-03 19:17:59 +00:00
struct ast_channel * bridged = AST_BRIDGED_P ( ch - > ast ) ;
2005-10-31 22:51:12 +00:00
2006-04-03 19:17:59 +00:00
if ( bridged ) {
struct chan_list * bridged_ch = MISDN_ASTERISK_TECH_PVT ( bridged ) ;
2005-10-31 22:51:12 +00:00
ch - > state = MISDN_HOLDED ;
ch - > l3id = bc - > l3_id ;
2006-04-03 19:17:59 +00:00
bc - > holded_bc = bridged_ch - > bc ;
2005-10-31 22:51:12 +00:00
misdn_lib_send_event ( bc , EVENT_HOLD_ACKNOWLEDGE ) ;
2006-04-03 19:17:59 +00:00
2006-07-19 20:44:39 +00:00
/* XXX This should queue an AST_CONTROL_HOLD frame on this channel
* instead of starting moh on the bridged channel directly */
ast_moh_start ( bridged , NULL , NULL ) ;
2005-10-31 22:51:12 +00:00
} else {
misdn_lib_send_event ( bc , EVENT_HOLD_REJECT ) ;
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 0 , bc - > port , " We aren't bridged to anybody \n " ) ;
2005-10-31 22:51:12 +00:00
}
}
break ;
2005-12-09 11:01:18 +00:00
case EVENT_FACILITY :
2006-08-15 16:49:26 +00:00
print_facility ( & ( bc - > fac_in ) , bc ) ;
2005-12-09 11:01:18 +00:00
2006-08-15 16:49:26 +00:00
switch ( bc - > fac_in . Function ) {
2006-08-16 13:19:54 +00:00
case Fac_CD :
{
struct ast_channel * bridged = AST_BRIDGED_P ( ch - > ast ) ;
struct chan_list * ch_br ;
if ( bridged & & MISDN_ASTERISK_TECH_PVT ( bridged ) ) {
ch_br = MISDN_ASTERISK_TECH_PVT ( bridged ) ;
/*ch->state=MISDN_FACILITY_DEFLECTED;*/
if ( ch_br - > bc ) {
if ( ast_exists_extension ( bridged , ch - > context , ( char * ) bc - > fac_in . u . CDeflection . DeflectedToNumber , 1 , bc - > oad ) ) {
ch_br - > state = MISDN_DIALING ;
if ( pbx_start_chan ( ch_br ) < 0 ) {
chan_misdn_log ( - 1 , ch_br - > bc - > port , " ast_pbx_start returned < 0 in misdn_overlap_dial_task \n " ) ;
}
2006-08-15 16:49:26 +00:00
}
}
2006-08-16 13:19:54 +00:00
2005-12-09 11:01:18 +00:00
}
2006-08-16 13:19:54 +00:00
misdn_lib_send_event ( bc , EVENT_DISCONNECT ) ;
}
break ;
case Fac_AOCDCurrency :
bc - > AOCDtype = Fac_AOCDCurrency ;
memcpy ( & ( bc - > AOCD . currency ) , & ( bc - > fac_in . u . AOCDcur ) , sizeof ( struct FacAOCDCurrency ) ) ;
break ;
case Fac_AOCDChargingUnit :
bc - > AOCDtype = Fac_AOCDChargingUnit ;
memcpy ( & ( bc - > AOCD . chargingUnit ) , & ( bc - > fac_in . u . AOCDchu ) , sizeof ( struct FacAOCDChargingUnit ) ) ;
break ;
2005-12-09 11:01:18 +00:00
default :
2006-08-15 16:49:26 +00:00
chan_misdn_log ( 0 , bc - > port , " --> not yet handled: facility type:%p \n " , bc - > fac_in . Function ) ;
2005-12-09 11:01:18 +00:00
}
break ;
2006-04-03 19:17:59 +00:00
case EVENT_RESTART :
2006-06-01 12:51:41 +00:00
stop_bc_tones ( ch ) ;
release_chan ( bc ) ;
2006-04-03 19:17:59 +00:00
break ;
2005-12-09 11:01:18 +00:00
2005-10-31 22:51:12 +00:00
default :
2006-06-21 15:21:46 +00:00
ast_log ( LOG_NOTICE , " Got Unknown Event \n " ) ;
2005-10-31 22:51:12 +00:00
break ;
}
return RESPONSE_OK ;
}
/** TE STUFF END **/
/******************************************
*
* Asterisk Channel Endpoint END
*
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-12-09 11:01:18 +00:00
static int g_config_initialized = 0 ;
2005-10-31 22:51:12 +00:00
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2006-04-17 16:42:21 +00:00
{
/* First, take us out of the channel loop */
ast_log ( LOG_VERBOSE , " -- Unregistering mISDN Channel Driver -- \n " ) ;
2006-07-11 19:30:35 +00:00
misdn_tasks_destroy ( ) ;
2006-04-17 16:42:21 +00:00
if ( ! g_config_initialized ) return 0 ;
2006-09-18 19:54:18 +00:00
ast_cli_unregister_multiple ( chan_misdn_clis , sizeof ( chan_misdn_clis ) / sizeof ( struct ast_cli_entry ) ) ;
2006-04-17 16:42:21 +00:00
/* ast_unregister_application("misdn_crypt"); */
ast_unregister_application ( " misdn_set_opt " ) ;
ast_unregister_application ( " misdn_facility " ) ;
ast_channel_unregister ( & misdn_tech ) ;
free_robin_list ( ) ;
misdn_cfg_destroy ( ) ;
misdn_lib_destroy ( ) ;
if ( misdn_debug )
free ( misdn_debug ) ;
if ( misdn_debug_only )
free ( misdn_debug_only ) ;
2006-08-17 09:14:01 +00:00
free ( misdn_ports ) ;
2006-04-17 16:42:21 +00:00
return 0 ;
}
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2005-10-31 22:51:12 +00:00
{
2006-07-11 19:30:35 +00:00
int i , port ;
2005-10-31 22:51:12 +00:00
char ports [ 256 ] = " " ;
2006-07-11 19:30:35 +00:00
2005-10-31 22:51:12 +00:00
max_ports = misdn_lib_maxports_get ( ) ;
if ( max_ports < = 0 ) {
ast_log ( LOG_ERROR , " Unable to initialize mISDN \n " ) ;
2006-08-16 19:13:47 +00:00
return 0 ;
2005-10-31 22:51:12 +00:00
}
2006-08-08 18:13:40 +00:00
if ( misdn_cfg_init ( max_ports ) ) {
ast_log ( LOG_ERROR , " Unable to initialize misdn_config. \n " ) ;
2006-08-31 21:00:20 +00:00
return AST_MODULE_LOAD_DECLINE ;
2006-08-08 18:13:40 +00:00
}
2005-10-31 22:51:12 +00:00
g_config_initialized = 1 ;
misdn_debug = ( int * ) malloc ( sizeof ( int ) * ( max_ports + 1 ) ) ;
2006-08-17 09:14:01 +00:00
misdn_ports = ( int * ) malloc ( sizeof ( int ) * ( max_ports + 1 ) ) ;
2005-10-31 22:51:12 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_DEBUG , & misdn_debug [ 0 ] , sizeof ( int ) ) ;
2006-08-17 09:14:01 +00:00
for ( i = 1 ; i < = max_ports ; i + + ) {
2005-10-31 22:51:12 +00:00
misdn_debug [ i ] = misdn_debug [ 0 ] ;
2006-08-17 09:14:01 +00:00
misdn_ports [ i ] = i ;
}
* misdn_ports = 0 ;
2005-10-31 22:51:12 +00:00
misdn_debug_only = ( int * ) calloc ( max_ports + 1 , sizeof ( int ) ) ;
{
2006-02-22 21:59:46 +00:00
char tempbuf [ BUFFERSIZE + 1 ] ;
2005-10-31 22:51:12 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_TRACEFILE , tempbuf , BUFFERSIZE ) ;
if ( strlen ( tempbuf ) )
tracing = 1 ;
}
2006-05-22 15:02:03 +00:00
misdn_in_calls = ( int * ) malloc ( sizeof ( int ) * ( max_ports + 1 ) ) ;
misdn_out_calls = ( int * ) malloc ( sizeof ( int ) * ( max_ports + 1 ) ) ;
2005-10-31 22:51:12 +00:00
2006-05-22 15:02:03 +00:00
for ( i = 1 ; i < = max_ports ; i + + ) {
misdn_in_calls [ i ] = 0 ;
misdn_out_calls [ i ] = 0 ;
}
2005-11-01 22:04:14 +00:00
ast_mutex_init ( & cl_te_lock ) ;
2006-02-02 21:15:34 +00:00
misdn_cfg_update_ptp ( ) ;
2005-10-31 22:51:12 +00:00
misdn_cfg_get_ports_string ( ports ) ;
2006-05-23 19:40:16 +00:00
2005-10-31 22:51:12 +00:00
if ( strlen ( ports ) )
chan_misdn_log ( 0 , 0 , " Got: %s from get_ports \n " , ports ) ;
{
struct misdn_lib_iface iface = {
. cb_event = cb_events ,
. cb_log = chan_misdn_log ,
2005-12-09 11:01:18 +00:00
. cb_jb_empty = chan_misdn_jb_empty ,
2005-10-31 22:51:12 +00:00
} ;
2006-05-23 19:40:16 +00:00
2005-10-31 22:51:12 +00:00
if ( misdn_lib_init ( ports , & iface , NULL ) )
chan_misdn_log ( 0 , 0 , " No te ports initialized \n " ) ;
2006-07-04 17:04:21 +00:00
int ntflags = 0 ;
char ntfile [ BUFFERSIZE + 1 ] ;
2005-10-31 22:51:12 +00:00
2006-07-04 17:04:21 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_NTDEBUGFLAGS , & ntflags , sizeof ( int ) ) ;
misdn_cfg_get ( 0 , MISDN_GEN_NTDEBUGFILE , & ntfile , BUFFERSIZE ) ;
2005-10-31 22:51:12 +00:00
2006-07-04 17:04:21 +00:00
misdn_lib_nt_debug_init ( ntflags , ntfile ) ;
2006-06-29 20:12:19 +00:00
2006-07-04 17:04:21 +00:00
}
2006-06-29 20:12:19 +00:00
2005-10-31 22:51:12 +00:00
{
if ( ast_channel_register ( & misdn_tech ) ) {
2005-12-09 11:01:18 +00:00
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , misdn_type ) ;
2006-08-21 02:11:39 +00:00
unload_module ( ) ;
2005-10-31 22:51:12 +00:00
return - 1 ;
}
}
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( chan_misdn_clis , sizeof ( chan_misdn_clis ) / sizeof ( struct ast_cli_entry ) ) ;
2005-10-31 22:51:12 +00:00
2006-05-23 12:38:06 +00:00
ast_register_application ( " misdn_set_opt " , misdn_set_opt_exec , " misdn_set_opt " ,
2005-10-31 22:51:12 +00:00
" misdn_set_opt(:<opt><optarg>:<opt><optarg>..): \n "
" Sets mISDN opts. and optargs \n "
" \n "
2006-05-23 12:38:06 +00:00
" The available options are: \n "
" d - Send display text on called phone, text is the optparam \n "
" n - don't detect dtmf tones on called channel \n "
" h - make digital outgoing call \n "
" c - make crypted outgoing call, param is keyindex \n "
" e - perform echo cancelation on this channel, \n "
" takes taps as arguments (32,64,128,256) \n "
" s - send Non Inband DTMF as inband \n "
" vr - rxgain control \n "
" vt - txgain control \n "
2005-10-31 22:51:12 +00:00
) ;
ast_register_application ( " misdn_facility " , misdn_facility_exec , " misdn_facility " ,
" misdn_facility(<FACILITY_TYPE>|<ARG1>|..) \n "
" Sends the Facility Message FACILITY_TYPE with \n "
" the given Arguments to the current ISDN Channel \n "
" Supported Facilities are: \n "
" \n "
" type=calldeflect args=Nr where to deflect \n "
) ;
2005-12-09 11:01:18 +00:00
misdn_cfg_get ( 0 , MISDN_GEN_TRACEFILE , global_tracefile , BUFFERSIZE ) ;
2006-05-22 15:02:03 +00:00
2006-07-11 19:30:35 +00:00
/* start the l1 watchers */
for ( port = misdn_cfg_get_next_port ( 0 ) ; port > = 0 ; port = misdn_cfg_get_next_port ( port ) ) {
int l1timeout ;
misdn_cfg_get ( port , MISDN_CFG_L1_TIMEOUT , & l1timeout , sizeof ( l1timeout ) ) ;
if ( l1timeout ) {
chan_misdn_log ( 4 , 0 , " Adding L1watcher task: port:%d timeout:%ds \n " , port , l1timeout ) ;
2006-08-17 09:14:01 +00:00
misdn_tasks_add ( l1timeout * 1000 , misdn_l1_task , & misdn_ports [ port ] ) ;
2006-07-11 19:30:35 +00:00
}
}
2005-12-09 11:01:18 +00:00
2006-09-19 18:48:17 +00:00
chan_misdn_log ( 0 , 0 , " -- mISDN Channel Driver Registered -- \n " ) ;
2005-10-31 22:51:12 +00:00
return 0 ;
}
2006-08-21 02:11:39 +00:00
static int reload ( void )
2006-02-10 14:17:28 +00:00
{
reload_config ( ) ;
return 0 ;
}
2005-10-31 22:51:12 +00:00
/*** SOME APPS ;)***/
static int misdn_facility_exec ( struct ast_channel * chan , void * data )
{
struct chan_list * ch = MISDN_ASTERISK_TECH_PVT ( chan ) ;
char * tok , * tokb ;
2005-12-09 11:01:18 +00:00
chan_misdn_log ( 0 , 0 , " TYPE: %s \n " , chan - > tech - > type ) ;
if ( strcasecmp ( chan - > tech - > type , " mISDN " ) ) {
2005-10-31 22:51:12 +00:00
ast_log ( LOG_WARNING , " misdn_facility makes only sense with chan_misdn channels! \n " ) ;
return - 1 ;
}
2005-11-08 01:55:31 +00:00
if ( ast_strlen_zero ( ( char * ) data ) ) {
2005-10-31 22:51:12 +00:00
ast_log ( LOG_WARNING , " misdn_facility Requires arguments \n " ) ;
return - 1 ;
}
tok = strtok_r ( ( char * ) data , " | " , & tokb ) ;
if ( ! tok ) {
ast_log ( LOG_WARNING , " misdn_facility Requires arguments \n " ) ;
return - 1 ;
}
if ( ! strcasecmp ( tok , " calldeflect " ) ) {
tok = strtok_r ( NULL , " | " , & tokb ) ;
if ( ! tok ) {
ast_log ( LOG_WARNING , " Facility: Call Defl Requires arguments \n " ) ;
}
2006-08-15 16:49:26 +00:00
if ( strlen ( tok ) > = sizeof ( ch - > bc - > fac_out . u . CDeflection . DeflectedToNumber ) ) {
ast_log ( LOG_WARNING , " Facility: Number argument too long (up to 15 digits are allowed). Ignoring. \n " ) ;
return 0 ;
}
2006-08-16 13:19:54 +00:00
ch - > bc - > fac_out . Function = Fac_CD ;
2006-08-15 16:49:26 +00:00
strncpy ( ( char * ) ch - > bc - > fac_out . u . CDeflection . DeflectedToNumber , tok , sizeof ( ch - > bc - > fac_out . u . CDeflection . DeflectedToNumber ) ) ;
misdn_lib_send_event ( ch - > bc , EVENT_FACILITY ) ;
2005-10-31 22:51:12 +00:00
} else {
ast_log ( LOG_WARNING , " Unknown Facility: %s \n " , tok ) ;
}
return 0 ;
}
static int misdn_set_opt_exec ( struct ast_channel * chan , void * data )
{
struct chan_list * ch = MISDN_ASTERISK_TECH_PVT ( chan ) ;
char * tok , * tokb ;
int keyidx = 0 ;
int rxgain = 0 ;
int txgain = 0 ;
2006-02-10 14:17:28 +00:00
int change_jitter = 0 ;
2005-12-09 11:01:18 +00:00
if ( strcasecmp ( chan - > tech - > type , " mISDN " ) ) {
2005-10-31 22:51:12 +00:00
ast_log ( LOG_WARNING , " misdn_set_opt makes only sense with chan_misdn channels! \n " ) ;
return - 1 ;
}
2005-11-08 01:55:31 +00:00
if ( ast_strlen_zero ( ( char * ) data ) ) {
2005-10-31 22:51:12 +00:00
ast_log ( LOG_WARNING , " misdn_set_opt Requires arguments \n " ) ;
return - 1 ;
}
for ( tok = strtok_r ( ( char * ) data , " : " , & tokb ) ;
tok ;
tok = strtok_r ( NULL , " : " , & tokb ) ) {
int neglect = 0 ;
if ( tok [ 0 ] = = ' ! ' ) {
neglect = 1 ;
tok + + ;
}
switch ( tok [ 0 ] ) {
case ' d ' :
2006-02-22 21:59:46 +00:00
ast_copy_string ( ch - > bc - > display , + + tok , 84 ) ;
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: Display:%s \n " , ch - > bc - > display ) ;
2005-10-31 22:51:12 +00:00
break ;
case ' n ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: No DSP \n " ) ;
2005-10-31 22:51:12 +00:00
ch - > bc - > nodsp = 1 ;
break ;
case ' j ' :
2006-02-10 14:17:28 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: jitter \n " ) ;
tok + + ;
change_jitter = 1 ;
switch ( tok [ 0 ] ) {
case ' b ' :
ch - > jb_len = atoi ( + + tok ) ;
chan_misdn_log ( 1 , ch - > bc - > port , " --> buffer_len:%d \n " , ch - > jb_len ) ;
break ;
case ' t ' :
ch - > jb_upper_threshold = atoi ( + + tok ) ;
chan_misdn_log ( 1 , ch - > bc - > port , " --> upper_threshold:%d \n " , ch - > jb_upper_threshold ) ;
break ;
case ' n ' :
ch - > bc - > nojitter = 1 ;
chan_misdn_log ( 1 , ch - > bc - > port , " --> nojitter \n " ) ;
break ;
default :
2006-02-28 11:46:55 +00:00
ch - > jb_len = 4000 ;
2006-02-10 14:17:28 +00:00
ch - > jb_upper_threshold = 0 ;
chan_misdn_log ( 1 , ch - > bc - > port , " --> buffer_len:%d (default) \n " , ch - > jb_len ) ;
chan_misdn_log ( 1 , ch - > bc - > port , " --> upper_threshold:%d (default) \n " , ch - > jb_upper_threshold ) ;
}
2005-10-31 22:51:12 +00:00
break ;
case ' v ' :
tok + + ;
switch ( tok [ 0 ] ) {
case ' r ' :
rxgain = atoi ( + + tok ) ;
if ( rxgain < - 8 ) rxgain = - 8 ;
if ( rxgain > 8 ) rxgain = 8 ;
ch - > bc - > rxgain = rxgain ;
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: Volume:%d \n " , rxgain ) ;
2005-10-31 22:51:12 +00:00
break ;
case ' t ' :
txgain = atoi ( + + tok ) ;
if ( txgain < - 8 ) txgain = - 8 ;
if ( txgain > 8 ) txgain = 8 ;
ch - > bc - > txgain = txgain ;
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: Volume:%d \n " , txgain ) ;
2005-10-31 22:51:12 +00:00
break ;
}
break ;
case ' c ' :
keyidx = atoi ( + + tok ) ;
if ( keyidx > misdn_key_vector_size | | keyidx < 0 ) {
ast_log ( LOG_WARNING , " You entered the keyidx: %d but we have only %d keys \n " , keyidx , misdn_key_vector_size ) ;
continue ;
}
{
2006-02-22 21:59:46 +00:00
ast_copy_string ( ch - > bc - > crypt_key , misdn_key_vector [ keyidx ] , sizeof ( ch - > bc - > crypt_key ) ) ;
2005-10-31 22:51:12 +00:00
}
2006-02-22 21:59:46 +00:00
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 0 , ch - > bc - > port , " SETOPT: crypt with key:%s \n " , misdn_key_vector [ keyidx ] ) ;
2005-10-31 22:51:12 +00:00
break ;
case ' e ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: EchoCancel \n " ) ;
2005-10-31 22:51:12 +00:00
if ( neglect ) {
2006-02-10 10:10:58 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " --> disabled \n " ) ;
2005-10-31 22:51:12 +00:00
ch - > bc - > ec_enable = 0 ;
} else {
ch - > bc - > ec_enable = 1 ;
ch - > bc - > orig = ch - > orginator ;
tok + + ;
if ( tok ) {
ch - > bc - > ec_deftaps = atoi ( tok ) ;
}
}
break ;
case ' h ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: Digital \n " ) ;
2006-02-02 21:15:34 +00:00
2005-10-31 22:51:12 +00:00
if ( strlen ( tok ) > 1 & & tok [ 1 ] = = ' 1 ' ) {
2006-02-02 21:15:34 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: HDLC \n " ) ;
ch - > bc - > hdlc = 1 ;
}
ch - > bc - > capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED ;
2005-10-31 22:51:12 +00:00
break ;
case ' s ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: Send DTMF \n " ) ;
2005-10-31 22:51:12 +00:00
ch - > bc - > send_dtmf = 1 ;
break ;
case ' f ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: Faxdetect \n " ) ;
2005-10-31 22:51:12 +00:00
ch - > faxdetect = 1 ;
2006-08-08 18:13:40 +00:00
misdn_cfg_get ( ch - > bc - > port , MISDN_CFG_FAXDETECT_TIMEOUT , & ch - > faxdetect_timeout , sizeof ( ch - > faxdetect_timeout ) ) ;
2005-10-31 22:51:12 +00:00
break ;
case ' a ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: AST_DSP (for DTMF) \n " ) ;
2005-10-31 22:51:12 +00:00
ch - > ast_dsp = 1 ;
break ;
case ' p ' :
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: callerpres: %s \n " , & tok [ 1 ] ) ;
2005-10-31 22:51:12 +00:00
/* CRICH: callingpres!!! */
if ( strstr ( tok , " allowed " ) ) {
ch - > bc - > pres = 0 ;
} else if ( strstr ( tok , " not_screened " ) ) {
ch - > bc - > pres = 1 ;
}
break ;
default :
break ;
}
}
2006-02-10 14:17:28 +00:00
if ( change_jitter )
config_jitterbuffer ( ch ) ;
2005-10-31 22:51:12 +00:00
if ( ch - > faxdetect | | ch - > ast_dsp ) {
if ( ! ch - > dsp ) ch - > dsp = ast_dsp_new ( ) ;
if ( ch - > dsp ) ast_dsp_set_features ( ch - > dsp , DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT ) ;
if ( ! ch - > trans ) ch - > trans = ast_translator_build_path ( AST_FORMAT_SLINEAR , AST_FORMAT_ALAW ) ;
}
if ( ch - > ast_dsp ) {
2005-11-01 22:04:14 +00:00
chan_misdn_log ( 1 , ch - > bc - > port , " SETOPT: with AST_DSP we deactivate mISDN_dsp \n " ) ;
2005-10-31 22:51:12 +00:00
ch - > bc - > nodsp = 1 ;
ch - > bc - > nojitter = 1 ;
}
return 0 ;
}
2005-12-09 11:01:18 +00:00
int chan_misdn_jb_empty ( struct misdn_bchannel * bc , char * buf , int len )
{
struct chan_list * ch = find_chan_by_bc ( cl_te , bc ) ;
if ( ch & & ch - > jb ) {
return misdn_jb_empty ( ch - > jb , buf , len ) ;
}
return - 1 ;
}
/*******************************************************/
/***************** JITTERBUFFER ************************/
/*******************************************************/
/* allocates the jb-structure and initialise the elements*/
struct misdn_jb * misdn_jb_init ( int size , int upper_threshold )
{
int i ;
struct misdn_jb * jb = ( struct misdn_jb * ) malloc ( sizeof ( struct misdn_jb ) ) ;
jb - > size = size ;
jb - > upper_threshold = upper_threshold ;
jb - > wp = 0 ;
jb - > rp = 0 ;
jb - > state_full = 0 ;
jb - > state_empty = 0 ;
jb - > bytes_wrote = 0 ;
jb - > samples = ( char * ) malloc ( size * sizeof ( char ) ) ;
2006-04-04 19:09:26 +00:00
if ( ! jb - > samples ) {
chan_misdn_log ( - 1 , 0 , " No free Mem for jb->samples \n " ) ;
return NULL ;
}
2005-12-09 11:01:18 +00:00
jb - > ok = ( char * ) malloc ( size * sizeof ( char ) ) ;
2006-04-04 19:09:26 +00:00
if ( ! jb - > ok ) {
chan_misdn_log ( - 1 , 0 , " No free Mem for jb->ok \n " ) ;
return NULL ;
}
2005-12-09 11:01:18 +00:00
for ( i = 0 ; i < size ; i + + )
jb - > ok [ i ] = 0 ;
ast_mutex_init ( & jb - > mutexjb ) ;
return jb ;
}
/* frees the data and destroys the given jitterbuffer struct */
void misdn_jb_destroy ( struct misdn_jb * jb )
{
ast_mutex_destroy ( & jb - > mutexjb ) ;
free ( jb - > samples ) ;
free ( jb ) ;
}
/* fills the jitterbuffer with len data returns < 0 if there was an
error ( bufferoverflow ) . */
int misdn_jb_fill ( struct misdn_jb * jb , const char * data , int len )
{
int i , j , rp , wp ;
2006-02-02 21:15:34 +00:00
if ( ! jb | | ! data ) return 0 ;
2005-12-09 11:01:18 +00:00
ast_mutex_lock ( & jb - > mutexjb ) ;
wp = jb - > wp ;
rp = jb - > rp ;
for ( i = 0 ; i < len ; i + + )
{
jb - > samples [ wp ] = data [ i ] ;
jb - > ok [ wp ] = 1 ;
wp = ( wp ! = jb - > size - 1 ? wp + 1 : 0 ) ;
if ( wp = = jb - > rp )
jb - > state_full = 1 ;
}
if ( wp > = rp )
jb - > state_buffer = wp - rp ;
else
jb - > state_buffer = jb - > size - rp + wp ;
chan_misdn_log ( 9 , 0 , " misdn_jb_fill: written:%d | Bufferstatus:%d p:%x \n " , len , jb - > state_buffer , jb ) ;
if ( jb - > state_full )
{
jb - > wp = wp ;
rp = wp ;
for ( j = 0 ; j < jb - > upper_threshold ; j + + )
rp = ( rp ! = 0 ? rp - 1 : jb - > size - 1 ) ;
jb - > rp = rp ;
jb - > state_full = 0 ;
jb - > state_empty = 1 ;
ast_mutex_unlock ( & jb - > mutexjb ) ;
return - 1 ;
}
if ( ! jb - > state_empty )
{
jb - > bytes_wrote + = len ;
if ( jb - > bytes_wrote > = jb - > upper_threshold )
{
jb - > state_empty = 1 ;
jb - > bytes_wrote = 0 ;
}
}
jb - > wp = wp ;
ast_mutex_unlock ( & jb - > mutexjb ) ;
return 0 ;
}
/* gets len bytes out of the jitterbuffer if available, else only the
available data is returned and the return value indicates the number
of data . */
int misdn_jb_empty ( struct misdn_jb * jb , char * data , int len )
{
int i , wp , rp , read = 0 ;
ast_mutex_lock ( & jb - > mutexjb ) ;
rp = jb - > rp ;
wp = jb - > wp ;
if ( jb - > state_empty )
{
for ( i = 0 ; i < len ; i + + )
{
if ( wp = = rp )
{
jb - > rp = rp ;
jb - > state_empty = 0 ;
ast_mutex_unlock ( & jb - > mutexjb ) ;
return read ;
}
else
{
if ( jb - > ok [ rp ] = = 1 )
{
data [ i ] = jb - > samples [ rp ] ;
jb - > ok [ rp ] = 0 ;
rp = ( rp ! = jb - > size - 1 ? rp + 1 : 0 ) ;
read + = 1 ;
}
}
}
if ( wp > = rp )
jb - > state_buffer = wp - rp ;
else
jb - > state_buffer = jb - > size - rp + wp ;
chan_misdn_log ( 9 , 0 , " misdn_jb_empty: read:%d | Bufferstatus:%d p:%x \n " , len , jb - > state_buffer , jb ) ;
jb - > rp = rp ;
}
else
chan_misdn_log ( 9 , 0 , " misdn_jb_empty: Wait...requested:%d p:%x \n " , len , jb ) ;
ast_mutex_unlock ( & jb - > mutexjb ) ;
return read ;
}
/*******************************************************/
/*************** JITTERBUFFER END *********************/
/*******************************************************/
void chan_misdn_log ( int level , int port , char * tmpl , . . . )
{
if ( ! ( ( 0 < = port ) & & ( port < = max_ports ) ) ) {
ast_log ( LOG_WARNING , " cb_log called with out-of-range port number! (%d) \n " , port ) ;
2006-04-04 19:09:26 +00:00
port = 0 ;
level = - 1 ;
2005-12-09 11:01:18 +00:00
}
va_list ap ;
char buf [ 1024 ] ;
char port_buf [ 8 ] ;
sprintf ( port_buf , " P[%2d] " , port ) ;
va_start ( ap , tmpl ) ;
vsnprintf ( buf , 1023 , tmpl , ap ) ;
va_end ( ap ) ;
if ( level = = - 1 )
ast_log ( LOG_WARNING , buf ) ;
2006-08-03 16:38:00 +00:00
2005-12-09 11:01:18 +00:00
else if ( misdn_debug_only [ port ] ?
( level = = 1 & & misdn_debug [ port ] ) | | ( level = = misdn_debug [ port ] )
: level < = misdn_debug [ port ] ) {
ast_console_puts ( port_buf ) ;
ast_console_puts ( buf ) ;
}
if ( ( level < = misdn_debug [ 0 ] ) & & ! ast_strlen_zero ( global_tracefile ) ) {
time_t tm = time ( NULL ) ;
char * tmp = ctime ( & tm ) , * p ;
FILE * fp = fopen ( global_tracefile , " a+ " ) ;
p = strchr ( tmp , ' \n ' ) ;
if ( p ) * p = ' : ' ;
if ( ! fp ) {
ast_console_puts ( " Error opening Tracefile: [ " ) ;
ast_console_puts ( global_tracefile ) ;
ast_console_puts ( " ] " ) ;
ast_console_puts ( strerror ( errno ) ) ;
ast_console_puts ( " \n " ) ;
return ;
}
fputs ( tmp , fp ) ;
fputs ( " " , fp ) ;
fputs ( port_buf , fp ) ;
fputs ( " " , fp ) ;
fputs ( buf , fp ) ;
fclose ( fp ) ;
}
}
2006-02-02 21:15:34 +00:00
2006-08-21 02:11:39 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , " Channel driver for mISDN Support (BRI/PRI) " ,
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
) ;