2005-06-02 18:47:35 +00:00
/*
2007-04-15 19:39:49 +00:00
* An implementation of Common ISDN API 2.0 for Asterisk
2005-06-02 18:47:35 +00:00
*
2010-02-10 08:47:06 +00:00
* Copyright ( C ) 2005 - 2010 Cytronics & Melware
2005-06-02 18:47:35 +00:00
*
* Armin Schindler < armin @ melware . de >
*
* Reworked , but based on the work of
* Copyright ( C ) 2002 - 2005 Junghanns . NET GmbH
*
* Klaus - Peter Junghanns < kapejod @ ns1 . jnetdns . de >
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License .
*/
2006-01-30 23:40:28 +00:00
# include <sys/time.h>
# include <sys/signal.h>
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <ctype.h>
# include <errno.h>
# include <unistd.h>
# include <fcntl.h>
2009-02-13 21:58:19 +00:00
# include <math.h>
2006-01-30 23:40:28 +00:00
# include <sys/types.h>
2009-03-12 15:56:20 +00:00
# include "chan_capi_platform.h"
2005-06-02 18:47:35 +00:00
# include "xlaw.h"
2005-09-11 08:39:29 +00:00
# include "chan_capi20.h"
2005-08-21 10:28:43 +00:00
# include "chan_capi.h"
2006-01-30 23:40:28 +00:00
# include "chan_capi_rtp.h"
2007-02-11 16:01:32 +00:00
# include "chan_capi_qsig.h"
2007-06-12 20:02:36 +00:00
# include "chan_capi_qsig_ecma.h"
2007-03-10 14:23:20 +00:00
# include "chan_capi_qsig_asn197ade.h"
# include "chan_capi_qsig_asn197no.h"
2007-04-15 19:39:49 +00:00
# include "chan_capi_utils.h"
# include "chan_capi_supplementary.h"
2007-04-27 23:02:27 +00:00
# include "chan_capi_chat.h"
2009-02-13 21:58:19 +00:00
# include "chan_capi_command.h"
2005-06-02 18:47:35 +00:00
2007-04-14 22:34:18 +00:00
/* #define CC_VERSION "x.y.z" */
2006-06-11 13:15:18 +00:00
# define CC_VERSION "$Revision$"
2005-06-15 07:31:28 +00:00
2005-06-02 18:47:35 +00:00
/*
* personal stuff
*/
2006-02-06 20:00:56 +00:00
# undef CAPI_APPLID_UNUSED
# define CAPI_APPLID_UNUSED 0xffffffff
unsigned capi_ApplID = CAPI_APPLID_UNUSED ;
2005-06-02 18:47:35 +00:00
2009-02-13 21:58:19 +00:00
# define CAPI_PLCI_VAR_NAME "CAPIPLCI"
# define CAPI_ECT_PLCI_VAR_NAME "CAPIECTPLCI"
# define CAPI_DETECTED_TONE_NAME "CAPIDETECTEDTONE"
typedef struct _diva_supported_tones {
unsigned char tone ;
const char * name ;
} diva_supported_tones_t ;
2009-02-14 20:56:14 +00:00
static const char * pbx_capi_map_detected_tone ( unsigned char tone ) ;
2009-02-13 21:58:19 +00:00
2006-11-11 20:07:19 +00:00
static const char tdesc [ ] = " Common ISDN API Driver ( " CC_VERSION " ) " ;
2008-02-24 12:57:52 +00:00
static const char channeltype [ ] = CC_MESSAGE_BIGNAME ;
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
# define AST_MODULE "chan_capi"
# else
2006-01-30 23:40:28 +00:00
static char * ccdesc = " Common ISDN API for Asterisk " ;
# endif
2005-06-02 18:47:35 +00:00
2008-02-24 12:57:52 +00:00
static char * commandtdesc = CC_MESSAGE_BIGNAME " command interface. \n "
2006-07-10 17:40:03 +00:00
" The dial command: \n "
2008-02-24 12:57:52 +00:00
" Dial( " CC_MESSAGE_BIGNAME " /g<group>/[<callerid>:]<destination>[/<params>]) \n "
" Dial( " CC_MESSAGE_BIGNAME " /contr<controller>/[<callerid>:]<destination>[/<params>]) \n "
" Dial( " CC_MESSAGE_BIGNAME " /<interface-name>/[<callerid>:]<destination>[/<params>]) \n "
2006-07-10 17:40:03 +00:00
" \" params \" can be: \n "
" early B3: \" b \" =always, \" B \" =on successful calls only \n "
" \" d \" :use callerID from capi.conf, \" o \" :overlap sending number \n "
2007-03-25 17:03:19 +00:00
" \n \" q \" :disable QSIG functions on outgoing call \n "
2006-07-10 17:40:03 +00:00
" \n "
" capicommand() where () can be: \n "
2007-02-11 12:37:53 +00:00
" \" progress \" send progress (for NT mode) \n "
2006-07-10 17:40:03 +00:00
" \" deflect|to_number \" forwards an unanswered call to number \n "
" \" malicous \" report a call of malicious nature \n "
" \" echocancel|<yes> or <no> \" echo-cancel provided by driver/hardware \n "
" \" echosquelch|<yes> or <no> \" very primitive echo-squelch by chan-capi \n "
" \" holdtype|<local> or <hold> \" set type of 'hold' \n "
" \" hold[|MYHOLDVAR] \" puts an answered call on hold \n "
" \" retrieve|${MYHOLDVAR} \" gets back the held call \n "
" \" ect|${MYHOLDVAR}) \" explicit call transfer of call on hold \n "
2007-02-11 12:37:53 +00:00
" \" 3pty_begin|${MYHOLDVAR}) \" Three-Party-Conference (3PTY) with active and held call \n "
2009-04-08 20:43:38 +00:00
" \" receivefax|filename|stationID|headline|options \" receive a " CC_MESSAGE_BIGNAME " fax \n "
2008-02-24 12:57:52 +00:00
" \" sendfax|filename.sff|stationID|headline \" send a " CC_MESSAGE_BIGNAME " fax \n "
2007-04-15 17:41:36 +00:00
" \" qsig_ssct|cidsrc|ciddst \" QSIG single step call transfer \n "
" \" qsig_ct|cidsrc|ciddst|marker|waitconnect \" QSIG call transfer \n "
" \" qsig_callmark|marker \" marks a QSIG call for later identification \n "
2006-07-10 17:40:03 +00:00
" Variables set after fax receive: \n "
" FAXSTATUS :0=OK, 1=Error \n "
" FAXREASON :B3 disconnect reason \n "
" FAXREASONTEXT :FAXREASON as text \n "
" FAXRATE :baud rate of fax connection \n "
" FAXRESOLUTION :0=standard, 1=high \n "
2009-04-08 22:44:14 +00:00
" FAXFORMAT :0=SFF, 8=native \n "
2006-07-10 17:40:03 +00:00
" FAXPAGES :Number of pages received \n "
" FAXID :ID of the remote fax machine \n "
" Asterisk variables used/set by chan_capi: \n "
" BCHANNELINFO,CALLEDTON,_CALLERHOLDID,CALLINGSUBADDRESS,CALLEDSUBADDRESS \n "
2010-04-21 07:11:10 +00:00
" CONNECTEDNUMBER,FAXEXTEN,PRI_CAUSE,REDIRECTINGNUMBER,REDIRECTREASON,ISDNPI1,ISDNPI2 \n "
2008-02-24 12:57:52 +00:00
" !!! for more details and samples, check the README of chan_capi !!! \n " ;
2006-07-10 17:40:03 +00:00
2008-02-24 12:57:52 +00:00
static char * commandapp = " capicommand " ;
static char * commandsynopsis = " Execute special chan_capi commands " ;
2006-11-11 20:07:19 +00:00
# ifndef CC_AST_HAS_VERSION_1_4
2005-07-27 17:20:09 +00:00
STANDARD_LOCAL_USER ;
LOCAL_USER_DECL ;
2006-11-11 20:07:19 +00:00
# endif
2005-07-27 17:20:09 +00:00
2005-06-02 18:47:35 +00:00
static int usecnt ;
2005-12-31 03:15:35 +00:00
/*
* LOCKING RULES
* = = = = = = = = = = = = =
*
* This channel driver uses several locks . One must be
* careful not to reverse the locking order , which will
* lead to a so called deadlock . Here is the locking order
* that must be followed :
*
* struct capi_pvt * i ;
*
* 1. cc_mutex_lock ( & i - > owner - > lock ) ; * *
*
* 2. cc_mutex_lock ( & i - > lock ) ;
*
2006-01-04 14:44:16 +00:00
* 3. cc_mutex_lock ( & iflock ) ;
2006-06-24 14:49:13 +00:00
* 4. cc_mutex_lock ( & messagenumber_lock ) ;
* 5. cc_mutex_lock ( & usecnt_lock ) ;
* 6. cc_mutex_lock ( & capi_put_lock ) ;
2005-12-31 03:15:35 +00:00
*
*
* * * the PBX will call the callback functions with
* this lock locked . This lock protects the
* structure pointed to by ' i - > owner ' . Also note
* that calling some PBX functions will lock
* this lock !
*/
2006-11-11 20:07:19 +00:00
# ifndef CC_AST_HAS_VERSION_1_4
2005-06-02 18:47:35 +00:00
AST_MUTEX_DEFINE_STATIC ( usecnt_lock ) ;
2006-11-11 20:07:19 +00:00
# endif
2005-06-02 18:47:35 +00:00
AST_MUTEX_DEFINE_STATIC ( iflock ) ;
2007-10-21 16:00:18 +00:00
static pthread_t capi_device_thread = ( pthread_t ) ( 0 - 1 ) ;
2005-06-02 18:47:35 +00:00
2007-04-29 22:28:30 +00:00
struct capi_pvt * capi_iflist = NULL ;
2007-04-18 11:48:07 +00:00
2005-11-20 16:15:33 +00:00
static struct cc_capi_controller * capi_controllers [ CAPI_MAX_CONTROLLERS + 1 ] ;
2005-06-02 18:47:35 +00:00
static int capi_num_controllers = 0 ;
2005-08-19 16:40:23 +00:00
static unsigned int capi_counter = 0 ;
2006-07-08 16:29:27 +00:00
static struct ast_channel * chan_for_task ;
static int channel_task ;
# define CAPI_CHANNEL_TASK_NONE 0
# define CAPI_CHANNEL_TASK_HANGUP 1
# define CAPI_CHANNEL_TASK_SOFTHANGUP 2
# define CAPI_CHANNEL_TASK_PICKUP 3
2007-04-08 21:20:47 +00:00
# define CAPI_CHANNEL_TASK_GOTOFAX 4
2005-06-02 18:47:35 +00:00
2007-05-11 06:32:50 +00:00
static struct capi_pvt * interface_for_task ;
static int interface_task ;
# define CAPI_INTERFACE_TASK_NONE 0
# define CAPI_INTERFACE_TASK_NULLIFREMOVE 1
2005-08-21 10:28:43 +00:00
static char capi_national_prefix [ AST_MAX_EXTENSION ] ;
static char capi_international_prefix [ AST_MAX_EXTENSION ] ;
2008-07-07 20:29:19 +00:00
static char capi_subscriber_prefix [ AST_MAX_EXTENSION ] ;
2005-06-02 18:47:35 +00:00
2005-12-28 14:22:54 +00:00
static char default_language [ MAX_LANGUAGE ] = " " ;
2010-03-01 17:59:31 +00:00
# ifdef CC_AST_HAS_FORMAT_T
format_t capi_capability = AST_FORMAT_ALAW ;
# else
2007-04-29 22:28:30 +00:00
int capi_capability = AST_FORMAT_ALAW ;
2010-03-01 17:59:31 +00:00
# endif
2007-04-29 22:28:30 +00:00
2009-05-06 20:38:13 +00:00
static int null_plci_dtmf_support = 1 ;
2007-02-10 23:18:57 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
/* Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
{
. flags = 0 ,
. max_size = - 1 ,
. resync_threshold = - 1 ,
. impl = " "
} ;
static struct ast_jb_conf global_jbconf ;
2007-02-11 14:34:10 +00:00
static char global_mohinterpret [ MAX_MUSICCLASS ] = " default " ;
2007-02-10 23:18:57 +00:00
# endif
2005-08-21 10:28:43 +00:00
/* local prototypes */
2007-09-30 21:09:15 +00:00
static int pbx_capi_hold ( struct ast_channel * c , char * param ) ;
2007-10-20 12:05:26 +00:00
static int pbx_capi_retrieve ( struct ast_channel * c , char * param ) ;
2006-05-12 16:43:30 +00:00
# ifdef CC_AST_HAS_INDICATE_DATA
2006-06-09 21:48:24 +00:00
static int pbx_capi_indicate ( struct ast_channel * c , int condition , const void * data , size_t datalen ) ;
2006-05-12 16:43:30 +00:00
# else
2006-06-09 21:48:24 +00:00
static int pbx_capi_indicate ( struct ast_channel * c , int condition ) ;
2006-05-12 16:43:30 +00:00
# endif
2009-04-15 12:28:40 +00:00
static struct capi_pvt * get_active_plci ( struct ast_channel * c ) ;
2009-05-08 13:03:31 +00:00
static _cstruct diva_get_b1_conf ( struct capi_pvt * i ) ;
2009-05-02 13:21:17 +00:00
static void clear_channel_fax_loop ( struct ast_channel * c , struct capi_pvt * i ) ;
2005-06-02 18:47:35 +00:00
2006-01-30 23:40:28 +00:00
/*
* B protocol settings
*/
static struct {
_cword b1protocol ;
_cword b2protocol ;
_cword b3protocol ;
_cstruct b1configuration ;
_cstruct b2configuration ;
_cstruct b3configuration ;
} b_protocol_table [ ] =
{
{ 0x01 , 0x01 , 0x00 , /* 0 */
NULL ,
NULL ,
NULL
} ,
2009-04-08 20:43:38 +00:00
{ 0x04 , 0x04 , 0x05 , /* 1 */
2006-01-30 23:40:28 +00:00
NULL ,
NULL ,
NULL
} ,
{ 0x1f , 0x1f , 0x1f , /* 2 */
( _cstruct ) " \x00 " ,
2006-06-23 18:07:31 +00:00
/* (_cstruct) "\x04\x01\x00\x00\x02", */
( _cstruct ) " \x06 \x01 \x00 \x58 \x02 \x32 \x00 " ,
2006-01-30 23:40:28 +00:00
( _cstruct ) " \x00 "
2009-05-08 13:03:31 +00:00
} ,
{ 0x1f , 1 , 0 , /* 3 */
NULL ,
NULL ,
NULL
2009-08-05 22:25:53 +00:00
} ,
{ 0x04 , 0x04 , 0x04 , /* 4 */
NULL ,
NULL ,
NULL
2006-01-30 23:40:28 +00:00
}
} ;
2006-06-27 14:54:03 +00:00
/*
* set the global - configuration ( b - channel operation )
*/
static _cstruct capi_set_global_configuration ( struct capi_pvt * i )
{
unsigned short dtedce = 0 ;
unsigned char * buf = i - > tmpbuf ;
buf [ 0 ] = 2 ; /* len */
if ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) {
if ( ( i - > outgoing ) & & ( ! ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) )
dtedce = 2 ;
if ( ( ! ( i - > outgoing ) ) & & ( ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) )
dtedce = 1 ;
}
write_capi_word ( & buf [ 1 ] , dtedce ) ;
if ( dtedce = = 0 )
buf = NULL ;
return ( _cstruct ) buf ;
}
2005-09-11 13:35:19 +00:00
/*
* command to string function
*/
static const char * capi_command_to_string ( unsigned short wCmd )
{
enum { lowest_value = CAPI_P_MIN ,
end_value = CAPI_P_MAX ,
range = end_value - lowest_value ,
} ;
# undef CHAN_CAPI_COMMAND_DESC
# define CHAN_CAPI_COMMAND_DESC(n, ENUM, value) \
[ CAPI_P_REQ ( ENUM ) - ( n ) ] = # ENUM " _REQ " , \
[ CAPI_P_CONF ( ENUM ) - ( n ) ] = # ENUM " _CONF " , \
[ CAPI_P_IND ( ENUM ) - ( n ) ] = # ENUM " _IND " , \
[ CAPI_P_RESP ( ENUM ) - ( n ) ] = # ENUM " _RESP " ,
static const char * const table [ range ] = {
CAPI_COMMANDS ( CHAN_CAPI_COMMAND_DESC , lowest_value )
} ;
wCmd - = lowest_value ;
if ( wCmd > = range ) {
goto error ;
}
if ( table [ wCmd ] = = NULL ) {
goto error ;
}
return table [ wCmd ] ;
error :
return " UNDEFINED " ;
}
2005-06-02 18:47:35 +00:00
2006-07-09 14:18:53 +00:00
/*
* wait for B3 up
*/
2007-04-28 16:48:00 +00:00
int capi_wait_for_b3_up ( struct capi_pvt * i )
2006-07-09 14:18:53 +00:00
{
struct timespec abstime ;
2007-04-29 14:00:32 +00:00
int ret = 1 ;
2006-07-09 14:18:53 +00:00
cc_mutex_lock ( & i - > lock ) ;
2007-05-01 16:05:09 +00:00
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
2006-07-09 14:18:53 +00:00
i - > waitevent = CAPI_WAITEVENT_B3_UP ;
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
cc_verbose ( 4 , 1 , " %s: wait for b3 up. \n " ,
i - > vname ) ;
if ( ast_cond_timedwait ( & i - > event_trigger , & i - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for b3 up. \n " ,
i - > vname ) ;
2007-04-29 14:00:32 +00:00
ret = 0 ;
2006-07-09 14:18:53 +00:00
} else {
cc_verbose ( 4 , 1 , " %s: cond signal received for b3 up. \n " ,
i - > vname ) ;
}
}
cc_mutex_unlock ( & i - > lock ) ;
2007-04-28 16:48:00 +00:00
return ret ;
2006-07-09 14:18:53 +00:00
}
2006-07-08 20:22:15 +00:00
/*
* wait for finishing answering state
*/
2007-04-28 10:09:58 +00:00
void capi_wait_for_answered ( struct capi_pvt * i )
2006-07-08 20:22:15 +00:00
{
struct timespec abstime ;
cc_mutex_lock ( & i - > lock ) ;
if ( i - > state = = CAPI_STATE_ANSWERING ) {
i - > waitevent = CAPI_WAITEVENT_ANSWER_FINISH ;
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
cc_verbose ( 4 , 1 , " %s: wait for finish answer. \n " ,
i - > vname ) ;
if ( ast_cond_timedwait ( & i - > event_trigger , & i - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for finish answer. \n " ,
i - > vname ) ;
} else {
cc_verbose ( 4 , 1 , " %s: cond signal received for finish answer. \n " ,
i - > vname ) ;
}
}
cc_mutex_unlock ( & i - > lock ) ;
}
2006-07-09 13:30:47 +00:00
/*
2006-12-02 12:35:30 +00:00
* function to tell if fax activity has finished
2006-07-09 13:30:47 +00:00
*/
2006-12-02 12:35:30 +00:00
static int capi_tell_fax_finish ( void * data )
2006-07-09 13:30:47 +00:00
{
2006-12-02 12:35:30 +00:00
struct capi_pvt * i = ( struct capi_pvt * ) data ;
2006-07-09 13:30:47 +00:00
if ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) {
2006-12-02 12:35:30 +00:00
return 1 ;
2006-07-09 13:30:47 +00:00
}
2006-12-02 12:35:30 +00:00
return 0 ;
2006-07-09 13:30:47 +00:00
}
2005-06-04 14:28:52 +00:00
/*
* TCAP - > CIP Translation Table ( TransferCapability - > CommonIsdnProfile )
*/
static struct {
unsigned short tcap ;
unsigned short cip ;
2006-05-08 15:51:08 +00:00
unsigned char digital ;
2005-06-04 14:28:52 +00:00
} translate_tcap2cip [ ] = {
2006-05-08 15:51:08 +00:00
{ PRI_TRANS_CAP_SPEECH , CAPI_CIPI_SPEECH , 0 } ,
{ PRI_TRANS_CAP_DIGITAL , CAPI_CIPI_DIGITAL , 1 } ,
{ PRI_TRANS_CAP_RESTRICTED_DIGITAL , CAPI_CIPI_RESTRICTED_DIGITAL , 1 } ,
{ PRI_TRANS_CAP_3K1AUDIO , CAPI_CIPI_3K1AUDIO , 0 } ,
{ PRI_TRANS_CAP_DIGITAL_W_TONES , CAPI_CIPI_DIGITAL_W_TONES , 1 } ,
{ PRI_TRANS_CAP_VIDEO , CAPI_CIPI_VIDEO , 1 }
2005-06-04 14:28:52 +00:00
} ;
static int tcap2cip ( unsigned short tcap )
{
int x ;
for ( x = 0 ; x < sizeof ( translate_tcap2cip ) / sizeof ( translate_tcap2cip [ 0 ] ) ; x + + ) {
if ( translate_tcap2cip [ x ] . tcap = = tcap )
return ( int ) translate_tcap2cip [ x ] . cip ;
}
2006-08-31 13:21:17 +00:00
return CAPI_CIPI_SPEECH ;
2005-06-04 14:28:52 +00:00
}
2007-04-29 22:28:30 +00:00
unsigned char capi_tcap_is_digital ( unsigned short tcap )
2006-05-08 15:51:08 +00:00
{
int x ;
for ( x = 0 ; x < sizeof ( translate_tcap2cip ) / sizeof ( translate_tcap2cip [ 0 ] ) ; x + + ) {
if ( translate_tcap2cip [ x ] . tcap = = tcap )
return translate_tcap2cip [ x ] . digital ;
}
return 0 ;
}
2005-06-04 14:28:52 +00:00
/*
* CIP - > TCAP Translation Table ( CommonIsdnProfile - > TransferCapability )
*/
static struct {
unsigned short cip ;
unsigned short tcap ;
} translate_cip2tcap [ ] = {
2005-09-11 08:39:29 +00:00
{ CAPI_CIPI_SPEECH , PRI_TRANS_CAP_SPEECH } ,
{ CAPI_CIPI_DIGITAL , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_RESTRICTED_DIGITAL , PRI_TRANS_CAP_RESTRICTED_DIGITAL } ,
{ CAPI_CIPI_3K1AUDIO , PRI_TRANS_CAP_3K1AUDIO } ,
{ CAPI_CIPI_7KAUDIO , PRI_TRANS_CAP_DIGITAL_W_TONES } ,
{ CAPI_CIPI_VIDEO , PRI_TRANS_CAP_VIDEO } ,
{ CAPI_CIPI_PACKET_MODE , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_56KBIT_RATE_ADAPTION , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_DIGITAL_W_TONES , PRI_TRANS_CAP_DIGITAL_W_TONES } ,
{ CAPI_CIPI_TELEPHONY , PRI_TRANS_CAP_SPEECH } ,
{ CAPI_CIPI_FAX_G2_3 , PRI_TRANS_CAP_3K1AUDIO } ,
{ CAPI_CIPI_FAX_G4C1 , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_FAX_G4C2_3 , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_TELETEX_PROCESSABLE , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_TELETEX_BASIC , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_VIDEOTEX , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_TELEX , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_X400 , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_X200 , PRI_TRANS_CAP_DIGITAL } ,
{ CAPI_CIPI_7K_TELEPHONY , PRI_TRANS_CAP_DIGITAL_W_TONES } ,
{ CAPI_CIPI_VIDEO_TELEPHONY_C1 , PRI_TRANS_CAP_DIGITAL_W_TONES } ,
{ CAPI_CIPI_VIDEO_TELEPHONY_C2 , PRI_TRANS_CAP_DIGITAL }
2005-06-04 14:28:52 +00:00
} ;
static unsigned short cip2tcap ( int cip )
{
int x ;
for ( x = 0 ; x < sizeof ( translate_cip2tcap ) / sizeof ( translate_cip2tcap [ 0 ] ) ; x + + ) {
if ( translate_cip2tcap [ x ] . cip = = ( unsigned short ) cip )
return translate_cip2tcap [ x ] . tcap ;
}
return 0 ;
}
/*
* TransferCapability to String conversion
*/
static char * transfercapability2str ( int transfercapability )
{
switch ( transfercapability ) {
case PRI_TRANS_CAP_SPEECH :
return " SPEECH " ;
case PRI_TRANS_CAP_DIGITAL :
return " DIGITAL " ;
case PRI_TRANS_CAP_RESTRICTED_DIGITAL :
return " RESTRICTED_DIGITAL " ;
case PRI_TRANS_CAP_3K1AUDIO :
return " 3K1AUDIO " ;
case PRI_TRANS_CAP_DIGITAL_W_TONES :
return " DIGITAL_W_TONES " ;
case PRI_TRANS_CAP_VIDEO :
return " VIDEO " ;
default :
return " UNKNOWN " ;
}
}
2007-05-11 06:32:50 +00:00
/*
* set task for an interface which need to be done out of lock
* ( after the capi thread loop )
*/
static void capi_interface_task ( struct capi_pvt * i , int task )
{
interface_for_task = i ;
interface_task = task ;
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: set interface task to %d \n " ,
i - > name , task ) ;
}
2006-07-08 16:29:27 +00:00
/*
* set task for a channel which need to be done out of lock
* ( after the capi thread loop )
*/
static void capi_channel_task ( struct ast_channel * c , int task )
{
chan_for_task = c ;
channel_task = task ;
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: set channel task to %d \n " ,
c - > name , task ) ;
}
2007-10-20 08:22:53 +00:00
/*
* Added date / time IE to facility structure
*/
static void capi_facility_add_datetime ( unsigned char * facilityarray )
{
unsigned int idx ;
time_t current_time ;
struct tm * time_local ;
unsigned char year ;
if ( ! facilityarray )
return ;
current_time = time ( NULL ) ;
time_local = localtime ( & current_time ) ;
year = time_local - > tm_year ;
while ( year > 99 ) {
year - = 100 ;
}
idx = facilityarray [ 0 ] + 1 ;
facilityarray [ idx + + ] = 0x29 ; /* date/time IE */
facilityarray [ idx + + ] = 5 ; /* length */
facilityarray [ idx + + ] = year ;
facilityarray [ idx + + ] = time_local - > tm_mon + 1 ;
facilityarray [ idx + + ] = time_local - > tm_mday ;
facilityarray [ idx + + ] = time_local - > tm_hour ;
facilityarray [ idx + + ] = time_local - > tm_min ;
facilityarray [ 0 ] = idx - 1 ;
return ;
}
2005-08-29 19:06:19 +00:00
/*
* Echo cancellation is for cards w / integrated echo cancellation only
*/
2007-04-29 14:00:32 +00:00
static void capi_echo_canceller ( struct capi_pvt * i , int function )
2005-06-02 18:47:35 +00:00
{
2007-01-21 14:14:16 +00:00
int ecAvail = 0 ;
2005-06-02 18:47:35 +00:00
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) )
2005-09-15 19:11:45 +00:00
return ;
2009-04-15 12:28:40 +00:00
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & &
2009-05-19 07:56:38 +00:00
( i - > line_plci = = NULL ) ) {
2007-04-29 14:00:32 +00:00
return ;
}
2006-05-21 12:10:53 +00:00
if ( ( ( function = = EC_FUNCTION_ENABLE ) & & ( i - > isdnstate & CAPI_ISDN_STATE_EC ) ) | |
( ( function ! = EC_FUNCTION_ENABLE ) & & ( ! ( i - > isdnstate & CAPI_ISDN_STATE_EC ) ) ) ) {
2006-05-21 13:13:16 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: echo canceller (PLCI=%#x, function=%d) unchanged \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI , function ) ;
2006-05-21 12:10:53 +00:00
/* nothing to do */
return ;
}
2007-01-21 14:14:16 +00:00
/* check for old echo-cancel configuration */
if ( ( i - > ecSelector ! = FACILITYSELECTOR_ECHO_CANCEL ) & &
( capi_controllers [ i - > controller ] - > broadband ) ) {
ecAvail = 1 ;
}
if ( ( i - > ecSelector = = FACILITYSELECTOR_ECHO_CANCEL ) & &
( capi_controllers [ i - > controller ] - > echocancel ) ) {
ecAvail = 1 ;
}
2009-04-15 13:39:57 +00:00
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & &
2009-05-19 07:56:38 +00:00
( i - > line_plci = = NULL ) ) {
2009-04-15 13:39:57 +00:00
return ;
}
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & & ( capi_controllers [ i - > controller ] - > ecPath & EC_ECHOCANCEL_PATH_IP ) = = 0 ) {
return ;
}
if ( ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) & & ( capi_controllers [ i - > controller ] - > ecPath & EC_ECHOCANCEL_PATH_IFC ) = = 0 ) {
return ;
}
2005-06-02 18:47:35 +00:00
/* If echo cancellation is not requested or supported, don't attempt to enable it */
2007-01-21 14:14:16 +00:00
if ( ! ecAvail | | ! i - > doEC ) {
2005-06-02 18:47:35 +00:00
return ;
}
2007-05-01 14:26:39 +00:00
if ( capi_tcap_is_digital ( i - > transfercapability ) ) {
2006-05-08 15:51:08 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: No echo canceller in digital mode (PLCI=%#x) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI ) ;
2006-05-08 15:51:08 +00:00
return ;
}
2006-06-20 16:03:36 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Setting up echo canceller (PLCI=%#x, function=%d, options=%d, tail=%d) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI , function , i - > ecOption , i - > ecTail ) ;
2005-06-02 18:47:35 +00:00
if ( function = = EC_FUNCTION_ENABLE ) {
2006-05-21 12:10:53 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_EC ;
} else {
i - > isdnstate & = ~ CAPI_ISDN_STATE_EC ;
2005-06-02 18:47:35 +00:00
}
2007-04-20 08:17:29 +00:00
capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2007-04-19 20:24:15 +00:00
" w(w(www)) " ,
i - > ecSelector ,
function ,
i - > ecOption , /* bit field - ignore echo canceller disable tone */
i - > ecTail , /* Tail length, ms */
0
) ;
2005-06-02 18:47:35 +00:00
return ;
}
2009-02-14 20:56:14 +00:00
static int capi_check_diva_tone_function_allowed ( struct capi_pvt * i )
{
2009-02-13 21:58:19 +00:00
int ecAvail = 0 ;
if ( ( i - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) )
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & &
2009-05-19 07:56:38 +00:00
( i - > line_plci = = NULL ) ) {
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-02-13 21:58:19 +00:00
}
/* check for old echo-cancel configuration */
if ( ( i - > ecSelector ! = FACILITYSELECTOR_ECHO_CANCEL ) & &
( capi_controllers [ i - > controller ] - > broadband ) ) {
ecAvail = 1 ;
}
if ( ( i - > ecSelector = = FACILITYSELECTOR_ECHO_CANCEL ) & &
( capi_controllers [ i - > controller ] - > echocancel ) ) {
ecAvail = 1 ;
}
2009-04-10 07:23:20 +00:00
if ( ( ecAvail = = 0 ) | |
( capi_controllers [ i - > controller ] - > divaExtendedFeaturesAvailable = = 0 ) ) {
return - 1 ;
2009-02-13 21:58:19 +00:00
}
if ( capi_tcap_is_digital ( i - > transfercapability ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: No audio features in digital mode (PLCI=%#x) \n " ,
i - > vname , i - > PLCI ) ;
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-02-13 21:58:19 +00:00
}
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
/*
* diva audio features
*/
static void capi_diva_audio_features ( struct capi_pvt * i )
{
if ( capi_check_diva_tone_function_allowed ( i ) ! = 0 )
return ;
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Setting up audio features (PLCI=%#x, function=%04x, rx=%u, tx=%u) \n " ,
i - > vname , i - > PLCI , i - > divaAudioFlags , i - > divaDigitalRxGain , i - > divaDigitalTxGain ) ;
capi_sendf ( i , 0 , CAPI_MANUFACTURER_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" dw(b(bwww)) " ,
_DI_MANU_ID ,
_DI_DSP_CTRL ,
0x1c ,
0x0b ,
i - > divaAudioFlags ,
i - > divaDigitalTxGain ,
i - > divaDigitalRxGain ) ;
}
static void capi_diva_clamping ( struct capi_pvt * i , unsigned int duration )
{
if ( capi_check_diva_tone_function_allowed ( i ) ! = 0 )
return ;
if ( duration ! = 0 ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Setting DTMF clamping ON for %u mSec (PLCI=%#x) \n " , i - > vname , duration , i - > PLCI ) ;
capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) , " w(www()) " , 1 , 244 , duration , duration ) ;
} else {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Setting DTMF clamping OFF (PLCI=%#x) \n " , i - > vname , i - > PLCI ) ;
capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) , " w(www()) " , 1 , 245 , 0 , 0 ) ;
}
}
static void capi_diva_tone_processing_function ( struct capi_pvt * i , unsigned char function )
{
if ( capi_check_diva_tone_function_allowed ( i ) ! = 0 )
return ;
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Apply tone processing function %u (PLCI=%#x) \n " , i - > vname , function , i - > PLCI ) ;
capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) , " w(www()) " , 1 , function , 0 , 0 ) ;
}
2009-04-10 07:23:20 +00:00
static void capi_diva_send_tone_function ( struct capi_pvt * i , unsigned char tone )
{
2009-02-13 21:58:19 +00:00
if ( capi_check_diva_tone_function_allowed ( i ) ! = 0 )
return ;
capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) , " w(www(b)()) " ,
2009-04-10 07:23:20 +00:00
FACILITYSELECTOR_DTMF , 252 , /* send tone */ 0 , 0 , tone ) ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static void capi_diva_pitch_control_command ( struct capi_pvt * i , int enable , unsigned short rxpitch , unsigned short txpitch )
{
2009-02-13 21:58:19 +00:00
if ( capi_check_diva_tone_function_allowed ( i ) ! = 0 )
return ;
capi_sendf ( i , 0 , CAPI_MANUFACTURER_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2009-02-14 20:56:14 +00:00
" dw(b(bwww)) " ,
_DI_MANU_ID ,
_DI_DSP_CTRL ,
0x1c ,
0x0a ,
enable = = 0 ? 0x0000 : 0x0001 ,
enable = = 0 ? 0 : rxpitch ,
enable = = 0 ? 0 : txpitch ) ;
2009-02-13 21:58:19 +00:00
}
2005-06-02 18:47:35 +00:00
/*
* turn on / off DTMF detection
*/
2007-04-29 14:00:32 +00:00
static int capi_detect_dtmf ( struct capi_pvt * i , int flag )
2005-06-02 18:47:35 +00:00
{
MESSAGE_EXCHANGE_ERROR error ;
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) )
2005-09-15 19:11:45 +00:00
return 0 ;
2009-04-10 07:23:20 +00:00
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & &
2009-05-19 07:56:38 +00:00
( ( ( i - > line_plci = = NULL ) & & ( null_plci_dtmf_support = = 0 ) ) | | ( i - > resource_plci_type = = CAPI_RESOURCE_PLCI_LINE ) ) ) {
2007-04-29 14:00:32 +00:00
return 0 ;
}
2007-05-01 14:26:39 +00:00
if ( capi_tcap_is_digital ( i - > transfercapability ) ) {
2006-05-22 11:04:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: No dtmf-detect in digital mode (PLCI=%#x) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI ) ;
2006-05-22 11:04:33 +00:00
return 0 ;
}
2006-06-24 16:20:27 +00:00
if ( ( ( flag = = 1 ) & & ( i - > isdnstate & CAPI_ISDN_STATE_DTMF ) ) | |
( ( flag = = 0 ) & & ( ! ( i - > isdnstate & CAPI_ISDN_STATE_DTMF ) ) ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: dtmf (PLCI=%#x, flag=%d) unchanged \n " ,
i - > vname , i - > PLCI , flag ) ;
/* nothing to do */
return 0 ;
}
2005-06-02 18:47:35 +00:00
/* does the controller support dtmf? and do we want to use it? */
2006-06-24 16:20:27 +00:00
if ( ( capi_controllers [ i - > controller ] - > dtmf ! = 1 ) | | ( i - > doDTMF ! = 0 ) )
return 0 ;
2005-06-02 18:47:35 +00:00
2006-06-24 16:20:27 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Setting up DTMF detector (PLCI=%#x, flag=%d) \n " ,
i - > vname , i - > PLCI , flag ) ;
2007-04-19 20:24:15 +00:00
2007-04-20 08:17:29 +00:00
error = capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2007-04-19 20:24:15 +00:00
" w(www()()) " ,
2009-05-06 20:38:13 +00:00
( ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) | | ( i - > line_plci ! = 0 ) ) ? FACILITYSELECTOR_DTMF : PRIV_SELECTOR_DTMF_ONDATA ,
2007-04-19 20:24:15 +00:00
( flag = = 1 ) ? 1 : 2 , /* start/stop DTMF listen */
CAPI_DTMF_DURATION ,
CAPI_DTMF_DURATION
) ;
if ( error ! = 0 ) {
2006-06-24 16:20:27 +00:00
return error ;
}
if ( flag = = 1 ) {
i - > isdnstate | = CAPI_ISDN_STATE_DTMF ;
} else {
i - > isdnstate & = ~ CAPI_ISDN_STATE_DTMF ;
2005-06-02 18:47:35 +00:00
}
return 0 ;
}
2006-02-06 19:21:38 +00:00
/*
2006-04-03 20:02:01 +00:00
* queue a frame to PBX
2006-02-06 19:21:38 +00:00
*/
2006-04-03 20:02:01 +00:00
static int local_queue_frame ( struct capi_pvt * i , struct ast_frame * f )
2006-02-06 19:21:38 +00:00
{
2006-06-10 11:58:50 +00:00
unsigned char * wbuf ;
int wbuflen ;
2006-04-01 17:00:57 +00:00
2006-04-03 20:02:01 +00:00
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_PBX ) ) {
/* if there is no PBX running yet,
we don ' t need any frames sent */
2006-02-06 19:21:38 +00:00
return - 1 ;
}
2006-06-10 11:58:50 +00:00
if ( ( i - > state = = CAPI_STATE_DISCONNECTING ) | |
( i - > isdnstate & CAPI_ISDN_STATE_HANGUP ) ) {
2006-05-18 14:36:09 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: no queue_frame in state disconnecting for %d/%d \n " ,
2010-03-01 17:59:31 +00:00
i - > vname , f - > frametype , FRAME_SUBCLASS_INTEGER ( f - > subclass ) ) ;
2006-05-18 14:36:09 +00:00
return 0 ;
}
2006-02-06 19:21:38 +00:00
2006-04-03 20:02:01 +00:00
if ( ( capidebug ) & & ( f - > frametype ! = AST_FRAME_VOICE ) ) {
2008-02-24 12:57:52 +00:00
ast_frame_dump ( i - > vname , f , VERBOSE_PREFIX_3 " chan_capi queue frame: " ) ;
2006-02-06 19:21:38 +00:00
}
2006-04-03 20:02:01 +00:00
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & &
2010-03-01 17:59:31 +00:00
( FRAME_SUBCLASS_INTEGER ( f - > subclass ) = = AST_CONTROL_HANGUP ) ) {
2006-05-20 22:01:26 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_HANGUP ;
2006-04-03 20:02:01 +00:00
}
2006-06-10 11:58:50 +00:00
if ( i - > writerfd = = - 1 ) {
2009-04-15 21:39:00 +00:00
if ( i - > resource_plci_type = = 0 ) {
2009-04-15 12:28:40 +00:00
cc_log ( LOG_ERROR , " No writerfd in local_queue_frame for %s \n " ,
i - > vname ) ;
return - 1 ;
} else {
return ( 0 ) ;
}
2006-02-06 19:21:38 +00:00
}
2006-04-03 20:02:01 +00:00
2006-06-10 11:58:50 +00:00
if ( f - > frametype ! = AST_FRAME_VOICE )
f - > datalen = 0 ;
2006-06-10 13:54:13 +00:00
wbuflen = sizeof ( struct ast_frame ) + f - > datalen ;
2006-06-10 11:58:50 +00:00
wbuf = alloca ( wbuflen ) ;
memcpy ( wbuf , f , sizeof ( struct ast_frame ) ) ;
2009-01-06 13:40:49 +00:00
if ( f - > datalen ) {
memcpy ( wbuf + sizeof ( struct ast_frame ) , f - > FRAME_DATA_PTR , f - > datalen ) ;
}
2006-06-10 11:58:50 +00:00
if ( write ( i - > writerfd , wbuf , wbuflen ) ! = wbuflen ) {
2009-05-02 13:21:17 +00:00
cc_log ( LOG_ERROR , " Could not write to pipe for %s fd:%d errno:%d \n " ,
i - > vname , i - > writerfd , errno ) ;
2006-06-10 11:58:50 +00:00
}
return 0 ;
2006-02-06 19:21:38 +00:00
}
2005-08-10 19:19:16 +00:00
/*
* set a new name for this channel
*/
2005-11-20 16:15:33 +00:00
static void update_channel_name ( struct capi_pvt * i )
2005-08-10 19:19:16 +00:00
{
char name [ AST_CHANNEL_NAME ] ;
2008-02-24 12:57:52 +00:00
snprintf ( name , sizeof ( name ) - 1 , CC_MESSAGE_BIGNAME " /%s/%s-%x " ,
2007-04-05 20:39:41 +00:00
i - > vname , i - > dnid , capi_counter + + ) ;
2007-05-01 14:26:39 +00:00
if ( i - > owner ) {
ast_change_name ( i - > owner , name ) ;
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: Updated channel name: %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , name ) ;
2005-08-10 19:19:16 +00:00
}
2005-07-17 19:01:14 +00:00
/*
* send digits via INFO_REQ
*/
2005-11-20 16:15:33 +00:00
static int capi_send_info_digits ( struct capi_pvt * i , char * digits , int len )
2005-07-17 19:01:14 +00:00
{
MESSAGE_EXCHANGE_ERROR error ;
2006-01-06 14:38:20 +00:00
char buf [ 64 ] ;
2005-07-17 19:01:14 +00:00
int a ;
memset ( buf , 0 , sizeof ( buf ) ) ;
2006-01-06 14:38:20 +00:00
if ( len > ( sizeof ( buf ) - 2 ) )
len = sizeof ( buf ) - 2 ;
2005-07-17 19:01:14 +00:00
buf [ 0 ] = len + 1 ;
buf [ 1 ] = 0x80 ;
for ( a = 0 ; a < len ; a + + ) {
buf [ a + 2 ] = digits [ a ] ;
}
2007-04-28 20:59:44 +00:00
error = capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" s() " ,
buf
) ;
if ( error ! = 0 ) {
2005-07-17 19:01:14 +00:00
return error ;
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: sent CALLEDPARTYNUMBER INFO digits = '%s' (PLCI=%#x) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , buf + 2 , i - > PLCI ) ;
2005-07-17 19:01:14 +00:00
return 0 ;
}
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
/*
* begin send DMTF
*/
static int pbx_capi_send_digit_begin ( struct ast_channel * c , char digit )
{
2007-05-31 20:28:03 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
if ( ( i - > state = = CAPI_STATE_CONNECTED ) & & ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
/* we have a real connection, so send real DTMF */
if ( ( capi_controllers [ i - > controller ] - > dtmf = = 0 ) | | ( i - > doDTMF > 0 ) ) {
/* let * fake it */
return - 1 ;
}
}
2006-11-11 20:07:19 +00:00
return 0 ;
}
# endif
2007-07-20 11:52:40 +00:00
/*
* send DTMF digit
*/
static int capi_send_dtmf_digits ( struct capi_pvt * i , char digit )
{
int ret ;
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " %s: send DTMF: B-channel not connected. \n " ,
i - > vname ) ;
return - 1 ;
}
2007-07-21 14:34:18 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: send DTMF '%c'. \n " ,
i - > vname , digit ) ;
2007-07-20 11:52:40 +00:00
if ( ( capi_controllers [ i - > controller ] - > dtmf = = 0 ) | | ( i - > doDTMF > 0 ) ) {
/* let * fake it */
return - 1 ;
}
ret = capi_sendf ( i , 0 , CAPI_FACILITY_REQ , i - > NCCI , get_capi_MessageNumber ( ) ,
" w(www(b)()) " ,
FACILITYSELECTOR_DTMF ,
3 , /* send DTMF digit */
CAPI_DTMF_DURATION , /* XXX: duration comes from asterisk in 1.4 */
CAPI_DTMF_DURATION ,
digit
) ;
if ( ret = = 0 ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " %s: sent dtmf '%c' \n " ,
i - > vname , digit ) ;
}
return ret ;
}
2005-06-02 18:47:35 +00:00
/*
2007-07-20 11:52:40 +00:00
* send a digit
2005-06-02 18:47:35 +00:00
*/
2007-02-11 14:34:10 +00:00
# if defined(CC_AST_HAS_VERSION_1_4) && defined(CC_AST_HAS_SEND_DIGIT_END_DURATION)
2007-01-21 17:04:39 +00:00
static int pbx_capi_send_digit ( struct ast_channel * c , char digit , unsigned int duration )
# else
2006-06-09 21:48:24 +00:00
static int pbx_capi_send_digit ( struct ast_channel * c , char digit )
2007-01-21 17:04:39 +00:00
# endif
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-10 19:19:16 +00:00
char did [ 2 ] ;
2005-10-01 13:21:28 +00:00
int ret = 0 ;
2005-06-02 18:47:35 +00:00
2005-08-10 19:19:16 +00:00
if ( i = = NULL ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " No interface! \n " ) ;
2005-08-10 19:19:16 +00:00
return - 1 ;
}
2007-07-16 19:18:56 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: send_digit '%c' in state %d(%d) \n " ,
i - > vname , digit , i - > state , c - > _state ) ;
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & i - > lock ) ;
2005-10-01 13:21:28 +00:00
2005-07-17 19:01:14 +00:00
if ( ( c - > _state = = AST_STATE_DIALING ) & &
( i - > state ! = CAPI_STATE_DISCONNECTING ) ) {
2007-07-20 11:52:40 +00:00
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_ISDNPROGRESS ) ) {
did [ 0 ] = digit ;
did [ 1 ] = 0 ;
strncat ( i - > dnid , did , sizeof ( i - > dnid ) - 1 ) ;
update_channel_name ( i ) ;
if ( ( i - > isdnstate & CAPI_ISDN_STATE_SETUP_ACK ) & &
( i - > doOverlap = = 0 ) ) {
ret = capi_send_info_digits ( i , & digit , 1 ) ;
} else {
/* if no SETUP-ACK yet, add it to the overlap list */
strncat ( i - > overlapdigits , & digit , 1 ) ;
i - > doOverlap = 1 ;
}
cc_mutex_unlock ( & i - > lock ) ;
return ret ;
2005-07-17 19:01:14 +00:00
} else {
2007-07-20 11:52:40 +00:00
/* if PROGRESS arrived, we sent as DTMF */
2007-07-22 15:16:14 +00:00
ret = capi_send_dtmf_digits ( i , digit ) ;
2007-07-20 11:52:40 +00:00
cc_mutex_unlock ( & i - > lock ) ;
return ret ;
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
}
2007-07-20 11:52:40 +00:00
if ( i - > state = = CAPI_STATE_CONNECTED ) {
2005-07-17 19:01:14 +00:00
/* we have a real connection, so send real DTMF */
2007-07-22 15:16:14 +00:00
ret = capi_send_dtmf_digits ( i , digit ) ;
2005-06-02 18:47:35 +00:00
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2005-10-01 13:21:28 +00:00
return ret ;
2005-06-02 18:47:35 +00:00
}
/*
* send ALERT to ISDN line
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_alert ( struct ast_channel * c )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2007-07-10 17:44:09 +00:00
unsigned char * facilityarray = NULL ;
2005-06-12 14:27:26 +00:00
2005-07-27 17:20:09 +00:00
if ( ( i - > state ! = CAPI_STATE_INCALL ) & &
2005-06-12 14:27:26 +00:00
( i - > state ! = CAPI_STATE_DID ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " %s: attempting ALERT in state %d \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > state ) ;
2005-07-18 20:03:25 +00:00
return - 1 ;
2005-06-12 14:27:26 +00:00
}
2007-08-09 07:53:12 +00:00
facilityarray = alloca ( CAPI_MAX_FACILITYDATAARRAY_SIZE ) ;
cc_qsig_add_call_alert_data ( facilityarray , i , c ) ;
2007-07-10 17:44:09 +00:00
2007-04-28 20:59:44 +00:00
if ( capi_sendf ( NULL , 0 , CAPI_ALERT_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2007-10-22 13:25:10 +00:00
" (()()()s()) " ,
facilityarray
2007-10-20 18:36:01 +00:00
) ! = 0 ) {
2005-06-02 18:47:35 +00:00
return - 1 ;
}
i - > state = CAPI_STATE_ALERTING ;
2005-07-17 19:01:14 +00:00
ast_setstate ( c , AST_STATE_RING ) ;
2005-06-02 18:47:35 +00:00
return 0 ;
}
/*
2005-07-17 19:01:14 +00:00
* cleanup the interface
2005-06-02 18:47:35 +00:00
*/
2005-11-20 16:15:33 +00:00
static void interface_cleanup ( struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2005-07-17 19:01:14 +00:00
if ( ! i )
return ;
2005-06-02 18:47:35 +00:00
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_2 " %s: Interface cleanup PLCI=%#x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI ) ;
2006-04-01 17:00:57 +00:00
2009-02-14 20:56:14 +00:00
pbx_capi_voicecommand_cleanup ( i ) ;
2009-02-13 21:58:19 +00:00
2006-06-10 11:58:50 +00:00
if ( i - > readerfd ! = - 1 ) {
close ( i - > readerfd ) ;
i - > readerfd = - 1 ;
}
if ( i - > writerfd ! = - 1 ) {
close ( i - > writerfd ) ;
i - > writerfd = - 1 ;
}
2005-07-17 19:01:14 +00:00
i - > isdnstate = 0 ;
2005-07-23 16:07:03 +00:00
i - > cause = 0 ;
2008-08-30 09:58:27 +00:00
i - > fsetting = 0 ;
2005-07-17 19:01:14 +00:00
2007-04-23 18:47:49 +00:00
i - > whentohangup = 0 ;
2007-04-24 11:45:54 +00:00
i - > whentoqueuehangup = 0 ;
2007-10-20 12:05:26 +00:00
i - > whentoretrieve = 0 ;
2007-04-23 18:47:49 +00:00
2006-05-27 12:49:57 +00:00
i - > FaxState & = ~ CAPI_FAX_STATE_MASK ;
2005-07-17 19:01:14 +00:00
i - > PLCI = 0 ;
2006-01-13 02:38:26 +00:00
i - > MessageNumber = 0 ;
2005-07-17 19:01:14 +00:00
i - > NCCI = 0 ;
i - > onholdPLCI = 0 ;
2006-11-25 16:13:40 +00:00
i - > doEC = i - > doEC_global ;
2007-04-24 20:21:04 +00:00
i - > ccbsnrhandle = 0 ;
2005-07-17 19:01:14 +00:00
memset ( i - > cid , 0 , sizeof ( i - > cid ) ) ;
memset ( i - > dnid , 0 , sizeof ( i - > dnid ) ) ;
2005-08-07 19:24:06 +00:00
i - > cid_ton = 0 ;
2005-07-17 19:01:14 +00:00
2006-01-30 23:40:28 +00:00
i - > rtpcodec = 0 ;
if ( i - > rtp ) {
2010-03-01 17:59:31 +00:00
# ifdef CC_AST_HAS_RTP_ENGINE_H
ast_rtp_instance_destroy ( i - > rtp ) ;
# else
2006-01-30 23:40:28 +00:00
ast_rtp_destroy ( i - > rtp ) ;
2010-03-01 17:59:31 +00:00
# endif
2006-06-24 16:20:27 +00:00
i - > rtp = NULL ;
2006-01-30 23:40:28 +00:00
}
2007-04-19 06:55:44 +00:00
interface_cleanup_qsig ( i ) ;
2007-04-19 06:51:54 +00:00
i - > peer = NULL ;
2005-07-17 19:01:14 +00:00
i - > owner = NULL ;
2007-04-23 18:47:49 +00:00
i - > used = NULL ;
2007-05-08 16:30:03 +00:00
2007-05-11 06:32:50 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) {
capi_interface_task ( i , CAPI_INTERFACE_TASK_NULLIFREMOVE ) ;
}
2007-05-08 16:30:03 +00:00
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
2006-02-06 19:21:38 +00:00
/*
* disconnect b3 and wait for confirmation
*/
static void cc_disconnect_b3 ( struct capi_pvt * i , int wait )
{
2006-07-09 13:30:47 +00:00
struct timespec abstime ;
2006-02-06 19:21:38 +00:00
if ( ! ( i - > isdnstate & ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ) )
return ;
2007-01-23 19:27:01 +00:00
if ( wait ) {
cc_mutex_lock ( & i - > lock ) ;
2007-04-28 20:59:44 +00:00
capi_sendf ( i , 1 , CAPI_DISCONNECT_B3_REQ , i - > NCCI , get_capi_MessageNumber ( ) , " () " ) ;
2007-01-23 19:27:01 +00:00
} else {
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_DISCONNECT_B3_REQ , i - > NCCI , get_capi_MessageNumber ( ) , " () " ) ;
2006-02-06 19:21:38 +00:00
return ;
2006-07-09 13:30:47 +00:00
}
2007-01-23 19:27:01 +00:00
2006-02-06 19:21:38 +00:00
/* wait for the B3 layer to go down */
2006-07-09 13:30:47 +00:00
if ( ( i - > isdnstate & ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ) ) {
i - > waitevent = CAPI_WAITEVENT_B3_DOWN ;
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
cc_verbose ( 4 , 1 , " %s: wait for b3 down. \n " ,
i - > vname ) ;
if ( ast_cond_timedwait ( & i - > event_trigger , & i - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for b3 down. \n " ,
i - > vname ) ;
} else {
cc_verbose ( 4 , 1 , " %s: cond signal received for b3 down. \n " ,
i - > vname ) ;
}
2006-02-06 19:21:38 +00:00
}
2006-07-09 13:30:47 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
cc_log ( LOG_ERROR , " capi disconnect b3: didn't disconnect NCCI=0x%08x \n " ,
i - > NCCI ) ;
}
return ;
}
/*
* send CONNECT_B3_REQ
*/
2007-04-15 19:39:49 +00:00
void cc_start_b3 ( struct capi_pvt * i )
2006-02-06 19:21:38 +00:00
{
if ( ! ( i - > isdnstate & ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ) ) {
i - > isdnstate | = CAPI_ISDN_STATE_B3_PEND ;
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_B3_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" s " , capi_rtp_ncpi ( i ) ) ;
2006-02-06 19:21:38 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: sent CONNECT_B3_REQ PLCI=%#x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI ) ;
2006-02-06 19:21:38 +00:00
}
}
/*
* start early B3
*/
static void start_early_b3 ( struct capi_pvt * i )
{
if ( i - > doB3 ! = CAPI_B3_DONT ) {
/* we do early B3 Connect */
cc_start_b3 ( i ) ;
}
}
/*
* signal ' progress ' to PBX
*/
static void send_progress ( struct capi_pvt * i )
{
2006-04-03 20:02:01 +00:00
struct ast_frame fr = { AST_FRAME_CONTROL , } ;
2006-02-06 19:21:38 +00:00
start_early_b3 ( i ) ;
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_PROGRESS ) ) {
i - > isdnstate | = CAPI_ISDN_STATE_PROGRESS ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_PROGRESS ;
2006-04-03 20:02:01 +00:00
local_queue_frame ( i , & fr ) ;
2006-02-06 19:21:38 +00:00
}
return ;
}
2007-04-23 18:47:49 +00:00
/*
* send disconnect_req
*/
2009-04-27 20:02:46 +00:00
static void capi_send_disconnect ( unsigned int PLCI )
2007-04-23 18:47:49 +00:00
{
2007-05-14 10:08:15 +00:00
if ( PLCI = = 0 ) {
return ;
}
2009-04-27 20:02:46 +00:00
capi_sendf ( NULL , 0 , CAPI_DISCONNECT_REQ , PLCI , get_capi_MessageNumber ( ) , " () " ) ;
2007-04-23 18:47:49 +00:00
}
2005-06-02 18:47:35 +00:00
/*
* hangup a line ( CAPI messages )
2007-01-23 14:39:33 +00:00
* ( this must be called with i - > lock held )
2005-06-02 18:47:35 +00:00
*/
2007-04-28 16:48:00 +00:00
void capi_activehangup ( struct capi_pvt * i , int state )
2005-06-02 18:47:35 +00:00
{
2007-04-28 16:48:00 +00:00
struct ast_channel * c = i - > owner ;
2006-01-23 21:00:21 +00:00
const char * cause ;
2005-06-02 18:47:35 +00:00
2007-04-28 16:48:00 +00:00
if ( c ) {
i - > cause = c - > hangupcause ;
if ( ( cause = pbx_builtin_getvar_helper ( c , " PRI_CAUSE " ) ) ) {
i - > cause = atoi ( cause ) ;
}
2005-07-23 16:07:03 +00:00
2007-04-28 16:48:00 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_ECT ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: activehangup ECT call \n " ,
i - > vname ) ;
}
2005-08-21 15:35:44 +00:00
}
2006-06-18 16:32:32 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " %s: activehangingup (cause=%d) for PLCI=%#x \n " ,
i - > vname , i - > cause , i - > PLCI ) ;
2005-07-23 16:07:03 +00:00
2005-06-26 13:34:17 +00:00
2005-07-27 17:20:09 +00:00
if ( ( state = = CAPI_STATE_ALERTING ) | |
( state = = CAPI_STATE_DID ) | | ( state = = CAPI_STATE_INCALL ) ) {
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , i - > PLCI , i - > MessageNumber ,
2007-04-29 14:00:32 +00:00
" w()()()()() " ,
2007-04-28 20:59:44 +00:00
( i - > cause ) ? ( 0x3480 | ( i - > cause & 0x7f ) ) : 2 ) ;
2005-06-02 18:47:35 +00:00
return ;
}
2007-04-23 18:47:49 +00:00
2008-08-30 09:58:27 +00:00
if ( ( i - > fsetting & CAPI_FSETTING_STAYONLINE ) ) {
2007-04-23 18:47:49 +00:00
/* user has requested to leave channel online for further actions
like CCBS */
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: disconnect deferred, stay-online mode PLCI=%#x \n " ,
i - > vname , i - > PLCI ) ;
i - > whentohangup = time ( NULL ) + 18 ; /* timeout 18 seconds */
return ;
}
2005-06-02 18:47:35 +00:00
/* active disconnect */
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
cc_disconnect_b3 ( i , 0 ) ;
2005-06-02 18:47:35 +00:00
return ;
}
2007-04-29 15:54:38 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) {
if ( i - > PLCI = = 0 ) {
interface_cleanup ( i ) ;
return ;
}
}
2005-06-02 18:47:35 +00:00
2005-07-18 19:41:31 +00:00
if ( ( state = = CAPI_STATE_CONNECTED ) | | ( state = = CAPI_STATE_CONNECTPENDING ) | |
2005-08-16 18:25:03 +00:00
( state = = CAPI_STATE_ANSWERING ) | | ( state = = CAPI_STATE_ONHOLD ) ) {
2006-08-07 13:11:59 +00:00
if ( i - > PLCI = = 0 ) {
/* CONNECT_CONF not received yet? */
capi_wait_conf ( i , CAPI_CONNECT_CONF ) ;
}
2009-04-27 20:02:46 +00:00
capi_send_disconnect ( i - > PLCI ) ;
2005-06-02 18:47:35 +00:00
}
return ;
}
/*
2005-12-15 19:49:38 +00:00
* PBX tells us to hangup a line
2005-06-02 18:47:35 +00:00
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_hangup ( struct ast_channel * c )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-07-17 19:01:14 +00:00
int cleanup = 0 ;
2006-06-26 20:45:25 +00:00
int state ;
2005-06-02 18:47:35 +00:00
/*
* hmm . . . . ok . . . this is called to free the capi interface ( passive disconnect )
* or to bring down the channel ( active disconnect )
*/
if ( i = = NULL ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " channel has no interface! \n " ) ;
2005-06-02 18:47:35 +00:00
return - 1 ;
}
2005-07-17 19:01:14 +00:00
2006-06-26 20:45:25 +00:00
cc_mutex_lock ( & i - > lock ) ;
state = i - > state ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: " CC_MESSAGE_BIGNAME
" Hangingup for PLCI=%#x in state %d \n " , i - > vname , i - > PLCI , state ) ;
2006-06-26 20:45:25 +00:00
2005-06-02 18:47:35 +00:00
/* are we down, yet? */
2006-06-26 20:45:25 +00:00
if ( state ! = CAPI_STATE_DISCONNECTED ) {
2005-06-02 18:47:35 +00:00
/* no */
2006-06-26 20:45:25 +00:00
i - > state = CAPI_STATE_DISCONNECTING ;
2005-06-04 20:07:00 +00:00
} else {
2005-07-17 19:01:14 +00:00
cleanup = 1 ;
2005-06-02 18:47:35 +00:00
}
2006-06-26 20:45:25 +00:00
if ( ( i - > doDTMF > 0 ) & & ( i - > vad ! = NULL ) ) {
ast_dsp_free ( i - > vad ) ;
i - > vad = NULL ;
}
2005-07-17 19:01:14 +00:00
if ( cleanup ) {
2005-06-04 20:07:00 +00:00
/* disconnect already done, so cleanup */
2005-07-17 19:01:14 +00:00
interface_cleanup ( i ) ;
2007-01-23 14:39:33 +00:00
} else {
2006-06-26 20:45:25 +00:00
/* not disconnected yet, we must actively do it */
2007-04-28 16:48:00 +00:00
capi_activehangup ( i , state ) ;
2006-06-26 20:45:25 +00:00
}
2007-04-23 18:47:49 +00:00
i - > owner = NULL ;
2006-06-27 08:20:19 +00:00
CC_CHANNEL_PVT ( c ) = NULL ;
2007-04-23 18:47:49 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2006-06-27 08:20:19 +00:00
ast_setstate ( c , AST_STATE_DOWN ) ;
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
ast_atomic_fetchadd_int ( & usecnt , - 1 ) ;
# else
2006-06-26 20:45:25 +00:00
cc_mutex_lock ( & usecnt_lock ) ;
usecnt - - ;
cc_mutex_unlock ( & usecnt_lock ) ;
2006-11-11 20:07:19 +00:00
# endif
ast_update_use_count ( ) ;
2006-06-26 20:45:25 +00:00
2005-06-02 18:47:35 +00:00
return 0 ;
}
/*
2005-12-15 19:49:38 +00:00
* PBX tells us to make a call
2005-06-02 18:47:35 +00:00
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_call ( struct ast_channel * c , char * idest , int timeout )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-10-09 16:45:03 +00:00
char * dest , * interface , * param , * ocid ;
2005-06-02 18:47:35 +00:00
char buffer [ AST_MAX_EXTENSION ] ;
char called [ AST_MAX_EXTENSION ] , calling [ AST_MAX_EXTENSION ] ;
2005-07-21 11:34:05 +00:00
char callerid [ AST_MAX_EXTENSION ] ;
2005-07-13 15:07:31 +00:00
int CLIR ;
2005-08-07 19:24:06 +00:00
int callernplan = 0 ;
2005-10-09 15:49:32 +00:00
int use_defaultcid = 0 ;
2009-03-25 12:38:46 +00:00
_cword cip ;
2006-01-23 21:00:21 +00:00
const char * ton , * p ;
2005-08-28 14:14:23 +00:00
char * osa = NULL ;
char * dsa = NULL ;
char callingsubaddress [ AST_MAX_EXTENSION ] ;
char calledsubaddress [ AST_MAX_EXTENSION ] ;
2007-02-11 16:01:32 +00:00
int doqsig ;
2007-10-20 13:30:35 +00:00
char * sending_complete ;
2007-04-28 20:59:44 +00:00
unsigned char * facilityarray = NULL ;
2005-06-02 18:47:35 +00:00
MESSAGE_EXCHANGE_ERROR error ;
2006-01-28 19:42:44 +00:00
cc_copy_string ( buffer , idest , sizeof ( buffer ) ) ;
2007-04-29 22:28:30 +00:00
capi_parse_dialstring ( buffer , & interface , & dest , & param , & ocid ) ;
2005-11-27 14:47:54 +00:00
2005-07-17 19:01:14 +00:00
/* init param settings */
2005-11-20 16:15:33 +00:00
i - > doB3 = CAPI_B3_DONT ;
2005-07-17 19:01:14 +00:00
i - > doOverlap = 0 ;
memset ( i - > overlapdigits , 0 , sizeof ( i - > overlapdigits ) ) ;
2007-02-11 16:04:58 +00:00
doqsig = i - > qsigfeat ;
2005-07-17 19:01:14 +00:00
/* parse the parameters */
while ( ( param ) & & ( * param ) ) {
switch ( * param ) {
case ' b ' : /* always B3 */
2005-11-20 16:15:33 +00:00
if ( i - > doB3 ! = CAPI_B3_DONT )
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " B3 already set in '%s' \n " , idest ) ;
2005-11-20 16:15:33 +00:00
i - > doB3 = CAPI_B3_ALWAYS ;
2005-07-17 19:01:14 +00:00
break ;
case ' B ' : /* only do B3 on successfull calls */
2005-11-20 16:15:33 +00:00
if ( i - > doB3 ! = CAPI_B3_DONT )
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " B3 already set in '%s' \n " , idest ) ;
2005-11-20 16:15:33 +00:00
i - > doB3 = CAPI_B3_ON_SUCCESS ;
2005-07-17 19:01:14 +00:00
break ;
2005-10-09 15:49:32 +00:00
case ' o ' : /* overlap sending of digits */
2005-07-17 19:01:14 +00:00
if ( i - > doOverlap )
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Overlap already set in '%s' \n " , idest ) ;
2005-07-17 19:01:14 +00:00
i - > doOverlap = 1 ;
break ;
2005-10-09 15:49:32 +00:00
case ' d ' : /* use default cid */
2005-12-15 19:49:38 +00:00
if ( use_defaultcid )
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Default CID already set in '%s' \n " , idest ) ;
2005-10-09 15:49:32 +00:00
use_defaultcid = 1 ;
break ;
2007-04-23 18:47:49 +00:00
case ' s ' : /* stay online */
2008-08-30 09:58:27 +00:00
if ( ( i - > fsetting & CAPI_FSETTING_STAYONLINE ) )
2007-04-23 18:47:49 +00:00
cc_log ( LOG_WARNING , " 'stay-online' already set in '%s' \n " , idest ) ;
2008-08-30 09:58:27 +00:00
i - > fsetting | = CAPI_FSETTING_STAYONLINE ;
break ;
case ' G ' : /* early bridge */
if ( ( i - > fsetting & CAPI_FSETTING_EARLY_BRIDGE ) )
cc_log ( LOG_WARNING , " 'early-bridge' already set in '%s' \n " , idest ) ;
i - > fsetting | = CAPI_FSETTING_EARLY_BRIDGE ;
2007-04-23 18:47:49 +00:00
break ;
2007-02-11 16:01:32 +00:00
case ' q ' : /* disable QSIG */
cc_verbose ( 4 , 0 , VERBOSE_PREFIX_4 " %s: QSIG extensions for this call disabled \n " ,
i - > vname ) ;
doqsig = 0 ;
break ;
2005-07-17 19:01:14 +00:00
default :
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Unknown parameter '%c' in '%s', ignoring. \n " ,
2005-07-17 19:01:14 +00:00
* param , idest ) ;
}
param + + ;
2005-06-02 18:47:35 +00:00
}
2005-11-20 16:15:33 +00:00
if ( ( ( ! dest ) | | ( ! dest [ 0 ] ) ) & & ( i - > doB3 ! = CAPI_B3_ALWAYS ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " No destination or dialtone requested in '%s' \n " , idest ) ;
2005-07-17 19:01:14 +00:00
return - 1 ;
2005-06-02 18:47:35 +00:00
}
2007-04-24 20:21:04 +00:00
i - > peer = cc_get_peer_link_id ( pbx_builtin_getvar_helper ( c , " CAPIPEERLINKID " ) ) ;
i - > outgoing = 1 ;
2007-05-01 14:26:39 +00:00
i - > transfercapability = c - > transfercapability ;
2007-04-24 20:21:04 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_PBX ;
i - > state = CAPI_STATE_CONNECTPENDING ;
ast_setstate ( c , AST_STATE_DIALING ) ;
i - > MessageNumber = get_capi_MessageNumber ( ) ;
/* if this is a CCBS/CCNR callback call */
if ( i - > ccbsnrhandle ) {
_cword rbref ;
2009-03-25 12:38:46 +00:00
cip = ( _cword ) tcap2cip ( i - > transfercapability ) ;
2007-04-24 20:21:04 +00:00
i - > doOverlap = 0 ;
rbref = capi_ccbsnr_take_ref ( i - > ccbsnrhandle ) ;
if ( ( rbref = = 0xdead ) | |
( ( capi_sendf ( NULL , 0 , CAPI_FACILITY_REQ , i - > controller , i - > MessageNumber ,
" w(w(www(wwwsss())()()()())) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0012 , /* CCBS call */
rbref , /* reference */
cip , /* CIP */
0 , /* reserved */
/* B protocol */
b_protocol_table [ i - > bproto ] . b1protocol ,
b_protocol_table [ i - > bproto ] . b2protocol ,
b_protocol_table [ i - > bproto ] . b3protocol ,
2009-05-08 20:15:41 +00:00
diva_get_b1_conf ( i ) ,
2007-04-24 20:21:04 +00:00
b_protocol_table [ i - > bproto ] . b2configuration ,
b_protocol_table [ i - > bproto ] . b3configuration
/* */ /* BC */
/* */ /* LLC */
/* */ /* HLC */
/* */ /* Additional Info */
) ) ) ) {
i - > state = CAPI_STATE_DISCONNECTED ;
ast_setstate ( c , AST_STATE_RESERVED ) ;
return 1 ;
}
return 0 ;
}
2005-07-13 15:07:31 +00:00
CLIR = c - > cid . cid_pres ;
2005-08-07 19:24:06 +00:00
callernplan = c - > cid . cid_ton & 0x7f ;
2006-06-24 11:53:47 +00:00
2005-08-28 14:14:23 +00:00
if ( ( ton = pbx_builtin_getvar_helper ( c , " CALLERTON " ) ) ) {
callernplan = atoi ( ton ) & 0x7f ;
}
2007-05-26 19:46:24 +00:00
i - > cid_ton = callernplan ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_2 " %s: Call %s %s%s (pres=0x%02x, ton=0x%02x) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name , i - > doB3 ? " with B3 " : " " ,
2005-08-28 14:14:23 +00:00
i - > doOverlap ? " overlap " : " " , CLIR , callernplan ) ;
2006-04-01 17:00:57 +00:00
2005-08-28 14:14:23 +00:00
if ( ( p = pbx_builtin_getvar_helper ( c , " CALLINGSUBADDRESS " ) ) ) {
callingsubaddress [ 0 ] = strlen ( p ) + 1 ;
callingsubaddress [ 1 ] = 0x80 ;
strncpy ( & callingsubaddress [ 2 ] , p , sizeof ( callingsubaddress ) - 3 ) ;
osa = callingsubaddress ;
}
if ( ( p = pbx_builtin_getvar_helper ( c , " CALLEDSUBADDRESS " ) ) ) {
calledsubaddress [ 0 ] = strlen ( p ) + 1 ;
calledsubaddress [ 1 ] = 0x80 ;
strncpy ( & calledsubaddress [ 2 ] , p , sizeof ( calledsubaddress ) - 3 ) ;
dsa = calledsubaddress ;
}
2009-03-25 12:38:46 +00:00
if ( ( p = pbx_builtin_getvar_helper ( c , " CAPI_CIP " ) ) ) {
cip = ( _cword ) atoi ( p ) ;
i - > transfercapability = cip2tcap ( cip ) ;
} else {
cip = tcap2cip ( i - > transfercapability ) ;
}
2007-05-01 14:26:39 +00:00
if ( capi_tcap_is_digital ( i - > transfercapability ) ) {
2006-05-18 14:36:09 +00:00
i - > bproto = CC_BPROTO_TRANSPARENT ;
2006-05-22 11:04:33 +00:00
cc_verbose ( 4 , 0 , VERBOSE_PREFIX_2 " %s: is digital call, set proto to TRANSPARENT \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-05-18 14:36:09 +00:00
}
2008-01-14 13:23:58 +00:00
if ( ( i - > doOverlap ) | | ( ! strlen ( dest ) ) ) {
2005-10-01 17:00:56 +00:00
called [ 0 ] = 1 ;
2007-10-20 13:30:35 +00:00
sending_complete = " \x00 " ;
2008-01-14 13:23:58 +00:00
if ( strlen ( dest ) ) {
cc_copy_string ( i - > overlapdigits , dest , sizeof ( i - > overlapdigits ) ) ;
} else {
i - > doOverlap = 0 ;
}
2005-07-17 19:01:14 +00:00
} else {
called [ 0 ] = strlen ( dest ) + 1 ;
2007-10-20 18:36:01 +00:00
sending_complete = " \x02 \x01 \x00 " ;
2005-07-17 19:01:14 +00:00
}
2009-07-22 08:18:46 +00:00
if ( ( p = pbx_builtin_getvar_helper ( c , " CALLEDTON " ) ) ) {
unsigned char ton = ( unsigned char ) atoi ( p ) ;
called [ 1 ] = ton | 0x80 ;
} else {
called [ 1 ] = 0x80 ;
}
2005-07-17 19:01:14 +00:00
strncpy ( & called [ 2 ] , dest , sizeof ( called ) - 3 ) ;
2005-06-02 18:47:35 +00:00
2006-06-24 11:53:47 +00:00
if ( c - > cid . cid_num ) {
2006-01-28 19:42:44 +00:00
cc_copy_string ( callerid , c - > cid . cid_num , sizeof ( callerid ) ) ;
2006-06-24 11:53:47 +00:00
} else {
2005-07-21 11:34:05 +00:00
memset ( callerid , 0 , sizeof ( callerid ) ) ;
2006-06-24 11:53:47 +00:00
}
2005-06-02 18:47:35 +00:00
2005-10-09 15:49:32 +00:00
if ( use_defaultcid ) {
2006-01-28 19:42:44 +00:00
cc_copy_string ( callerid , i - > defaultcid , sizeof ( callerid ) ) ;
2005-12-07 06:00:25 +00:00
} else if ( ocid ) {
2006-01-28 19:42:44 +00:00
cc_copy_string ( callerid , ocid , sizeof ( callerid ) ) ;
2005-10-09 15:49:32 +00:00
}
2006-04-01 15:39:31 +00:00
cc_copy_string ( i - > cid , callerid , sizeof ( i - > cid ) ) ;
2005-10-09 15:49:32 +00:00
2005-07-21 11:34:05 +00:00
calling [ 0 ] = strlen ( callerid ) + 2 ;
2005-08-07 19:24:06 +00:00
calling [ 1 ] = callernplan ;
2005-07-13 15:07:31 +00:00
calling [ 2 ] = 0x80 | ( CLIR & 0x63 ) ;
2005-07-21 11:34:05 +00:00
strncpy ( & calling [ 3 ] , callerid , sizeof ( calling ) - 4 ) ;
2005-06-02 18:47:35 +00:00
2007-02-11 16:01:32 +00:00
if ( doqsig ) {
2007-04-28 20:59:44 +00:00
facilityarray = alloca ( CAPI_MAX_FACILITYDATAARRAY_SIZE ) ;
2007-03-25 17:03:19 +00:00
cc_qsig_add_call_setup_data ( facilityarray , i , c ) ;
2007-02-11 16:01:32 +00:00
}
2007-04-28 20:59:44 +00:00
error = capi_sendf ( NULL , 0 , CAPI_CONNECT_REQ , i - > controller , i - > MessageNumber ,
2007-10-20 13:30:35 +00:00
" wssss(wwwsss())()()()((w)()()ss) " ,
2009-03-25 12:38:46 +00:00
cip , /* CIP value */
2007-04-28 20:59:44 +00:00
called , /* called party number */
calling , /* calling party number */
dsa , /* called party subaddress */
osa , /* calling party subaddress */
/* B protocol */
b_protocol_table [ i - > bproto ] . b1protocol ,
b_protocol_table [ i - > bproto ] . b2protocol ,
b_protocol_table [ i - > bproto ] . b3protocol ,
2009-07-20 12:31:24 +00:00
diva_get_b1_conf ( i ) ,
2007-04-28 20:59:44 +00:00
b_protocol_table [ i - > bproto ] . b2configuration ,
b_protocol_table [ i - > bproto ] . b3configuration ,
/* BC */
/* LLC */
/* HLC */
/* Additional Info */
0x0000 , /* B channel info */
/* Keypad facility */
/* User-User data */
2007-10-20 13:30:35 +00:00
facilityarray , /* Facility data array */
sending_complete /* Sending complete */
2007-04-28 20:59:44 +00:00
) ;
if ( error ) {
2006-07-08 18:40:20 +00:00
i - > state = CAPI_STATE_DISCONNECTED ;
ast_setstate ( c , AST_STATE_RESERVED ) ;
2005-06-02 18:47:35 +00:00
return error ;
}
2006-06-18 20:29:33 +00:00
2005-06-02 18:47:35 +00:00
/* now we shall return .... the rest has to be done by handle_msg */
return 0 ;
}
2009-05-08 13:03:31 +00:00
static _cstruct diva_get_b1_conf ( struct capi_pvt * i ) {
_cstruct b1conf = b_protocol_table [ i - > bproto ] . b1configuration ;
if ( i - > bproto = = CC_BPROTO_VOCODER ) {
switch ( i - > codec ) {
case AST_FORMAT_ALAW :
b1conf = ( _cstruct ) " \x06 \x08 \x04 \x03 \x00 \xa0 \x00 " ;
break ;
case AST_FORMAT_ULAW :
b1conf = ( _cstruct ) " \x06 \x00 \x04 \x03 \x00 \xa0 \x00 " ;
break ;
case AST_FORMAT_GSM :
b1conf = ( _cstruct ) " \x06 \x03 \x04 \x0f \x00 \xa0 \x00 " ;
break ;
case AST_FORMAT_G723_1 :
b1conf = ( _cstruct ) " \x06 \x04 \x04 \x01 \x00 \xa0 \x00 " ;
break ;
case AST_FORMAT_G726 :
b1conf = ( _cstruct ) " \x06 \x02 \x04 \x0f \x00 \xa0 \x00 " ;
break ;
case AST_FORMAT_ILBC : /* 30 mSec 240 samples */
b1conf = ( _cstruct ) " \x06 \x1b \x04 \x03 \x00 \xf0 \x00 " ;
break ;
case AST_FORMAT_G729A :
b1conf = ( _cstruct ) " \x06 \x12 \x04 \x0f \x00 \xa0 \x00 " ;
break ;
default :
cc_log ( LOG_ERROR , " %s: format %s(%d) invalid. \n " ,
i - > vname , ast_getformatname ( i - > codec ) , i - > codec ) ;
break ;
}
}
return ( b1conf ) ;
}
2005-06-02 18:47:35 +00:00
/*
2005-08-14 12:32:18 +00:00
* answer a capi call
2005-06-02 18:47:35 +00:00
*/
2006-01-30 23:40:28 +00:00
static int capi_send_answer ( struct ast_channel * c , _cstruct b3conf )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
char buf [ CAPI_MAX_STRING ] ;
2006-01-23 21:00:21 +00:00
const char * dnid ;
const char * connectednumber ;
2007-07-10 17:44:09 +00:00
unsigned char * facilityarray = NULL ;
2009-05-08 13:03:31 +00:00
_cstruct b1conf ;
2005-06-02 18:47:35 +00:00
2007-09-26 20:03:14 +00:00
if ( i - > state = = CAPI_STATE_DISCONNECTED ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Not answering disconnected call. \n " ,
i - > vname ) ;
return - 1 ;
}
2005-11-20 16:15:33 +00:00
if ( ( i - > isdnmode = = CAPI_ISDNMODE_DID ) & &
2005-07-17 19:01:14 +00:00
( ( strlen ( i - > incomingmsn ) < strlen ( i - > dnid ) ) & &
( strcmp ( i - > incomingmsn , " * " ) ) ) ) {
2005-06-02 18:47:35 +00:00
dnid = i - > dnid + strlen ( i - > incomingmsn ) ;
} else {
dnid = i - > dnid ;
}
2005-08-25 12:54:04 +00:00
if ( ( connectednumber = pbx_builtin_getvar_helper ( c , " CONNECTEDNUMBER " ) ) ) {
dnid = connectednumber ;
}
2005-06-02 18:47:35 +00:00
2005-08-18 07:25:17 +00:00
if ( strlen ( dnid ) ) {
buf [ 0 ] = strlen ( dnid ) + 2 ;
2007-10-20 12:47:28 +00:00
buf [ 1 ] = 0x01 ;
2005-08-18 07:25:17 +00:00
buf [ 2 ] = 0x80 ;
strncpy ( & buf [ 3 ] , dnid , sizeof ( buf ) - 4 ) ;
2007-04-28 20:59:44 +00:00
} else {
buf [ 0 ] = 0x00 ;
}
if ( ! b3conf ) {
2006-01-30 23:40:28 +00:00
b3conf = b_protocol_table [ i - > bproto ] . b3configuration ;
2007-04-28 20:59:44 +00:00
}
2005-06-02 18:47:35 +00:00
2009-07-20 12:31:24 +00:00
b1conf = diva_get_b1_conf ( i ) ;
2009-05-08 13:03:31 +00:00
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Answering for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , dnid ) ;
2005-06-02 18:47:35 +00:00
2007-08-09 07:53:12 +00:00
facilityarray = alloca ( CAPI_MAX_FACILITYDATAARRAY_SIZE ) ;
cc_qsig_add_call_answer_data ( facilityarray , i , c ) ;
2007-07-10 17:44:09 +00:00
2007-10-20 08:22:53 +00:00
if ( i - > ntmode ) {
/* in NT-mode we send the current local time to device */
capi_facility_add_datetime ( facilityarray ) ;
}
2007-04-28 20:59:44 +00:00
if ( capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , i - > PLCI , i - > MessageNumber ,
2007-07-10 17:44:09 +00:00
" w(wwwssss)s()()(()()()s()) " ,
2007-04-28 20:59:44 +00:00
0 , /* accept call */
/* B protocol */
b_protocol_table [ i - > bproto ] . b1protocol ,
b_protocol_table [ i - > bproto ] . b2protocol ,
b_protocol_table [ i - > bproto ] . b3protocol ,
2009-05-08 13:03:31 +00:00
b1conf ,
2007-04-28 20:59:44 +00:00
b_protocol_table [ i - > bproto ] . b2configuration ,
b3conf ,
capi_set_global_configuration ( i ) ,
2007-07-10 17:44:09 +00:00
buf , /* connected number */
2007-04-28 20:59:44 +00:00
/* connected subaddress */
/* LLC */
/* Additional info */
2007-07-10 17:44:09 +00:00
facilityarray
2007-04-28 20:59:44 +00:00
) ! = 0 ) {
2005-06-02 18:47:35 +00:00
return - 1 ;
}
i - > state = CAPI_STATE_ANSWERING ;
2005-11-20 16:15:33 +00:00
i - > doB3 = CAPI_B3_DONT ;
2005-06-02 18:47:35 +00:00
i - > outgoing = 0 ;
return 0 ;
}
2005-08-14 12:32:18 +00:00
/*
2005-12-15 19:49:38 +00:00
* PBX tells us to answer a call
2005-08-14 12:32:18 +00:00
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_answer ( struct ast_channel * c )
2005-08-14 12:32:18 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-10-01 13:21:28 +00:00
int ret ;
2006-01-30 23:40:28 +00:00
2009-05-08 13:03:31 +00:00
i - > bproto = ( ( i - > bproto = = CC_BPROTO_VOCODER ) & & ( i - > codec ! = 0 ) ) ? i - > bproto : CC_BPROTO_TRANSPARENT ;
2006-05-18 14:36:09 +00:00
2006-01-30 23:40:28 +00:00
if ( i - > rtp ) {
2007-05-01 14:26:39 +00:00
if ( ! capi_tcap_is_digital ( i - > transfercapability ) )
2006-05-18 14:36:09 +00:00
i - > bproto = CC_BPROTO_RTP ;
2006-01-30 23:40:28 +00:00
}
2005-08-14 12:32:18 +00:00
2006-01-30 23:40:28 +00:00
ret = capi_send_answer ( c , NULL ) ;
2005-10-01 13:21:28 +00:00
return ret ;
2005-08-14 12:32:18 +00:00
}
2005-06-02 18:47:35 +00:00
/*
2006-04-01 17:00:57 +00:00
* read for a channel
2005-06-02 18:47:35 +00:00
*/
2006-06-09 21:48:24 +00:00
static struct ast_frame * pbx_capi_read ( struct ast_channel * c )
2005-06-02 18:47:35 +00:00
{
2007-04-29 22:28:30 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2006-06-10 11:58:50 +00:00
struct ast_frame * f ;
2006-04-01 17:00:57 +00:00
2007-04-29 22:28:30 +00:00
f = capi_read_pipeframe ( i ) ;
2006-06-10 11:58:50 +00:00
2007-04-29 22:28:30 +00:00
if ( ( f ) & & ( f - > frametype = = AST_FRAME_VOICE ) & & ( f - > datalen > 0 ) ) {
2006-06-10 11:58:50 +00:00
if ( ( i - > doDTMF > 0 ) & & ( i - > vad ! = NULL ) ) {
f = ast_dsp_process ( c , i - > vad , f ) ;
}
}
return f ;
2005-06-02 18:47:35 +00:00
}
/*
2005-12-15 19:49:38 +00:00
* PBX tells us to write for a channel
2005-06-02 18:47:35 +00:00
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_write ( struct ast_channel * c , struct ast_frame * f )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2006-01-30 23:40:28 +00:00
int ret = 0 ;
2005-06-02 18:47:35 +00:00
2007-04-29 22:28:30 +00:00
ret = capi_write_frame ( i , f ) ;
2005-06-02 18:47:35 +00:00
2006-06-12 10:22:31 +00:00
return ret ;
2005-06-02 18:47:35 +00:00
}
/*
2006-07-08 16:29:27 +00:00
* new channel ( masq )
2005-06-02 18:47:35 +00:00
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( newchan ) ;
2005-06-02 18:47:35 +00:00
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: %s fixup now %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , oldchan - > name , newchan - > name ) ;
2005-07-17 19:01:14 +00:00
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & i - > lock ) ;
2005-07-17 19:01:14 +00:00
i - > owner = newchan ;
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2005-06-02 18:47:35 +00:00
return 0 ;
}
2006-02-06 19:21:38 +00:00
/*
* activate ( another B protocol )
*/
static void cc_select_b ( struct capi_pvt * i , _cstruct b3conf )
{
2007-04-28 20:59:44 +00:00
if ( ! b3conf ) {
2006-02-06 19:21:38 +00:00
b3conf = b_protocol_table [ i - > bproto ] . b3configuration ;
2007-04-28 20:59:44 +00:00
}
2006-02-06 19:21:38 +00:00
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_SELECT_B_PROTOCOL_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" (wwwssss) " ,
b_protocol_table [ i - > bproto ] . b1protocol ,
b_protocol_table [ i - > bproto ] . b2protocol ,
b_protocol_table [ i - > bproto ] . b3protocol ,
2009-07-20 12:31:24 +00:00
diva_get_b1_conf ( i ) ,
2007-04-28 20:59:44 +00:00
b_protocol_table [ i - > bproto ] . b2configuration ,
b3conf ,
capi_set_global_configuration ( i )
) ;
2006-02-06 19:21:38 +00:00
}
2005-09-15 19:11:45 +00:00
/*
* do line initerconnect
*/
2005-11-20 16:15:33 +00:00
static int line_interconnect ( struct capi_pvt * i0 , struct capi_pvt * i1 , int start )
2005-09-15 19:11:45 +00:00
{
if ( ( i0 - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) | |
( i1 - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) )
return - 1 ;
2005-12-11 10:48:08 +00:00
if ( start ) {
/* connect */
2007-04-20 08:17:29 +00:00
capi_sendf ( i1 , 0 , CAPI_FACILITY_REQ , i0 - > PLCI , get_capi_MessageNumber ( ) ,
" w(w(d((dd)))) " ,
FACILITYSELECTOR_LINE_INTERCONNECT ,
0x0001 ,
/* struct LI Request Parameter */
0x00000000 , /* Data Path */
/* struct */
/* struct LI Request Connect Participant */
i1 - > PLCI ,
0x00000003 /* Data Path Participant */
) ;
2005-09-15 19:11:45 +00:00
i0 - > isdnstate | = CAPI_ISDN_STATE_LI ;
i1 - > isdnstate | = CAPI_ISDN_STATE_LI ;
} else {
2007-04-20 08:17:29 +00:00
/* disconnect */
capi_sendf ( i1 , 0 , CAPI_FACILITY_REQ , i0 - > PLCI , get_capi_MessageNumber ( ) ,
" w(w(d)) " ,
FACILITYSELECTOR_LINE_INTERCONNECT ,
0x0002 ,
i1 - > PLCI
) ;
2005-09-15 19:11:45 +00:00
i0 - > isdnstate & = ~ CAPI_ISDN_STATE_LI ;
i1 - > isdnstate & = ~ CAPI_ISDN_STATE_LI ;
}
2007-04-20 08:17:29 +00:00
2005-09-15 19:11:45 +00:00
return 0 ;
}
2006-04-01 13:31:56 +00:00
#if 0
2006-02-06 19:21:38 +00:00
/*
* disconnect b3 and bring it up with another protocol
*/
static void cc_switch_b_protocol ( struct capi_pvt * i )
{
int waitcount = 200 ;
cc_disconnect_b3 ( i , 1 ) ;
i - > isdnstate | = CAPI_ISDN_STATE_B3_CHANGE ;
cc_select_b ( i , NULL ) ;
if ( i - > outgoing ) {
/* on outgoing call we must do the connect-b3 request */
cc_start_b3 ( i ) ;
}
/* wait for the B3 layer to come up */
while ( ( waitcount > 0 ) & &
( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) ) {
usleep ( 10000 ) ;
waitcount - - ;
}
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
cc_log ( LOG_ERROR , " capi switch b3: no b3 up \n " ) ;
}
}
/*
* set the b3 protocol to transparent
*/
static int cc_set_transparent ( struct capi_pvt * i )
{
if ( i - > bproto ! = CC_BPROTO_RTP ) {
/* nothing to do */
return 0 ;
}
i - > bproto = CC_BPROTO_TRANSPARENT ;
cc_switch_b_protocol ( i ) ;
return 1 ;
}
/*
* set the b3 protocol to RTP ( if wanted )
*/
static void cc_unset_transparent ( struct capi_pvt * i , int rtpwanted )
{
if ( ( ! rtpwanted ) | |
( i - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) )
return ;
i - > bproto = CC_BPROTO_RTP ;
cc_switch_b_protocol ( i ) ;
return ;
}
2006-04-01 13:31:56 +00:00
# endif
2006-02-06 19:21:38 +00:00
2007-09-30 21:09:15 +00:00
/*
* try call transfer instead of bridge
*/
static int pbx_capi_bridge_transfer (
struct ast_channel * c0 ,
struct ast_channel * c1 ,
struct capi_pvt * i0 ,
struct capi_pvt * i1 )
{
int ret = 0 ;
ast_group_t tgroup0 = i0 - > transfergroup ;
ast_group_t tgroup1 = i1 - > transfergroup ;
struct timespec abstime ;
const char * var ;
2007-10-20 12:05:26 +00:00
struct capi_pvt * heldcall ;
struct capi_pvt * consultationcall ;
2007-09-30 21:09:15 +00:00
/* variable may override config */
if ( ( var = pbx_builtin_getvar_helper ( c0 , " TRANSFERGROUP " ) ) ! = NULL ) {
tgroup0 = ast_get_group ( ( char * ) var ) ;
}
if ( ( var = pbx_builtin_getvar_helper ( c1 , " TRANSFERGROUP " ) ) ! = NULL ) {
tgroup1 = ast_get_group ( ( char * ) var ) ;
}
if ( ( ! ( ( 1 < < i0 - > controller ) & tgroup1 ) ) | |
( ! ( ( 1 < < i1 - > controller ) & tgroup0 ) ) ) {
/* transfer between those controllers is not allowed */
cc_verbose ( 4 , 1 , " %s: transfergroup mismatch %d(0x%x),%d(0x%x) \n " ,
i0 - > vname , i0 - > controller , tgroup1 , i1 - > controller , tgroup0 ) ;
return 0 ;
}
if ( ( i0 - > qsigfeat ) & & ( i1 - > qsigfeat ) ) {
/* QSIG */
ret = pbx_capi_qsig_bridge ( i0 , i1 ) ;
if ( ret = = 2 ) {
/* don't do bridge - call transfer is active */
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s:%s cancelled bridge (path replacement was sent) for %s and %s \n " ,
i0 - > vname , i1 - > vname , c0 - > name , c1 - > name ) ;
}
} else {
/* standard ECT */
2007-10-20 12:05:26 +00:00
if ( i0 - > isdnstate & CAPI_ISDN_STATE_HOLD ) {
if ( i1 - > isdnstate & CAPI_ISDN_STATE_HOLD ) {
2007-10-20 18:20:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s:%s both channels on hold, retrieving second one. \n " ,
i0 - > vname , i1 - > vname ) ;
pbx_capi_retrieve ( c1 , NULL ) ;
capi_wait_for_b3_up ( i1 ) ;
2007-09-30 21:09:15 +00:00
}
2007-10-20 12:05:26 +00:00
heldcall = i0 ;
consultationcall = i1 ;
} else if ( i1 - > isdnstate & CAPI_ISDN_STATE_HOLD ) {
heldcall = i1 ;
consultationcall = i0 ;
} else {
/* no one on hold */
/* put first call on hold */
cc_mutex_lock ( & i0 - > lock ) ;
pbx_capi_hold ( c0 , NULL ) ;
if ( ( i0 - > onholdPLCI ! = 0 ) & & ( i0 - > state ! = CAPI_STATE_ONHOLD ) ) {
i0 - > waitevent = CAPI_WAITEVENT_HOLD_IND ;
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
if ( ast_cond_timedwait ( & i0 - > event_trigger , & i0 - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for HOLD. \n " , i0 - > vname ) ;
} else {
cc_verbose ( 4 , 1 , " %s: cond signal received for HOLD. \n " , i0 - > vname ) ;
}
}
cc_mutex_unlock ( & i0 - > lock ) ;
2007-09-30 21:09:15 +00:00
2007-10-20 12:05:26 +00:00
if ( i0 - > state ! = CAPI_STATE_ONHOLD ) {
cc_verbose ( 4 , 1 , " %s: HOLD impossible, transfer aborted. \n " , i0 - > vname ) ;
return 0 ;
}
heldcall = i0 ;
consultationcall = i1 ;
2007-09-30 21:09:15 +00:00
}
2007-10-20 12:05:26 +00:00
heldcall - > whentoretrieve = 0 ;
2007-09-30 21:09:15 +00:00
/* start the ECT */
2007-10-20 12:05:26 +00:00
cc_disconnect_b3 ( consultationcall , 1 ) ;
2007-09-30 21:09:15 +00:00
2007-10-20 12:05:26 +00:00
cc_mutex_lock ( & consultationcall - > lock ) ;
2007-09-30 21:09:15 +00:00
/* ECT */
2007-10-20 12:05:26 +00:00
capi_sendf ( consultationcall , 1 , CAPI_FACILITY_REQ , consultationcall - > PLCI ,
get_capi_MessageNumber ( ) ,
2007-09-30 21:09:15 +00:00
" w(w(d)) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0006 , /* ECT */
2007-10-20 12:05:26 +00:00
heldcall - > PLCI
2007-09-30 21:09:15 +00:00
) ;
2007-10-20 12:05:26 +00:00
heldcall - > isdnstate & = ~ CAPI_ISDN_STATE_HOLD ;
heldcall - > isdnstate | = CAPI_ISDN_STATE_ECT ;
consultationcall - > isdnstate | = CAPI_ISDN_STATE_ECT ;
2007-09-30 21:09:15 +00:00
2007-10-20 12:05:26 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent ECT for PLCI=%#x to PLCI=%#x \n " ,
consultationcall - > vname , heldcall - > PLCI , consultationcall - > PLCI ) ;
consultationcall - > waitevent = CAPI_WAITEVENT_ECT_IND ;
2007-10-01 16:10:37 +00:00
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
2007-10-20 12:05:26 +00:00
if ( ast_cond_timedwait ( & consultationcall - > event_trigger ,
& consultationcall - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for ECT. \n " , consultationcall - > vname ) ;
2007-10-01 16:10:37 +00:00
} else {
2007-10-20 12:05:26 +00:00
cc_verbose ( 4 , 1 , " %s: cond signal received for ECT. \n " , consultationcall - > vname ) ;
2007-10-01 16:10:37 +00:00
}
2007-10-20 12:05:26 +00:00
cc_mutex_unlock ( & consultationcall - > lock ) ;
2007-09-30 21:09:15 +00:00
2007-10-20 12:05:26 +00:00
if ( consultationcall - > isdnstate & CAPI_ISDN_STATE_ECT ) {
/* ECT was activated */
ret = 1 ;
} else {
cc_log ( LOG_WARNING , " %s: ECT was not activated, trying to resume normal operation. \n " ,
consultationcall - > vname ) ;
cc_start_b3 ( consultationcall ) ;
capi_wait_for_b3_up ( consultationcall ) ;
pbx_capi_retrieve ( heldcall - > owner , NULL ) ;
ret = 0 ;
}
2007-09-30 21:09:15 +00:00
}
return ret ;
}
2008-08-30 09:58:27 +00:00
/*
* activate / deactivate b - channel bridge
*/
static int capi_bridge ( int start , struct capi_pvt * i0 , struct capi_pvt * i1 , int flags )
{
int ret = 0 ;
if ( start ) {
if ( ( i0 - > isdnstate & CAPI_ISDN_STATE_LI ) | |
( i1 - > isdnstate & CAPI_ISDN_STATE_LI ) ) {
/* already in bridge */
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s/%s: already in bridge. \n " ,
i0 - > vname , i1 - > vname ) ;
return 0 ;
}
if ( ! ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) )
capi_detect_dtmf ( i0 , 0 ) ;
if ( ! ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) )
capi_detect_dtmf ( i1 , 0 ) ;
capi_echo_canceller ( i0 , EC_FUNCTION_DISABLE ) ;
capi_echo_canceller ( i1 , EC_FUNCTION_DISABLE ) ;
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s/%s: activating bridge. \n " ,
i0 - > vname , i1 - > vname ) ;
ret = line_interconnect ( i0 , i1 , 1 ) ;
} else {
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s/%s: deactivating bridge. \n " ,
i0 - > vname , i1 - > vname ) ;
line_interconnect ( i0 , i1 , 0 ) ;
capi_detect_dtmf ( i0 , 1 ) ;
capi_detect_dtmf ( i1 , 1 ) ;
capi_echo_canceller ( i0 , EC_FUNCTION_ENABLE ) ;
capi_echo_canceller ( i1 , EC_FUNCTION_ENABLE ) ;
}
return ret ;
}
2005-09-15 19:11:45 +00:00
/*
* native bridging / line interconnect
*/
2007-09-30 21:09:15 +00:00
static CC_BRIDGE_RETURN pbx_capi_bridge (
struct ast_channel * c0 ,
struct ast_channel * c1 ,
int flags , struct ast_frame * * fo ,
struct ast_channel * * rc ,
int timeoutms )
2005-09-15 19:11:45 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i0 = CC_CHANNEL_PVT ( c0 ) ;
struct capi_pvt * i1 = CC_CHANNEL_PVT ( c1 ) ;
2005-09-15 19:11:45 +00:00
CC_BRIDGE_RETURN ret = AST_BRIDGE_COMPLETE ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s:%s Requested native bridge for %s and %s \n " ,
2006-06-18 16:32:32 +00:00
i0 - > vname , i1 - > vname , c0 - > name , c1 - > name ) ;
2005-09-15 19:11:45 +00:00
2006-08-12 14:30:04 +00:00
if ( ( i0 - > isdnstate & CAPI_ISDN_STATE_ECT ) | |
2007-06-04 18:37:12 +00:00
( i1 - > isdnstate & CAPI_ISDN_STATE_ECT ) ) {
2007-09-30 21:09:15 +00:00
/* If an ECT is already in progress, forget about the bridge */
2006-08-12 14:30:04 +00:00
return AST_BRIDGE_FAILED ;
}
2007-06-04 18:37:12 +00:00
2007-09-30 21:09:15 +00:00
switch ( pbx_capi_bridge_transfer ( c0 , c1 , i0 , i1 ) ) {
case 1 : /* transfer was sucessful */
return ret ;
case 2 : /* not successful, abort */
return AST_BRIDGE_FAILED_NOWARN ;
default : /* go on with line-interconnect */
break ;
2007-06-04 18:37:12 +00:00
}
2007-09-30 21:09:15 +00:00
/* do bridge aka line-interconnect here */
if ( ( ! i0 - > bridge ) | | ( ! i1 - > bridge ) )
return AST_BRIDGE_FAILED_NOWARN ;
2006-07-09 14:18:53 +00:00
2007-09-30 21:09:15 +00:00
if ( ( ! capi_controllers [ i0 - > controller ] - > lineinterconnect ) | |
( ! capi_controllers [ i1 - > controller ] - > lineinterconnect ) ) {
return AST_BRIDGE_FAILED_NOWARN ;
}
2006-07-09 14:18:53 +00:00
capi_wait_for_b3_up ( i0 ) ;
capi_wait_for_b3_up ( i1 ) ;
2007-06-04 18:37:12 +00:00
2008-08-30 09:58:27 +00:00
if ( capi_bridge ( 1 , i0 , i1 , flags ) ) {
return AST_BRIDGE_FAILED ;
2005-09-15 19:11:45 +00:00
}
for ( ; ; ) {
struct ast_channel * c0_priority [ 2 ] = { c0 , c1 } ;
struct ast_channel * c1_priority [ 2 ] = { c1 , c0 } ;
int priority = 0 ;
struct ast_frame * f ;
struct ast_channel * who ;
2005-11-15 14:10:51 +00:00
who = ast_waitfor_n ( priority ? c0_priority : c1_priority , 2 , & timeoutms ) ;
2005-09-15 19:11:45 +00:00
if ( ! who ) {
2005-11-27 18:16:19 +00:00
if ( ! timeoutms ) {
ret = AST_BRIDGE_RETRY ;
break ;
}
2005-09-15 19:11:45 +00:00
continue ;
}
f = ast_read ( who ) ;
if ( ! f | | ( f - > frametype = = AST_FRAME_CONTROL )
| | ( f - > frametype = = AST_FRAME_DTMF ) ) {
* fo = f ;
* rc = who ;
ret = AST_BRIDGE_COMPLETE ;
break ;
}
if ( who = = c0 ) {
ast_write ( c1 , f ) ;
} else {
ast_write ( c0 , f ) ;
}
ast_frfree ( f ) ;
/* Swap who gets priority */
priority = ! priority ;
}
2008-08-30 09:58:27 +00:00
capi_bridge ( 0 , i0 , i1 , 0 ) ;
2005-09-15 19:11:45 +00:00
return ret ;
}
2005-06-02 18:47:35 +00:00
/*
* a new channel is needed
*/
2009-07-24 20:30:47 +00:00
static struct ast_channel * capi_new ( struct capi_pvt * i , int state , const char * linkedid )
2005-06-02 18:47:35 +00:00
{
struct ast_channel * tmp ;
int fmt ;
2006-11-19 14:45:32 +00:00
# ifdef CC_AST_HAS_EXT_CHAN_ALLOC
2010-02-07 19:16:12 +00:00
tmp = ast_channel_alloc ( 0 , state , i - > cid , emptyid ,
2007-04-18 21:04:49 +00:00
# ifdef CC_AST_HAS_EXT2_CHAN_ALLOC
2009-07-24 20:30:47 +00:00
i - > accountcode , i - > dnid , i - > context ,
# ifdef CC_AST_HAS_LINKEDID_CHAN_ALLOC
linkedid ,
# endif
i - > amaflags ,
2007-04-18 21:04:49 +00:00
# endif
2008-02-24 12:57:52 +00:00
CC_MESSAGE_BIGNAME " /%s/%s-%x " , i - > vname , i - > dnid , capi_counter + + ) ;
2006-11-19 14:45:32 +00:00
# else
2006-06-10 11:58:50 +00:00
tmp = ast_channel_alloc ( 0 ) ;
2006-11-19 14:45:32 +00:00
# endif
2005-06-02 18:47:35 +00:00
if ( tmp = = NULL ) {
2007-04-23 22:18:36 +00:00
cc_log ( LOG_ERROR , " Unable to allocate channel! \n " ) ;
return NULL ;
2005-06-02 18:47:35 +00:00
}
2006-11-19 14:45:32 +00:00
# ifndef CC_AST_HAS_EXT_CHAN_ALLOC
2006-02-04 12:48:10 +00:00
# ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL
2008-02-24 12:57:52 +00:00
ast_string_field_build ( tmp , name , CC_MESSAGE_BIGNAME " /%s/%s-%x " ,
2007-04-05 20:39:41 +00:00
i - > vname , i - > dnid , capi_counter + + ) ;
2006-02-04 12:48:10 +00:00
# else
2008-02-24 12:57:52 +00:00
snprintf ( tmp - > name , sizeof ( tmp - > name ) - 1 , CC_MESSAGE_BIGNAME " /%s/%s-%x " ,
2007-04-05 20:39:41 +00:00
i - > vname , i - > dnid , capi_counter + + ) ;
2006-02-04 12:48:10 +00:00
# endif
2006-11-19 14:45:32 +00:00
# endif
2006-11-11 20:07:19 +00:00
# ifndef CC_AST_HAS_VERSION_1_4
2005-08-16 10:11:43 +00:00
tmp - > type = channeltype ;
2006-11-11 20:07:19 +00:00
# endif
2005-06-02 18:47:35 +00:00
2007-04-29 22:28:30 +00:00
if ( ! ( capi_create_reader_writer_pipe ( i ) ) ) {
2009-07-24 20:30:47 +00:00
ast_channel_release ( tmp ) ;
2006-06-10 11:58:50 +00:00
return NULL ;
}
tmp - > fds [ 0 ] = i - > readerfd ;
2005-06-19 10:01:35 +00:00
if ( i - > smoother ! = NULL ) {
2005-11-20 16:15:33 +00:00
ast_smoother_reset ( i - > smoother , CAPI_MAX_B3_BLOCK_SIZE ) ;
2005-06-02 18:47:35 +00:00
}
2006-04-03 20:02:01 +00:00
2005-06-02 18:47:35 +00:00
i - > state = CAPI_STATE_DISCONNECTED ;
2005-06-05 19:48:21 +00:00
i - > calledPartyIsISDN = 1 ;
2005-11-20 16:15:33 +00:00
i - > doB3 = CAPI_B3_DONT ;
2005-08-25 17:45:39 +00:00
i - > doES = i - > ES ;
2005-06-02 18:47:35 +00:00
i - > outgoing = 0 ;
i - > onholdPLCI = 0 ;
2005-08-25 18:16:44 +00:00
i - > doholdtype = i - > holdtype ;
2005-06-19 10:01:35 +00:00
i - > B3q = 0 ;
2007-03-30 16:21:58 +00:00
i - > B3count = 0 ;
2005-06-02 18:47:35 +00:00
memset ( i - > txavg , 0 , ECHO_TX_COUNT ) ;
2009-02-13 21:58:19 +00:00
i - > divaAudioFlags = 0 ;
i - > divaDigitalRxGain = 0 ;
i - > divaDigitalRxGainDB = 0 ;
i - > divaDigitalTxGain = 0 ;
i - > divaDigitalTxGainDB = 0 ;
i - > rxPitch = 8000 ;
i - > txPitch = 8000 ;
i - > special_tone_extension [ 0 ] = 0 ;
2009-02-14 20:56:14 +00:00
pbx_capi_voicecommand_cleanup ( i ) ;
2009-02-13 21:58:19 +00:00
2005-08-07 12:21:36 +00:00
if ( i - > doDTMF > 0 ) {
2005-06-02 18:47:35 +00:00
i - > vad = ast_dsp_new ( ) ;
2008-04-05 20:44:02 +00:00
# ifdef CC_AST_HAS_DSP_SET_DIGITMODE
ast_dsp_set_features ( i - > vad , DSP_FEATURE_DIGIT_DETECT ) ;
if ( i - > doDTMF > 1 ) {
ast_dsp_set_digitmode ( i - > vad , DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF ) ;
}
# else
2005-06-02 18:47:35 +00:00
ast_dsp_set_features ( i - > vad , DSP_FEATURE_DTMF_DETECT ) ;
2005-08-07 12:21:36 +00:00
if ( i - > doDTMF > 1 ) {
ast_dsp_digitmode ( i - > vad , DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF ) ;
}
2008-04-05 20:44:02 +00:00
# endif
2005-06-02 18:47:35 +00:00
}
2005-11-20 16:15:33 +00:00
CC_CHANNEL_PVT ( tmp ) = i ;
2005-06-02 18:47:35 +00:00
tmp - > callgroup = i - > callgroup ;
2006-07-08 16:29:27 +00:00
tmp - > pickupgroup = i - > pickupgroup ;
2005-06-02 18:47:35 +00:00
tmp - > nativeformats = capi_capability ;
2006-01-30 23:40:28 +00:00
i - > bproto = CC_BPROTO_TRANSPARENT ;
2009-05-08 13:03:31 +00:00
2006-01-30 23:40:28 +00:00
if ( ( i - > rtpcodec = ( capi_controllers [ i - > controller ] - > rtpcodec & i - > capability ) ) ) {
2009-05-08 13:03:31 +00:00
#if 0 /* VOCODER */
2006-01-30 23:40:28 +00:00
if ( capi_alloc_rtp ( i ) ) {
/* error on rtp alloc */
i - > rtpcodec = 0 ;
} else {
/* start with rtp */
tmp - > nativeformats = i - > rtpcodec ;
i - > bproto = CC_BPROTO_RTP ;
}
2009-05-08 13:03:31 +00:00
# else
tmp - > nativeformats = i - > rtpcodec ;
i - > bproto = CC_BPROTO_VOCODER ;
# endif
2006-01-30 23:40:28 +00:00
}
2005-06-02 18:47:35 +00:00
fmt = ast_best_codec ( tmp - > nativeformats ) ;
2006-01-30 23:40:28 +00:00
i - > codec = fmt ;
2005-06-02 18:47:35 +00:00
tmp - > readformat = fmt ;
tmp - > writeformat = fmt ;
2005-06-28 13:29:21 +00:00
tmp - > tech = & capi_tech ;
2005-06-02 18:47:35 +00:00
tmp - > rawreadformat = fmt ;
tmp - > rawwriteformat = fmt ;
2006-06-24 11:53:47 +00:00
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: setting format %s - %s%s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , ast_getformatname ( fmt ) ,
2006-01-30 23:40:28 +00:00
ast_getformatname_multiple ( alloca ( 80 ) , 80 ,
tmp - > nativeformats ) ,
2009-05-08 13:03:31 +00:00
( i - > bproto = = CC_BPROTO_VOCODER ) ? " VOCODER " : ( ( i - > rtp ) ? " (RTP) " : " " ) ) ;
2006-06-24 11:53:47 +00:00
2006-08-06 18:44:56 +00:00
if ( ! ast_strlen_zero ( i - > cid ) ) {
if ( tmp - > cid . cid_num ) {
free ( tmp - > cid . cid_num ) ;
}
tmp - > cid . cid_num = strdup ( i - > cid ) ;
}
2006-02-12 20:58:02 +00:00
if ( ! ast_strlen_zero ( i - > dnid ) ) {
if ( tmp - > cid . cid_dnid ) {
2006-02-13 15:11:56 +00:00
free ( tmp - > cid . cid_dnid ) ;
2006-02-12 20:58:02 +00:00
}
2005-07-12 20:15:50 +00:00
tmp - > cid . cid_dnid = strdup ( i - > dnid ) ;
2006-02-12 20:58:02 +00:00
}
2006-03-07 21:17:58 +00:00
tmp - > cid . cid_ton = i - > cid_ton ;
2007-04-18 21:04:49 +00:00
# ifndef CC_AST_HAS_EXT2_CHAN_ALLOC
2006-07-08 22:13:47 +00:00
if ( i - > amaflags )
tmp - > amaflags = i - > amaflags ;
2005-06-04 14:28:52 +00:00
2007-04-18 21:04:49 +00:00
cc_copy_string ( tmp - > context , i - > context , sizeof ( tmp - > context ) ) ;
2006-01-28 19:42:44 +00:00
cc_copy_string ( tmp - > exten , i - > dnid , sizeof ( tmp - > exten ) ) ;
2006-02-04 12:48:10 +00:00
# ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL
ast_string_field_set ( tmp , accountcode , i - > accountcode ) ;
ast_string_field_set ( tmp , language , i - > language ) ;
# else
2006-01-28 19:42:44 +00:00
cc_copy_string ( tmp - > accountcode , i - > accountcode , sizeof ( tmp - > accountcode ) ) ;
cc_copy_string ( tmp - > language , i - > language , sizeof ( tmp - > language ) ) ;
2006-02-04 12:48:10 +00:00
# endif
2007-04-18 21:04:49 +00:00
# endif
# ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL
ast_string_field_set ( tmp , language , i - > language ) ;
# else
cc_copy_string ( tmp - > language , i - > language , sizeof ( tmp - > language ) ) ;
# endif
2005-06-02 18:47:35 +00:00
i - > owner = tmp ;
2007-04-23 18:47:49 +00:00
i - > used = tmp ;
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
ast_atomic_fetchadd_int ( & usecnt , 1 ) ;
2007-02-10 23:18:57 +00:00
ast_jb_configure ( tmp , & i - > jbconf ) ;
2006-11-11 20:07:19 +00:00
# else
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & usecnt_lock ) ;
2005-06-02 18:47:35 +00:00
usecnt + + ;
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & usecnt_lock ) ;
2006-11-11 20:07:19 +00:00
# endif
2005-06-02 18:47:35 +00:00
ast_update_use_count ( ) ;
2005-07-12 19:50:54 +00:00
2006-11-19 14:45:32 +00:00
# ifndef CC_AST_HAS_EXT_CHAN_ALLOC
2005-07-12 19:50:54 +00:00
ast_setstate ( tmp , state ) ;
2006-11-19 14:45:32 +00:00
# endif
2005-07-12 19:50:54 +00:00
2005-06-02 18:47:35 +00:00
return tmp ;
}
/*
2005-12-15 19:49:38 +00:00
* PBX wants us to dial . . .
2005-06-02 18:47:35 +00:00
*/
2009-07-24 20:30:47 +00:00
# ifdef CC_AST_HAS_REQUEST_REQUESTOR
2010-03-01 17:59:31 +00:00
# ifdef CC_AST_HAS_REQUEST_FORMAT_T
2009-07-24 20:30:47 +00:00
static struct ast_channel *
2010-03-01 17:59:31 +00:00
pbx_capi_request ( const char * type , format_t format , const struct ast_channel * requestor , void * data , int * cause )
2009-07-24 20:30:47 +00:00
/* TODO: new field requestor to link to called channel */
# else
2006-02-12 21:27:20 +00:00
static struct ast_channel *
2010-03-01 17:59:31 +00:00
pbx_capi_request ( const char * type , int format , const struct ast_channel * requestor , void * data , int * cause )
# endif
# else
static struct ast_channel *
2006-06-09 21:48:24 +00:00
pbx_capi_request ( const char * type , int format , void * data , int * cause )
2009-07-24 20:30:47 +00:00
# endif
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i ;
2005-06-02 18:47:35 +00:00
struct ast_channel * tmp = NULL ;
2005-10-09 16:45:03 +00:00
char * dest , * interface , * param , * ocid ;
2005-11-20 16:15:33 +00:00
char buffer [ CAPI_MAX_STRING ] ;
2006-01-30 23:40:28 +00:00
ast_group_t capigroup = 0 ;
unsigned int controller = 0 ;
2007-04-24 20:21:04 +00:00
unsigned int ccbsnrhandle = 0 ;
2005-06-02 18:47:35 +00:00
2006-05-28 16:10:28 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 " data = %s format=%d \n " , ( char * ) data , format ) ;
2005-06-02 18:47:35 +00:00
2006-01-28 19:42:44 +00:00
cc_copy_string ( buffer , ( char * ) data , sizeof ( buffer ) ) ;
2007-04-29 22:28:30 +00:00
capi_parse_dialstring ( buffer , & interface , & dest , & param , & ocid ) ;
2005-06-02 18:47:35 +00:00
2005-07-12 20:40:31 +00:00
if ( ( ! interface ) | | ( ! dest ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Syntax error in dialstring. Read the docs! \n " ) ;
2005-08-21 10:28:43 +00:00
* cause = AST_CAUSE_INVALID_NUMBER_FORMAT ;
2005-07-12 20:40:31 +00:00
return NULL ;
}
2005-07-27 18:17:41 +00:00
if ( interface [ 0 ] = = ' g ' ) {
capigroup = ast_get_group ( interface + 1 ) ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_NAME " request group = %d \n " ,
2006-01-30 23:40:28 +00:00
( unsigned int ) capigroup ) ;
2005-06-02 18:47:35 +00:00
} else if ( ! strncmp ( interface , " contr " , 5 ) ) {
2005-07-27 18:17:41 +00:00
controller = atoi ( interface + 5 ) ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_NAME " request controller = %d \n " ,
2005-06-02 18:47:35 +00:00
controller ) ;
2007-04-24 20:21:04 +00:00
} else if ( ! strncmp ( interface , " ccbs " , 4 ) ) {
ccbsnrhandle = ( unsigned int ) strtoul ( dest , NULL , 0 ) ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_NAME " request ccbs handle = %u \n " ,
2007-04-24 20:21:04 +00:00
ccbsnrhandle ) ;
if ( ( controller = capi_get_ccbsnrcontroller ( ccbsnrhandle ) ) = = 0 ) {
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " didn't find CCBS handle %u \n " ,
ccbsnrhandle ) ;
* cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL ;
return NULL ;
}
2005-06-02 18:47:35 +00:00
} else {
2008-02-24 12:57:52 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_NAME " request for interface '%s' \n " ,
2005-07-27 18:17:41 +00:00
interface ) ;
2005-06-02 18:47:35 +00:00
}
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & iflock ) ;
2005-06-02 18:47:35 +00:00
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2007-04-23 18:47:49 +00:00
if ( ( i - > used ) | | ( i - > channeltype ! = CAPI_CHANNELTYPE_B ) ) {
2005-10-01 15:17:10 +00:00
/* if already in use or no real channel */
2005-06-02 18:47:35 +00:00
continue ;
}
/* unused channel */
if ( controller ) {
/* DIAL(CAPI/contrX/...) */
2006-06-24 14:49:13 +00:00
if ( i - > controller ! = controller ) {
2005-06-02 18:47:35 +00:00
/* keep on running! */
continue ;
}
} else {
/* DIAL(CAPI/gX/...) */
2005-07-27 18:17:41 +00:00
if ( ( interface [ 0 ] = = ' g ' ) & & ( ! ( i - > group & capigroup ) ) ) {
/* keep on running! */
continue ;
}
/* DIAL(CAPI/<interface-name>/...) */
if ( ( interface [ 0 ] ! = ' g ' ) & & ( strcmp ( interface , i - > name ) ) ) {
2005-06-02 18:47:35 +00:00
/* keep on running! */
continue ;
}
}
/* when we come here, we found a free controller match */
2006-01-28 19:42:44 +00:00
cc_copy_string ( i - > dnid , dest , sizeof ( i - > dnid ) ) ;
2009-07-24 20:30:47 +00:00
tmp = capi_new ( i , AST_STATE_RESERVED ,
# ifdef CC_AST_HAS_REQUEST_REQUESTOR
requestor ? requestor - > linkedid : NULL
# else
NULL
# endif
) ;
2005-07-17 19:01:14 +00:00
if ( ! tmp ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_ERROR , " cannot create new " CC_MESSAGE_NAME " channel \n " ) ;
2005-07-17 19:01:14 +00:00
interface_cleanup ( i ) ;
}
2005-06-02 18:47:35 +00:00
i - > PLCI = 0 ;
i - > outgoing = 1 ; /* this is an outgoing line */
2007-04-24 20:21:04 +00:00
i - > ccbsnrhandle = ccbsnrhandle ;
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-06-02 18:47:35 +00:00
return tmp ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " didn't find " CC_MESSAGE_NAME
" device for interface '%s' \n " , interface ) ;
2005-08-21 10:28:43 +00:00
* cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL ;
2005-06-02 18:47:35 +00:00
return NULL ;
}
2005-08-14 12:32:18 +00:00
/*
2009-08-05 22:25:53 +00:00
* fill out extended fax conf struct
2009-04-08 20:43:38 +00:00
*
* b3_protocol_options :
* [ Bit 0 ] : Enable high resolution
* [ Bit 1 ] : Accept incoming fax - polling requests
* [ Bit 10 ] : Enable JPEG negotiation ( continuous - tone colour mode according to T .4 Annex E ) ( see note 1 )
* [ Bit 11 ] : Enable JBIG colour and gray - scale negotiation according to T .43 ( see note 1 )
* [ Bit 12 ] : Do not use JBIG progressive bi - level image compression
* [ Bit 13 ] : Do not use MR compression
* [ Bit 14 ] : Do not use MMR compression
* [ Bit 15 ] : Do not use ECM
*
2005-08-14 12:32:18 +00:00
*/
2009-04-08 20:43:38 +00:00
static void setup_b3_fax_config ( B3_PROTO_FAXG3 * b3conf , int fax_format , char * stationid , char * headline , unsigned short b3_protocol_options )
2005-08-14 12:32:18 +00:00
{
int len1 ;
int len2 ;
2009-04-08 20:43:38 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " Setup fax b3conf fmt=%d, stationid='%s' headline='%s' options=%04x \n " ,
fax_format , stationid , headline , b3_protocol_options ) ;
b3conf - > resolution = b3_protocol_options ;
2005-08-14 12:32:18 +00:00
b3conf - > format = ( unsigned short ) fax_format ;
len1 = strlen ( stationid ) ;
b3conf - > Infos [ 0 ] = ( unsigned char ) len1 ;
strcpy ( ( char * ) & b3conf - > Infos [ 1 ] , stationid ) ;
len2 = strlen ( headline ) ;
b3conf - > Infos [ len1 + 1 ] = ( unsigned char ) len2 ;
strcpy ( ( char * ) & b3conf - > Infos [ len1 + 2 ] , headline ) ;
b3conf - > len = ( unsigned char ) ( 2 * sizeof ( unsigned short ) + len1 + len2 + 2 ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-08-14 12:32:18 +00:00
}
2009-08-05 22:25:53 +00:00
/*
* fill out basic fax conf struct
*/
static void setup_b3_basic_fax_config ( B3_PROTO_FAXG3 * b3conf , int fax_format , char * stationid , char * headline )
{
int len1 ;
int len2 ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " Setup fax b3conf fmt=%d, stationid='%s' headline='%s' \n " ,
fax_format , stationid , headline ) ;
b3conf - > resolution = 0 ;
b3conf - > format = ( unsigned short ) fax_format ;
len1 = strlen ( stationid ) ;
b3conf - > Infos [ 0 ] = ( unsigned char ) len1 ;
strcpy ( ( char * ) & b3conf - > Infos [ 1 ] , stationid ) ;
len2 = strlen ( headline ) ;
b3conf - > Infos [ len1 + 1 ] = ( unsigned char ) len2 ;
strcpy ( ( char * ) & b3conf - > Infos [ len1 + 2 ] , headline ) ;
b3conf - > len = ( unsigned char ) ( 2 * sizeof ( unsigned short ) + len1 + len2 + 2 ) ;
return ;
}
2005-08-14 12:32:18 +00:00
/*
* change b protocol to fax
*/
2009-05-02 13:21:17 +00:00
static void capi_change_bchan_fax ( struct capi_pvt * i , B3_PROTO_FAXG3 * b3conf )
2005-08-14 12:32:18 +00:00
{
2006-06-27 14:54:03 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_B3_SELECT ;
2006-02-06 19:21:38 +00:00
cc_disconnect_b3 ( i , 1 ) ;
cc_select_b ( i , ( _cstruct ) b3conf ) ;
2005-08-14 12:32:18 +00:00
return ;
}
/*
2009-08-05 22:25:53 +00:00
* capicommand ' receivefax ' using B3 fax T .30 extended
2005-08-14 12:32:18 +00:00
*/
2009-08-05 22:25:53 +00:00
static int pbx_capi_receive_extended_fax ( struct ast_channel * c , struct capi_pvt * i , char * data )
2005-08-14 12:32:18 +00:00
{
int res = 0 ;
2007-04-05 19:33:01 +00:00
int keepbadfax = 0 ;
char * filename , * stationid , * headline , * options ;
2005-08-14 12:32:18 +00:00
B3_PROTO_FAXG3 b3conf ;
2006-06-27 14:54:03 +00:00
char buffer [ CAPI_MAX_STRING ] ;
2009-08-05 21:03:12 +00:00
unsigned short b3_protocol_options = 0x0001 ;
2009-04-09 11:02:48 +00:00
int extended_resolution = 0 ;
2005-08-14 12:32:18 +00:00
filename = strsep ( & data , " | " ) ;
stationid = strsep ( & data , " | " ) ;
2007-04-05 19:33:01 +00:00
headline = strsep ( & data , " | " ) ;
options = data ;
2005-08-14 12:32:18 +00:00
if ( ! stationid )
stationid = emptyid ;
if ( ! headline )
headline = emptyid ;
2007-04-05 19:33:01 +00:00
if ( ! options )
options = emptyid ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: '%s' '%s' '%s' '%s' \n " ,
2007-04-05 19:33:01 +00:00
filename , stationid , headline , options ) ;
/* parse the options */
while ( ( options ) & & ( * options ) ) {
switch ( * options ) {
case ' k ' : /* keepbadfax */
cc_verbose ( 3 , 1 ,
2008-02-24 12:57:52 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: if fax is bad, "
2007-04-05 19:33:01 +00:00
" file won't be deleted. \n " ) ;
keepbadfax = 1 ;
break ;
2009-04-08 22:44:14 +00:00
case ' f ' : /* use Fine resolution */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: Allow Fine resolution \n " ) ;
b3_protocol_options | = 0x0001 ;
2009-04-08 22:44:14 +00:00
break ;
2009-08-05 21:03:12 +00:00
case ' F ' : /* do not use Fine resolution */
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: Allow Fine resolution \n " ) ;
if ( extended_resolution = = 0 )
b3_protocol_options & = ~ 0x0001 ;
break ;
2009-04-09 11:02:48 +00:00
case ' u ' : /* use Fine resolution */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: Allow Super/Ultra fine resolution \n " ) ;
b3_protocol_options | = 0x0001 ;
2009-04-09 11:02:48 +00:00
extended_resolution = 1 ;
break ;
2009-04-08 20:43:38 +00:00
case ' j ' : /* enable JPEG encoding */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: enable JPEG coding \n " ) ;
2009-04-08 20:43:38 +00:00
b3_protocol_options | = 0x0400 ;
break ;
case ' b ' : /* enable T.43 encoding */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: enable T.43 coding \n " ) ;
2009-04-08 20:43:38 +00:00
b3_protocol_options | = 0x0800 ;
break ;
case ' t ' : /* diasble T.85 encoding */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: Do not use T.85 coding \n " ) ;
b3_protocol_options | = 0x1000 ;
2009-04-08 20:43:38 +00:00
break ;
case ' e ' : /* disable ECM encoding */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: Do not use ECM \n " ) ;
b3_protocol_options | = 0x8000 ;
2009-04-08 20:43:38 +00:00
break ;
case ' m ' : /* disable MMR encoding */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: do not use MMR (T.6) coding \n " ) ;
b3_protocol_options | = 0x4000 ;
2009-04-08 20:43:38 +00:00
break ;
case ' d ' : /* disable MR encoding */
cc_verbose ( 3 , 1 ,
2009-04-10 07:23:20 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: do not use MR (2D) coding \n " ) ;
b3_protocol_options | = 0x2000 ;
2009-04-08 20:43:38 +00:00
break ;
2009-08-05 22:25:53 +00:00
case ' X ' :
case ' x ' :
break ;
2007-04-05 19:33:01 +00:00
default :
cc_log ( LOG_WARNING , " Unknown option '%c' for receivefax. \n " ,
* options ) ;
}
options + + ;
}
2005-08-14 12:32:18 +00:00
2006-07-08 20:22:15 +00:00
capi_wait_for_answered ( i ) ;
2006-10-10 11:57:37 +00:00
i - > FaxState & = ~ CAPI_FAX_STATE_CONN ;
2005-08-14 12:32:18 +00:00
if ( ( i - > fFax = fopen ( filename , " wb " ) ) = = NULL ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " can't create fax output file (%s) \n " , strerror ( errno ) ) ;
2009-05-02 13:21:17 +00:00
capi_remove_nullif ( i ) ;
2005-08-14 12:32:18 +00:00
return - 1 ;
}
2009-04-09 11:02:48 +00:00
if ( capi_controllers [ i - > controller ] - > divaExtendedFeaturesAvailable ! = 0 & & extended_resolution ! = 0 ) {
/*
Per PLCI control is available only starting with Diva 9.0 SU1
Without per PLCI control setting is applied to controller
2009-04-10 07:23:20 +00:00
*/
2009-04-09 11:02:48 +00:00
capi_sendf ( NULL , 0 , CAPI_MANUFACTURER_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2009-04-10 07:23:20 +00:00
" dw(d) " , _DI_MANU_ID , _DI_OPTIONS_REQUEST , 0x00000040L ) ;
2009-04-09 11:02:48 +00:00
}
2006-05-27 12:49:57 +00:00
i - > FaxState | = CAPI_FAX_STATE_ACTIVE ;
2009-04-08 20:43:38 +00:00
setup_b3_fax_config ( & b3conf , FAX_SFF_FORMAT , stationid , headline , b3_protocol_options ) ;
2005-08-14 12:32:18 +00:00
2006-01-30 23:40:28 +00:00
i - > bproto = CC_BPROTO_FAXG3 ;
2005-08-14 12:32:18 +00:00
switch ( i - > state ) {
case CAPI_STATE_ALERTING :
case CAPI_STATE_DID :
case CAPI_STATE_INCALL :
2006-06-10 14:16:36 +00:00
capi_send_answer ( c , ( _cstruct ) & b3conf ) ;
2005-08-14 12:32:18 +00:00
break ;
case CAPI_STATE_CONNECTED :
2009-05-02 13:21:17 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) {
capi_wait_for_b3_up ( i ) ;
}
capi_change_bchan_fax ( i , & b3conf ) ;
2005-08-14 12:32:18 +00:00
break ;
default :
2006-05-27 12:49:57 +00:00
i - > FaxState & = ~ CAPI_FAX_STATE_ACTIVE ;
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " receive fax in wrong state (%d) \n " ,
2005-08-14 12:32:18 +00:00
i - > state ) ;
2009-05-02 13:21:17 +00:00
capi_remove_nullif ( i ) ;
2005-08-14 12:32:18 +00:00
return - 1 ;
}
2006-12-02 12:35:30 +00:00
2009-05-02 13:21:17 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
while ( capi_tell_fax_finish ( i ) ) {
if ( ast_safe_sleep_conditional ( c , 1000 , capi_tell_fax_finish , i ) ! = 0 ) {
/* we got a hangup */
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: hangup. \n " ) ;
break ;
}
2006-12-02 12:35:30 +00:00
}
2009-05-02 13:21:17 +00:00
} else {
clear_channel_fax_loop ( c , i ) ;
2006-12-02 12:35:30 +00:00
}
cc_mutex_lock ( & i - > lock ) ;
2005-08-14 12:32:18 +00:00
2006-06-27 14:54:03 +00:00
res = ( i - > FaxState & CAPI_FAX_STATE_ERROR ) ? 1 : 0 ;
2006-05-27 12:49:57 +00:00
i - > FaxState & = ~ ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_ERROR ) ;
2005-08-14 12:32:18 +00:00
/* if the file has zero length */
if ( ftell ( i - > fFax ) = = 0L ) {
2006-06-27 14:54:03 +00:00
res = 1 ;
2005-08-14 12:32:18 +00:00
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " Closing fax file... \n " ) ;
2005-08-14 12:32:18 +00:00
fclose ( i - > fFax ) ;
i - > fFax = NULL ;
2006-12-02 12:35:30 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2005-08-14 12:32:18 +00:00
if ( res ! = 0 ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 0 ,
2008-02-24 12:57:52 +00:00
VERBOSE_PREFIX_1 CC_MESSAGE_NAME
" receivefax: fax receive failed reason=0x%04x reasonB3=0x%04x \n " ,
2005-08-14 12:32:18 +00:00
i - > reason , i - > reasonb3 ) ;
2007-04-05 19:33:01 +00:00
if ( ! keepbadfax ) {
cc_verbose ( 3 , 1 ,
2008-02-24 12:57:52 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: removing fax file. \n " ) ;
2007-04-05 19:33:01 +00:00
unlink ( filename ) ;
}
2005-08-14 12:32:18 +00:00
} else {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 0 ,
2008-02-24 12:57:52 +00:00
VERBOSE_PREFIX_1 CC_MESSAGE_NAME " receivefax: fax receive successful. \n " ) ;
2005-08-14 12:32:18 +00:00
}
2006-06-27 14:54:03 +00:00
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , res ) ;
pbx_builtin_setvar_helper ( c , " FAXSTATUS " , buffer ) ;
2009-05-02 13:21:17 +00:00
capi_remove_nullif ( i ) ;
2006-06-27 14:54:03 +00:00
return 0 ;
}
2009-08-05 22:25:53 +00:00
/*
* capicommand ' receivefax ' using B3 fax T .30
*/
static int pbx_capi_receive_basic_fax ( struct ast_channel * c , struct capi_pvt * i , char * data )
{
int res = 0 ;
int keepbadfax = 0 ;
char * filename , * stationid , * headline , * options ;
B3_PROTO_FAXG3 b3conf ;
char buffer [ CAPI_MAX_STRING ] ;
filename = strsep ( & data , " | " ) ;
stationid = strsep ( & data , " | " ) ;
headline = strsep ( & data , " | " ) ;
options = data ;
if ( ! stationid )
stationid = emptyid ;
if ( ! headline )
headline = emptyid ;
if ( ! options )
options = emptyid ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: '%s' '%s' '%s' '%s' \n " ,
filename , stationid , headline , options ) ;
/* parse the options */
while ( ( options ) & & ( * options ) ) {
switch ( * options ) {
case ' k ' : /* keepbadfax */
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: if fax is bad, "
" file won't be deleted. \n " ) ;
keepbadfax = 1 ;
break ;
case ' f ' : /* use Fine resolution */
case ' F ' : /* do not use Fine resolution */
case ' u ' : /* use Fine resolution */
case ' j ' : /* enable JPEG encoding */
case ' b ' : /* enable T.43 encoding */
case ' t ' : /* diasble T.85 encoding */
case ' e ' : /* disable ECM encoding */
case ' m ' : /* disable MMR encoding */
case ' d ' : /* disable MR encoding */
cc_log ( LOG_WARNING , " Option '%c' requires B3 fax T.30 extended. \n " ,
* options ) ;
break ;
case ' X ' :
case ' x ' :
break ;
default :
cc_log ( LOG_WARNING , " Unknown option '%c' for receivefax. \n " ,
* options ) ;
}
options + + ;
}
capi_wait_for_answered ( i ) ;
i - > FaxState & = ~ CAPI_FAX_STATE_CONN ;
if ( ( i - > fFax = fopen ( filename , " wb " ) ) = = NULL ) {
cc_log ( LOG_WARNING , " can't create fax output file (%s) \n " , strerror ( errno ) ) ;
return - 1 ;
}
i - > FaxState | = CAPI_FAX_STATE_ACTIVE ;
setup_b3_basic_fax_config ( & b3conf , FAX_SFF_FORMAT , stationid , headline ) ;
i - > bproto = CC_BPROTO_FAX3_BASIC ;
switch ( i - > state ) {
case CAPI_STATE_ALERTING :
case CAPI_STATE_DID :
case CAPI_STATE_INCALL :
capi_send_answer ( c , ( _cstruct ) & b3conf ) ;
break ;
case CAPI_STATE_CONNECTED :
capi_change_bchan_fax ( i , & b3conf ) ;
break ;
default :
i - > FaxState & = ~ CAPI_FAX_STATE_ACTIVE ;
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " receive fax in wrong state (%d) \n " ,
i - > state ) ;
return - 1 ;
}
while ( capi_tell_fax_finish ( i ) ) {
if ( ast_safe_sleep_conditional ( c , 1000 , capi_tell_fax_finish , i ) ! = 0 ) {
/* we got a hangup */
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: hangup. \n " ) ;
break ;
}
}
cc_mutex_lock ( & i - > lock ) ;
res = ( i - > FaxState & CAPI_FAX_STATE_ERROR ) ? 1 : 0 ;
i - > FaxState & = ~ ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_ERROR ) ;
/* if the file has zero length */
if ( ftell ( i - > fFax ) = = 0L ) {
res = 1 ;
}
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " Closing fax file... \n " ) ;
fclose ( i - > fFax ) ;
i - > fFax = NULL ;
cc_mutex_unlock ( & i - > lock ) ;
if ( res ! = 0 ) {
cc_verbose ( 2 , 0 ,
VERBOSE_PREFIX_1 CC_MESSAGE_NAME
" receivefax: fax receive failed reason=0x%04x reasonB3=0x%04x \n " ,
i - > reason , i - > reasonb3 ) ;
if ( ! keepbadfax ) {
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " receivefax: removing fax file. \n " ) ;
unlink ( filename ) ;
}
} else {
cc_verbose ( 2 , 0 ,
VERBOSE_PREFIX_1 CC_MESSAGE_NAME " receivefax: fax receive successful. \n " ) ;
}
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , res ) ;
pbx_builtin_setvar_helper ( c , " FAXSTATUS " , buffer ) ;
return 0 ;
}
/*
* capicommand ' receivefax '
*/
static int pbx_capi_receive_fax ( struct ast_channel * c , char * data )
{
struct capi_pvt * i = get_active_plci ( c ) ;
int force_extended = 0 , force_no_extended = 0 ;
char * ldata_mem , * ldata ;
if ( ( i = = NULL ) | | ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & & ( i - > line_plci = = NULL ) ) ) {
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " receivefax requires resource PLCI \n " ) ;
return - 1 ;
}
if ( ! data | | ! * data ) { /* no data implies no filename or anything is present */
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " receivefax requires a filename \n " ) ;
capi_remove_nullif ( i ) ;
return - 1 ;
}
ldata_mem = ldata = strdup ( data ) ;
if ( ! ldata_mem ) {
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " out of memory \n " ) ;
capi_remove_nullif ( i ) ;
return - 1 ;
}
( void ) strsep ( & ldata , " | " ) ;
( void ) strsep ( & ldata , " | " ) ;
( void ) strsep ( & ldata , " | " ) ;
while ( ( ldata ) & & ( * ldata ) ) {
switch ( * ldata ) {
case ' X ' :
force_extended = 1 ;
force_no_extended = 0 ;
break ;
case ' x ' :
force_extended = 0 ;
force_no_extended = 1 ;
break ;
}
ldata + + ;
}
free ( ldata_mem ) ;
if ( ( force_extended ! = 0 ) & & ( capi_controllers [ i - > controller ] - > fax_t30_extended = = 0 ) ) {
force_extended = 0 ;
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " fax T.30 extended not available \n " ) ;
}
force_extended | = ( ( capi_controllers [ i - > controller ] - > divaExtendedFeaturesAvailable ! = 0 ) & & ( force_no_extended = = 0 ) ) ; /* Always use fax T.30 extended for Diva */
force_extended | = ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) ; /* always use fax T.30 extended for clear channel fax */
if ( force_extended ! = 0 ) {
return ( pbx_capi_receive_extended_fax ( c , i , data ) ) ;
} else {
return ( pbx_capi_receive_basic_fax ( c , i , data ) ) ;
}
}
2009-07-20 12:31:24 +00:00
static void clear_channel_fax_loop ( struct ast_channel * c , struct capi_pvt * i )
2009-05-02 13:21:17 +00:00
{
struct ast_frame * f ;
int ms ;
int exception ;
int ready_fd ;
int waitfd ;
int nfds = 1 ;
struct ast_channel * rchan ;
struct ast_channel * chan = c ;
ast_indicate ( chan , - 1 ) ;
waitfd = i - > readerfd ;
ast_set_read_format ( chan , capi_capability ) ;
ast_set_write_format ( chan , capi_capability ) ;
while ( capi_tell_fax_finish ( i ) ) {
ready_fd = 0 ;
ms = 10 ;
errno = 0 ;
exception = 0 ;
rchan = ast_waitfor_nandfds ( & chan , 1 , & waitfd , nfds , & exception , & ready_fd , & ms ) ;
if ( rchan ) {
f = ast_read ( chan ) ;
if ( ! f ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: clear channel fax: no frame, hangup. \n " ,
i - > vname ) ;
break ;
}
2010-03-01 17:59:31 +00:00
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & &
( FRAME_SUBCLASS_INTEGER ( f - > subclass ) = = AST_CONTROL_HANGUP ) ) {
2009-05-02 13:21:17 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: clear channel fax: hangup frame. \n " ,
i - > vname ) ;
ast_frfree ( f ) ;
break ;
} else if ( f - > frametype = = AST_FRAME_VOICE ) {
cc_verbose ( 5 , 1 , VERBOSE_PREFIX_3 " %s: clear channel fax: voice frame. \n " ,
i - > vname ) ;
capi_write_frame ( i , f ) ;
} else if ( f - > frametype = = AST_FRAME_NULL ) {
/* ignore NULL frame */
cc_verbose ( 5 , 1 , VERBOSE_PREFIX_3 " %s: cler channel fax: NULL frame, ignoring. \n " ,
i - > vname ) ;
} else {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: cler channel fax: unhandled frame %d/%d. \n " ,
2010-03-01 17:59:31 +00:00
i - > vname , f - > frametype , FRAME_SUBCLASS_INTEGER ( f - > subclass ) ) ;
2009-05-02 13:21:17 +00:00
}
ast_frfree ( f ) ;
} else if ( ready_fd = = i - > readerfd ) {
if ( exception ) {
cc_verbose ( 1 , 0 , VERBOSE_PREFIX_3 " %s: cler channel fax: exception on readerfd \n " ,
i - > vname ) ;
break ;
}
f = capi_read_pipeframe ( i ) ;
if ( f - > frametype = = AST_FRAME_VOICE ) {
ast_write ( chan , f ) ;
}
/* ignore other nullplci frames */
} else {
if ( ( ready_fd < 0 ) & & ms ) {
if ( errno = = 0 | | errno = = EINTR )
continue ;
cc_log ( LOG_WARNING , " %s: Wait failed (%s). \n " ,
chan - > name , strerror ( errno ) ) ;
break ;
}
}
}
}
2006-06-27 14:54:03 +00:00
/*
* capicommand ' sendfax '
*/
2009-08-06 08:49:25 +00:00
static int pbx_capi_send_extended_fax ( struct ast_channel * c , struct capi_pvt * i , char * data )
2006-06-27 14:54:03 +00:00
{
int res = 0 ;
2009-04-08 22:44:14 +00:00
char * filename , * stationid , * headline , * options ;
2006-06-27 14:54:03 +00:00
B3_PROTO_FAXG3 b3conf ;
char buffer [ CAPI_MAX_STRING ] ;
2009-04-08 22:44:14 +00:00
int file_format ;
unsigned short b3_protocol_options = 0 ;
2009-04-09 11:02:48 +00:00
int extended_resolution = 0 ;
2006-06-27 14:54:03 +00:00
filename = strsep ( & data , " | " ) ;
stationid = strsep ( & data , " | " ) ;
2009-04-08 22:44:14 +00:00
headline = strsep ( & data , " | " ) ;
options = data ;
2006-06-27 14:54:03 +00:00
if ( ! stationid )
stationid = emptyid ;
if ( ! headline )
headline = emptyid ;
2009-04-08 22:44:14 +00:00
if ( ! options )
options = emptyid ;
2006-06-27 14:54:03 +00:00
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: '%s' '%s' '%s' \n " ,
2007-04-05 19:33:01 +00:00
filename , stationid , headline ) ;
2006-07-08 20:22:15 +00:00
capi_wait_for_answered ( i ) ;
2006-06-27 14:54:03 +00:00
if ( ( i - > fFax = fopen ( filename , " rb " ) ) = = NULL ) {
cc_log ( LOG_WARNING , " can't open fax file (%s) \n " , strerror ( errno ) ) ;
2009-05-02 13:21:17 +00:00
capi_remove_nullif ( i ) ;
2006-06-27 14:54:03 +00:00
return - 1 ;
}
2009-04-08 22:44:14 +00:00
/*
Get file format
2009-04-10 07:23:20 +00:00
*/
2009-04-08 22:44:14 +00:00
{
unsigned char tmp [ 2 ] = { 0 , 0 } ;
2009-04-10 07:23:20 +00:00
if ( fread ( tmp , 1 , 2 , i - > fFax ) ! = 2 ) {
2009-04-08 22:44:14 +00:00
cc_log ( LOG_WARNING , " can't read fax file (%s) \n " , strerror ( errno ) ) ;
2009-04-10 07:23:20 +00:00
fclose ( i - > fFax ) ;
2009-04-08 22:44:14 +00:00
i - > fFax = 0 ;
2009-05-02 13:21:17 +00:00
capi_remove_nullif ( i ) ;
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-04-08 22:44:14 +00:00
}
2009-04-10 07:23:20 +00:00
if ( ( tmp [ 0 ] = = 0x53 ) & & ( tmp [ 1 ] = = 0x66 ) ) { /* SFF */
2009-04-08 22:44:14 +00:00
file_format = FAX_SFF_FORMAT ;
2009-04-10 07:23:20 +00:00
} else if ( ( tmp [ 0 ] = = 0xff ) & & ( tmp [ 1 ] = = 0xd8 ) ) { /* JPEG */
2009-04-08 22:44:14 +00:00
file_format = FAX_NATIVE_FILE_TRANSFER_FORMAT ;
b3_protocol_options | = 0x0400 ;
2009-04-10 07:23:20 +00:00
} else if ( ( tmp [ 0 ] = = 0xff ) & & ( tmp [ 1 ] = = 0xa8 ) ) { /* T.43 */
2009-04-08 22:44:14 +00:00
file_format = FAX_NATIVE_FILE_TRANSFER_FORMAT ;
b3_protocol_options | = 0x0800 ;
} else { /* TXT */
file_format = FAX_ASCII_FORMAT ;
}
}
2009-04-10 07:23:20 +00:00
rewind ( i - > fFax ) ;
2009-04-08 22:44:14 +00:00
/* parse the options */
while ( ( options ) & & ( * options ) ) {
switch ( * options ) {
case ' f ' : /* use Fine resolution */
cc_verbose ( 3 , 1 ,
2009-08-06 08:49:25 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: Use Fine resolution \n " ) ;
2009-04-10 07:23:20 +00:00
b3_protocol_options | = 0x0001 ;
2009-04-08 22:44:14 +00:00
break ;
2009-04-09 11:02:48 +00:00
case ' u ' : /* use Fine resolution */
cc_verbose ( 3 , 1 ,
2009-08-06 08:49:25 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: Allow Super/Ultra fine resolution \n " ) ;
2009-04-10 07:23:20 +00:00
b3_protocol_options | = 0x0001 ;
2009-04-09 11:02:48 +00:00
extended_resolution = 1 ;
break ;
case ' j ' : /* enable JPEG encoding */
2009-04-08 22:44:14 +00:00
case ' t ' : /* diasble T.85 encoding */
cc_verbose ( 3 , 1 ,
2009-08-06 08:49:25 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: Do not use T.85 coding \n " ) ;
2009-04-10 07:23:20 +00:00
b3_protocol_options | = 0x1000 ;
2009-04-08 22:44:14 +00:00
break ;
case ' e ' : /* disable ECM encoding */
cc_verbose ( 3 , 1 ,
2009-08-06 08:49:25 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: Do not use ECM \n " ) ;
2009-04-10 07:23:20 +00:00
b3_protocol_options | = 0x8000 ;
2009-04-08 22:44:14 +00:00
break ;
case ' m ' : /* disable MMR encoding */
cc_verbose ( 3 , 1 ,
2009-08-06 08:49:25 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: do not use MMR (T.6) coding \n " ) ;
2009-04-10 07:23:20 +00:00
b3_protocol_options | = 0x4000 ;
2009-04-08 22:44:14 +00:00
break ;
case ' d ' : /* disable MR encoding */
cc_verbose ( 3 , 1 ,
2009-08-06 08:49:25 +00:00
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: do not use MR (2D) coding \n " ) ;
2009-04-10 07:23:20 +00:00
b3_protocol_options | = 0x2000 ;
2009-04-08 22:44:14 +00:00
break ;
2009-08-06 08:49:25 +00:00
case ' X ' :
case ' x ' :
break ;
2009-04-08 22:44:14 +00:00
default :
2009-08-06 08:49:25 +00:00
cc_log ( LOG_WARNING , " Unknown option '%c' for sendfax. \n " ,
2009-04-08 22:44:14 +00:00
* options ) ;
}
options + + ;
}
2009-04-09 11:02:48 +00:00
if ( capi_controllers [ i - > controller ] - > divaExtendedFeaturesAvailable ! = 0 & & extended_resolution ! = 0 ) {
/*
Per PLCI control is available only starting with Diva 9.0 SU1
Without per PLCI control setting is applied to controller
2009-04-10 07:23:20 +00:00
*/
2009-04-09 11:02:48 +00:00
capi_sendf ( NULL , 0 , CAPI_MANUFACTURER_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2009-04-10 07:23:20 +00:00
" dw(d) " , _DI_MANU_ID , _DI_OPTIONS_REQUEST , 0x00000040L ) ;
2009-04-09 11:02:48 +00:00
}
2009-05-02 13:21:17 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
i - > FaxState | = ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_SENDMODE ) ;
}
2009-04-08 22:44:14 +00:00
setup_b3_fax_config ( & b3conf , file_format , stationid , headline , b3_protocol_options ) ;
2006-06-27 14:54:03 +00:00
i - > bproto = CC_BPROTO_FAXG3 ;
switch ( i - > state ) {
case CAPI_STATE_ALERTING :
case CAPI_STATE_DID :
case CAPI_STATE_INCALL :
capi_send_answer ( c , ( _cstruct ) & b3conf ) ;
break ;
case CAPI_STATE_CONNECTED :
2009-05-02 13:21:17 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) {
capi_wait_for_b3_up ( i ) ;
i - > FaxState | = ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_SENDMODE ) ;
}
capi_change_bchan_fax ( i , & b3conf ) ;
2006-06-27 14:54:03 +00:00
break ;
default :
i - > FaxState & = ~ CAPI_FAX_STATE_ACTIVE ;
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " send fax in wrong state (%d) \n " ,
2006-06-27 14:54:03 +00:00
i - > state ) ;
2009-05-02 13:21:17 +00:00
capi_remove_nullif ( i ) ;
2006-06-27 14:54:03 +00:00
return - 1 ;
}
2009-05-02 13:21:17 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
while ( capi_tell_fax_finish ( i ) ) {
if ( ast_safe_sleep_conditional ( c , 1000 , capi_tell_fax_finish , i ) ! = 0 ) {
/* we got a hangup */
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: hangup. \n " ) ;
break ;
}
2006-12-02 12:35:30 +00:00
}
2009-05-02 13:21:17 +00:00
} else {
clear_channel_fax_loop ( c , i ) ;
2006-12-02 12:35:30 +00:00
}
cc_mutex_lock ( & i - > lock ) ;
2006-06-27 14:54:03 +00:00
res = ( i - > FaxState & CAPI_FAX_STATE_ERROR ) ? 1 : 0 ;
i - > FaxState & = ~ ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_ERROR ) ;
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " Closing fax file... \n " ) ;
fclose ( i - > fFax ) ;
i - > fFax = NULL ;
2006-12-02 12:35:30 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2006-06-27 14:54:03 +00:00
if ( res ! = 0 ) {
cc_verbose ( 2 , 0 ,
2008-02-24 12:57:52 +00:00
VERBOSE_PREFIX_1 CC_MESSAGE_NAME
" sendfax: fax send failed reason=0x%04x reasonB3=0x%04x \n " ,
2006-06-27 14:54:03 +00:00
i - > reason , i - > reasonb3 ) ;
} else {
cc_verbose ( 2 , 0 ,
2008-02-24 12:57:52 +00:00
VERBOSE_PREFIX_1 CC_MESSAGE_NAME " sendfax: fax sent successful. \n " ) ;
2006-06-27 14:54:03 +00:00
}
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , res ) ;
pbx_builtin_setvar_helper ( c , " FAXSTATUS " , buffer ) ;
2009-05-02 13:21:17 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) {
struct timespec abstime ;
cc_mutex_lock ( & i - > lock ) ;
/* wait for the B3 layer to go down */
if ( ( i - > isdnstate & ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ) ) {
i - > waitevent = CAPI_WAITEVENT_B3_DOWN ;
abstime . tv_sec = time ( NULL ) + 2 ;
abstime . tv_nsec = 0 ;
cc_verbose ( 4 , 1 , " %s: wait for b3 down. \n " ,
i - > vname ) ;
if ( ast_cond_timedwait ( & i - > event_trigger , & i - > lock , & abstime ) ! = 0 ) {
cc_log ( LOG_WARNING , " %s: timed out waiting for b3 down. \n " ,
i - > vname ) ;
} else {
cc_verbose ( 4 , 1 , " %s: cond signal received for b3 down. \n " ,
i - > vname ) ;
}
}
cc_mutex_unlock ( & i - > lock ) ;
}
capi_remove_nullif ( i ) ;
2006-06-27 14:54:03 +00:00
return 0 ;
2005-08-14 12:32:18 +00:00
}
2009-08-06 08:49:25 +00:00
static int pbx_capi_send_basic_fax ( struct ast_channel * c , struct capi_pvt * i , char * data )
{
int res = 0 ;
char * filename , * stationid , * headline , * options ;
B3_PROTO_FAXG3 b3conf ;
char buffer [ CAPI_MAX_STRING ] ;
filename = strsep ( & data , " | " ) ;
stationid = strsep ( & data , " | " ) ;
headline = strsep ( & data , " | " ) ;
options = data ;
if ( ! stationid )
stationid = emptyid ;
if ( ! headline )
headline = emptyid ;
while ( ( options ) & & ( * options ) ) {
switch ( * options ) {
case ' f ' : /* use Fine resolution */
case ' u ' : /* use Fine resolution */
break ;
case ' j ' : /* enable JPEG encoding */
case ' t ' : /* diasble T.85 encoding */
case ' e ' : /* disable ECM encoding */
case ' m ' : /* disable MMR encoding */
case ' d ' : /* disable MR encoding */
cc_log ( LOG_WARNING , " Option '%c' requires B3 fax T.30 extended. \n " ,
* options ) ;
break ;
case ' X ' :
case ' x ' :
break ;
default :
cc_log ( LOG_WARNING , " Unknown option '%c' for receivefax. \n " ,
* options ) ;
}
options + + ;
}
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: '%s' '%s' '%s' \n " ,
filename , stationid , headline ) ;
capi_wait_for_answered ( i ) ;
if ( ( i - > fFax = fopen ( filename , " rb " ) ) = = NULL ) {
cc_log ( LOG_WARNING , " can't open fax file (%s) \n " , strerror ( errno ) ) ;
return - 1 ;
}
i - > FaxState | = ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_SENDMODE ) ;
setup_b3_basic_fax_config ( & b3conf , FAX_SFF_FORMAT , stationid , headline ) ;
i - > bproto = CC_BPROTO_FAX3_BASIC ;
switch ( i - > state ) {
case CAPI_STATE_ALERTING :
case CAPI_STATE_DID :
case CAPI_STATE_INCALL :
capi_send_answer ( c , ( _cstruct ) & b3conf ) ;
break ;
case CAPI_STATE_CONNECTED :
capi_change_bchan_fax ( i , & b3conf ) ;
break ;
default :
i - > FaxState & = ~ CAPI_FAX_STATE_ACTIVE ;
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " send fax in wrong state (%d) \n " ,
i - > state ) ;
return - 1 ;
}
while ( capi_tell_fax_finish ( i ) ) {
if ( ast_safe_sleep_conditional ( c , 1000 , capi_tell_fax_finish , i ) ! = 0 ) {
/* we got a hangup */
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_3 CC_MESSAGE_NAME " sendfax: hangup. \n " ) ;
break ;
}
}
cc_mutex_lock ( & i - > lock ) ;
res = ( i - > FaxState & CAPI_FAX_STATE_ERROR ) ? 1 : 0 ;
i - > FaxState & = ~ ( CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_ERROR ) ;
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " Closing fax file... \n " ) ;
fclose ( i - > fFax ) ;
i - > fFax = NULL ;
cc_mutex_unlock ( & i - > lock ) ;
if ( res ! = 0 ) {
cc_verbose ( 2 , 0 ,
VERBOSE_PREFIX_1 CC_MESSAGE_NAME
" sendfax: fax send failed reason=0x%04x reasonB3=0x%04x \n " ,
i - > reason , i - > reasonb3 ) ;
} else {
cc_verbose ( 2 , 0 ,
VERBOSE_PREFIX_1 CC_MESSAGE_NAME " sendfax: fax sent successful. \n " ) ;
}
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , res ) ;
pbx_builtin_setvar_helper ( c , " FAXSTATUS " , buffer ) ;
return 0 ;
}
static int pbx_capi_send_fax ( struct ast_channel * c , char * data )
{
struct capi_pvt * i = get_active_plci ( c ) ;
int force_extended = 0 , force_no_extended = 0 ;
char * ldata_mem , * ldata ;
if ( ( i = = NULL ) | | ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & & ( i - > line_plci = = NULL ) ) ) {
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " sendfax requires resource PLCI \n " ) ;
return - 1 ;
}
if ( ! data | | ! * data ) { /* no data implies no filename or anything is present */
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " sendfax requires a filename \n " ) ;
capi_remove_nullif ( i ) ;
return - 1 ;
}
ldata_mem = ldata = strdup ( data ) ;
if ( ! ldata_mem ) {
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " out of memory \n " ) ;
capi_remove_nullif ( i ) ;
return - 1 ;
}
( void ) strsep ( & ldata , " | " ) ;
( void ) strsep ( & ldata , " | " ) ;
( void ) strsep ( & ldata , " | " ) ;
while ( ( ldata ) & & ( * ldata ) ) {
switch ( * ldata ) {
case ' X ' :
force_extended = 1 ;
force_no_extended = 0 ;
break ;
case ' x ' :
force_extended = 0 ;
force_no_extended = 1 ;
break ;
}
ldata + + ;
}
free ( ldata_mem ) ;
if ( ( force_extended ! = 0 ) & & ( capi_controllers [ i - > controller ] - > fax_t30_extended = = 0 ) ) {
force_extended = 0 ;
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " fax T.30 extended not available \n " ) ;
}
force_extended | = ( ( capi_controllers [ i - > controller ] - > divaExtendedFeaturesAvailable ! = 0 ) & & ( force_no_extended = = 0 ) ) ; /* Always use fax T.30 extended for Diva */
force_extended | = ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) ; /* always use fax T.30 extended for clear channel fax */
if ( force_extended ! = 0 ) {
return ( pbx_capi_send_extended_fax ( c , i , data ) ) ;
} else {
return ( pbx_capi_send_basic_fax ( c , i , data ) ) ;
}
}
2005-06-04 14:28:52 +00:00
/*
* Fax guard tone - - Handle and return NULL
*/
2006-06-11 13:15:18 +00:00
static void capi_handle_dtmf_fax ( struct capi_pvt * i )
2005-06-04 14:28:52 +00:00
{
2006-06-11 13:15:18 +00:00
struct ast_channel * c = i - > owner ;
2005-06-04 14:28:52 +00:00
2005-11-20 16:15:33 +00:00
if ( ! c ) {
2007-05-01 14:26:39 +00:00
/* no channel, ignore */
2005-07-17 19:01:14 +00:00
return ;
}
2006-06-11 13:15:18 +00:00
if ( i - > FaxState & CAPI_FAX_STATE_HANDLED ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_DEBUG , " Fax already handled \n " ) ;
2005-06-04 14:28:52 +00:00
return ;
}
2006-06-11 13:15:18 +00:00
i - > FaxState | = CAPI_FAX_STATE_HANDLED ;
2006-05-27 12:49:57 +00:00
2006-06-11 13:15:18 +00:00
if ( ( ( i - > outgoing = = 1 ) & & ( ! ( i - > FaxState & CAPI_FAX_DETECT_OUTGOING ) ) ) | |
( ( i - > outgoing = = 0 ) & & ( ! ( i - > FaxState & CAPI_FAX_DETECT_INCOMING ) ) ) ) {
2006-05-27 12:49:57 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: Fax detected, but not configured for redirection \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-05-27 12:49:57 +00:00
return ;
}
2008-06-29 11:33:46 +00:00
if ( ( i - > faxdetecttime > 0 ) & & ( c - > cdr ) ) {
struct timeval now ;
gettimeofday ( & now , NULL ) ;
if ( ( c - > cdr - > start . tv_sec + i - > faxdetecttime ) < now . tv_sec ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3
" %s: Fax detected after %ld seconds, limit %u - ignored \n " ,
i - > vname , ( long ) ( now . tv_sec - c - > cdr - > start . tv_sec ) ,
i - > faxdetecttime ) ;
return ;
}
}
2005-06-04 14:28:52 +00:00
2005-11-20 16:15:33 +00:00
if ( ! strcmp ( c - > exten , " fax " ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_DEBUG , " Already in a fax extension, not redirecting \n " ) ;
2005-06-04 14:28:52 +00:00
return ;
}
2005-09-27 17:52:13 +00:00
2006-06-11 13:15:18 +00:00
if ( ! ast_exists_extension ( c , c - > context , " fax " , 1 , i - > cid ) ) {
2008-03-19 18:29:37 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3
" Fax tone detected, but no fax extension for %s in context '%s' \n " ,
c - > name , c - > context ) ;
2005-06-04 14:28:52 +00:00
return ;
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " %s: Redirecting %s to fax extension \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-06-04 14:28:52 +00:00
2007-04-08 21:20:47 +00:00
capi_channel_task ( c , CAPI_CHANNEL_TASK_GOTOFAX ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-04 14:28:52 +00:00
}
2005-06-02 18:47:35 +00:00
/*
* see if did matches
*/
static int search_did ( struct ast_channel * c )
{
/*
* Returns
* - 1 = Failure
* 0 = Match
* 1 = possible match
*/
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-06-02 18:47:35 +00:00
char * exten ;
2005-08-18 07:25:17 +00:00
if ( ! strlen ( i - > dnid ) & & ( i - > immediate ) ) {
exten = " s " ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: %s: %s matches in context %s for immediate \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name , exten , c - > context ) ;
2005-08-18 07:25:17 +00:00
} else {
if ( strlen ( i - > dnid ) < strlen ( i - > incomingmsn ) )
return 0 ;
exten = i - > dnid ;
}
2005-06-02 18:47:35 +00:00
2005-09-27 17:42:28 +00:00
if ( ast_exists_extension ( NULL , c - > context , exten , 1 , i - > cid ) ) {
2005-06-02 18:47:35 +00:00
c - > priority = 1 ;
2006-01-28 19:42:44 +00:00
cc_copy_string ( c - > exten , exten , sizeof ( c - > exten ) ) ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: %s: %s matches in context %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name , exten , c - > context ) ;
2005-06-02 18:47:35 +00:00
return 0 ;
}
2005-09-27 17:42:28 +00:00
if ( ast_canmatch_extension ( NULL , c - > context , exten , 1 , i - > cid ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: %s: %s would possibly match in context %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name , exten , c - > context ) ;
2005-06-02 18:47:35 +00:00
return 1 ;
}
return - 1 ;
}
/*
2005-06-05 19:48:21 +00:00
* Progress Indicator
2005-06-02 18:47:35 +00:00
*/
2005-11-20 16:15:33 +00:00
static void handle_progress_indicator ( _cmsg * CMSG , unsigned int PLCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2005-06-05 19:48:21 +00:00
if ( INFO_IND_INFOELEMENT ( CMSG ) [ 0 ] < 2 ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: Progress description missing \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-02 18:47:35 +00:00
return ;
}
2005-06-05 19:48:21 +00:00
switch ( INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] & 0x7f ) {
case 0x01 :
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: Not end-to-end ISDN \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x02 :
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: Destination is non ISDN \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-17 19:01:14 +00:00
i - > calledPartyIsISDN = 0 ;
2005-06-05 19:48:21 +00:00
break ;
case 0x03 :
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: Origination is non ISDN \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x04 :
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: Call returned to ISDN \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x05 :
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: Interworking occured \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x08 :
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: In-band information available \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
default :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: Unknown progress description %02x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] ) ;
2005-06-05 19:48:21 +00:00
}
2005-09-04 13:51:50 +00:00
send_progress ( i ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-05 19:48:21 +00:00
}
2005-06-02 18:47:35 +00:00
2005-07-22 10:40:51 +00:00
/*
* if the dnid matches , start the pbx
*/
2005-11-20 16:15:33 +00:00
static void start_pbx_on_match ( struct capi_pvt * i , unsigned int PLCI , _cword MessageNumber )
2005-07-22 10:40:51 +00:00
{
2006-07-08 16:29:27 +00:00
struct ast_channel * c ;
2005-07-22 10:40:51 +00:00
2006-07-08 16:29:27 +00:00
c = i - > owner ;
2006-07-05 12:23:58 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_PBX_DONT ) ) {
/* we already found non-match here */
return ;
}
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_PBX ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: pbx already started on channel %s \n " ,
2006-07-08 16:29:27 +00:00
i - > vname , c - > name ) ;
return ;
}
/* check for internal pickup extension first */
if ( ! strcmp ( i - > dnid , ast_pickup_ext ( ) ) ) {
i - > isdnstate | = CAPI_ISDN_STATE_PBX ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Pickup extension '%s' found. \n " ,
i - > vname , i - > dnid ) ;
cc_copy_string ( c - > exten , i - > dnid , sizeof ( c - > exten ) ) ;
pbx_capi_alert ( c ) ;
capi_channel_task ( c , CAPI_CHANNEL_TASK_PICKUP ) ;
2005-09-26 11:35:13 +00:00
return ;
}
2007-04-23 18:47:49 +00:00
switch ( search_did ( c ) ) {
2005-07-22 10:40:51 +00:00
case 0 : /* match */
2005-09-26 11:35:13 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_PBX ;
2006-07-08 16:29:27 +00:00
ast_setstate ( c , AST_STATE_RING ) ;
2007-04-23 18:47:49 +00:00
if ( ast_pbx_start ( c ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " %s: Unable to start pbx on channel! \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-07-08 16:29:27 +00:00
capi_channel_task ( c , CAPI_CHANNEL_TASK_HANGUP ) ;
2005-07-22 10:40:51 +00:00
} else {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_2 " Started pbx on channel %s \n " ,
2006-07-08 16:29:27 +00:00
c - > name ) ;
2005-07-22 10:40:51 +00:00
}
break ;
case 1 :
/* would possibly match */
2005-11-20 16:15:33 +00:00
if ( i - > isdnmode = = CAPI_ISDNMODE_DID )
2005-09-26 11:35:13 +00:00
break ;
/* fall through for MSN mode, because there won't be a longer msn */
2005-07-22 10:40:51 +00:00
case - 1 :
default :
/* doesn't match */
2006-07-05 12:23:58 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_PBX_DONT ; /* don't try again */
2005-12-08 22:06:16 +00:00
cc_log ( LOG_NOTICE , " %s: did not find exten for '%s', ignoring call. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > dnid ) ;
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , PLCI , MessageNumber ,
2007-04-29 14:00:32 +00:00
" w()()()()() " , 1 /* ignore */ ) ;
2005-07-22 10:40:51 +00:00
}
2005-09-11 13:35:19 +00:00
return ;
2005-07-22 10:40:51 +00:00
}
2005-06-05 19:48:21 +00:00
/*
* Called Party Number via INFO_IND
*/
2007-09-02 15:41:06 +00:00
static void capidev_handle_did_digits ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI ,
struct capi_pvt * i , unsigned int skip )
2005-06-05 19:48:21 +00:00
{
char * did ;
2006-04-03 20:02:01 +00:00
struct ast_frame fr = { AST_FRAME_NULL , } ;
2005-07-17 19:01:14 +00:00
int a ;
2005-06-02 18:47:35 +00:00
2005-07-17 19:01:14 +00:00
if ( ! i - > owner ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " No channel for interface! \n " ) ;
2005-06-05 19:48:21 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
2005-06-05 19:48:21 +00:00
2005-07-17 19:01:14 +00:00
if ( i - > state ! = CAPI_STATE_DID ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: INFO_IND DID digits not used in this state. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-02 18:47:35 +00:00
return ;
}
2005-06-05 19:48:21 +00:00
2007-09-02 15:41:06 +00:00
did = capi_number ( INFO_IND_INFOELEMENT ( CMSG ) , skip ) ;
2005-10-01 09:52:46 +00:00
if ( ( ! ( i - > isdnstate & CAPI_ISDN_STATE_DID ) ) & &
( strlen ( i - > dnid ) & & ! strcasecmp ( i - > dnid , did ) ) ) {
did = NULL ;
2005-06-05 19:48:21 +00:00
}
2005-10-01 09:52:46 +00:00
2007-09-02 15:41:06 +00:00
if ( ( did ) & & ( strlen ( i - > dnid ) < ( sizeof ( i - > dnid ) - 1 ) ) ) {
2007-10-21 15:08:50 +00:00
if ( ( ! strlen ( i - > dnid ) ) & & ( INFO_IND_INFONUMBER ( CMSG ) = = 0x002c ) ) {
2007-09-02 15:41:06 +00:00
/* start of keypad */
strcat ( i - > dnid , " K " ) ;
}
2005-10-01 09:52:46 +00:00
strcat ( i - > dnid , did ) ;
2007-09-02 15:41:06 +00:00
}
2005-10-01 09:52:46 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_DID ;
2005-08-10 19:19:16 +00:00
update_channel_name ( i ) ;
2005-07-17 19:01:14 +00:00
if ( i - > owner - > pbx ! = NULL ) {
2008-12-11 09:43:02 +00:00
if ( did ) {
/* we are already in pbx, so we send the digits as dtmf */
for ( a = 0 ; a < strlen ( did ) ; a + + ) {
fr . frametype = AST_FRAME_DTMF ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = did [ a ] ;
2008-12-11 09:43:02 +00:00
local_queue_frame ( i , & fr ) ;
}
}
2005-07-17 19:01:14 +00:00
return ;
}
2005-07-22 10:40:51 +00:00
2005-09-11 13:35:19 +00:00
start_pbx_on_match ( i , PLCI , HEADER_MSGNUM ( CMSG ) ) ;
return ;
2005-06-05 19:48:21 +00:00
}
2005-07-13 12:31:06 +00:00
/*
* send control according to cause code
*/
2007-04-29 22:28:30 +00:00
void capi_queue_cause_control ( struct capi_pvt * i , int control )
2005-07-13 12:31:06 +00:00
{
2010-03-09 12:21:52 +00:00
struct ast_frame fr = { AST_FRAME_CONTROL , } ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_HANGUP ;
2005-07-13 12:31:06 +00:00
2005-07-17 19:01:14 +00:00
if ( ( i - > owner ) & & ( control ) ) {
int cause = i - > owner - > hangupcause ;
2005-08-12 17:12:11 +00:00
if ( cause = = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION ) {
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_CONGESTION ;
2005-08-12 17:12:11 +00:00
} else if ( ( cause ! = AST_CAUSE_NO_USER_RESPONSE ) & &
( cause ! = AST_CAUSE_NO_ANSWER ) ) {
2005-07-13 12:31:06 +00:00
/* not NOANSWER */
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_BUSY ;
2005-07-13 12:31:06 +00:00
}
}
2006-04-03 20:02:01 +00:00
local_queue_frame ( i , & fr ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-07-13 12:31:06 +00:00
}
2005-06-05 19:48:21 +00:00
/*
* Disconnect via INFO_IND
*/
2006-06-09 21:48:24 +00:00
static void capidev_handle_info_disconnect ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-05 19:48:21 +00:00
{
2005-09-15 19:11:45 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_DISCONNECT ;
2007-04-22 11:24:25 +00:00
if ( ( PLCI = = i - > onholdPLCI ) | | ( i - > isdnstate & CAPI_ISDN_STATE_ECT ) ) {
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: Disconnect onhold/ECT call \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-02 18:47:35 +00:00
/* the caller onhold hung up (or ECTed away) */
/* send a disconnect_req , we cannot hangup the channel here!!! */
2009-04-27 20:02:46 +00:00
capi_send_disconnect ( PLCI ) ;
2005-06-02 18:47:35 +00:00
return ;
}
/* case 1: B3 on success or no B3 at all */
2005-11-20 16:15:33 +00:00
if ( ( i - > doB3 ! = CAPI_B3_ALWAYS ) & & ( i - > outgoing = = 1 ) ) {
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: Disconnect case 1 \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2007-04-24 11:45:54 +00:00
if ( i - > state = = CAPI_STATE_CONNECTED ) {
2008-08-12 08:30:27 +00:00
if ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) {
/* in fax mode, we wait for DISCONNECT_B3_IND */
return ;
}
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 0 ) ;
2007-04-24 11:45:54 +00:00
} else {
2008-08-30 09:58:27 +00:00
if ( ( i - > fsetting & CAPI_FSETTING_STAYONLINE ) ) {
2007-04-24 11:45:54 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: stay-online hangup frame queued. \n " ,
i - > vname ) ;
i - > whentoqueuehangup = time ( NULL ) + 1 ;
} else {
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 1 ) ;
2007-04-24 11:45:54 +00:00
}
}
2005-06-02 18:47:35 +00:00
return ;
}
/* case 2: we are doing B3, and receive the 0x8045 after a successful call */
2005-11-20 16:15:33 +00:00
if ( ( i - > doB3 ! = CAPI_B3_DONT ) & &
2005-12-08 22:06:16 +00:00
( i - > state = = CAPI_STATE_CONNECTED ) & & ( i - > outgoing = = 1 ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: Disconnect case 2 \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 1 ) ;
2005-06-02 18:47:35 +00:00
return ;
}
/*
* case 3 : this channel is an incoming channel ! the user hung up !
* it is much better to hangup now instead of waiting for a timeout and
* network caused DISCONNECT_IND !
*/
2005-07-17 19:01:14 +00:00
if ( i - > outgoing = = 0 ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: Disconnect case 3 \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-05-27 12:49:57 +00:00
if ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) {
2005-09-24 19:42:07 +00:00
/* in fax mode, we just hangup */
2009-04-27 20:02:46 +00:00
capi_send_disconnect ( i - > PLCI ) ;
2005-06-05 19:48:21 +00:00
return ;
}
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 0 ) ;
2005-06-02 18:47:35 +00:00
return ;
}
/* case 4 (a.k.a. the italian case): B3 always. call is unsuccessful */
2005-12-08 22:06:16 +00:00
if ( ( i - > doB3 = = CAPI_B3_ALWAYS ) & & ( i - > outgoing = = 1 ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: Disconnect case 4 \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-12-08 22:06:16 +00:00
if ( ( i - > state = = CAPI_STATE_CONNECTED ) & &
( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 1 ) ;
2005-09-03 16:52:48 +00:00
return ;
}
2005-06-02 18:47:35 +00:00
/* wait for the 0x001e (PROGRESS), play audio and wait for a timeout from the network */
return ;
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: Other case DISCONNECT INFO_IND \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-05 19:48:21 +00:00
}
2005-06-02 18:47:35 +00:00
2005-08-28 14:14:23 +00:00
/*
* incoming call SETUP
*/
2006-06-09 21:48:24 +00:00
static void capidev_handle_setup_element ( _cmsg * CMSG , unsigned int PLCI , struct capi_pvt * i )
2005-08-28 14:14:23 +00:00
{
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_SETUP ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " %s: IE SETUP / SENDING-COMPLETE already received. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-08-29 15:21:12 +00:00
return ;
}
i - > isdnstate | = CAPI_ISDN_STATE_SETUP ;
2005-08-28 14:14:23 +00:00
if ( ! i - > owner ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " No channel for interface! \n " ) ;
2005-08-28 14:14:23 +00:00
return ;
}
2005-11-20 16:15:33 +00:00
if ( i - > isdnmode = = CAPI_ISDNMODE_DID ) {
2007-09-02 15:41:06 +00:00
if ( strlen ( i - > dnid ) | | ( i - > immediate ) ) {
2005-09-11 13:35:19 +00:00
start_pbx_on_match ( i , PLCI , HEADER_MSGNUM ( CMSG ) ) ;
2005-08-28 14:14:23 +00:00
}
} else {
2005-09-11 13:35:19 +00:00
start_pbx_on_match ( i , PLCI , HEADER_MSGNUM ( CMSG ) ) ;
2005-08-28 14:14:23 +00:00
}
2005-09-11 13:35:19 +00:00
return ;
2005-08-28 14:14:23 +00:00
}
2007-09-01 22:11:48 +00:00
/*
* Send info elements back to calling channel if in NT - mode
* ( this works with peerlink only )
*/
static void capidev_sendback_info ( struct capi_pvt * i , _cmsg * CMSG )
{
struct capi_pvt * i2 ;
unsigned char fac [ CAPI_MAX_FACILITYDATAARRAY_SIZE ] ;
unsigned char length ;
if ( ! ( i - > peer ) )
return ;
if ( i - > peer - > tech ! = & capi_tech )
return ;
i2 = CC_CHANNEL_PVT ( i - > peer ) ;
if ( ! ( i2 - > ntmode ) )
return ;
length = INFO_IND_INFOELEMENT ( CMSG ) [ 0 ] ;
fac [ 0 ] = length + 2 ;
fac [ 1 ] = ( unsigned char ) INFO_IND_INFONUMBER ( CMSG ) & 0xff ;
memcpy ( & fac [ 2 ] , & INFO_IND_INFOELEMENT ( CMSG ) [ 0 ] , length + 1 ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i2 - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s()) " ,
fac
) ;
}
2005-06-05 19:48:21 +00:00
/*
* CAPI INFO_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_info_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-05 19:48:21 +00:00
{
2006-04-03 20:02:01 +00:00
struct ast_frame fr = { AST_FRAME_NULL , } ;
2005-08-28 14:14:23 +00:00
char * p = NULL ;
2007-04-06 23:00:41 +00:00
char * p2 = NULL ;
2005-08-28 14:14:23 +00:00
int val = 0 ;
2005-06-02 18:47:35 +00:00
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_INFO_RESP , PLCI , HEADER_MSGNUM ( CMSG ) , " " ) ;
2005-06-02 18:47:35 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " INFO_IND " ) ;
2005-06-05 19:48:21 +00:00
switch ( INFO_IND_INFONUMBER ( CMSG ) ) {
case 0x0008 : /* Cause */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CAUSE %02x %02x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] , INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] ) ;
2005-07-17 19:01:14 +00:00
if ( i - > owner ) {
i - > owner - > hangupcause = INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] & 0x7f ;
2005-07-13 12:31:06 +00:00
}
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2005-06-05 19:48:21 +00:00
break ;
2005-08-12 18:08:56 +00:00
case 0x0014 : /* Call State */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CALL STATE %02x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] ) ;
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2005-08-12 18:08:56 +00:00
break ;
case 0x0018 : /* Channel Identification */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CHANNEL IDENTIFICATION %02x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] ) ;
2007-05-28 08:46:01 +00:00
if ( i - > doB3 = = CAPI_B3_ON_SUCCESS ) {
/* try early B3 Connect */
cc_start_b3 ( i ) ;
}
2005-07-12 19:50:54 +00:00
break ;
2005-07-13 12:31:06 +00:00
case 0x001c : /* Facility Q.932 */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element FACILITY \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-13 12:31:06 +00:00
break ;
2005-07-12 19:50:54 +00:00
case 0x001e : /* Progress Indicator */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element PI %02x %02x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] , INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] ) ;
2010-04-21 07:11:10 +00:00
if ( i - > owner ) {
char pibuf [ 16 ] ;
snprintf ( pibuf , sizeof ( pibuf ) - 1 , " %d " , INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] ) ;
pbx_builtin_setvar_helper ( i - > owner , " ISDNPI1 " , pibuf ) ;
snprintf ( pibuf , sizeof ( pibuf ) - 1 , " %d " , INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] ) ;
pbx_builtin_setvar_helper ( i - > owner , " ISDNPI2 " , pibuf ) ;
}
2005-07-17 19:01:14 +00:00
handle_progress_indicator ( CMSG , PLCI , i ) ;
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2005-06-05 19:48:21 +00:00
break ;
2005-08-19 16:16:19 +00:00
case 0x0027 : { /* Notification Indicator */
char * desc = " ? " ;
if ( INFO_IND_INFOELEMENT ( CMSG ) [ 0 ] > 0 ) {
switch ( INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] ) {
case 0 :
desc = " User suspended " ;
break ;
case 1 :
desc = " User resumed " ;
break ;
case 2 :
desc = " Bearer service changed " ;
break ;
2006-06-26 12:11:31 +00:00
case 0xf9 :
desc = " User put on hold " ;
break ;
case 0xfa :
desc = " User retrieved from hold " ;
break ;
2005-08-19 16:16:19 +00:00
}
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element NOTIFICATION INDICATOR '%s' (0x%02x) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , desc , INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] ) ;
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2005-08-19 16:16:19 +00:00
break ;
}
2005-06-05 19:48:21 +00:00
case 0x0028 : /* DSP */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element DSP \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x0029 : /* Date/Time */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element Date/Time %02d/%02d/%02d %02d:%02d \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ,
2005-06-05 19:48:21 +00:00
INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] , INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] ,
INFO_IND_INFOELEMENT ( CMSG ) [ 3 ] , INFO_IND_INFOELEMENT ( CMSG ) [ 4 ] ,
INFO_IND_INFOELEMENT ( CMSG ) [ 5 ] ) ;
2005-07-12 19:50:54 +00:00
break ;
2007-09-02 15:41:06 +00:00
case 0x002c : /* Keypad facility */
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element KEYPAD FACILITY \n " ,
i - > vname ) ;
/* we handle keypad digits as normal digits */
capidev_handle_did_digits ( CMSG , PLCI , NCCI , i , 0 ) ;
break ;
2005-07-12 19:50:54 +00:00
case 0x0070 : /* Called Party Number */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CALLED PARTY NUMBER \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2007-09-02 15:41:06 +00:00
capidev_handle_did_digits ( CMSG , PLCI , NCCI , i , 1 ) ;
2005-07-12 19:50:54 +00:00
break ;
case 0x0074 : /* Redirecting Number */
2005-08-25 11:22:34 +00:00
p = capi_number ( INFO_IND_INFOELEMENT ( CMSG ) , 3 ) ;
2005-08-28 14:14:23 +00:00
if ( INFO_IND_INFOELEMENT ( CMSG ) [ 0 ] > 2 ) {
val = INFO_IND_INFOELEMENT ( CMSG ) [ 3 ] & 0x0f ;
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element REDIRECTING NUMBER '%s' Reason=0x%02x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , p , val ) ;
2005-08-25 11:22:34 +00:00
if ( i - > owner ) {
2005-08-28 14:14:23 +00:00
char reasonbuf [ 16 ] ;
snprintf ( reasonbuf , sizeof ( reasonbuf ) - 1 , " %d " , val ) ;
2005-08-25 11:22:34 +00:00
pbx_builtin_setvar_helper ( i - > owner , " REDIRECTINGNUMBER " , p ) ;
2005-08-28 14:14:23 +00:00
pbx_builtin_setvar_helper ( i - > owner , " REDIRECTREASON " , reasonbuf ) ;
2006-02-12 20:58:02 +00:00
if ( i - > owner - > cid . cid_rdnis ) {
2006-02-13 15:11:56 +00:00
free ( i - > owner - > cid . cid_rdnis ) ;
2006-02-12 20:58:02 +00:00
}
2005-11-09 12:33:11 +00:00
i - > owner - > cid . cid_rdnis = strdup ( p ) ;
2005-08-25 11:22:34 +00:00
}
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2005-07-12 19:50:54 +00:00
break ;
2007-04-06 23:00:41 +00:00
case 0x0076 : /* Redirection Number */
p = capi_number ( INFO_IND_INFOELEMENT ( CMSG ) , 2 ) ;
p2 = emptyid ;
if ( INFO_IND_INFOELEMENT ( CMSG ) [ 0 ] > 1 ) {
val = INFO_IND_INFOELEMENT ( CMSG ) [ 1 ] & 0x70 ;
if ( val = = CAPI_ETSI_NPLAN_NATIONAL ) {
p2 = capi_national_prefix ;
} else if ( val = = CAPI_ETSI_NPLAN_INTERNAT ) {
p2 = capi_international_prefix ;
2008-07-07 20:29:19 +00:00
} else if ( val = = CAPI_ETSI_NPLAN_SUBSCRIBER ) {
p2 = capi_subscriber_prefix ;
2007-04-06 23:00:41 +00:00
}
}
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element REDIRECTION NUMBER '(%s)%s' \n " ,
i - > vname , p2 , p ) ;
if ( i - > owner ) {
char numberbuf [ 64 ] ;
snprintf ( numberbuf , sizeof ( numberbuf ) - 1 , " %s%s " , p2 , p ) ;
pbx_builtin_setvar_helper ( i - > owner , " REDIRECTIONNUMBER " , numberbuf ) ;
}
2007-09-01 22:11:48 +00:00
capidev_sendback_info ( i , CMSG ) ;
2007-04-06 23:00:41 +00:00
break ;
2005-08-31 07:22:32 +00:00
case 0x00a1 : /* Sending Complete */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element Sending Complete \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-06-09 21:48:24 +00:00
capidev_handle_setup_element ( CMSG , PLCI , i ) ;
2005-08-31 07:22:32 +00:00
break ;
2005-07-27 17:20:09 +00:00
case 0x4000 : /* CHARGE in UNITS */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CHARGE in UNITS \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-27 17:20:09 +00:00
break ;
case 0x4001 : /* CHARGE in CURRENCY */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CHARGE in CURRENCY \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-27 17:20:09 +00:00
break ;
2005-07-12 19:50:54 +00:00
case 0x8001 : /* ALERTING */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element ALERTING \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-01-28 20:22:52 +00:00
send_progress ( i ) ;
2005-07-12 19:50:54 +00:00
fr . frametype = AST_FRAME_CONTROL ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_RINGING ;
2006-04-03 20:02:01 +00:00
local_queue_frame ( i , & fr ) ;
2006-06-27 20:29:15 +00:00
if ( i - > owner )
ast_setstate ( i - > owner , AST_STATE_RINGING ) ;
2007-04-15 17:41:36 +00:00
2005-07-12 19:50:54 +00:00
break ;
case 0x8002 : /* CALL PROCEEDING */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CALL PROCEEDING \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-16 11:57:01 +00:00
fr . frametype = AST_FRAME_CONTROL ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_PROCEEDING ;
2006-04-03 20:02:01 +00:00
local_queue_frame ( i , & fr ) ;
2005-07-12 19:50:54 +00:00
break ;
case 0x8003 : /* PROGRESS */
2007-07-21 14:34:18 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_ISDNPROGRESS ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element PROGRESS \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-08-12 17:56:06 +00:00
/*
* rain - some networks will indicate a USER BUSY cause , send
* PROGRESS message , and then send audio for a busy signal for
* a moment before dropping the line . This delays sending the
* busy to the end user , so we explicitly check for it here .
*
* FIXME : should have better CAUSE handling so that we can
* distinguish things like status responses and invalid IE
* content messages ( from bad SetCallerID ) from errors actually
* related to the call setup ; then , we could always abort if we
* get a PROGRESS with a hangupcause set ( safer ? )
*/
2005-11-20 16:15:33 +00:00
if ( i - > doB3 = = CAPI_B3_DONT ) {
2005-08-28 14:14:23 +00:00
if ( ( i - > owner ) & &
( i - > owner - > hangupcause = = AST_CAUSE_USER_BUSY ) ) {
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 1 ) ;
2005-08-28 14:14:23 +00:00
break ;
}
2005-08-12 17:56:06 +00:00
}
2005-09-04 13:51:50 +00:00
send_progress ( i ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x8005 : /* SETUP */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element SETUP \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-06-09 21:48:24 +00:00
capidev_handle_setup_element ( CMSG , PLCI , i ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x8007 : /* CONNECT */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CONNECT \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x800d : /* SETUP ACK */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element SETUP ACK \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-17 19:01:14 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_SETUP_ACK ;
/* if some digits of initial CONNECT_REQ are left to dial */
if ( strlen ( i - > overlapdigits ) ) {
capi_send_info_digits ( i , i - > overlapdigits ,
strlen ( i - > overlapdigits ) ) ;
i - > overlapdigits [ 0 ] = 0 ;
i - > doOverlap = 0 ;
}
2005-06-05 19:48:21 +00:00
break ;
2005-07-12 19:50:54 +00:00
case 0x800f : /* CONNECT ACK */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element CONNECT ACK \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
2005-07-12 19:50:54 +00:00
case 0x8045 : /* DISCONNECT */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element DISCONNECT \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-06-09 21:48:24 +00:00
capidev_handle_info_disconnect ( CMSG , PLCI , NCCI , i ) ;
2005-06-05 19:48:21 +00:00
break ;
case 0x804d : /* RELEASE */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element RELEASE \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
2005-07-12 19:50:54 +00:00
case 0x805a : /* RELEASE COMPLETE */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element RELEASE COMPLETE \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-05 19:48:21 +00:00
break ;
2005-08-21 15:35:44 +00:00
case 0x8062 : /* FACILITY */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element FACILITY \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-08-21 15:35:44 +00:00
break ;
2005-08-19 16:16:19 +00:00
case 0x806e : /* NOTIFY */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element NOTIFY \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-08-19 16:16:19 +00:00
break ;
2005-07-27 17:20:09 +00:00
case 0x807b : /* INFORMATION */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element INFORMATION \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-27 17:20:09 +00:00
break ;
2005-08-12 18:08:56 +00:00
case 0x807d : /* STATUS */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: info element STATUS \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-08-12 18:08:56 +00:00
break ;
2005-07-12 19:50:54 +00:00
default :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: unhandled INFO_IND %#x (PLCI=%#x) \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , INFO_IND_INFONUMBER ( CMSG ) , PLCI ) ;
2005-07-12 19:50:54 +00:00
break ;
2005-06-02 18:47:35 +00:00
}
2007-04-19 18:18:42 +00:00
/* QSIG worker - is only executed, if QSIG is enabled */
pbx_capi_qsig_handle_info_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
2007-04-15 18:25:29 +00:00
/*
* CAPI FACILITY_IND line interconnect
*/
2007-04-21 07:19:44 +00:00
static int handle_facility_indication_line_interconnect (
2007-04-15 18:25:29 +00:00
_cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
{
if ( ( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 1 ] = = 0x01 ) & &
( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 2 ] = = 0x00 ) ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: Line Interconnect activated \n " ,
i - > vname ) ;
}
if ( ( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 1 ] = = 0x02 ) & &
( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 2 ] = = 0x00 ) & &
( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 0 ] > 8 ) ) {
show_capi_info ( i , read_capi_word ( & FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 8 ] ) ) ;
}
2007-04-21 07:19:44 +00:00
return 0 ;
2007-04-15 18:25:29 +00:00
}
2006-12-18 19:09:52 +00:00
2007-04-15 18:25:29 +00:00
/*
* CAPI FACILITY_IND dtmf received
*/
2007-04-21 07:19:44 +00:00
static int handle_facility_indication_dtmf (
2007-04-15 18:25:29 +00:00
_cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
{
struct ast_frame fr = { AST_FRAME_NULL , } ;
char dtmf ;
unsigned dtmflen = 0 ;
unsigned dtmfpos = 0 ;
if ( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 0 ] ! = ( 0xff ) ) {
dtmflen = FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 0 ] ;
FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) + = 1 ;
} else {
dtmflen = read_capi_word ( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) + 1 ) ;
FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) + = 3 ;
}
2009-05-06 20:38:13 +00:00
2007-04-15 18:25:29 +00:00
while ( dtmflen ) {
dtmf = ( FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) ) [ dtmfpos ] ;
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 " %s: c_dtmf = %c \n " ,
i - > vname , dtmf ) ;
if ( ( ! ( i - > ntmode ) ) | | ( i - > state = = CAPI_STATE_CONNECTED ) ) {
if ( ( dtmf = = ' X ' ) | | ( dtmf = = ' Y ' ) ) {
capi_handle_dtmf_fax ( i ) ;
2005-06-02 18:47:35 +00:00
} else {
2009-02-13 21:58:19 +00:00
int ignore_digit = 0 ;
if ( capi_controllers [ i - > controller ] - > divaExtendedFeaturesAvailable ! = 0 ) {
switch ( ( unsigned char ) dtmf ) {
2009-02-14 20:56:14 +00:00
case 0x23 : /* DTMF '#' */
case 0x2a : /* DTMF '*' */
case ' 0 ' : /* DTMF '0' */
case ' 1 ' : /* DTMF '1' */
case ' 2 ' : /* DTMF '2' */
case ' 3 ' : /* DTMF '3' */
case ' 4 ' : /* DTMF '4' */
case ' 5 ' : /* DTMF '5' */
case ' 6 ' : /* DTMF '6' */
case ' 7 ' : /* DTMF '7' */
case ' 8 ' : /* DTMF '8' */
case ' 9 ' : /* DTMF '9' */
case 0x41 : /* DTMF 'A' */
case 0x42 : /* DTMF 'B' */
case 0x43 : /* DTMF 'C' */
case 0x44 : /* DTMF 'D' */
break ;
/* Dial pulse listen active: Signals in order of detection */
/* MF listen active: Signals in order of detection */
case 0xE0 : /* Dial pulse digit '1' detected */
case 0xF1 : /* MF '1' detected */
dtmf = ' 1 ' ;
break ;
case 0xE1 : /* Dial pulse digit '2' detected */
case 0xF2 : /* MF '2' detected */
dtmf = ' 2 ' ;
break ;
case 0xE2 : /* Dial pulse digit '3' detected */
case 0xF3 : /* MF '3' detected */
dtmf = ' 3 ' ;
break ;
case 0xE3 : /* Dial pulse digit '4' detected */
case 0xF4 : /* MF '4' detected */
dtmf = ' 4 ' ;
break ;
case 0xE4 : /* Dial pulse digit '5' detected */
case 0xF5 : /* MF '5' detected */
dtmf = ' 5 ' ;
break ;
case 0xE5 : /* Dial pulse digit '6' detected */
case 0xF6 : /* MF '6' detected */
dtmf = ' 6 ' ;
break ;
case 0xE6 : /* Dial pulse digit '7' detected */
case 0xF7 : /* MF '7' detected */
dtmf = ' 7 ' ;
break ;
case 0xE7 : /* Dial pulse digit '8' detected */
case 0xF8 : /* MF '8' detected */
dtmf = ' 8 ' ;
break ;
case 0xE8 : /* Dial pulse digit '9' detected */
case 0xF9 : /* MF '9' detected */
dtmf = ' 9 ' ;
break ;
case 0xE9 : /* Dial pulse digit '0' detected */
case 0xFA : /* MF '0' detected */
dtmf = ' 0 ' ;
break ;
case 0x80 : /* End of signal detected */
case 0x81 : /* Unidentified tone detected */
case 0xEA : /* Dial pulse reserved */
case 0xF0 : /* recognition of falling edge of MF tone */
case 0xEB : /* Dial pulse reserved */
case 0xEC : /* Dial pulse reserved */
case 0xED : /* Dial pulse reserved */
case 0xEF : /* Dial pulse reserved */
ignore_digit = 1 ;
break ;
case 0xFB : /* MF K1 detected */
dtmf = ' A ' ;
break ;
case 0xFC : /* MF K2 detected */
dtmf = ' B ' ;
break ;
case 0xFD : /* MF KP detected */
dtmf = ' C ' ;
break ;
case 0xFE : /* MF S1 detected */
dtmf = ' D ' ;
break ;
case 0xFF : /* MF ST detected */
dtmf = ' * ' ;
break ;
2009-04-10 07:23:20 +00:00
default :
{
2009-02-14 20:56:14 +00:00
const char * special_tone_name = pbx_capi_map_detected_tone ( dtmf ) ;
if ( ( special_tone_name ! = 0 ) & & ( i - > owner ! = 0 ) ) {
int n = 0 ;
char buffer [ 32 ] ;
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: map detected '%s' %02x tone to '%s' \n " ,
i - > vname , special_tone_name , ( unsigned char ) dtmf ,
i - > special_tone_extension ) ;
2009-02-13 21:58:19 +00:00
ignore_digit = 1 ;
2009-02-14 20:56:14 +00:00
snprintf ( buffer , sizeof ( buffer ) - 1 , " %u " , ( unsigned char ) dtmf ) ;
buffer [ sizeof ( buffer ) - 1 ] = 0 ;
pbx_builtin_setvar_helper ( i - > owner , CAPI_DETECTED_TONE_NAME , buffer ) ;
pbx_builtin_setvar_helper ( i - > owner , CAPI_DETECTED_TONE_NAME " VISUAL " ,
special_tone_name ) ;
while ( i - > special_tone_extension [ n ] ! = 0 ) {
fr . frametype = AST_FRAME_DTMF ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = i - > special_tone_extension [ n + + ] ;
2009-02-14 20:56:14 +00:00
local_queue_frame ( i , & fr ) ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
}
2009-04-10 07:23:20 +00:00
}
break ;
2009-02-13 21:58:19 +00:00
}
}
if ( ignore_digit = = 0 ) {
2009-05-18 22:37:21 +00:00
if ( pbx_capi_voicecommand_process_digit ( i , 0 , dtmf ) = = 0 ) {
2009-02-13 21:58:19 +00:00
fr . frametype = AST_FRAME_DTMF ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = dtmf ;
2009-02-13 21:58:19 +00:00
local_queue_frame ( i , & fr ) ;
}
}
2005-06-02 18:47:35 +00:00
}
}
2007-04-15 18:25:29 +00:00
dtmflen - - ;
dtmfpos + + ;
2007-04-21 07:19:44 +00:00
}
return 0 ;
2007-04-15 18:25:29 +00:00
}
/*
* CAPI FACILITY_IND
*/
static void capidev_handle_facility_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
{
2007-04-21 07:19:44 +00:00
int resp_done = 0 ;
2007-04-15 18:25:29 +00:00
switch ( FACILITY_IND_FACILITYSELECTOR ( CMSG ) ) {
case FACILITYSELECTOR_LINE_INTERCONNECT :
return_on_no_interface ( " FACILITY_IND LI " ) ;
2007-04-21 07:19:44 +00:00
resp_done = handle_facility_indication_line_interconnect ( CMSG , PLCI , NCCI , i ) ;
2007-04-15 18:25:29 +00:00
break ;
case FACILITYSELECTOR_DTMF :
2009-05-06 20:38:13 +00:00
case PRIV_SELECTOR_DTMF_ONDATA :
2007-04-15 18:25:29 +00:00
return_on_no_interface ( " FACILITY_IND DTMF " ) ;
2007-04-21 07:19:44 +00:00
resp_done = handle_facility_indication_dtmf ( CMSG , PLCI , NCCI , i ) ;
2007-04-15 18:25:29 +00:00
break ;
case FACILITYSELECTOR_SUPPLEMENTARY :
2007-04-21 07:19:44 +00:00
resp_done = handle_facility_indication_supplementary ( CMSG , PLCI , NCCI , i ) ;
2007-04-15 18:25:29 +00:00
break ;
default :
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: unhandled FACILITY_IND selector %d \n " ,
( i ) ? i - > vname : " ??? " , FACILITY_IND_FACILITYSELECTOR ( CMSG ) ) ;
2005-06-02 18:47:35 +00:00
}
2007-04-21 07:19:44 +00:00
if ( ! resp_done ) {
2007-04-27 23:02:27 +00:00
capi_sendf ( NULL , 0 , CAPI_FACILITY_RESP , PLCI , HEADER_MSGNUM ( CMSG ) ,
" w() " ,
2007-05-13 11:30:34 +00:00
FACILITY_IND_FACILITYSELECTOR ( CMSG )
2007-04-27 23:02:27 +00:00
) ;
2007-04-21 07:19:44 +00:00
}
2005-06-02 18:47:35 +00:00
}
/*
* CAPI DATA_B3_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_data_b3_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2006-04-03 20:02:01 +00:00
struct ast_frame fr = { AST_FRAME_NULL , } ;
2005-12-16 11:21:57 +00:00
unsigned char * b3buf = NULL ;
2005-06-02 18:47:35 +00:00
int b3len = 0 ;
int j ;
int rxavg = 0 ;
int txavg = 0 ;
2006-01-30 23:40:28 +00:00
int rtpoffset = 0 ;
2005-06-02 18:47:35 +00:00
2005-12-16 11:21:57 +00:00
if ( i ! = NULL ) {
2006-05-22 11:04:33 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_RTP ) ) rtpoffset = RTP_HEADER_SIZE ;
2005-12-16 11:21:57 +00:00
b3len = DATA_B3_IND_DATALENGTH ( CMSG ) ;
2006-01-30 23:40:28 +00:00
b3buf = & ( i - > rec_buffer [ AST_FRIENDLY_OFFSET - rtpoffset ] ) ;
2005-12-16 11:21:57 +00:00
memcpy ( b3buf , ( char * ) DATA_B3_IND_DATA ( CMSG ) , b3len ) ;
}
2005-06-19 10:01:35 +00:00
2005-06-02 18:47:35 +00:00
/* send a DATA_B3_RESP very quickly to free the buffer in capi */
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_DATA_B3_RESP , NCCI , HEADER_MSGNUM ( CMSG ) ,
" w " , DATA_B3_IND_DATAHANDLE ( CMSG ) ) ;
2005-06-02 18:47:35 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " DATA_B3_IND " ) ;
2005-12-11 10:48:08 +00:00
2005-07-17 19:01:14 +00:00
if ( i - > fFax ) {
2006-06-27 14:54:03 +00:00
/* we are in fax mode and have a file open */
2005-11-20 16:15:33 +00:00
cc_verbose ( 6 , 1 , VERBOSE_PREFIX_3 " %s: DATA_B3_IND (len=%d) Fax \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , b3len ) ;
2006-10-10 11:57:37 +00:00
if ( ( ! ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) & &
( i - > FaxState & CAPI_FAX_STATE_CONN ) ) {
2006-06-27 14:54:03 +00:00
if ( fwrite ( b3buf , 1 , b3len , i - > fFax ) ! = b3len )
cc_log ( LOG_WARNING , " %s : error writing output file (%s) \n " ,
i - > vname , strerror ( errno ) ) ;
}
2006-12-10 16:26:37 +00:00
# ifndef CC_AST_HAS_VERSION_1_4
fr . frametype = AST_FRAME_CONTROL ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_PROGRESS ;
2006-12-10 16:26:37 +00:00
local_queue_frame ( i , & fr ) ;
# endif
2005-06-04 14:28:52 +00:00
return ;
}
2006-01-30 23:40:28 +00:00
2006-05-20 22:01:26 +00:00
if ( ( ( i - > isdnstate &
( CAPI_ISDN_STATE_B3_CHANGE | CAPI_ISDN_STATE_LI | CAPI_ISDN_STATE_HANGUP ) ) ) | |
( i - > state = = CAPI_STATE_DISCONNECTING ) ) {
/* drop voice frames when we don't want them */
return ;
}
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_RTP ) ) {
2006-01-30 23:40:28 +00:00
struct ast_frame * f = capi_read_rtp ( i , b3buf , b3len ) ;
if ( f )
2006-04-03 20:02:01 +00:00
local_queue_frame ( i , f ) ;
2006-01-30 23:40:28 +00:00
return ;
}
2006-02-13 15:18:56 +00:00
if ( i - > B3q < ( ( ( CAPI_MAX_B3_BLOCKS - 1 ) * CAPI_MAX_B3_BLOCK_SIZE ) + 1 ) ) {
2005-07-17 19:01:14 +00:00
i - > B3q + = b3len ;
2005-06-28 17:42:14 +00:00
}
2009-05-08 13:03:31 +00:00
if ( i - > bproto ! = CC_BPROTO_VOCODER ) {
if ( ( i - > doES = = 1 ) & & ( ! capi_tcap_is_digital ( i - > transfercapability ) ) ) {
for ( j = 0 ; j < b3len ; j + + ) {
* ( b3buf + j ) = capi_reversebits [ * ( b3buf + j ) ] ;
if ( capi_capability = = AST_FORMAT_ULAW ) {
rxavg + = abs ( capiULAW2INT [ capi_reversebits [ * ( b3buf + j ) ] ] ) ;
} else {
rxavg + = abs ( capiALAW2INT [ capi_reversebits [ * ( b3buf + j ) ] ] ) ;
}
2005-08-10 19:19:16 +00:00
}
2009-05-08 13:03:31 +00:00
rxavg = rxavg / j ;
for ( j = 0 ; j < ECHO_EFFECTIVE_TX_COUNT ; j + + ) {
txavg + = i - > txavg [ j ] ;
2005-08-10 19:19:16 +00:00
}
2009-05-08 13:03:31 +00:00
txavg = txavg / j ;
if ( ( txavg / ECHO_TXRX_RATIO ) > rxavg ) {
if ( capi_capability = = AST_FORMAT_ULAW ) {
memset ( b3buf , 255 , b3len ) ;
} else {
memset ( b3buf , 85 , b3len ) ;
}
cc_verbose ( 6 , 1 , VERBOSE_PREFIX_3 " %s: SUPPRESSING ECHO rx=%d, tx=%d \n " ,
i - > vname , rxavg , txavg ) ;
2005-09-24 18:19:14 +00:00
}
} else {
2009-05-08 13:03:31 +00:00
if ( ( i - > rxgain = = 1.0 ) | | ( capi_tcap_is_digital ( i - > transfercapability ) ) ) {
for ( j = 0 ; j < b3len ; j + + ) {
* ( b3buf + j ) = capi_reversebits [ * ( b3buf + j ) ] ;
}
} else {
for ( j = 0 ; j < b3len ; j + + ) {
* ( b3buf + j ) = capi_reversebits [ i - > g . rxgains [ * ( b3buf + j ) ] ] ;
}
2005-09-24 18:19:14 +00:00
}
2005-06-02 18:47:35 +00:00
}
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_CODEC ( fr . subclass ) = capi_capability ;
2009-05-08 13:03:31 +00:00
} else {
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_CODEC ( fr . subclass ) = i - > codec ;
2005-06-02 18:47:35 +00:00
}
fr . frametype = AST_FRAME_VOICE ;
2009-01-06 13:40:49 +00:00
fr . FRAME_DATA_PTR = b3buf ;
2005-06-02 18:47:35 +00:00
fr . datalen = b3len ;
fr . samples = b3len ;
fr . offset = AST_FRIENDLY_OFFSET ;
fr . mallocd = 0 ;
2006-06-24 11:53:47 +00:00
fr . delivery = ast_tv ( 0 , 0 ) ;
2005-06-02 18:47:35 +00:00
fr . src = NULL ;
2010-03-01 17:59:31 +00:00
cc_verbose ( 8 , 1 , VERBOSE_PREFIX_3 " %s: DATA_B3_IND (len=%d) fr.datalen=%d fr.subclass=%ld \n " ,
i - > vname , b3len , fr . datalen , FRAME_SUBCLASS_CODEC ( fr . subclass ) ) ;
2006-04-03 20:02:01 +00:00
local_queue_frame ( i , & fr ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
2005-12-08 22:06:16 +00:00
/*
* signal ' answer ' to PBX
*/
static void capi_signal_answer ( struct capi_pvt * i )
{
2010-03-09 12:21:52 +00:00
struct ast_frame fr = { AST_FRAME_CONTROL , } ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_ANSWER ;
2005-12-08 22:06:16 +00:00
2006-04-03 20:02:01 +00:00
if ( i - > outgoing = = 1 ) {
local_queue_frame ( i , & fr ) ;
}
2005-12-08 22:06:16 +00:00
}
2006-06-27 14:54:03 +00:00
/*
* send the next data
*/
static void capidev_send_faxdata ( struct capi_pvt * i )
{
2006-12-10 16:26:37 +00:00
# ifndef CC_AST_HAS_VERSION_1_4
struct ast_frame fr = { AST_FRAME_CONTROL , AST_CONTROL_PROGRESS , } ;
# endif
2006-06-27 14:54:03 +00:00
unsigned char faxdata [ CAPI_MAX_B3_BLOCK_SIZE ] ;
size_t len ;
2007-03-15 10:16:41 +00:00
if ( i - > NCCI = = 0 ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: send_faxdata on NCCI = 0. \n " ,
i - > vname ) ;
return ;
}
2006-12-10 16:26:37 +00:00
if ( i - > state = = CAPI_STATE_DISCONNECTING ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: send_faxdata in DISCONNECTING. \n " ,
i - > vname ) ;
return ;
}
2006-06-27 14:54:03 +00:00
if ( ( i - > fFax ) & & ( ! ( feof ( i - > fFax ) ) ) ) {
len = fread ( faxdata , 1 , CAPI_MAX_B3_BLOCK_SIZE , i - > fFax ) ;
if ( len > 0 ) {
i - > send_buffer_handle + + ;
2007-08-23 13:30:05 +00:00
capi_sendf ( NULL , 0 , CAPI_DATA_B3_REQ , i - > NCCI , get_capi_MessageNumber ( ) ,
" dwww " , faxdata , len , i - > send_buffer_handle , 0 ) ;
2006-06-27 14:54:03 +00:00
cc_verbose ( 5 , 1 , VERBOSE_PREFIX_3 " %s: send %d fax bytes. \n " ,
i - > vname , len ) ;
2006-12-10 16:26:37 +00:00
# ifndef CC_AST_HAS_VERSION_1_4
local_queue_frame ( i , & fr ) ;
# endif
2006-06-27 14:54:03 +00:00
return ;
}
}
/* finished send fax, so we hangup */
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: completed faxsend. \n " ,
i - > vname ) ;
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_DISCONNECT_B3_REQ , i - > NCCI , get_capi_MessageNumber ( ) ,
" () " ) ;
2006-06-27 14:54:03 +00:00
}
2006-09-24 10:44:40 +00:00
/*
* CAPI MANUFACTURER_IND
*/
static void capidev_handle_manufacturer_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
{
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_MANUFACTURER_RESP , MANUFACTURER_IND_CONTROLLER ( CMSG ) , HEADER_MSGNUM ( CMSG ) ,
" d " , MANUFACTURER_IND_MANUID ( CMSG ) ) ;
2006-09-24 10:44:40 +00:00
return_on_no_interface ( " MANUFACTURER_IND " ) ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: Ignored MANUFACTURER_IND Id=0x%x \n " ,
i - > vname , MANUFACTURER_IND_MANUID ( CMSG ) ) ;
return ;
}
2005-06-02 18:47:35 +00:00
/*
* CAPI CONNECT_ACTIVE_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_connect_active_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_ACTIVE_RESP , PLCI , HEADER_MSGNUM ( CMSG ) , " " ) ;
2005-06-02 18:47:35 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " CONNECT_ACTIVE_IND " ) ;
2005-06-02 18:47:35 +00:00
2005-07-18 19:41:31 +00:00
if ( i - > state = = CAPI_STATE_DISCONNECTING ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: CONNECT_ACTIVE in DISCONNECTING. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-07-18 19:41:31 +00:00
return ;
}
2005-12-08 22:06:16 +00:00
i - > state = CAPI_STATE_CONNECTED ;
2006-06-27 14:54:03 +00:00
if ( ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) {
cc_start_b3 ( i ) ;
return ;
}
2006-05-27 12:49:57 +00:00
if ( ( i - > owner ) & & ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) ) {
2006-08-12 15:40:32 +00:00
ast_setstate ( i - > owner , AST_STATE_UP ) ;
if ( i - > owner - > cdr )
ast_cdr_answer ( i - > owner - > cdr ) ;
2005-06-05 19:48:21 +00:00
return ;
}
2005-06-02 18:47:35 +00:00
/* normal processing */
2005-12-08 22:06:16 +00:00
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
2005-06-02 18:47:35 +00:00
/* send a CONNECT_B3_REQ */
2005-07-17 19:01:14 +00:00
if ( i - > outgoing = = 1 ) {
2005-06-02 18:47:35 +00:00
/* outgoing call */
2007-05-05 11:33:41 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) {
2009-04-14 21:58:03 +00:00
if ( i - > resource_plci_type ! = CAPI_RESOURCE_PLCI_LINE ) {
/* NULL-PLCI needs a virtual connection */
capi_sendf ( NULL , 0 , CAPI_FACILITY_REQ , PLCI , get_capi_MessageNumber ( ) ,
" w(w(d())) " ,
FACILITYSELECTOR_LINE_INTERCONNECT ,
0x0001 , /* CONNECT */
2009-05-19 07:56:38 +00:00
( i - > line_plci = = NULL ) ? 0x00000030 : 0x00000000 /* mask */
2009-04-14 21:58:03 +00:00
) ;
}
2007-05-05 11:33:41 +00:00
}
2006-02-06 19:21:38 +00:00
cc_start_b3 ( i ) ;
2005-06-02 18:47:35 +00:00
} else {
/* incoming call */
/* RESP already sent ... wait for CONNECT_B3_IND */
}
} else {
2005-12-08 22:06:16 +00:00
capi_signal_answer ( i ) ;
2005-06-02 18:47:35 +00:00
}
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
/*
* CAPI CONNECT_B3_ACTIVE_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_connect_b3_active_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_B3_ACTIVE_RESP , NCCI , HEADER_MSGNUM ( CMSG ) , " " ) ;
2005-06-02 18:47:35 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " CONNECT_ACTIVE_B3_IND " ) ;
2005-06-02 18:47:35 +00:00
2005-07-17 19:01:14 +00:00
if ( i - > state = = CAPI_STATE_DISCONNECTING ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: CONNECT_B3_ACTIVE_IND during disconnect for NCCI %#x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , NCCI ) ;
2005-07-12 19:50:54 +00:00
return ;
}
2005-12-08 22:06:16 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_B3_UP ;
i - > isdnstate & = ~ CAPI_ISDN_STATE_B3_PEND ;
2005-07-17 19:01:14 +00:00
2006-02-06 19:21:38 +00:00
if ( i - > bproto = = CC_BPROTO_RTP ) {
i - > isdnstate | = CAPI_ISDN_STATE_RTP ;
} else {
i - > isdnstate & = ~ CAPI_ISDN_STATE_RTP ;
}
2007-03-30 16:21:58 +00:00
i - > B3q = ( CAPI_MAX_B3_BLOCK_SIZE * 3 ) ;
2006-06-27 14:54:03 +00:00
if ( ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: Start sending fax. \n " ,
i - > vname ) ;
capidev_send_faxdata ( i ) ;
}
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_B3_CHANGE ) ) {
i - > isdnstate & = ~ CAPI_ISDN_STATE_B3_CHANGE ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: B3 protocol changed. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-02-06 19:21:38 +00:00
return ;
}
2006-05-27 12:49:57 +00:00
if ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) {
2006-10-10 11:57:37 +00:00
i - > FaxState | = CAPI_FAX_STATE_CONN ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: Fax connection, no EC/DTMF \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-06-04 20:07:00 +00:00
} else {
2007-04-29 14:00:32 +00:00
capi_echo_canceller ( i , EC_FUNCTION_ENABLE ) ;
capi_detect_dtmf ( i , 1 ) ;
2005-06-04 20:07:00 +00:00
}
2005-06-02 18:47:35 +00:00
2008-08-30 09:58:27 +00:00
if ( i - > fsetting & CAPI_FSETTING_EARLY_BRIDGE ) {
if ( ( i - > peer ! = NULL ) & & ( i - > peer - > tech = = & capi_tech ) ) {
struct capi_pvt * i1 ;
i1 = CC_CHANNEL_PVT ( i - > peer ) ;
if ( ( capi_controllers [ i - > controller ] - > lineinterconnect ) & &
( capi_controllers [ i1 - > controller ] - > lineinterconnect ) & &
( i - > bridge ) & & ( i1 - > bridge ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: activate early bridge to %s \n " ,
i - > vname , i1 - > vname ) ;
capi_bridge ( 1 , i , i1 , 0 ) ;
}
}
}
2005-12-08 22:06:16 +00:00
if ( i - > state = = CAPI_STATE_CONNECTED ) {
capi_signal_answer ( i ) ;
2005-06-02 18:47:35 +00:00
}
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
/*
* CAPI DISCONNECT_B3_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_disconnect_b3_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_DISCONNECT_B3_RESP , NCCI , HEADER_MSGNUM ( CMSG ) , " " ) ;
2005-06-02 18:47:35 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " DISCONNECT_B3_IND " ) ;
2005-06-02 18:47:35 +00:00
2006-05-20 22:01:26 +00:00
i - > isdnstate & = ~ ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ;
2005-07-17 19:01:14 +00:00
i - > reasonb3 = DISCONNECT_B3_IND_REASON_B3 ( CMSG ) ;
i - > NCCI = 0 ;
2005-06-02 18:47:35 +00:00
2006-05-27 12:49:57 +00:00
if ( ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) & & ( i - > owner ) ) {
2005-12-29 16:31:22 +00:00
char buffer [ CAPI_MAX_STRING ] ;
2006-06-27 14:54:03 +00:00
char * infostring ;
2005-12-29 16:31:22 +00:00
unsigned char * ncpi = ( unsigned char * ) DISCONNECT_B3_IND_NCPI ( CMSG ) ;
/* if we have fax infos, set them as variables */
2006-06-27 14:54:03 +00:00
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , i - > reasonb3 ) ;
pbx_builtin_setvar_helper ( i - > owner , " FAXREASON " , buffer ) ;
2006-09-24 10:01:21 +00:00
if ( i - > reasonb3 = = 0 ) {
pbx_builtin_setvar_helper ( i - > owner , " FAXREASONTEXT " , " OK " ) ;
} else if ( ( infostring = capi_info_string ( i - > reasonb3 ) ) ! = NULL ) {
2006-06-27 14:54:03 +00:00
pbx_builtin_setvar_helper ( i - > owner , " FAXREASONTEXT " , infostring ) ;
} else {
pbx_builtin_setvar_helper ( i - > owner , " FAXREASONTEXT " , " " ) ;
}
2005-12-29 16:31:22 +00:00
if ( ncpi ) {
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , read_capi_word ( & ncpi [ 1 ] ) ) ;
pbx_builtin_setvar_helper ( i - > owner , " FAXRATE " , buffer ) ;
2009-04-08 20:43:38 +00:00
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , read_capi_word ( & ncpi [ 3 ] ) & 1 ) ;
2005-12-29 16:31:22 +00:00
pbx_builtin_setvar_helper ( i - > owner , " FAXRESOLUTION " , buffer ) ;
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , read_capi_word ( & ncpi [ 5 ] ) ) ;
pbx_builtin_setvar_helper ( i - > owner , " FAXFORMAT " , buffer ) ;
2009-04-08 20:43:38 +00:00
strcpy ( buffer , " 0 " ) ;
if ( read_capi_word ( & ncpi [ 5 ] ) = = 8 ) {
unsigned short options = read_capi_word ( & ncpi [ 3 ] ) ;
if ( options & 0x0400 ) {
strcpy ( buffer , " 1 " ) ;
} else if ( options & 0x0800 ) {
strcpy ( buffer , " 2 " ) ;
}
}
pbx_builtin_setvar_helper ( i - > owner , " FAXCFFFORMAT " , buffer ) ;
2005-12-29 16:31:22 +00:00
snprintf ( buffer , CAPI_MAX_STRING - 1 , " %d " , read_capi_word ( & ncpi [ 7 ] ) ) ;
pbx_builtin_setvar_helper ( i - > owner , " FAXPAGES " , buffer ) ;
memcpy ( buffer , & ncpi [ 10 ] , ncpi [ 9 ] ) ;
buffer [ ncpi [ 9 ] ] = 0 ;
pbx_builtin_setvar_helper ( i - > owner , " FAXID " , buffer ) ;
}
}
2007-04-23 18:47:49 +00:00
if ( ( i - > state = = CAPI_STATE_DISCONNECTING ) ) {
2008-08-30 09:58:27 +00:00
if ( ! ( i - > fsetting & CAPI_FSETTING_STAYONLINE ) ) {
2007-04-23 18:47:49 +00:00
/* active disconnect */
2009-04-27 20:02:46 +00:00
capi_send_disconnect ( PLCI ) ;
2007-04-23 18:47:49 +00:00
}
} else if ( ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_SELECT ) ) & &
( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) {
2009-04-27 20:02:46 +00:00
capi_send_disconnect ( PLCI ) ;
2005-06-02 18:47:35 +00:00
}
2005-06-05 19:48:21 +00:00
2007-04-29 14:00:32 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
capi_controllers [ i - > controller ] - > nfreebchannels + + ;
}
2005-06-02 18:47:35 +00:00
}
/*
* CAPI CONNECT_B3_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_connect_b3_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_B3_RESP , NCCI , HEADER_MSGNUM ( CMSG ) ,
" ws " ,
0x0000 , /* accept */
capi_rtp_ncpi ( i ) ) ;
2005-12-16 11:21:57 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " CONNECT_B3_IND " ) ;
2005-06-02 18:47:35 +00:00
2005-07-17 19:01:14 +00:00
i - > NCCI = NCCI ;
2007-03-30 16:21:58 +00:00
i - > B3count = 0 ;
2005-06-02 18:47:35 +00:00
2008-08-08 08:13:29 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
capi_controllers [ i - > controller ] - > nfreebchannels - - ;
}
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
/*
* CAPI DISCONNECT_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_disconnect_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * i )
2005-06-02 18:47:35 +00:00
{
2010-03-09 12:21:52 +00:00
struct ast_frame fr = { AST_FRAME_CONTROL , } ;
2005-08-07 13:33:48 +00:00
int state ;
2005-06-02 18:47:35 +00:00
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_HANGUP ;
2010-04-08 22:10:54 +00:00
# ifdef DIVA_STREAMING
if ( i - > diva_stream_entry ! = 0 )
capi_DivaStreamingRemove ( i ) ;
# endif
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_DISCONNECT_RESP , PLCI , HEADER_MSGNUM ( CMSG ) , " " ) ;
2005-06-02 18:47:35 +00:00
2006-06-18 16:32:32 +00:00
show_capi_info ( i , DISCONNECT_IND_REASON ( CMSG ) ) ;
2005-08-30 11:21:58 +00:00
2006-01-28 19:42:44 +00:00
return_on_no_interface ( " DISCONNECT_IND " ) ;
2005-06-05 19:48:21 +00:00
2005-08-07 13:33:48 +00:00
state = i - > state ;
i - > state = CAPI_STATE_DISCONNECTED ;
2005-06-05 19:48:21 +00:00
i - > reason = DISCONNECT_IND_REASON ( CMSG ) ;
2006-02-12 21:04:54 +00:00
2006-02-13 15:11:56 +00:00
if ( ( i - > owner ) & & ( i - > owner - > hangupcause = = 0 ) ) {
2006-02-12 21:04:54 +00:00
/* set hangupcause, in case there is no
* " cause " information element :
*/
i - > owner - > hangupcause =
2006-02-13 15:11:56 +00:00
( ( i - > reason & 0xFF00 ) = = 0x3400 ) ?
i - > reason & 0x7F : AST_CAUSE_NORMAL_CLEARING ;
2006-02-12 21:04:54 +00:00
}
2006-05-27 12:49:57 +00:00
if ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) {
2005-08-14 12:32:18 +00:00
/* in capiFax */
switch ( i - > reason ) {
2006-09-24 09:50:47 +00:00
case 0x3400 :
2005-08-14 12:32:18 +00:00
case 0x3490 :
case 0x349f :
2006-05-27 12:49:57 +00:00
if ( i - > reasonb3 ! = 0 )
i - > FaxState | = CAPI_FAX_STATE_ERROR ;
2005-08-14 12:32:18 +00:00
break ;
default :
2006-05-27 12:49:57 +00:00
i - > FaxState | = CAPI_FAX_STATE_ERROR ;
2005-08-14 12:32:18 +00:00
}
2006-05-27 12:49:57 +00:00
i - > FaxState & = ~ CAPI_FAX_STATE_ACTIVE ;
2005-08-14 12:32:18 +00:00
}
2005-08-31 07:32:09 +00:00
if ( ( i - > owner ) & &
( ( state = = CAPI_STATE_DID ) | | ( state = = CAPI_STATE_INCALL ) ) & &
2006-07-05 12:23:58 +00:00
( ! ( i - > isdnstate & CAPI_ISDN_STATE_PBX ) ) ) {
2005-07-27 17:20:09 +00:00
/* the pbx was not started yet */
2005-12-11 10:48:08 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: DISCONNECT_IND on incoming without pbx, doing hangup. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2006-07-08 16:29:27 +00:00
capi_channel_task ( i - > owner , CAPI_CHANNEL_TASK_HANGUP ) ;
2005-07-27 17:20:09 +00:00
return ;
}
2005-06-02 18:47:35 +00:00
if ( DISCONNECT_IND_REASON ( CMSG ) = = 0x34a2 ) {
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_CONGESTION ;
2005-06-02 18:47:35 +00:00
}
2005-06-04 20:07:00 +00:00
2005-08-07 13:33:48 +00:00
if ( state = = CAPI_STATE_DISCONNECTING ) {
2005-07-17 19:01:14 +00:00
interface_cleanup ( i ) ;
2006-04-03 20:02:01 +00:00
} else {
local_queue_frame ( i , & fr ) ;
2007-01-28 13:51:58 +00:00
/* PLCI is now removed, make sure it doesn't match with new one */
i - > PLCI = 0xdead0000 ;
2005-06-04 20:07:00 +00:00
}
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
/*
* CAPI CONNECT_IND
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_connect_indication ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * * interface )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i ;
2005-06-02 18:47:35 +00:00
char * DNID ;
char * CID ;
2007-09-20 13:15:27 +00:00
char * KEYPAD = NULL ;
2005-08-07 19:24:06 +00:00
int callernplan = 0 , callednplan = 0 ;
2005-06-02 18:47:35 +00:00
int controller = 0 ;
char * msn ;
2005-11-20 16:15:33 +00:00
char buffer [ CAPI_MAX_STRING ] ;
char buffer_r [ CAPI_MAX_STRING ] ;
2005-06-05 19:48:21 +00:00
char * buffer_rp = buffer_r ;
2005-06-02 18:47:35 +00:00
char * magicmsn = " * \0 " ;
2005-08-13 09:31:07 +00:00
char * emptydnid = " \0 " ;
2005-07-18 18:50:43 +00:00
int callpres = 0 ;
2005-10-01 15:17:10 +00:00
char bchannelinfo [ 2 ] = { ' 0 ' , 0 } ;
2005-06-02 18:47:35 +00:00
2005-09-15 19:11:45 +00:00
if ( * interface ) {
2005-09-11 13:35:19 +00:00
/* chan_capi does not support
* double connect indications !
* ( This is used to update
* telephone numbers and
* other information )
*/
return ;
}
2007-09-20 13:15:27 +00:00
if ( CONNECT_IND_KEYPADFACILITY ( CMSG ) ) {
KEYPAD = capi_number ( CONNECT_IND_KEYPADFACILITY ( CMSG ) , 0 ) ;
}
2005-08-07 19:24:06 +00:00
DNID = capi_number ( CONNECT_IND_CALLEDPARTYNUMBER ( CMSG ) , 1 ) ;
2005-08-13 09:31:07 +00:00
if ( ! DNID ) {
2007-09-02 15:41:06 +00:00
if ( ! KEYPAD ) {
DNID = emptydnid ;
} else {
/* if keypad is signaled instead, use it as DID with 'K' */
DNID = alloca ( AST_MAX_EXTENSION ) ;
snprintf ( DNID , AST_MAX_EXTENSION - 1 , " K%s " , KEYPAD ) ;
}
2005-06-02 18:47:35 +00:00
}
2007-09-02 15:41:06 +00:00
2005-08-07 19:24:06 +00:00
if ( CONNECT_IND_CALLEDPARTYNUMBER ( CMSG ) [ 0 ] > 1 ) {
callednplan = ( CONNECT_IND_CALLEDPARTYNUMBER ( CMSG ) [ 1 ] & 0x7f ) ;
}
2005-07-18 18:50:43 +00:00
2005-06-02 18:47:35 +00:00
CID = capi_number ( CONNECT_IND_CALLINGPARTYNUMBER ( CMSG ) , 2 ) ;
2005-07-18 18:50:43 +00:00
if ( CONNECT_IND_CALLINGPARTYNUMBER ( CMSG ) [ 0 ] > 1 ) {
2005-08-07 19:24:06 +00:00
callernplan = ( CONNECT_IND_CALLINGPARTYNUMBER ( CMSG ) [ 1 ] & 0x7f ) ;
2005-07-18 18:50:43 +00:00
callpres = ( CONNECT_IND_CALLINGPARTYNUMBER ( CMSG ) [ 2 ] & 0x63 ) ;
}
2005-06-02 18:47:35 +00:00
controller = PLCI & 0xff ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_3 " CONNECT_IND (PLCI=%#x,DID=%s,CID=%s,CIP=%#x,CONTROLLER=%#x) \n " ,
2005-06-02 18:47:35 +00:00
PLCI , DNID , CID , CONNECT_IND_CIPVALUE ( CMSG ) , controller ) ;
2007-09-03 19:41:40 +00:00
if ( CONNECT_IND_BCHANNELINFORMATION ( CMSG ) & & ( CONNECT_IND_BCHANNELINFORMATION ( CMSG ) [ 0 ] > 0 ) ) {
2005-10-01 15:17:10 +00:00
bchannelinfo [ 0 ] = CONNECT_IND_BCHANNELINFORMATION ( CMSG ) [ 1 ] + ' 0 ' ;
2005-06-02 18:47:35 +00:00
}
/* well...somebody is calling us. let's set up a channel */
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2007-04-23 18:47:49 +00:00
if ( i - > used ) {
/* is already used */
2005-06-02 18:47:35 +00:00
continue ;
}
2006-06-24 14:49:13 +00:00
if ( i - > controller ! = controller ) {
2005-06-02 18:47:35 +00:00
continue ;
}
2005-10-01 15:17:10 +00:00
if ( i - > channeltype = = CAPI_CHANNELTYPE_B ) {
if ( bchannelinfo [ 0 ] ! = ' 0 ' )
continue ;
} else {
if ( bchannelinfo [ 0 ] = = ' 0 ' )
continue ;
}
2006-01-28 19:42:44 +00:00
cc_copy_string ( buffer , i - > incomingmsn , sizeof ( buffer ) ) ;
2005-06-05 19:48:21 +00:00
for ( msn = strtok_r ( buffer , " , " , & buffer_rp ) ; msn ; msn = strtok_r ( NULL , " , " , & buffer_rp ) ) {
2005-08-13 09:31:07 +00:00
if ( ! strlen ( DNID ) ) {
2005-06-02 18:47:35 +00:00
/* if no DNID, only accept if '*' was specified */
if ( strncasecmp ( msn , magicmsn , strlen ( msn ) ) ) {
continue ;
}
2006-01-28 19:42:44 +00:00
cc_copy_string ( i - > dnid , emptydnid , sizeof ( i - > dnid ) ) ;
2005-06-02 18:47:35 +00:00
} else {
/* make sure the number match exactly or may match on ptp mode */
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: msn='%s' DNID='%s' %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , msn , DNID ,
2005-11-20 16:15:33 +00:00
( i - > isdnmode = = CAPI_ISDNMODE_MSN ) ? " MSN " : " DID " ) ;
2005-06-02 18:47:35 +00:00
if ( ( strcasecmp ( msn , DNID ) ) & &
2005-11-20 16:15:33 +00:00
( ( i - > isdnmode = = CAPI_ISDNMODE_MSN ) | |
2005-06-02 18:47:35 +00:00
( strlen ( msn ) > = strlen ( DNID ) ) | |
( strncasecmp ( msn , DNID , strlen ( msn ) ) ) ) & &
( strncasecmp ( msn , magicmsn , strlen ( msn ) ) ) ) {
continue ;
}
2006-01-28 19:42:44 +00:00
cc_copy_string ( i - > dnid , DNID , sizeof ( i - > dnid ) ) ;
2005-06-02 18:47:35 +00:00
}
if ( CID ! = NULL ) {
2005-08-07 19:24:06 +00:00
if ( ( callernplan & 0x70 ) = = CAPI_ETSI_NPLAN_NATIONAL )
2005-06-02 18:47:35 +00:00
snprintf ( i - > cid , ( sizeof ( i - > cid ) - 1 ) , " %s%s%s " ,
i - > prefix , capi_national_prefix , CID ) ;
2005-08-07 19:24:06 +00:00
else if ( ( callernplan & 0x70 ) = = CAPI_ETSI_NPLAN_INTERNAT )
2005-06-02 18:47:35 +00:00
snprintf ( i - > cid , ( sizeof ( i - > cid ) - 1 ) , " %s%s%s " ,
i - > prefix , capi_international_prefix , CID ) ;
2008-07-07 20:29:19 +00:00
else if ( ( callernplan & 0x70 ) = = CAPI_ETSI_NPLAN_SUBSCRIBER )
snprintf ( i - > cid , ( sizeof ( i - > cid ) - 1 ) , " %s%s%s " ,
i - > prefix , capi_subscriber_prefix , CID ) ;
2005-06-02 18:47:35 +00:00
else
snprintf ( i - > cid , ( sizeof ( i - > cid ) - 1 ) , " %s%s " ,
i - > prefix , CID ) ;
2005-07-18 18:50:43 +00:00
} else {
2006-01-28 19:42:44 +00:00
cc_copy_string ( i - > cid , emptyid , sizeof ( i - > cid ) ) ;
2005-07-18 18:50:43 +00:00
}
2005-06-04 14:28:52 +00:00
i - > cip = CONNECT_IND_CIPVALUE ( CMSG ) ;
2005-06-02 18:47:35 +00:00
i - > PLCI = PLCI ;
2005-09-11 13:35:19 +00:00
i - > MessageNumber = HEADER_MSGNUM ( CMSG ) ;
2005-08-07 19:24:06 +00:00
i - > cid_ton = callernplan ;
2005-06-02 18:47:35 +00:00
2009-07-24 20:30:47 +00:00
capi_new ( i , AST_STATE_DOWN , NULL ) ;
2005-11-20 16:15:33 +00:00
if ( i - > isdnmode = = CAPI_ISDNMODE_DID ) {
2005-06-02 18:47:35 +00:00
i - > state = CAPI_STATE_DID ;
} else {
2005-07-27 17:20:09 +00:00
i - > state = CAPI_STATE_INCALL ;
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
if ( ! i - > owner ) {
interface_cleanup ( i ) ;
break ;
}
2007-05-01 14:26:39 +00:00
i - > transfercapability = cip2tcap ( i - > cip ) ;
i - > owner - > transfercapability = i - > transfercapability ;
if ( capi_tcap_is_digital ( i - > transfercapability ) ) {
2006-05-22 11:04:33 +00:00
i - > bproto = CC_BPROTO_TRANSPARENT ;
}
2005-07-18 18:50:43 +00:00
i - > owner - > cid . cid_pres = callpres ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Incoming call '%s' -> '%s' \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > cid , i - > dnid ) ;
2005-09-27 09:33:21 +00:00
* interface = i ;
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2006-01-13 02:03:32 +00:00
cc_mutex_lock ( & i - > lock ) ;
2006-01-28 19:42:44 +00:00
2007-05-01 14:26:39 +00:00
pbx_builtin_setvar_helper ( i - > owner , " TRANSFERCAPABILITY " , transfercapability2str ( i - > transfercapability ) ) ;
2005-10-01 15:17:10 +00:00
pbx_builtin_setvar_helper ( i - > owner , " BCHANNELINFO " , bchannelinfo ) ;
2005-08-07 19:24:06 +00:00
sprintf ( buffer , " %d " , callednplan ) ;
pbx_builtin_setvar_helper ( i - > owner , " CALLEDTON " , buffer ) ;
2009-03-25 12:38:46 +00:00
sprintf ( buffer , " %d " , i - > cip ) ;
pbx_builtin_setvar_helper ( i - > owner , " CAPI_CIP " , buffer ) ;
2005-08-28 14:14:23 +00:00
/*
pbx_builtin_setvar_helper ( i - > owner , " CALLINGSUBADDRESS " ,
CONNECT_IND_CALLINGPARTYSUBADDRESS ( CMSG ) ) ;
pbx_builtin_setvar_helper ( i - > owner , " CALLEDSUBADDRESS " ,
CONNECT_IND_CALLEDPARTYSUBADDRESS ( CMSG ) ) ;
pbx_builtin_setvar_helper ( i - > owner , " USERUSERINFO " ,
CONNECT_IND_USERUSERDATA ( CMSG ) ) ;
*/
/* TODO : set some more variables on incoming call */
/*
2005-08-10 19:19:16 +00:00
pbx_builtin_setvar_helper ( i - > owner , " ANI2 " , buffer ) ;
pbx_builtin_setvar_helper ( i - > owner , " SECONDCALLERID " , buffer ) ;
*/
2007-02-11 16:01:32 +00:00
2007-06-07 19:24:32 +00:00
/* Handle QSIG informations, if any */
cc_qsig_handle_capiind ( CONNECT_IND_FACILITYDATAARRAY ( CMSG ) , i ) ;
2010-04-08 22:10:54 +00:00
# ifdef DIVA_STREAMING
i - > diva_stream_entry = 0 ;
if ( capi_controllers [ i - > controller ] - > divaStreaming ! = 0 ) {
capi_DivaStreamingOn ( i ) ;
}
# endif
2008-02-07 09:02:22 +00:00
if ( i - > immediate ) {
if ( ( i - > isdnmode = = CAPI_ISDNMODE_MSN ) | | ( ! ( strlen ( i - > dnid ) ) ) ) {
/* if we don't want to wait for SETUP/SENDING-COMPLETE in MSN mode */
/* or if no DNID in DID mode is provided (e.g. Austrian line) */
start_pbx_on_match ( i , PLCI , HEADER_MSGNUM ( CMSG ) ) ;
}
2005-09-26 11:35:13 +00:00
}
2005-06-02 18:47:35 +00:00
return ;
}
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-06-02 18:47:35 +00:00
/* obviously we are not called...so tell capi to ignore this call */
if ( capidebug ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " did not find device for msn = %s \n " , DNID ) ;
2005-06-02 18:47:35 +00:00
}
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , CONNECT_IND_PLCI ( CMSG ) , HEADER_MSGNUM ( CMSG ) ,
2007-04-29 14:00:32 +00:00
" w()()()()() " , 1 /* ignore */ ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
/*
2005-09-25 15:39:13 +00:00
* CAPI FACILITY_CONF
2005-06-02 18:47:35 +00:00
*/
2007-04-24 20:21:04 +00:00
static void capidev_handle_facility_confirmation ( _cmsg * CMSG , unsigned int PLCI , unsigned int NCCI , struct capi_pvt * * i )
2005-06-02 18:47:35 +00:00
{
2006-06-09 21:25:49 +00:00
int selector ;
2007-04-20 16:42:20 +00:00
selector = FACILITY_CONF_FACILITYSELECTOR ( CMSG ) ;
if ( selector = = FACILITYSELECTOR_SUPPLEMENTARY ) {
handle_facility_confirmation_supplementary ( CMSG , PLCI , NCCI , i ) ;
return ;
}
2007-04-24 20:21:04 +00:00
if ( * i = = NULL )
2006-06-09 21:25:49 +00:00
return ;
2009-05-19 07:56:38 +00:00
if ( ( selector = = PRIV_SELECTOR_DTMF_ONDATA ) & & ( i [ 0 ] - > channeltype = = CAPI_CHANNELTYPE_NULL ) & & ( i [ 0 ] - > line_plci = = NULL ) ) {
2009-05-06 20:38:13 +00:00
if ( FACILITY_CONF_INFO ( CMSG ) ) {
if ( FACILITY_CONF_INFO ( CMSG ) = = 0x300b ) {
null_plci_dtmf_support = 0 ;
cc_log ( LOG_WARNING , " no support for DTMF detection on NULL PLCI in this CAPI version. Please update CAPI driver. \n " ) ;
}
return ;
}
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: NULL PLCI DTMF conf(PLCI=%#x) \n " ,
( * i ) - > vname , PLCI ) ;
return ;
}
2005-08-29 19:06:19 +00:00
if ( selector = = FACILITYSELECTOR_DTMF ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: DTMF conf(PLCI=%#x) \n " ,
2007-04-24 20:21:04 +00:00
( * i ) - > vname , PLCI ) ;
2005-08-29 19:06:19 +00:00
return ;
}
2007-04-24 20:21:04 +00:00
if ( selector = = ( * i ) - > ecSelector ) {
2005-06-06 16:10:54 +00:00
if ( FACILITY_CONF_INFO ( CMSG ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " %s: Error setting up echo canceller (PLCI=%#x) \n " ,
2007-04-24 20:21:04 +00:00
( * i ) - > vname , PLCI ) ;
2005-08-29 19:06:19 +00:00
return ;
2005-06-06 16:10:54 +00:00
}
if ( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 1 ] = = EC_FUNCTION_DISABLE ) {
2006-06-20 16:03:36 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: Echo canceller successfully disabled (PLCI=%#x) \n " ,
2007-04-24 20:21:04 +00:00
( * i ) - > vname , PLCI ) ;
2005-06-06 16:10:54 +00:00
} else {
2006-06-20 16:03:36 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: Echo canceller successfully set up (PLCI=%#x) \n " ,
2007-04-24 20:21:04 +00:00
( * i ) - > vname , PLCI ) ;
2005-06-06 16:10:54 +00:00
}
2005-08-29 19:06:19 +00:00
return ;
}
2005-09-15 19:11:45 +00:00
if ( selector = = FACILITYSELECTOR_LINE_INTERCONNECT ) {
if ( ( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 1 ] = = 0x1 ) & &
( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 2 ] = = 0x0 ) ) {
/* enable */
2006-05-08 15:30:05 +00:00
if ( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 0 ] > 12 ) {
2007-04-24 20:21:04 +00:00
show_capi_info ( * i , read_capi_word ( & FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 12 ] ) ) ;
2005-09-15 19:11:45 +00:00
}
} else {
/* disable */
2006-05-08 15:30:05 +00:00
if ( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 0 ] > 12 ) {
2007-04-24 20:21:04 +00:00
show_capi_info ( * i , read_capi_word ( & FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( CMSG ) [ 12 ] ) ) ;
2005-09-15 19:11:45 +00:00
}
}
return ;
}
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " %s: unhandled FACILITY_CONF 0x%x \n " ,
2007-04-24 20:21:04 +00:00
( * i ) - > vname , FACILITY_CONF_FACILITYSELECTOR ( CMSG ) ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-13 11:15:51 +00:00
/*
* show error in confirmation
*/
2005-11-20 16:15:33 +00:00
static void show_capi_conf_error ( struct capi_pvt * i ,
2005-09-11 08:39:29 +00:00
unsigned int PLCI , u_int16_t wInfo ,
u_int16_t wCmd )
2005-08-13 11:15:51 +00:00
{
2005-08-16 10:11:43 +00:00
const char * name = channeltype ;
2005-08-13 11:15:51 +00:00
if ( i )
2006-06-18 16:32:32 +00:00
name = i - > vname ;
2006-05-30 09:48:16 +00:00
if ( ( wCmd = = CAPI_P_CONF ( ALERT ) ) & & ( wInfo = = 0x0003 ) ) {
/* Alert already sent by another application */
return ;
}
2005-08-13 11:15:51 +00:00
2005-09-11 08:39:29 +00:00
if ( wInfo = = 0x2002 ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_3 " %s: "
2005-09-11 08:39:29 +00:00
" 0x%x (wrong state) PLCI=0x%x "
2005-09-11 13:35:19 +00:00
" Command=%s,0x%04x \n " ,
name , wInfo , PLCI , capi_command_to_string ( wCmd ) , wCmd ) ;
2005-08-13 11:15:51 +00:00
} else {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " %s: conf_error 0x%04x "
2005-09-11 13:35:19 +00:00
" PLCI=0x%x Command=%s,0x%04x \n " ,
name , wInfo , PLCI , capi_command_to_string ( wCmd ) , wCmd ) ;
2005-08-13 11:15:51 +00:00
}
2005-09-11 08:39:29 +00:00
return ;
2005-08-13 11:15:51 +00:00
}
2006-05-27 15:01:17 +00:00
/*
* check special conditions , wake waiting threads and send outstanding commands
* for the given interface
*/
2006-06-09 21:25:49 +00:00
static void capidev_post_handling ( struct capi_pvt * i , _cmsg * CMSG )
2006-05-27 15:01:17 +00:00
{
2006-08-07 13:11:59 +00:00
unsigned short capicommand = CAPICMD ( CMSG - > Command , CMSG - > Subcommand ) ;
2006-05-27 15:01:17 +00:00
2006-07-09 14:18:53 +00:00
if ( ( i - > waitevent = = CAPI_WAITEVENT_B3_UP ) & &
( ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) ) {
i - > waitevent = 0 ;
ast_cond_signal ( & i - > event_trigger ) ;
cc_verbose ( 4 , 1 , " %s: found and signal for b3 up state. \n " ,
i - > vname ) ;
return ;
}
2006-07-09 13:30:47 +00:00
if ( ( i - > waitevent = = CAPI_WAITEVENT_B3_DOWN ) & &
( ! ( i - > isdnstate & ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ) ) ) {
i - > waitevent = 0 ;
ast_cond_signal ( & i - > event_trigger ) ;
cc_verbose ( 4 , 1 , " %s: found and signal for b3 down state. \n " ,
i - > vname ) ;
return ;
}
2006-07-08 20:22:15 +00:00
if ( ( i - > waitevent = = CAPI_WAITEVENT_ANSWER_FINISH ) & &
( i - > state ! = CAPI_STATE_ANSWERING ) ) {
i - > waitevent = 0 ;
ast_cond_signal ( & i - > event_trigger ) ;
cc_verbose ( 4 , 1 , " %s: found and signal for finished ANSWER state. \n " ,
i - > vname ) ;
return ;
}
2007-09-30 21:09:15 +00:00
if ( ( i - > waitevent = = CAPI_WAITEVENT_HOLD_IND ) & &
( HEADER_CMD ( CMSG ) = = CAPI_P_IND ( FACILITY ) ) & &
( FACILITY_IND_FACILITYSELECTOR ( CMSG ) = = FACILITYSELECTOR_SUPPLEMENTARY ) & &
( read_capi_word ( & FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 1 ] ) = = 0x0002 ) ) {
i - > waitevent = 0 ;
ast_cond_signal ( & i - > event_trigger ) ;
cc_verbose ( 4 , 1 , " %s: found and signal for HOLD indication. \n " ,
i - > vname ) ;
return ;
}
2007-10-01 16:10:37 +00:00
if ( ( i - > waitevent = = CAPI_WAITEVENT_ECT_IND ) & &
( HEADER_CMD ( CMSG ) = = CAPI_P_IND ( FACILITY ) ) & &
( FACILITY_IND_FACILITYSELECTOR ( CMSG ) = = FACILITYSELECTOR_SUPPLEMENTARY ) & &
( read_capi_word ( & FACILITY_IND_FACILITYINDICATIONPARAMETER ( CMSG ) [ 1 ] ) = = 0x0006 ) ) {
i - > waitevent = 0 ;
ast_cond_signal ( & i - > event_trigger ) ;
cc_verbose ( 4 , 1 , " %s: found and signal for ECT indication. \n " ,
i - > vname ) ;
return ;
}
2006-05-27 15:01:17 +00:00
if ( i - > waitevent = = capicommand ) {
i - > waitevent = 0 ;
ast_cond_signal ( & i - > event_trigger ) ;
cc_verbose ( 4 , 1 , " %s: found and signal for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , capi_cmd2str ( CMSG - > Command , CMSG - > Subcommand ) ) ;
2006-07-08 20:22:15 +00:00
return ;
2006-05-27 15:01:17 +00:00
}
}
2007-04-24 20:21:04 +00:00
/*
* handle CONNECT_CONF or FACILITY_CONF ( CCBS call )
*/
void capidev_handle_connection_conf ( struct capi_pvt * * i , unsigned int PLCI ,
unsigned short wInfo , unsigned short wMsgNum )
{
struct capi_pvt * ii ;
2010-03-09 12:21:52 +00:00
struct ast_frame fr = { AST_FRAME_CONTROL , } ;
2010-03-01 17:59:31 +00:00
FRAME_SUBCLASS_INTEGER ( fr . subclass ) = AST_CONTROL_BUSY ;
2007-04-24 20:21:04 +00:00
if ( * i ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_ERROR , CC_MESSAGE_BIGNAME " : CONNECT_CONF for already "
2007-04-24 20:21:04 +00:00
" defined interface received \n " ) ;
return ;
}
2007-04-29 22:28:30 +00:00
* i = capi_find_interface_by_msgnum ( wMsgNum ) ;
2007-04-24 20:21:04 +00:00
ii = * i ;
2007-04-28 16:48:00 +00:00
if ( ii = = NULL ) {
2007-04-24 20:21:04 +00:00
return ;
}
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_3 " %s: received CONNECT_CONF PLCI = %#x \n " ,
ii - > vname , PLCI ) ;
cc_mutex_lock ( & ii - > lock ) ;
if ( wInfo = = 0 ) {
ii - > PLCI = PLCI ;
} else {
/* error in connect, so set correct state and signal busy */
ii - > state = CAPI_STATE_DISCONNECTED ;
2007-04-28 16:48:00 +00:00
if ( ii - > owner ) {
local_queue_frame ( ii , & fr ) ;
}
2007-04-24 20:21:04 +00:00
}
}
2005-06-02 18:47:35 +00:00
/*
2005-09-11 13:35:19 +00:00
* handle CAPI msg
2005-06-02 18:47:35 +00:00
*/
2006-06-09 21:25:49 +00:00
static void capidev_handle_msg ( _cmsg * CMSG )
2005-06-02 18:47:35 +00:00
{
2005-09-11 13:35:19 +00:00
unsigned int NCCI = HEADER_CID ( CMSG ) ;
unsigned int PLCI = ( NCCI & 0xffff ) ;
unsigned short wCmd = HEADER_CMD ( CMSG ) ;
2005-09-15 19:11:45 +00:00
unsigned short wMsgNum = HEADER_MSGNUM ( CMSG ) ;
2005-09-11 13:35:19 +00:00
unsigned short wInfo = 0xffff ;
2007-04-29 22:28:30 +00:00
struct capi_pvt * i = capi_find_interface_by_plci ( PLCI ) ;
2005-09-11 13:35:19 +00:00
if ( ( wCmd = = CAPI_P_IND ( DATA_B3 ) ) | |
( wCmd = = CAPI_P_CONF ( DATA_B3 ) ) ) {
2008-02-20 11:02:09 +00:00
cc_verbose ( 7 , 1 , " CAPI: ApplId=0x%04x Command=0x%02x SubCommand=0x%02x MsgNum=0x%04x NCCI=0x%08x \n " ,
CMSG - > ApplId , CMSG - > Command , CMSG - > Subcommand , CMSG - > Messagenumber , CMSG - > adr . adrNCCI ) ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 7 , 1 , " %s \n " , capi_cmsg2str ( CMSG ) ) ;
2005-09-11 13:35:19 +00:00
} else {
2008-02-20 11:02:09 +00:00
cc_verbose ( 4 , 1 , " CAPI: ApplId=0x%04x Command=0x%02x SubCommand=0x%02x MsgNum=0x%04x NCCI=0x%08x \n " ,
CMSG - > ApplId , CMSG - > Command , CMSG - > Subcommand , CMSG - > Messagenumber , CMSG - > adr . adrNCCI ) ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 1 , " %s \n " , capi_cmsg2str ( CMSG ) ) ;
2005-09-11 13:35:19 +00:00
}
2006-01-28 19:42:44 +00:00
if ( i ! = NULL )
cc_mutex_lock ( & i - > lock ) ;
2005-09-11 13:35:19 +00:00
/* main switch table */
switch ( wCmd ) {
/*
* CAPI indications
*/
case CAPI_P_IND ( CONNECT ) :
2006-06-09 21:25:49 +00:00
capidev_handle_connect_indication ( CMSG , PLCI , NCCI , & i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( DATA_B3 ) :
2006-06-09 21:25:49 +00:00
capidev_handle_data_b3_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( CONNECT_B3 ) :
2006-06-09 21:25:49 +00:00
capidev_handle_connect_b3_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( CONNECT_B3_ACTIVE ) :
2006-06-09 21:25:49 +00:00
capidev_handle_connect_b3_active_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( DISCONNECT_B3 ) :
2006-06-09 21:25:49 +00:00
capidev_handle_disconnect_b3_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( DISCONNECT ) :
2006-06-09 21:25:49 +00:00
capidev_handle_disconnect_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( FACILITY ) :
2006-06-09 21:25:49 +00:00
capidev_handle_facility_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( INFO ) :
2006-06-09 21:25:49 +00:00
capidev_handle_info_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( CONNECT_ACTIVE ) :
2006-06-09 21:25:49 +00:00
capidev_handle_connect_active_indication ( CMSG , PLCI , NCCI , i ) ;
2005-09-11 13:35:19 +00:00
break ;
2006-09-24 10:44:40 +00:00
case CAPI_P_IND ( MANUFACTURER ) :
capidev_handle_manufacturer_indication ( CMSG , PLCI , NCCI , i ) ;
break ;
2005-06-02 18:47:35 +00:00
2005-09-11 13:35:19 +00:00
/*
* CAPI confirmations
*/
2005-06-02 18:47:35 +00:00
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( FACILITY ) :
wInfo = FACILITY_CONF_INFO ( CMSG ) ;
2007-04-24 20:21:04 +00:00
capidev_handle_facility_confirmation ( CMSG , PLCI , NCCI , & i ) ;
2005-06-06 16:10:54 +00:00
break ;
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( CONNECT ) :
wInfo = CONNECT_CONF_INFO ( CMSG ) ;
2007-04-24 20:21:04 +00:00
capidev_handle_connection_conf ( & i , PLCI , wInfo , wMsgNum ) ;
2005-06-06 16:10:54 +00:00
break ;
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( CONNECT_B3 ) :
2005-09-11 08:39:29 +00:00
wInfo = CONNECT_B3_CONF_INFO ( CMSG ) ;
2005-09-11 13:35:19 +00:00
if ( i = = NULL ) break ;
2009-09-17 18:12:02 +00:00
if ( ( wInfo & 0xff00 ) = = 0 ) {
2005-07-17 19:01:14 +00:00
i - > NCCI = NCCI ;
2008-08-08 08:13:29 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
capi_controllers [ i - > controller ] - > nfreebchannels - - ;
}
2005-06-06 16:10:54 +00:00
} else {
2005-12-08 22:06:16 +00:00
i - > isdnstate & = ~ ( CAPI_ISDN_STATE_B3_UP | CAPI_ISDN_STATE_B3_PEND ) ;
2005-06-06 16:10:54 +00:00
}
break ;
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( ALERT ) :
2005-09-11 08:39:29 +00:00
wInfo = ALERT_CONF_INFO ( CMSG ) ;
2005-09-11 13:35:19 +00:00
if ( i = = NULL ) break ;
if ( ! i - > owner ) break ;
2005-09-11 08:39:29 +00:00
if ( ( wInfo & 0xff00 ) = = 0 ) {
2005-07-17 19:01:14 +00:00
if ( i - > state ! = CAPI_STATE_DISCONNECTING ) {
i - > state = CAPI_STATE_ALERTING ;
if ( i - > owner - > _state = = AST_STATE_RING ) {
i - > owner - > rings = 1 ;
2005-07-13 18:27:58 +00:00
}
2005-06-05 19:48:21 +00:00
}
2005-06-06 16:10:54 +00:00
}
break ;
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( SELECT_B_PROTOCOL ) :
2005-09-11 08:39:29 +00:00
wInfo = SELECT_B_PROTOCOL_CONF_INFO ( CMSG ) ;
2005-09-11 13:35:19 +00:00
if ( i = = NULL ) break ;
if ( ! wInfo ) {
2006-06-27 14:54:03 +00:00
i - > isdnstate & = ~ CAPI_ISDN_STATE_B3_SELECT ;
if ( ( i - > outgoing ) & & ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) {
cc_start_b3 ( i ) ;
}
2006-05-27 12:49:57 +00:00
if ( ( i - > owner ) & & ( i - > FaxState & CAPI_FAX_STATE_ACTIVE ) ) {
2007-04-29 14:00:32 +00:00
capi_echo_canceller ( i , EC_FUNCTION_DISABLE ) ;
capi_detect_dtmf ( i , 0 ) ;
2005-06-04 14:28:52 +00:00
}
2007-03-30 15:53:39 +00:00
} else {
i - > isdnstate & = ~ CAPI_ISDN_STATE_B3_PEND ;
2005-06-06 16:10:54 +00:00
}
break ;
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( DATA_B3 ) :
2005-09-11 08:39:29 +00:00
wInfo = DATA_B3_CONF_INFO ( CMSG ) ;
2007-03-30 16:21:58 +00:00
if ( ( i ) & & ( i - > B3count > 0 ) ) {
i - > B3count - - ;
2006-05-08 16:48:57 +00:00
}
2006-06-27 14:54:03 +00:00
if ( ( i ) & & ( i - > FaxState & CAPI_FAX_STATE_SENDMODE ) ) {
capidev_send_faxdata ( i ) ;
}
2005-06-19 10:01:35 +00:00
break ;
2005-09-11 08:39:29 +00:00
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( DISCONNECT ) :
2005-09-11 08:39:29 +00:00
wInfo = DISCONNECT_CONF_INFO ( CMSG ) ;
2005-09-11 13:35:19 +00:00
break ;
2005-09-11 08:39:29 +00:00
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( DISCONNECT_B3 ) :
2005-09-11 08:39:29 +00:00
wInfo = DISCONNECT_B3_CONF_INFO ( CMSG ) ;
2005-09-11 13:35:19 +00:00
break ;
2005-09-11 08:39:29 +00:00
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( LISTEN ) :
2005-09-11 08:39:29 +00:00
wInfo = LISTEN_CONF_INFO ( CMSG ) ;
2005-09-11 13:35:19 +00:00
break ;
2005-09-11 08:39:29 +00:00
2005-09-11 13:35:19 +00:00
case CAPI_P_CONF ( INFO ) :
2005-09-11 08:39:29 +00:00
wInfo = INFO_CONF_INFO ( CMSG ) ;
2005-06-06 16:10:54 +00:00
break ;
2005-06-02 18:47:35 +00:00
2009-02-13 21:58:19 +00:00
case CAPI_P_CONF ( MANUFACTURER ) :
if ( CMSG - > ManuID = = _DI_MANU_ID ) {
switch ( CMSG - > Class & 0xffff ) {
2009-02-14 20:56:14 +00:00
case _DI_OPTIONS_REQUEST :
case _DI_DSP_CTRL :
wInfo = ( unsigned short ) ( CMSG - > Class > > 16 ) ;
break ;
2009-04-09 21:13:43 +00:00
case _DI_ASSIGN_PLCI :
wInfo = ( unsigned short ) ( CMSG - > Class > > 16 ) ;
capidev_handle_connection_conf ( & i , PLCI , wInfo , wMsgNum ) ;
break ;
2009-02-14 20:56:14 +00:00
default :
cc_log ( LOG_ERROR , CC_MESSAGE_BIGNAME " : unknown manufacturer command: %04x " ,
CMSG - > Class & 0xffff ) ;
break ;
2009-02-13 21:58:19 +00:00
}
break ;
}
2005-09-11 13:35:19 +00:00
default :
2008-02-24 12:57:52 +00:00
cc_log ( LOG_ERROR , CC_MESSAGE_BIGNAME " : Command=%s,0x%04x " ,
2005-09-11 13:35:19 +00:00
capi_command_to_string ( wCmd ) , wCmd ) ;
break ;
2005-06-02 18:47:35 +00:00
}
2005-09-11 13:35:19 +00:00
if ( wInfo ! = 0xffff ) {
if ( wInfo ) {
show_capi_conf_error ( i , PLCI , wInfo , wCmd ) ;
}
2006-06-18 16:32:32 +00:00
show_capi_info ( i , wInfo ) ;
2005-06-02 18:47:35 +00:00
}
2005-10-01 13:21:28 +00:00
2006-05-27 15:01:17 +00:00
if ( i = = NULL ) {
2008-02-24 12:57:52 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 CC_MESSAGE_BIGNAME
" : Command=%s,0x%04x: no interface for PLCI= "
2006-05-27 15:01:17 +00:00
" %#x, MSGNUM=%#x! \n " , capi_command_to_string ( wCmd ) ,
wCmd , PLCI , wMsgNum ) ;
} else {
2006-06-09 21:25:49 +00:00
capidev_post_handling ( i , CMSG ) ;
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2006-05-22 19:13:19 +00:00
}
2005-12-08 22:06:16 +00:00
2005-09-11 08:39:29 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
2005-08-16 18:25:03 +00:00
2009-04-15 12:28:40 +00:00
static struct capi_pvt * get_active_plci ( struct ast_channel * c ) {
2009-05-19 07:56:38 +00:00
struct capi_pvt * i ;
2009-04-15 12:28:40 +00:00
2009-05-19 07:56:38 +00:00
if ( c - > tech = = & capi_tech ) {
2009-04-15 12:28:40 +00:00
i = CC_CHANNEL_PVT ( c ) ;
2009-05-19 07:56:38 +00:00
} else {
i = pbx_check_resource_plci ( c ) ;
}
2009-04-15 12:28:40 +00:00
return ( i ) ;
}
2006-06-09 21:48:24 +00:00
/*
* deflect a call
*/
static int pbx_capi_call_deflect ( struct ast_channel * c , char * param )
{
2009-07-30 18:13:10 +00:00
# define DEFLECT_NUMBER_MAX_LEN 35
2006-06-09 21:48:24 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
char * number ;
int numberlen ;
2009-07-30 18:13:10 +00:00
char facnumber [ DEFLECT_NUMBER_MAX_LEN + 4 ] ;
2006-06-09 21:48:24 +00:00
if ( ! param ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME
" deflection requires an argument (destination phone number) \n " ) ;
2006-06-09 21:48:24 +00:00
return - 1 ;
}
number = strsep ( & param , " | " ) ;
numberlen = strlen ( number ) ;
if ( ! numberlen ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME
" deflection requires an argument (destination phone number) \n " ) ;
2006-06-09 21:48:24 +00:00
return - 1 ;
}
2009-07-30 18:13:10 +00:00
if ( numberlen > DEFLECT_NUMBER_MAX_LEN ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , CC_MESSAGE_NAME
2009-07-30 18:13:10 +00:00
" deflection does only support phone number up to %d digits \n " ,
DEFLECT_NUMBER_MAX_LEN ) ;
2006-06-09 21:48:24 +00:00
return - 1 ;
}
if ( ! ( capi_controllers [ i - > controller ] - > CD ) ) {
cc_log ( LOG_NOTICE , " %s: CALL DEFLECT for %s not supported by controller. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2006-06-09 21:48:24 +00:00
return - 1 ;
}
cc_mutex_lock ( & i - > lock ) ;
if ( ( i - > state ! = CAPI_STATE_INCALL ) & &
( i - > state ! = CAPI_STATE_DID ) & &
( i - > state ! = CAPI_STATE_ALERTING ) ) {
cc_mutex_unlock ( & i - > lock ) ;
cc_log ( LOG_WARNING , " wrong state of call for call deflection \n " ) ;
return - 1 ;
}
if ( i - > state ! = CAPI_STATE_ALERTING ) {
pbx_capi_alert ( c ) ;
}
2007-04-20 08:17:29 +00:00
facnumber [ 0 ] = 0x03 + numberlen ;
facnumber [ 1 ] = 0x00 ; /* type of facility number */
facnumber [ 2 ] = 0x00 ; /* number plan */
facnumber [ 3 ] = 0x00 ; /* presentation allowed */
memcpy ( & facnumber [ 4 ] , number , numberlen ) ;
2006-06-09 21:48:24 +00:00
2007-04-20 08:17:29 +00:00
capi_sendf ( i , 1 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" w(w(ws())) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x000d , /* call deflection */
0x0001 , /* display of own address allowed */
& facnumber [ 0 ]
) ;
2006-06-09 21:48:24 +00:00
cc_mutex_unlock ( & i - > lock ) ;
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " %s: sent FACILITY_REQ for CD PLCI = %#x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI ) ;
2006-06-09 21:48:24 +00:00
2007-04-20 08:17:29 +00:00
return 0 ;
2006-06-09 21:48:24 +00:00
}
2009-01-06 14:15:47 +00:00
/*
* store the peer for future actions
*/
static int pbx_capi_get_id ( struct ast_channel * c , char * param )
{
char buffer [ 32 ] ;
if ( ( ! param ) | | ( ! ( * param ) ) ) {
cc_log ( LOG_WARNING , " Parameter for getid missing. \n " ) ;
return - 1 ;
}
snprintf ( buffer , sizeof ( buffer ) - 1 , " %d " , capi_ApplID ) ;
pbx_builtin_setvar_helper ( c , param , buffer ) ;
return 0 ;
}
2007-04-17 21:04:42 +00:00
/*
* store the peer for future actions
*/
static int pbx_capi_peer_link ( struct ast_channel * c , char * param )
{
char buffer [ 32 ] ;
int id ;
id = cc_add_peer_link_id ( c ) ;
if ( id > = 0 ) {
snprintf ( buffer , sizeof ( buffer ) - 1 , " %d " , id ) ;
pbx_builtin_setvar_helper ( c , " _CAPIPEERLINKID " , buffer ) ;
}
2008-02-24 12:57:52 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " Added %s as " CC_MESSAGE_BIGNAME " peer link. \n " ,
2007-04-18 11:48:07 +00:00
c - > name ) ;
2007-04-17 21:04:42 +00:00
return 0 ;
}
2005-08-16 18:25:03 +00:00
/*
* retrieve a hold on call
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_retrieve ( struct ast_channel * c , char * param )
2005-08-16 18:25:03 +00:00
{
2006-02-04 12:48:10 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-28 14:14:23 +00:00
unsigned int plci = 0 ;
2006-11-11 20:07:19 +00:00
if ( c - > tech = = & capi_tech ) {
2005-08-28 14:14:23 +00:00
plci = i - > onholdPLCI ;
2006-02-04 12:48:10 +00:00
} else {
i = NULL ;
2005-08-28 14:14:23 +00:00
}
2005-08-16 18:25:03 +00:00
2007-10-20 12:05:26 +00:00
if ( ( param ) & & ( * param ) ) {
2005-08-21 10:28:43 +00:00
plci = ( unsigned int ) strtoul ( param , NULL , 0 ) ;
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2005-08-21 10:28:43 +00:00
if ( i - > onholdPLCI = = plci )
break ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-08-21 10:28:43 +00:00
if ( ! i ) {
plci = 0 ;
}
}
2005-08-28 14:14:23 +00:00
if ( ! i ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , " %s is not valid or not on hold to retrieve! \n " ,
2005-08-28 14:14:23 +00:00
c - > name ) ;
return 0 ;
}
2005-08-21 10:28:43 +00:00
if ( ( i - > state ! = CAPI_STATE_ONHOLD ) & &
( i - > isdnstate & CAPI_ISDN_STATE_HOLD ) ) {
2005-12-28 14:22:54 +00:00
int waitcount = 20 ;
2005-08-21 10:28:43 +00:00
while ( ( waitcount > 0 ) & & ( i - > state ! = CAPI_STATE_ONHOLD ) ) {
usleep ( 10000 ) ;
2005-12-28 14:22:54 +00:00
waitcount - - ;
2005-08-21 10:28:43 +00:00
}
}
if ( ( ! plci ) | | ( i - > state ! = CAPI_STATE_ONHOLD ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " %s: 0x%x is not valid or not on hold to retrieve! \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , plci ) ;
2005-08-21 15:35:44 +00:00
return 0 ;
2005-08-16 18:25:03 +00:00
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: using PLCI=%#x for retrieve \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , plci ) ;
2005-08-21 10:28:43 +00:00
2005-08-19 17:18:10 +00:00
if ( ! ( capi_controllers [ i - > controller ] - > holdretrieve ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " %s: RETRIEVE for %s not supported by controller. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-19 17:18:10 +00:00
return - 1 ;
}
2005-08-16 18:25:03 +00:00
2007-08-16 09:30:43 +00:00
if ( param ! = NULL )
cc_mutex_lock ( & i - > lock ) ;
2007-04-20 08:22:04 +00:00
2007-08-16 09:30:43 +00:00
capi_sendf ( i , ( param = = NULL ) ? 0 : 1 , CAPI_FACILITY_REQ , plci , get_capi_MessageNumber ( ) ,
2007-04-20 08:17:29 +00:00
" w(w()) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0003 /* retrieve */
) ;
2007-04-20 08:22:04 +00:00
i - > isdnstate & = ~ CAPI_ISDN_STATE_HOLD ;
2007-08-16 09:30:43 +00:00
if ( param ! = NULL )
cc_mutex_unlock ( & i - > lock ) ;
2005-08-16 18:25:03 +00:00
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent RETRIEVE for PLCI=%#x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , plci ) ;
2005-08-21 10:28:43 +00:00
2005-08-21 15:35:44 +00:00
pbx_builtin_setvar_helper ( i - > owner , " _CALLERHOLDID " , NULL ) ;
2005-08-21 10:28:43 +00:00
return 0 ;
}
/*
* explicit transfer a held call
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_ect ( struct ast_channel * c , char * param )
2005-08-21 10:28:43 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
struct capi_pvt * ii = NULL ;
2006-01-23 21:00:21 +00:00
const char * id ;
2005-08-21 15:35:44 +00:00
unsigned int plci = 0 ;
2007-04-22 11:24:25 +00:00
unsigned int ectplci ;
char * holdid ;
2009-02-13 21:58:19 +00:00
int explicit_peer_plci = 0 ;
2005-08-21 10:28:43 +00:00
2005-08-21 15:35:44 +00:00
if ( ( id = pbx_builtin_getvar_helper ( c , " CALLERHOLDID " ) ) ) {
plci = ( unsigned int ) strtoul ( id , NULL , 0 ) ;
}
2007-04-22 11:24:25 +00:00
holdid = strsep ( & param , " | " ) ;
if ( holdid ) {
plci = ( unsigned int ) strtoul ( holdid , NULL , 0 ) ;
2005-08-21 15:35:44 +00:00
}
2005-08-21 10:28:43 +00:00
2009-02-13 21:58:19 +00:00
if ( plci = = 0 ) {
2009-02-14 20:56:14 +00:00
if ( ( id = pbx_builtin_getvar_helper ( c , CAPI_ECT_PLCI_VAR_NAME ) ) ) {
plci = ( unsigned int ) strtoul ( id , NULL , 0 ) ;
}
if ( plci = = 0 ) {
cc_log ( LOG_WARNING , " %s: No id for ECT ! \n " , i - > vname ) ;
return - 1 ;
} else {
explicit_peer_plci = 1 ;
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: using explicit ect PLCI=%#x for PLCI=%x \n " ,
i - > vname , plci , i - > PLCI ) ;
cc_log ( LOG_WARNING , " %s: using explicit PLCI=%#x \n " , i - > vname , plci ) ;
}
2009-02-13 21:58:19 +00:00
}
2005-08-21 15:35:44 +00:00
if ( ! plci ) {
2006-06-18 16:32:32 +00:00
cc_log ( LOG_WARNING , " %s: No id for ECT ! \n " , i - > vname ) ;
2005-08-21 10:28:43 +00:00
return - 1 ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( ii = capi_iflist ; ii ; ii = ii - > next ) {
2009-02-14 20:56:14 +00:00
if ( ( ( explicit_peer_plci ! = 0 ) & & ( ii - > PLCI = = plci ) ) | | ( ii - > onholdPLCI = = plci ) )
2005-08-21 10:28:43 +00:00
break ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-08-21 15:35:44 +00:00
2005-08-21 10:28:43 +00:00
if ( ! ii ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " %s: 0x%x is not %s ! \n " ,
i - > vname , plci , ( explicit_peer_plci = = 0 ) ? " on hold " : " found " ) ;
2005-08-21 10:28:43 +00:00
return - 1 ;
}
2007-04-22 11:24:25 +00:00
ectplci = plci ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
if ( ( param ! = 0 ) & & ( * param ! = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_NOTICE , " %s: ECT param '%s' \n " , i - > name , param ) ;
} else {
cc_log ( LOG_NOTICE , " %s: no ECT param \n " , i - > name ) ;
}
if ( explicit_peer_plci = = 0 ) {
if ( ( param ) & & ( * param = = ' x ' ) ) {
ectplci = i - > PLCI ;
}
} else {
plci = i - > PLCI ;
2007-04-22 11:24:25 +00:00
}
2009-02-13 21:58:19 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: using %sPLCI=%#x for ECT \n " ,
i - > vname , ( explicit_peer_plci = = 0 ) ? " " : " explicit " , ectplci ) ;
2005-08-21 10:28:43 +00:00
if ( ! ( capi_controllers [ i - > controller ] - > ECT ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " %s: ECT for %s not supported by controller. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-21 10:28:43 +00:00
return - 1 ;
}
2009-02-14 20:56:14 +00:00
if ( ( explicit_peer_plci = = 0 ) & & ( ! ( ii - > isdnstate & CAPI_ISDN_STATE_HOLD ) ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " %s: PLCI %#x (%s) is not on hold for ECT \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , plci , ii - > vname ) ;
2005-08-21 15:35:44 +00:00
return - 1 ;
}
2009-02-13 21:58:19 +00:00
if ( explicit_peer_plci = = 0 )
cc_disconnect_b3 ( i , 1 ) ;
2005-08-21 15:35:44 +00:00
if ( i - > state ! = CAPI_STATE_CONNECTED ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " %s: destination not connected for ECT \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-08-21 15:35:44 +00:00
return - 1 ;
}
2007-04-20 08:17:29 +00:00
cc_mutex_lock ( & ii - > lock ) ;
2005-08-21 10:28:43 +00:00
2007-09-30 21:09:15 +00:00
/* implicit ECT */
2007-04-22 11:24:25 +00:00
capi_sendf ( ii , 1 , CAPI_FACILITY_REQ , ectplci , get_capi_MessageNumber ( ) ,
2007-04-20 08:17:29 +00:00
" w(w(d)) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0006 , /* ECT */
plci
) ;
2005-08-21 10:28:43 +00:00
2005-08-21 15:35:44 +00:00
ii - > isdnstate & = ~ CAPI_ISDN_STATE_HOLD ;
ii - > isdnstate | = CAPI_ISDN_STATE_ECT ;
i - > isdnstate | = CAPI_ISDN_STATE_ECT ;
2006-08-12 14:30:04 +00:00
cc_mutex_unlock ( & ii - > lock ) ;
2006-05-22 19:13:19 +00:00
2009-02-13 21:58:19 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent ECT for %sPLCI=%#x to PLCI=%#x \n " ,
i - > vname , ( explicit_peer_plci = = 0 ) ? " " : " explicit " , plci , ectplci ) ;
2005-08-16 18:25:03 +00:00
return 0 ;
}
/*
* hold a call
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_hold ( struct ast_channel * c , char * param )
2005-08-16 18:25:03 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-21 15:35:44 +00:00
char buffer [ 16 ] ;
2005-08-16 18:25:03 +00:00
2005-08-28 14:14:23 +00:00
/* TODO: support holdtype notify */
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_HOLD ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " %s: %s already on hold. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-21 15:35:44 +00:00
return 0 ;
}
2005-12-08 22:06:16 +00:00
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " %s: Cannot put on hold %s while not connected. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-28 14:14:23 +00:00
return 0 ;
2005-08-16 18:25:03 +00:00
}
2005-08-19 17:18:10 +00:00
if ( ! ( capi_controllers [ i - > controller ] - > holdretrieve ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " %s: HOLD for %s not supported by controller. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-28 14:14:23 +00:00
return 0 ;
2005-08-19 17:18:10 +00:00
}
2005-08-16 18:25:03 +00:00
2007-10-20 12:05:26 +00:00
if ( param ! = NULL ) {
cc_mutex_lock ( & i - > lock ) ;
}
2007-04-20 08:22:04 +00:00
2007-10-20 12:05:26 +00:00
capi_sendf ( i , ( param = = NULL ) ? 0 : 1 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
2007-04-20 08:17:29 +00:00
" w(w()) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0002 /* hold */
) ;
2005-08-16 18:25:03 +00:00
2005-12-28 14:22:54 +00:00
i - > onholdPLCI = i - > PLCI ;
2005-08-21 10:28:43 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_HOLD ;
2007-10-20 12:05:26 +00:00
if ( param ! = NULL ) {
cc_mutex_unlock ( & i - > lock ) ;
}
2007-04-20 08:22:04 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent HOLD for PLCI=%#x \n " ,
i - > vname , i - > PLCI ) ;
2005-08-21 15:35:44 +00:00
snprintf ( buffer , sizeof ( buffer ) - 1 , " %d " , i - > PLCI ) ;
2005-08-21 10:28:43 +00:00
if ( param ) {
pbx_builtin_setvar_helper ( i - > owner , param , buffer ) ;
}
2005-08-21 15:35:44 +00:00
pbx_builtin_setvar_helper ( i - > owner , " _CALLERHOLDID " , buffer ) ;
2005-08-16 18:25:03 +00:00
return 0 ;
}
2005-08-14 14:57:04 +00:00
/*
* report malicious call
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_malicious ( struct ast_channel * c , char * param )
2005-08-14 14:57:04 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-14 14:57:04 +00:00
2005-08-19 17:18:10 +00:00
if ( ! ( capi_controllers [ i - > controller ] - > MCID ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " %s: MCID for %s not supported by controller. \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-19 17:18:10 +00:00
return - 1 ;
}
2007-04-20 08:17:29 +00:00
cc_mutex_lock ( & i - > lock ) ;
2005-08-14 14:57:04 +00:00
2007-04-20 08:17:29 +00:00
capi_sendf ( i , 1 , CAPI_FACILITY_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" w(w()) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x000e /* MCID */
) ;
2005-08-14 14:57:04 +00:00
2006-05-22 19:13:19 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2005-08-14 14:57:04 +00:00
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent MCID for PLCI=%#x \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > PLCI ) ;
2005-08-14 14:57:04 +00:00
return 0 ;
}
2005-06-02 18:47:35 +00:00
2006-05-21 12:10:53 +00:00
/*
* set echo cancel
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_echocancel ( struct ast_channel * c , char * param )
2006-05-21 12:10:53 +00:00
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2006-05-21 12:10:53 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2006-05-21 12:10:53 +00:00
if ( ! param ) {
cc_log ( LOG_WARNING , " Parameter for echocancel missing. \n " ) ;
return - 1 ;
}
if ( ast_true ( param ) ) {
i - > doEC = 1 ;
2007-04-29 14:00:32 +00:00
capi_echo_canceller ( i , EC_FUNCTION_ENABLE ) ;
2006-05-21 12:10:53 +00:00
} else if ( ast_false ( param ) ) {
2007-04-29 14:00:32 +00:00
capi_echo_canceller ( i , EC_FUNCTION_DISABLE ) ;
2006-05-21 12:10:53 +00:00
i - > doEC = 0 ;
} else {
cc_log ( LOG_WARNING , " Parameter for echocancel invalid. \n " ) ;
return - 1 ;
}
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: echocancel switched %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > doEC ? " ON " : " OFF " ) ;
2006-05-21 12:10:53 +00:00
return 0 ;
}
2009-02-13 21:58:19 +00:00
/*
* noise suppressor
*/
static int pbx_capi_noisesuppressor ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( param = = NULL ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for noise suppressor missing. \n " ) ;
return - 1 ;
}
if ( ast_true ( param ) ) {
i - > divaAudioFlags | = 0x0080 ;
capi_diva_audio_features ( i ) ;
} else if ( ast_false ( param ) ) {
i - > divaAudioFlags & = ~ 0x0080 ;
capi_diva_audio_features ( i ) ;
} else {
cc_log ( LOG_WARNING , " Parameter for noise suppressor invalid. \n " ) ;
return - 1 ;
}
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: noise suppressor switched %s \n " ,
2009-04-10 07:23:20 +00:00
i - > vname , ( i - > divaAudioFlags & 0x0080 ) ! = 0 ? " ON " : " OFF " ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
/*
* + 6 dB to - 14 dB in 0.1 dB increments coded in the range 0xFF74 0x003C
*/
2009-02-14 20:56:14 +00:00
static unsigned short dbGain2DivaGain ( float dbGain )
2009-02-13 21:58:19 +00:00
{
float newGain ;
if ( dbGain < - 126 )
2009-04-10 07:23:20 +00:00
return 0x100 ;
2009-02-13 21:58:19 +00:00
if ( dbGain = = - 126 )
2009-04-10 07:23:20 +00:00
return 0x101 ;
2009-02-13 21:58:19 +00:00
if ( dbGain = = 0 )
2009-04-10 07:23:20 +00:00
return 0x8000 ;
2009-02-13 21:58:19 +00:00
if ( dbGain > = 6 )
2009-04-10 07:23:20 +00:00
return 0x8600 ;
2009-02-13 21:58:19 +00:00
newGain = 0x8000 + ( dbGain * 256.0 ) ;
return ( ( unsigned short ) floorf ( newGain ) ) ;
}
static int pbx_capi_rxdgain ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
float dbGain ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( param = = NULL ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for rx gain missing. \n " ) ;
return - 1 ;
}
2009-04-10 07:23:20 +00:00
dbGain = atof ( param ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_lock ( & i - > lock ) ;
i - > divaDigitalRxGainDB = dbGain ;
i - > divaDigitalRxGain = dbGain2DivaGain ( dbGain ) ;
cc_mutex_unlock ( & i - > lock ) ;
capi_diva_audio_features ( i ) ;
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: rx gain %f : %04x \n " ,
i - > vname , dbGain , i - > divaDigitalRxGain ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_incrxdgain ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
float dbGainInc ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( param = = NULL ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for nncremental rx gain missing. \n " ) ;
return - 1 ;
}
cc_mutex_lock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
dbGainInc = atof ( param ) ;
2009-02-13 21:58:19 +00:00
i - > divaDigitalRxGainDB + = dbGainInc ;
2009-02-14 20:56:14 +00:00
i - > divaDigitalRxGain = dbGain2DivaGain ( i - > divaDigitalRxGainDB ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_unlock ( & i - > lock ) ;
capi_diva_audio_features ( i ) ;
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: inc rx gain %f : %04x \n " ,
i - > vname , i - > divaDigitalRxGainDB , i - > divaDigitalRxGain ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
static int pbx_capi_txdgain ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
float dbGain ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( param = = NULL ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for tx gain missing. \n " ) ;
return - 1 ;
}
cc_mutex_lock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
dbGain = atof ( param ) ;
2009-02-13 21:58:19 +00:00
i - > divaDigitalTxGainDB = dbGain ;
2009-02-14 20:56:14 +00:00
i - > divaDigitalTxGain = dbGain2DivaGain ( dbGain ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_unlock ( & i - > lock ) ;
capi_diva_audio_features ( i ) ;
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: tx gain %f : %04x \n " ,
i - > vname , dbGain , i - > divaDigitalTxGain ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
static int pbx_capi_inctxdgain ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
float dbGainInc ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-14 20:56:14 +00:00
if ( ( param = = 0 ) | | ( * param = = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for incremental tx gain missing. \n " ) ;
return - 1 ;
}
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: inc tx gain %s:%f \n " ,
i - > vname , param , atof ( param ) ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_lock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
dbGainInc = atof ( param ) ;
2009-02-13 21:58:19 +00:00
i - > divaDigitalTxGainDB + = dbGainInc ;
2009-02-14 20:56:14 +00:00
i - > divaDigitalTxGain = dbGain2DivaGain ( i - > divaDigitalTxGainDB ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_unlock ( & i - > lock ) ;
capi_diva_audio_features ( i ) ;
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: inc tx gain %f : %04x \n " ,
i - > vname , i - > divaDigitalTxGainDB , i - > divaDigitalTxGain ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
static int pbx_capi_rxagc ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-13 21:58:19 +00:00
if ( ! param ) {
cc_log ( LOG_WARNING , " Parameter for rx agc missing. \n " ) ;
return - 1 ;
}
if ( ast_true ( param ) ) {
i - > divaAudioFlags | = 0x0008 ;
capi_diva_audio_features ( i ) ;
} else if ( ast_false ( param ) ) {
i - > divaAudioFlags & = ~ 0x0008 ;
capi_diva_audio_features ( i ) ;
} else {
cc_log ( LOG_WARNING , " Parameter for rx agc invalid. \n " ) ;
return - 1 ;
}
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: rx AGC switched %s \n " ,
2009-04-10 07:23:20 +00:00
i - > vname , ( i - > divaAudioFlags & 0x0008 ) ! = 0 ? " ON " : " OFF " ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
static int pbx_capi_txagc ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-13 21:58:19 +00:00
if ( ! param ) {
cc_log ( LOG_WARNING , " Parameter for tx agc missing. \n " ) ;
return - 1 ;
}
if ( ast_true ( param ) ) {
i - > divaAudioFlags | = 0x0004 ;
capi_diva_audio_features ( i ) ;
} else if ( ast_false ( param ) ) {
i - > divaAudioFlags & = ~ 0x0004 ;
capi_diva_audio_features ( i ) ;
} else {
cc_log ( LOG_WARNING , " Parameter for noise suppressor invalid. \n " ) ;
return - 1 ;
}
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: tx AGC switched %s \n " ,
2009-04-10 07:23:20 +00:00
i - > vname , ( i - > divaAudioFlags & 0x0004 ) ! = 0 ? " ON " : " OFF " ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_getplci ( struct ast_channel * c , char * param )
2009-02-13 21:58:19 +00:00
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2009-02-14 20:56:14 +00:00
if ( ( i ! = 0 ) & & ( i - > owner ! = 0 ) ) {
2009-02-13 21:58:19 +00:00
char buffer [ 128 ] ;
snprintf ( buffer , sizeof ( buffer ) - 1 , " %d " , i - > PLCI ) ;
buffer [ sizeof ( buffer ) - 1 ] = 0 ;
pbx_builtin_setvar_helper ( c , " CAPIPLCI " , buffer ) ;
}
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
/*
* DTMF suppression
*/
2009-02-14 20:56:14 +00:00
static int pbx_capi_clamping ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
int duration = 0 ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( param ! = NULL ) {
2009-02-14 20:56:14 +00:00
duration = atoi ( param ) ;
2009-02-13 21:58:19 +00:00
if ( duration ! = 0 & & duration < 10 )
duration = 10 ;
if ( duration > 200 )
duration = 200 ;
}
2009-02-14 20:56:14 +00:00
capi_diva_clamping ( i , ( unsigned short ) duration ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_mftonedetection ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
unsigned char function ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-14 20:56:14 +00:00
if ( ! param ) {
cc_log ( LOG_WARNING , " Parameter for MF tone detection missing. \n " ) ;
return - 1 ;
}
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
if ( ast_true ( param ) ) {
2009-02-13 21:58:19 +00:00
function = 253 ; /* Start MF listen on B channel data */
2009-02-14 20:56:14 +00:00
} else if ( ast_false ( param ) ) {
2009-02-13 21:58:19 +00:00
function = 254 ; /* Stop MF listen */
2009-02-14 20:56:14 +00:00
} else {
cc_log ( LOG_WARNING , " Parameter for MF tone detection invalid. \n " ) ;
return - 1 ;
}
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
capi_diva_tone_processing_function ( i , function ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: MF tone detection switched %s \n " ,
i - > vname , function = = 253 ? " ON " : " OFF " ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_pulsedetection ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
unsigned char function ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-14 20:56:14 +00:00
if ( ! param ) {
cc_log ( LOG_WARNING , " Parameter for Pulse detection missing. \n " ) ;
return - 1 ;
}
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
if ( ast_true ( param ) ) {
2009-02-13 21:58:19 +00:00
function = 246 ; /* Start dial pulse detector */
2009-02-14 20:56:14 +00:00
} else if ( ast_false ( param ) ) {
2009-02-13 21:58:19 +00:00
function = 247 ; /* Stop dial pulse detector */
2009-02-14 20:56:14 +00:00
} else {
cc_log ( LOG_WARNING , " Parameter for Pulse detection invalid. \n " ) ;
return - 1 ;
}
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
capi_diva_tone_processing_function ( i , function ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: Pulse detection switched %s \n " ,
i - > vname , function = = 253 ? " ON " : " OFF " ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_sendtone ( struct ast_channel * c , char * param )
{
2009-02-13 21:58:19 +00:00
static diva_supported_tones_t diva_tx_tones [ ] = {
{ 0x82 , " Dial tone " } ,
{ 0x83 , " PABX internal dial tone " } ,
{ 0x84 , " Special dial tone (stutter dial tone) " } ,
{ 0x85 , " Second dial tone " } ,
{ 0x86 , " Ringing tone " } ,
{ 0x87 , " Special ringing tone " } ,
{ 0x88 , " Busy tone " } ,
{ 0x89 , " Congestion tone (reorder tone) " } ,
{ 0x8A , " Special information tone " } ,
{ 0x8B , " Comfort tone " } ,
{ 0x8C , " Hold tone " } ,
{ 0x8D , " Record tone " } ,
{ 0x8E , " Caller waiting tone " } ,
{ 0x8F , " Call waiting tone " } ,
{ 0x90 , " Pay tone " } ,
{ 0x91 , " Positive indication tone " } ,
{ 0x92 , " Negative indication tone " } ,
{ 0x93 , " Warning tone " } ,
{ 0x94 , " Intrusion tone " } ,
{ 0x95 , " Calling card service tone " } ,
{ 0x96 , " Payphone recognition tone " } ,
{ 0x97 , " CPE alerting signal " } ,
{ 0x98 , " Off hook warning tone " } ,
{ 0xA0 , " Special information tone 0 " } ,
{ 0xA1 , " Special information tone 1 " } ,
{ 0xA2 , " Special information tone 2 " } ,
{ 0xA3 , " Special information tone 3 " } ,
{ 0xA4 , " Special information tone (operator intercept) " } ,
{ 0xA5 , " Special information tone (vacant circuit) " } ,
{ 0xA6 , " Special information tone (reorder) " } ,
{ 0xA7 , " Special information tone (no circuit found) " } ,
{ 0xBF , " Intercept tone " } ,
{ 0xC0 , " Modem calling tone " } ,
{ 0xC1 , " FAX calling tone " } ,
{ 0xC2 , " Answer tone " } ,
{ 0xC3 , " Answer tone with phase reversals " } ,
{ 0xC4 , " ANSam " } ,
{ 0xC5 , " ANSam with phase reversals " } ,
{ 0xC6 , " 2225 Hz (Bell 103 answer mode) " } ,
{ 0xC7 , " FAX flags " } ,
{ 0xC8 , " G2 FAX group ID " } ,
{ 0xCA , " Answering Machine Tone (390 Hz) " } ,
{ 0xCB , " Tone Alerting Signal (for Caller ID in PSTN) " } ,
} ;
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
unsigned char tone ;
unsigned int n ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-14 20:56:14 +00:00
if ( ( ! param ) | | ( * param = = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for tone generation missing. \n " ) ;
return - 1 ;
}
tone = ( unsigned char ) strtol ( param , 0 , 0 ) ;
for ( n = 0 ; n < sizeof ( diva_tx_tones ) / sizeof ( diva_tx_tones [ 0 ] ) & & diva_tx_tones [ n ] . tone ! = tone ; n + + ) ;
if ( n > = sizeof ( diva_tx_tones ) / sizeof ( diva_tx_tones [ 0 ] ) ) {
cc_log ( LOG_WARNING , " Unsupported tone %02x \n " , tone ) ;
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
capi_diva_send_tone_function ( i , tone ) ;
2009-02-13 21:58:19 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: started transmission of '%s' %02x tone \n " ,
2009-02-14 20:56:14 +00:00
i - > vname , diva_tx_tones [ n ] . name , diva_tx_tones [ n ] . tone ) ;
2009-02-13 21:58:19 +00:00
return 0 ;
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_stoptone ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-14 20:56:14 +00:00
capi_diva_send_tone_function ( i , 0x80 ) ;
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: stopped transmission of tones \n " ,
i - > vname ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static const char * pbx_capi_map_detected_tone ( unsigned char tone )
{
2009-02-13 21:58:19 +00:00
static diva_supported_tones_t diva_detected_tones [ ] = {
/* { 0x80, "End of signal detected" }, */
/* { 0x81, "Unidentified tone detected" }, */
{ 0x82 , " Dial tone detected " } ,
{ 0x83 , " PABX internal dial tone detected " } ,
{ 0x84 , " Special dial tone (stutter dial tone) detected " } ,
{ 0x85 , " Second dial tone detected " } ,
{ 0x86 , " Ringing tone detected " } ,
{ 0x87 , " Special ringing tone detected " } ,
{ 0x88 , " Busy tone detected " } ,
{ 0x89 , " Congestion tone (reorder tone) detected " } ,
{ 0x8A , " Special information tone detected " } ,
{ 0x8B , " Comfort tone detected " } ,
{ 0x8C , " Hold tone detected " } ,
{ 0x8D , " Record tone detected " } ,
{ 0x8E , " Caller waiting tone detected " } ,
{ 0x8F , " Call waiting tone detected " } ,
{ 0x90 , " Pay tone detected " } ,
{ 0x91 , " Positive indication tone detected " } ,
{ 0x92 , " Negative indication tone detected " } ,
{ 0x93 , " Warning tone detected " } ,
{ 0x94 , " Intrusion tone detected " } ,
{ 0x95 , " Calling card service tone detected " } ,
{ 0x96 , " Payphone recognition tone detected " } ,
{ 0x97 , " CPE alerting signal detected " } ,
{ 0x98 , " Off hook warning tone detected " } ,
{ 0xA0 , " Special information tone 0 " } ,
{ 0xA1 , " Special information tone 1 " } ,
{ 0xA2 , " Special information tone 2 " } ,
{ 0xA3 , " Special information tone 3 " } ,
{ 0xA4 , " Special information tone (operator intercept) " } ,
{ 0xA5 , " Special information tone (vacant circuit) " } ,
{ 0xA6 , " Special information tone (reorder) " } ,
{ 0xA7 , " Special information tone (no circuit found) " } ,
{ 0xBF , " Intercept tone detected " } ,
{ 0xC0 , " Modem calling tone detected " } ,
{ 0xC1 , " FAX calling tone detected " } ,
{ 0xC2 , " Answer tone detected " } ,
{ 0xC3 , " Answer tone with phase reversals detected " } ,
{ 0xC4 , " ANSam detected " } ,
{ 0xC5 , " ANSam with phase reversals detected " } ,
{ 0xC6 , " 2225 Hz (Bell 103 answer mode) detected " } ,
{ 0xC7 , " FAX flags detected " } ,
{ 0xC8 , " G2 FAX group ID detected " } ,
{ 0xC9 , " Human speech detected " } ,
{ 0xCA , " Answering Machine Tone (390 Hz) detected " } ,
{ 0xCB , " Tone Alerting Signal detected (for Caller ID in PSTN) " }
} ;
int n ;
for ( n = 0 ; n < sizeof ( diva_detected_tones ) / sizeof ( diva_detected_tones [ 0 ] ) ; n + + ) {
if ( diva_detected_tones [ n ] . tone = = tone ) {
return ( diva_detected_tones [ n ] . name ) ;
}
}
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_starttonedetection ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-14 20:56:14 +00:00
if ( ( param = = 0 ) | | ( * param = = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for starttonedetection missing. \n " ) ;
return ( - 1 ) ;
}
2009-02-14 20:56:14 +00:00
if ( ( strlen ( param ) ) > ( sizeof ( i - > special_tone_extension ) - 1 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for starttonedetection too long. \n " ) ;
return ( - 1 ) ;
}
cc_mutex_lock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
strcpy ( i - > special_tone_extension , param ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
capi_diva_tone_processing_function ( i , 250 /* Start tone detector */ ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: Tone detection switched ON \n " ,
i - > vname ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_stoptonedetection ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-02-13 21:58:19 +00:00
cc_mutex_lock ( & i - > lock ) ;
i - > special_tone_extension [ 0 ] = 0 ;
cc_mutex_unlock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
capi_diva_tone_processing_function ( i , 251 /* Stop tone detector */ ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: Tone detection switched OFF \n " ,
i - > vname ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_pitchcontrol ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
unsigned short rxpitch = 0 , txpitch = 0 ;
int enabled = 1 ;
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( ( param ! = NULL ) & & ( * param ! = 0 ) ) {
char * p = NULL ;
2009-02-13 21:58:19 +00:00
txpitch = rxpitch = ( unsigned short ) strtol ( param , & p , 0 ) ;
if ( p = = param ) {
rxpitch = 0 ;
}
2009-02-14 20:56:14 +00:00
if ( ( rxpitch ! = 0 ) & & ( p ! = 0 ) & & ( * p ! = 0 ) ) {
2009-02-13 21:58:19 +00:00
param = p + 1 ;
txpitch = ( unsigned short ) strtol ( param , & p , 0 ) ;
if ( p = = param ) {
txpitch = 0 ;
}
}
2009-02-14 20:56:14 +00:00
if ( ( rxpitch = = 0 ) | | ( txpitch = = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Wrong parameter for pitch control. \n " ) ;
return ( - 1 ) ;
}
rxpitch = ( rxpitch < 1250 ) ? 1250 : rxpitch ;
txpitch = ( txpitch < 1250 ) ? 1250 : txpitch ;
rxpitch = ( rxpitch > 51200 ) ? 51200 : rxpitch ;
txpitch = ( txpitch > 51200 ) ? 51200 : txpitch ;
cc_mutex_lock ( & i - > lock ) ;
i - > rxPitch = rxpitch ;
i - > txPitch = txpitch ;
cc_mutex_unlock ( & i - > lock ) ;
} else {
cc_mutex_lock ( & i - > lock ) ;
i - > rxPitch = 8000 ;
i - > txPitch = 8000 ;
cc_mutex_unlock ( & i - > lock ) ;
enabled = 0 ;
}
2009-02-14 20:56:14 +00:00
capi_diva_pitch_control_command ( i , enabled , rxpitch , txpitch ) ;
2009-02-13 21:58:19 +00:00
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: Pitch control Rx:%u Tx:%u \n " ,
i - > vname , rxpitch , txpitch ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2009-02-14 20:56:14 +00:00
static int pbx_capi_incpitchcontrol ( struct ast_channel * c , char * param )
{
2009-04-15 12:28:40 +00:00
struct capi_pvt * i = get_active_plci ( c ) ;
2009-02-13 21:58:19 +00:00
signed short rxpitchinc = 0 , txpitchinc = 0 ;
int rxPitch = i - > rxPitch , txPitch = i - > txPitch ;
2009-04-10 07:23:20 +00:00
char * p = NULL ;
2009-02-13 21:58:19 +00:00
2009-05-19 07:56:38 +00:00
if ( i = = NULL ) {
/*
Ignore command silently to ensure same context can be used to process
all types of calls or in case of fallback to NULL PLCI
*/
return ( 0 ) ;
}
2009-04-10 07:23:20 +00:00
if ( ( param = = NULL ) | | ( * param = = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Parameter for incremental pitch control missing. \n " ) ;
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-02-13 21:58:19 +00:00
}
rxpitchinc = ( signed short ) atoi ( param ) ;
2009-02-14 20:56:14 +00:00
p = strchr ( param , ' | ' ) ;
2009-04-10 07:23:20 +00:00
if ( p = = NULL ) {
2009-02-13 21:58:19 +00:00
txpitchinc = rxpitchinc ;
} else {
txpitchinc = ( signed short ) atoi ( & p [ 1 ] ) ;
}
2009-02-14 20:56:14 +00:00
if ( ( rxpitchinc = = 0 ) & & ( txpitchinc = = 0 ) ) {
2009-02-13 21:58:19 +00:00
cc_log ( LOG_WARNING , " Wrong parameter for incremental pitch control. \n " ) ;
2009-04-10 07:23:20 +00:00
return - 1 ;
2009-02-13 21:58:19 +00:00
}
rxPitch + = rxpitchinc ;
txPitch + = txpitchinc ;
rxPitch = ( rxPitch < 1250 ) ? 1250 : rxPitch ;
txPitch = ( txPitch < 1250 ) ? 1250 : txPitch ;
rxPitch = ( rxPitch > 51200 ) ? 51200 : rxPitch ;
txPitch = ( txPitch > 51200 ) ? 51200 : txPitch ;
2009-02-14 20:56:14 +00:00
capi_diva_pitch_control_command ( i , 1 , ( unsigned short ) rxPitch , ( unsigned short ) txPitch ) ;
2009-02-13 21:58:19 +00:00
cc_mutex_lock ( & i - > lock ) ;
i - > rxPitch = ( unsigned short ) rxPitch ;
i - > txPitch = ( unsigned short ) txPitch ;
cc_mutex_unlock ( & i - > lock ) ;
2009-02-14 20:56:14 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: Pitch control Rx:%u Tx:%u \n " ,
i - > vname , rxPitch , txPitch ) ;
2009-02-13 21:58:19 +00:00
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2005-08-14 13:59:16 +00:00
/*
* set echo squelch
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_echosquelch ( struct ast_channel * c , char * param )
2005-08-14 13:59:16 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-14 13:59:16 +00:00
if ( ! param ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Parameter for echosquelch missing. \n " ) ;
2005-08-14 13:59:16 +00:00
return - 1 ;
}
if ( ast_true ( param ) ) {
i - > doES = 1 ;
} else if ( ast_false ( param ) ) {
i - > doES = 0 ;
} else {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Parameter for echosquelch invalid. \n " ) ;
2005-08-14 13:59:16 +00:00
return - 1 ;
}
2006-05-21 12:10:53 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: echosquelch switched %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , i - > doES ? " ON " : " OFF " ) ;
2005-08-14 13:59:16 +00:00
return 0 ;
}
2005-08-25 19:30:31 +00:00
/*
* set holdtype
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_holdtype ( struct ast_channel * c , char * param )
2005-08-25 19:30:31 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-25 19:30:31 +00:00
if ( ! param ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Parameter for holdtype missing. \n " ) ;
2005-08-25 19:30:31 +00:00
return - 1 ;
}
if ( ! strcasecmp ( param , " hold " ) ) {
i - > doholdtype = CC_HOLDTYPE_HOLD ;
} else if ( ! strcasecmp ( param , " notify " ) ) {
i - > doholdtype = CC_HOLDTYPE_NOTIFY ;
} else if ( ! strcasecmp ( param , " local " ) ) {
i - > doholdtype = CC_HOLDTYPE_LOCAL ;
} else {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Parameter for holdtype invalid. \n " ) ;
2005-08-25 19:30:31 +00:00
return - 1 ;
}
2006-05-21 12:10:53 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_4 " %s: holdtype switched to %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , param ) ;
2005-08-25 19:30:31 +00:00
return 0 ;
}
2007-04-23 18:47:49 +00:00
/*
* send the disconnect commands to capi
*/
static void capi_disconnect ( struct capi_pvt * i )
{
cc_mutex_lock ( & i - > lock ) ;
2008-08-30 09:58:27 +00:00
i - > fsetting & = ~ CAPI_FSETTING_STAYONLINE ;
2007-04-23 18:47:49 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
cc_disconnect_b3 ( i , 0 ) ;
} else {
2009-04-27 20:02:46 +00:00
capi_send_disconnect ( i - > PLCI ) ;
2007-04-23 18:47:49 +00:00
}
cc_mutex_unlock ( & i - > lock ) ;
}
/*
* really hangup a channel if the stay - online mode was activated
*/
static int pbx_capi_realhangup ( struct ast_channel * c , char * param )
{
struct capi_pvt * i ;
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2007-04-23 18:47:49 +00:00
if ( i - > peer = = c )
break ;
}
cc_mutex_unlock ( & iflock ) ;
if ( ( i ) & & ( i - > state = = CAPI_STATE_DISCONNECTING ) ) {
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: " CC_MESSAGE_NAME
" command hangup PLCI=0x%#x. \n " , i - > vname , i - > PLCI ) ;
2007-04-23 18:47:49 +00:00
capi_disconnect ( i ) ;
}
return 0 ;
}
2005-07-27 17:20:09 +00:00
/*
2005-10-01 18:34:04 +00:00
* set early - B3 ( progress ) for incoming connections
2008-08-29 11:03:54 +00:00
* ( mainly for NT mode )
2005-07-27 17:20:09 +00:00
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_signal_progress ( struct ast_channel * c , char * param )
2005-07-27 17:20:09 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2008-08-29 11:03:54 +00:00
unsigned char fac [ ] = " \x04 \x1e \x02 \x82 \x88 " ; /* In-Band info available (for NT-mode) */
2005-07-27 17:20:09 +00:00
2008-08-29 11:03:54 +00:00
if ( ( i - > state ! = CAPI_STATE_DID ) & & ( i - > state ! = CAPI_STATE_INCALL ) & &
( i - > state ! = CAPI_STATE_ALERTING ) ) {
2006-04-01 13:31:56 +00:00
cc_log ( LOG_DEBUG , " wrong channel state to signal PROGRESS \n " ) ;
2005-10-01 18:34:04 +00:00
return 0 ;
}
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
2005-12-08 22:06:16 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: signal_progress in NT: B-channel already up \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2005-12-08 22:06:16 +00:00
return 0 ;
}
2007-03-30 15:53:39 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_B3_PEND ) ) {
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: signal_progress in NT: B-channel already pending \n " ,
i - > vname ) ;
return 0 ;
}
2008-08-29 11:03:54 +00:00
if ( ! ( i - > ntmode ) ) {
if ( i - > state ! = CAPI_STATE_ALERTING ) {
pbx_capi_alert ( c ) ;
}
}
2007-03-30 15:53:39 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_B3_PEND ;
2005-07-27 17:20:09 +00:00
2006-02-06 19:21:38 +00:00
cc_select_b ( i , NULL ) ;
2005-07-27 17:20:09 +00:00
2008-08-29 11:03:54 +00:00
if ( ( i - > ntmode ) ) {
/* send facility for Progress 'In-Band info available' */
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()()()s()) " ,
fac
) ;
}
2007-09-01 20:55:52 +00:00
2005-07-27 17:20:09 +00:00
return 0 ;
}
2005-08-28 14:14:23 +00:00
2006-12-18 19:09:52 +00:00
/*
* Initiate a Three - Party - Conference ( 3 PTY ) with one active and one
* held call
*/
static int pbx_capi_3pty_begin ( struct ast_channel * c , char * param )
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
struct capi_pvt * ii = NULL ;
const char * id ;
unsigned int plci = 0 ;
if ( ( id = pbx_builtin_getvar_helper ( c , " CALLERHOLDID " ) ) ) {
plci = ( unsigned int ) strtoul ( id , NULL , 0 ) ;
}
if ( param ) {
plci = ( unsigned int ) strtoul ( param , NULL , 0 ) ;
}
if ( ! plci ) {
cc_log ( LOG_WARNING , " %s: No id for 3PTY ! \n " , i - > vname ) ;
return - 1 ;
}
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( ii = capi_iflist ; ii ; ii = ii - > next ) {
2006-12-18 19:09:52 +00:00
if ( ii - > onholdPLCI = = plci )
break ;
}
cc_mutex_unlock ( & iflock ) ;
if ( ! ii ) {
cc_log ( LOG_WARNING , " %s: 0x%x is not on hold ! \n " ,
i - > vname , plci ) ;
return - 1 ;
}
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: using PLCI=%#x for 3PTY \n " ,
i - > vname , plci ) ;
if ( ! ( ii - > isdnstate & CAPI_ISDN_STATE_HOLD ) ) {
cc_log ( LOG_WARNING , " %s: PLCI %#x (%s) is not on hold for 3PTY \n " ,
i - > vname , plci , ii - > vname ) ;
return - 1 ;
}
if ( ! ( i - > isdnstate & CAPI_ISDN_STATE_B3_UP ) ) {
cc_log ( LOG_NOTICE , " %s: Cannot initiate conference %s while not connected. \n " ,
i - > vname , c - > name ) ;
return 0 ;
}
if ( ! ( capi_controllers [ i - > controller ] - > threePTY ) ) {
cc_log ( LOG_NOTICE , " %s: 3PTY for %s not supported by controller. \n " ,
i - > vname , c - > name ) ;
return 0 ;
}
cc_mutex_lock ( & ii - > lock ) ;
2007-04-20 08:17:29 +00:00
capi_sendf ( ii , 1 , CAPI_FACILITY_REQ , plci , get_capi_MessageNumber ( ) ,
" w(w(d)) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0007 , /* 3PTY begin */
plci
) ;
2006-12-18 19:09:52 +00:00
ii - > isdnstate & = ~ CAPI_ISDN_STATE_HOLD ;
ii - > isdnstate | = CAPI_ISDN_STATE_3PTY ;
i - > isdnstate | = CAPI_ISDN_STATE_3PTY ;
cc_mutex_unlock ( & ii - > lock ) ;
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent 3PTY for PLCI=%#x to PLCI=%#x \n " ,
i - > vname , plci , i - > PLCI ) ;
return 0 ;
}
2005-08-28 14:14:23 +00:00
/*
* struct of capi commands
*/
static struct capicommands_s {
char * cmdname ;
2009-02-13 21:58:19 +00:00
pbx_capi_command_proc_t cmd ;
2005-08-28 14:14:23 +00:00
int capionly ;
2009-04-09 22:44:44 +00:00
int resourceplcisupported ;
2005-08-28 14:14:23 +00:00
} capicommands [ ] = {
2009-04-09 22:44:44 +00:00
{ " getid " , pbx_capi_get_id , 0 , 0 } ,
{ " peerlink " , pbx_capi_peer_link , 0 , 0 } ,
{ " progress " , pbx_capi_signal_progress , 1 , 0 } ,
{ " deflect " , pbx_capi_call_deflect , 1 , 0 } ,
2009-05-02 13:21:17 +00:00
{ " receivefax " , pbx_capi_receive_fax , 1 , 1 } ,
{ " sendfax " , pbx_capi_send_fax , 1 , 1 } ,
2009-04-09 22:44:44 +00:00
{ " echosquelch " , pbx_capi_echosquelch , 1 , 0 } ,
{ " echocancel " , pbx_capi_echocancel , 1 , 1 } ,
{ " noisesuppressor " , pbx_capi_noisesuppressor , 1 , 1 } ,
{ " rxagc " , pbx_capi_rxagc , 1 , 1 } ,
{ " txagc " , pbx_capi_txagc , 1 , 1 } ,
{ " rxdgain " , pbx_capi_rxdgain , 1 , 1 } ,
{ " incrxdgain " , pbx_capi_incrxdgain , 1 , 1 } ,
{ " txdgain " , pbx_capi_txdgain , 1 , 1 } ,
{ " inctxdgain " , pbx_capi_inctxdgain , 1 , 1 } ,
{ " clamping " , pbx_capi_clamping , 1 , 1 } ,
{ " mftonedetection " , pbx_capi_mftonedetection , 1 , 1 } ,
{ " pulsedetection " , pbx_capi_pulsedetection , 1 , 1 } ,
{ " sendtone " , pbx_capi_sendtone , 1 , 1 } ,
{ " stoptone " , pbx_capi_stoptone , 1 , 1 } ,
{ " starttonedetection " , pbx_capi_starttonedetection , 1 , 1 } ,
{ " stoptonedetection " , pbx_capi_stoptonedetection , 1 , 1 } ,
{ " pitchcontrol " , pbx_capi_pitchcontrol , 1 , 1 } ,
{ " incpitchcontrol " , pbx_capi_incpitchcontrol , 1 , 1 } ,
{ " vc " , pbx_capi_voicecommand , 1 , 1 } ,
{ " vctransparency " , pbx_capi_voicecommand_transparency , 1 , 1 } ,
{ " getplci " , pbx_capi_getplci , 1 , 0 } ,
{ " malicious " , pbx_capi_malicious , 1 , 0 } ,
{ " hold " , pbx_capi_hold , 1 , 0 } ,
{ " holdtype " , pbx_capi_holdtype , 1 , 0 } ,
{ " retrieve " , pbx_capi_retrieve , 0 , 0 } ,
{ " ect " , pbx_capi_ect , 1 , 0 } ,
{ " 3pty_begin " , pbx_capi_3pty_begin , 1 , 0 } ,
{ " ccbs " , pbx_capi_ccbs , 0 , 0 } ,
{ " ccbsstop " , pbx_capi_ccbsstop , 0 , 0 } ,
{ " ccpartybusy " , pbx_capi_ccpartybusy , 0 , 0 } ,
{ " chat " , pbx_capi_chat , 0 , 0 } ,
2009-07-16 14:16:13 +00:00
{ " chat_command " , pbx_capi_chat_command , 0 , 0 } ,
2009-05-01 10:21:14 +00:00
{ " chat_mute " , pbx_capi_chat_mute , 0 , 0 } ,
2009-05-14 21:57:35 +00:00
{ " chat_play " , pbx_capi_chat_play , 0 , 0 } ,
2009-04-09 22:44:44 +00:00
{ " resource " , pbx_capi_chat_associate_resource_plci , 0 , 0 } ,
{ " hangup " , pbx_capi_realhangup , 0 , 0 } ,
{ " qsig_ssct " , pbx_capi_qsig_ssct , 1 , 0 } ,
{ " qsig_ct " , pbx_capi_qsig_ct , 1 , 0 } ,
{ " qsig_callmark " , pbx_capi_qsig_callmark , 1 , 0 } ,
{ " qsig_getplci " , pbx_capi_qsig_getplci , 1 , 0 } ,
2007-04-15 17:41:36 +00:00
{ NULL , NULL , 0 }
2005-08-28 14:14:23 +00:00
} ;
2005-07-27 17:20:09 +00:00
2009-02-14 20:56:14 +00:00
pbx_capi_command_proc_t pbx_capi_lockup_command_by_name ( const char * name )
{
2009-02-13 21:58:19 +00:00
int i ;
for ( i = 0 ; capicommands [ i ] . cmdname ! = 0 ; i + + ) {
2009-02-14 20:56:14 +00:00
if ( strcmp ( capicommands [ i ] . cmdname , name ) = = 0 ) {
2009-02-13 21:58:19 +00:00
return ( capicommands [ i ] . cmd ) ;
}
}
2009-04-10 07:23:20 +00:00
return 0 ;
2009-02-13 21:58:19 +00:00
}
2005-07-27 17:20:09 +00:00
/*
* capi command interface
*/
2009-07-24 20:30:47 +00:00
# ifdef CC_AST_HAS_CONST_CHAR_IN_REGAPPL
static int pbx_capicommand_exec ( struct ast_channel * chan , const char * data )
# else
2006-06-09 21:48:24 +00:00
static int pbx_capicommand_exec ( struct ast_channel * chan , void * data )
2009-07-24 20:30:47 +00:00
# endif
2005-07-27 17:20:09 +00:00
{
int res = 0 ;
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
struct ast_module_user * u ;
# else
2005-07-27 17:20:09 +00:00
struct localuser * u ;
2006-11-11 20:07:19 +00:00
# endif
2006-01-28 19:42:44 +00:00
char * s ;
2005-08-14 12:32:18 +00:00
char * stringp ;
2005-07-27 17:20:09 +00:00
char * command , * params ;
2005-08-28 14:14:23 +00:00
struct capicommands_s * capicmd = & capicommands [ 0 ] ;
2005-07-27 17:20:09 +00:00
if ( ! data ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , " capicommand requires arguments \n " ) ;
2005-07-27 17:20:09 +00:00
return - 1 ;
}
2005-08-28 14:14:23 +00:00
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
u = ast_module_user_add ( chan ) ;
# else
2005-08-28 14:14:23 +00:00
LOCAL_USER_ADD ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2005-08-28 14:14:23 +00:00
2006-01-28 19:42:44 +00:00
s = ast_strdupa ( data ) ;
stringp = s ;
2005-08-13 18:21:20 +00:00
command = strsep ( & stringp , " | " ) ;
params = stringp ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " capicommand: '%s' '%s' \n " ,
2005-07-27 17:20:09 +00:00
command , params ) ;
2005-08-28 14:14:23 +00:00
while ( capicmd - > cmd ) {
if ( ! strcasecmp ( capicmd - > cmdname , command ) )
break ;
capicmd + + ;
}
if ( ! capicmd - > cmd ) {
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2009-04-10 07:23:20 +00:00
ast_module_user_remove ( u ) ;
2006-11-11 20:07:19 +00:00
# else
2005-08-28 14:14:23 +00:00
LOCAL_USER_REMOVE ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , " Unknown command '%s' for capicommand \n " ,
2005-07-27 17:20:09 +00:00
command ) ;
2005-08-28 14:14:23 +00:00
return - 1 ;
}
2009-04-15 12:28:40 +00:00
if ( chan - > tech ! = & capi_tech ) {
if ( capicmd - > capionly ! = 0 ) {
struct capi_pvt * resource_plci = pbx_check_resource_plci ( chan ) ;
if ( ( capicmd - > resourceplcisupported = = 0 ) | |
2009-05-19 07:56:38 +00:00
( resource_plci = = NULL ) | |
( resource_plci - > line_plci = = NULL ) ) {
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2009-04-15 12:28:40 +00:00
ast_module_user_remove ( u ) ;
2006-11-11 20:07:19 +00:00
# else
2009-04-15 12:28:40 +00:00
LOCAL_USER_REMOVE ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2009-04-15 12:28:40 +00:00
cc_log ( LOG_WARNING , " This capicommand works on " CC_MESSAGE_NAME
" channels only, check your extensions.conf! \n " ) ;
return - 1 ;
}
}
2005-07-27 17:20:09 +00:00
}
2005-08-28 14:14:23 +00:00
res = ( capicmd - > cmd ) ( chan , params ) ;
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
ast_module_user_remove ( u ) ;
# else
2005-07-27 17:20:09 +00:00
LOCAL_USER_REMOVE ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2009-04-10 07:23:20 +00:00
return res ;
2005-07-27 17:20:09 +00:00
}
2005-06-02 18:47:35 +00:00
2005-08-21 10:28:43 +00:00
/*
* we don ' t support own indications
*/
2006-05-12 16:43:30 +00:00
# ifdef CC_AST_HAS_INDICATE_DATA
2006-06-09 21:48:24 +00:00
static int pbx_capi_indicate ( struct ast_channel * c , int condition , const void * data , size_t datalen )
2006-05-12 16:43:30 +00:00
# else
2006-06-09 21:48:24 +00:00
static int pbx_capi_indicate ( struct ast_channel * c , int condition )
2006-05-12 16:43:30 +00:00
# endif
2005-08-21 10:28:43 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
2005-08-21 10:28:43 +00:00
int ret = - 1 ;
if ( i = = NULL ) {
return - 1 ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & i - > lock ) ;
2005-10-01 13:21:28 +00:00
2005-08-21 10:28:43 +00:00
switch ( condition ) {
case AST_CONTROL_RINGING :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested RINGING-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-28 14:14:23 +00:00
/* TODO somehow enable unhold on ringing, but when wanted only */
2005-09-15 19:19:16 +00:00
/*
2005-08-28 14:14:23 +00:00
if ( i - > isdnstate & CAPI_ISDN_STATE_HOLD )
2006-06-09 21:48:24 +00:00
pbx_capi_retrieve ( c , NULL ) ;
2005-09-15 19:19:16 +00:00
*/
2005-12-08 22:06:16 +00:00
if ( i - > ntmode ) {
2006-06-09 21:48:24 +00:00
pbx_capi_signal_progress ( c , NULL ) ;
pbx_capi_alert ( c ) ;
2005-12-08 22:06:16 +00:00
} else {
2006-06-09 21:48:24 +00:00
ret = pbx_capi_alert ( c ) ;
2005-12-08 22:06:16 +00:00
}
2005-08-21 10:28:43 +00:00
break ;
case AST_CONTROL_BUSY :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested BUSY-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-21 10:28:43 +00:00
if ( ( i - > state = = CAPI_STATE_ALERTING ) | |
( i - > state = = CAPI_STATE_DID ) | | ( i - > state = = CAPI_STATE_INCALL ) ) {
2007-04-29 14:00:32 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , i - > PLCI , i - > MessageNumber ,
" w()()()()() " , 3 ) ;
2005-08-21 10:28:43 +00:00
ret = 0 ;
}
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_HOLD ) )
2006-06-09 21:48:24 +00:00
pbx_capi_retrieve ( c , NULL ) ;
2005-08-21 10:28:43 +00:00
break ;
case AST_CONTROL_CONGESTION :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested CONGESTION-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-21 10:28:43 +00:00
if ( ( i - > state = = CAPI_STATE_ALERTING ) | |
( i - > state = = CAPI_STATE_DID ) | | ( i - > state = = CAPI_STATE_INCALL ) ) {
2007-04-29 14:00:32 +00:00
capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , i - > PLCI , i - > MessageNumber ,
" w()()()()() " , 4 ) ;
2005-08-21 10:28:43 +00:00
ret = 0 ;
}
2006-02-06 19:21:38 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_HOLD ) )
2006-06-09 21:48:24 +00:00
pbx_capi_retrieve ( c , NULL ) ;
2005-08-21 10:28:43 +00:00
break ;
case AST_CONTROL_PROGRESS :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested PROGRESS-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2006-06-09 21:48:24 +00:00
if ( i - > ntmode ) pbx_capi_signal_progress ( c , NULL ) ;
2005-08-21 10:28:43 +00:00
break ;
case AST_CONTROL_PROCEEDING :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested PROCEEDING-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2006-06-09 21:48:24 +00:00
if ( i - > ntmode ) pbx_capi_signal_progress ( c , NULL ) ;
2005-08-21 10:28:43 +00:00
break ;
case AST_CONTROL_HOLD :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested HOLD-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-25 18:16:44 +00:00
if ( i - > doholdtype ! = CC_HOLDTYPE_LOCAL ) {
2006-06-09 21:48:24 +00:00
ret = pbx_capi_hold ( c , NULL ) ;
2005-08-21 10:28:43 +00:00
}
2007-02-11 14:34:10 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
else {
ast_moh_start ( c , data , i - > mohinterpret ) ;
}
# endif
2005-08-21 10:28:43 +00:00
break ;
case AST_CONTROL_UNHOLD :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested UNHOLD-Indication for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2005-08-25 18:16:44 +00:00
if ( i - > doholdtype ! = CC_HOLDTYPE_LOCAL ) {
2007-10-20 12:05:26 +00:00
if ( i - > transfergroup ) {
/* we assume bridge transfer, so wait a little bit to see
* if bridge is activated */
i - > whentoretrieve = time ( NULL ) + 1 ; /* timeout 1 second */
} else {
pbx_capi_retrieve ( c , NULL ) ;
}
ret = 0 ;
2005-08-21 10:28:43 +00:00
}
2007-02-11 14:34:10 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
else {
ast_moh_stop ( c ) ;
}
# endif
2005-08-21 10:28:43 +00:00
break ;
case - 1 : /* stop indications */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested Indication-STOP for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , c - > name ) ;
2007-10-20 12:05:26 +00:00
if ( ( i - > isdnstate & CAPI_ISDN_STATE_HOLD ) ) {
if ( i - > transfergroup ) {
/* we assume bridge transfer, so wait a little bit to see
* if bridge is activated */
i - > whentoretrieve = time ( NULL ) + 1 ; /* timeout 1 second */
} else {
pbx_capi_retrieve ( c , NULL ) ;
}
}
2005-08-21 10:28:43 +00:00
break ;
default :
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Requested unknown Indication %d for %s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname , condition , c - > name ) ;
2005-08-21 10:28:43 +00:00
break ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2005-08-21 10:28:43 +00:00
return ( ret ) ;
}
2005-12-28 14:22:54 +00:00
/*
* PBX wants to know the state for a specific device
*/
2006-06-09 21:48:24 +00:00
static int pbx_capi_devicestate ( void * data )
2005-12-28 14:22:54 +00:00
{
2007-10-20 14:07:01 +00:00
char * s ;
char * target ;
2007-10-22 08:59:54 +00:00
int res = AST_DEVICE_UNKNOWN ;
2007-10-20 14:07:01 +00:00
struct capi_pvt * i ;
2005-12-28 14:22:54 +00:00
if ( ! data ) {
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " No data for "
CC_MESSAGE_NAME " devicestate \n " ) ;
2005-12-28 14:22:54 +00:00
return res ;
}
2007-10-20 14:07:01 +00:00
s = ast_strdupa ( data ) ;
target = strsep ( & s , " / " ) ;
cc_mutex_lock ( & iflock ) ;
for ( i = capi_iflist ; i ; i = i - > next ) {
if ( ! ( strcmp ( target , i - > vname ) ) )
break ;
}
cc_mutex_unlock ( & iflock ) ;
if ( ! i ) {
cc_log ( LOG_WARNING , " Unknown target '%s' for devicestate. \n " ,
target ) ;
} else {
switch ( i - > state ) {
case 0 :
case CAPI_STATE_DISCONNECTED :
case CAPI_STATE_DISCONNECTING :
res = AST_DEVICE_NOT_INUSE ;
break ;
case CAPI_STATE_ALERTING :
2007-10-21 11:19:33 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2007-10-20 14:07:01 +00:00
res = AST_DEVICE_RINGINUSE ;
break ;
2007-10-21 11:19:33 +00:00
# endif
2007-10-20 14:07:01 +00:00
case CAPI_STATE_DID :
case CAPI_STATE_INCALL :
res = AST_DEVICE_RINGING ;
break ;
2007-10-21 11:19:33 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2007-10-20 14:07:01 +00:00
case CAPI_STATE_ONHOLD :
res = AST_DEVICE_ONHOLD ;
break ;
2007-10-21 11:19:33 +00:00
# endif
2007-10-20 14:07:01 +00:00
case CAPI_STATE_CONNECTED :
case CAPI_STATE_CONNECTPENDING :
case CAPI_STATE_ANSWERING :
res = AST_DEVICE_INUSE ;
break ;
default :
res = AST_DEVICE_UNKNOWN ;
break ;
/* AST_DEVICE_BUSY */
/* AST_DEVICE_UNAVAILABLE */
}
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_4 " chan_capi devicestate requested for %s is '%s' \n " ,
2009-07-24 20:30:47 +00:00
( char * ) data , ast_devstate2str ( res ) ) ;
2007-10-20 14:07:01 +00:00
}
2005-12-28 14:22:54 +00:00
return res ;
}
2007-05-11 06:32:50 +00:00
static void capi_do_interface_task ( void )
{
if ( interface_for_task = = NULL )
return ;
switch ( interface_task ) {
case CAPI_INTERFACE_TASK_NULLIFREMOVE :
/* remove an old null-plci interface */
capi_remove_nullif ( interface_for_task ) ;
break ;
default :
/* nothing to do */
break ;
}
interface_for_task = NULL ;
interface_task = CAPI_INTERFACE_TASK_NONE ;
}
2006-07-08 16:29:27 +00:00
static void capi_do_channel_task ( void )
{
if ( chan_for_task = = NULL )
return ;
2007-05-11 06:32:50 +00:00
switch ( channel_task ) {
2006-07-08 16:29:27 +00:00
case CAPI_CHANNEL_TASK_HANGUP :
/* deferred (out of lock) hangup */
ast_hangup ( chan_for_task ) ;
break ;
case CAPI_CHANNEL_TASK_SOFTHANGUP :
/* deferred (out of lock) soft-hangup */
ast_softhangup ( chan_for_task , AST_SOFTHANGUP_DEV ) ;
break ;
case CAPI_CHANNEL_TASK_PICKUP :
if ( ast_pickup_call ( chan_for_task ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Pickup not possible. \n " ,
chan_for_task - > name ) ;
}
ast_hangup ( chan_for_task ) ;
break ;
2007-04-08 21:20:47 +00:00
case CAPI_CHANNEL_TASK_GOTOFAX :
/* deferred (out of lock) async goto fax extension */
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
pbx_builtin_setvar_helper ( chan_for_task , " FAXEXTEN " , chan_for_task - > exten ) ;
if ( ast_async_goto ( chan_for_task , chan_for_task - > context , " fax " , 1 ) ) {
cc_log ( LOG_WARNING , " Failed to async goto '%s' into fax of '%s' \n " ,
chan_for_task - > name , chan_for_task - > context ) ;
}
break ;
2006-07-08 16:29:27 +00:00
default :
/* nothing to do */
break ;
}
chan_for_task = NULL ;
channel_task = CAPI_CHANNEL_TASK_NONE ;
}
2007-04-23 18:47:49 +00:00
/*
* check for tasks every second
*/
static void capidev_run_secondly ( time_t now )
{
struct capi_pvt * i ;
/* check for channels to hangup (timeout) */
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2007-04-24 11:45:54 +00:00
if ( i - > used = = NULL ) {
continue ;
}
if ( ( i - > whentohangup ) & & ( i - > whentohangup < now ) ) {
2007-04-23 18:47:49 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: stay-online timeout, hanging up. \n " ,
i - > vname ) ;
i - > whentohangup = 0 ;
capi_disconnect ( i ) ;
}
2007-04-24 11:45:54 +00:00
if ( ( i - > whentoqueuehangup ) & & ( i - > whentoqueuehangup < now ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: stay-online queue-hangup. \n " ,
i - > vname ) ;
2007-04-29 22:28:30 +00:00
capi_queue_cause_control ( i , 1 ) ;
2007-04-24 11:45:54 +00:00
i - > whentoqueuehangup = 0 ;
}
2007-10-20 12:05:26 +00:00
if ( ( i - > whentoretrieve ) & & ( i - > whentoretrieve < now ) ) {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: deferred retrieve. \n " ,
i - > vname ) ;
i - > whentoretrieve = 0 ;
if ( i - > owner ) {
pbx_capi_retrieve ( i - > owner , NULL ) ;
}
}
2007-04-23 18:47:49 +00:00
}
cc_mutex_unlock ( & iflock ) ;
}
2005-08-16 10:11:43 +00:00
/*
2007-10-21 16:00:18 +00:00
* Main loop to read the capi_device .
2005-08-16 10:11:43 +00:00
*/
2006-06-09 21:25:49 +00:00
static void * capidev_loop ( void * data )
2005-06-02 18:47:35 +00:00
{
unsigned int Info ;
_cmsg monCMSG ;
2007-04-23 18:47:49 +00:00
time_t lastcall = 0 ;
time_t newtime ;
2005-06-02 18:47:35 +00:00
2009-01-06 14:15:47 +00:00
cc_log ( LOG_NOTICE , " Started CAPI device thread for CAPI Appl-ID %d. \n " , capi_ApplID ) ;
2007-05-03 09:28:32 +00:00
2005-06-02 18:47:35 +00:00
for ( /* for ever */ ; ; ) {
2006-06-09 21:25:49 +00:00
switch ( Info = capidev_check_wait_get_cmsg ( & monCMSG ) ) {
2005-06-06 16:10:54 +00:00
case 0x0000 :
2006-06-09 21:25:49 +00:00
capidev_handle_msg ( & monCMSG ) ;
2006-07-08 16:29:27 +00:00
capi_do_channel_task ( ) ;
2007-05-11 06:32:50 +00:00
capi_do_interface_task ( ) ;
2005-06-06 16:10:54 +00:00
break ;
case 0x1104 :
/* CAPI queue is empty */
break ;
2005-12-31 03:55:54 +00:00
case 0x1101 :
/* The application ID is no longer valid.
* This error is fatal , and " chan_capi "
* should restart .
*/
2006-01-28 19:42:44 +00:00
cc_log ( LOG_ERROR , " CAPI reports application ID no longer valid, PANIC \n " ) ;
2005-12-31 03:55:54 +00:00
return NULL ;
2005-06-06 16:10:54 +00:00
default :
/* something is wrong! */
break ;
2005-06-02 18:47:35 +00:00
} /* switch */
2007-04-23 18:47:49 +00:00
newtime = time ( NULL ) ;
if ( lastcall ! = newtime ) {
lastcall = newtime ;
capidev_run_secondly ( newtime ) ;
}
2010-04-08 22:10:54 +00:00
# ifdef DIVA_STREAMING
divaStreamingWakeup ( ) ;
# endif
2005-06-02 18:47:35 +00:00
} /* for */
/* never reached */
return NULL ;
}
/*
* GAIN
*/
2007-04-30 15:19:28 +00:00
void capi_gains ( struct cc_capi_gains * g , float rxgain , float txgain )
2005-06-02 18:47:35 +00:00
{
2005-06-06 16:10:54 +00:00
int i = 0 ;
int x = 0 ;
2005-06-02 18:47:35 +00:00
if ( rxgain ! = 1.0 ) {
for ( i = 0 ; i < 256 ; i + + ) {
2005-08-10 19:19:16 +00:00
if ( capi_capability = = AST_FORMAT_ULAW ) {
x = ( int ) ( ( ( float ) capiULAW2INT [ i ] ) * rxgain ) ;
} else {
x = ( int ) ( ( ( float ) capiALAW2INT [ i ] ) * rxgain ) ;
}
2005-06-02 18:47:35 +00:00
if ( x > 32767 )
x = 32767 ;
if ( x < - 32767 )
x = - 32767 ;
2005-08-10 19:19:16 +00:00
if ( capi_capability = = AST_FORMAT_ULAW ) {
g - > rxgains [ i ] = capi_int2ulaw ( x ) ;
} else {
g - > rxgains [ i ] = capi_int2alaw ( x ) ;
}
2005-06-02 18:47:35 +00:00
}
}
if ( txgain ! = 1.0 ) {
for ( i = 0 ; i < 256 ; i + + ) {
2005-08-10 19:19:16 +00:00
if ( capi_capability = = AST_FORMAT_ULAW ) {
x = ( int ) ( ( ( float ) capiULAW2INT [ i ] ) * txgain ) ;
} else {
x = ( int ) ( ( ( float ) capiALAW2INT [ i ] ) * txgain ) ;
}
2005-06-02 18:47:35 +00:00
if ( x > 32767 )
x = 32767 ;
if ( x < - 32767 )
x = - 32767 ;
2005-08-10 19:19:16 +00:00
if ( capi_capability = = AST_FORMAT_ULAW ) {
g - > txgains [ i ] = capi_int2ulaw ( x ) ;
} else {
g - > txgains [ i ] = capi_int2alaw ( x ) ;
}
2005-06-02 18:47:35 +00:00
}
}
}
/*
* create new interface
*/
2005-11-20 16:15:33 +00:00
int mkif ( struct cc_capi_conf * conf )
2005-06-02 18:47:35 +00:00
{
2005-11-20 16:15:33 +00:00
struct capi_pvt * tmp ;
2005-06-02 18:47:35 +00:00
int i = 0 ;
2006-06-18 20:57:56 +00:00
u_int16_t unit ;
2005-06-02 18:47:35 +00:00
2005-10-01 15:17:10 +00:00
for ( i = 0 ; i < = conf - > devices ; i + + ) {
2005-11-20 16:15:33 +00:00
tmp = malloc ( sizeof ( struct capi_pvt ) ) ;
2005-06-02 18:47:35 +00:00
if ( ! tmp ) {
return - 1 ;
}
2005-11-20 16:15:33 +00:00
memset ( tmp , 0 , sizeof ( struct capi_pvt ) ) ;
2006-06-10 11:58:50 +00:00
tmp - > readerfd = - 1 ;
tmp - > writerfd = - 1 ;
2005-06-02 18:47:35 +00:00
2006-01-30 23:40:28 +00:00
cc_mutex_init ( & tmp - > lock ) ;
2006-05-22 19:13:19 +00:00
ast_cond_init ( & tmp - > event_trigger , NULL ) ;
2005-10-01 15:17:10 +00:00
if ( i = = 0 ) {
snprintf ( tmp - > name , sizeof ( tmp - > name ) - 1 , " %s-pseudo-D " , conf - > name ) ;
tmp - > channeltype = CAPI_CHANNELTYPE_D ;
} else {
2006-01-28 19:42:44 +00:00
cc_copy_string ( tmp - > name , conf - > name , sizeof ( tmp - > name ) ) ;
2005-10-01 15:17:10 +00:00
tmp - > channeltype = CAPI_CHANNELTYPE_B ;
}
2006-06-18 16:32:32 +00:00
snprintf ( tmp - > vname , sizeof ( tmp - > vname ) - 1 , " %s#%02d " , conf - > name , i ) ;
2006-01-28 19:42:44 +00:00
cc_copy_string ( tmp - > context , conf - > context , sizeof ( tmp - > context ) ) ;
cc_copy_string ( tmp - > incomingmsn , conf - > incomingmsn , sizeof ( tmp - > incomingmsn ) ) ;
cc_copy_string ( tmp - > defaultcid , conf - > defaultcid , sizeof ( tmp - > defaultcid ) ) ;
cc_copy_string ( tmp - > prefix , conf - > prefix , sizeof ( tmp - > prefix ) ) ;
cc_copy_string ( tmp - > accountcode , conf - > accountcode , sizeof ( tmp - > accountcode ) ) ;
cc_copy_string ( tmp - > language , conf - > language , sizeof ( tmp - > language ) ) ;
2007-02-11 14:34:10 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
cc_copy_string ( tmp - > mohinterpret , conf - > mohinterpret , sizeof ( tmp - > mohinterpret ) ) ;
memcpy ( & tmp - > jbconf , & conf - > jbconf , sizeof ( struct ast_jb_conf ) ) ;
# endif
2006-01-28 19:42:44 +00:00
2006-06-18 20:57:56 +00:00
unit = atoi ( conf - > controllerstr ) ;
2005-09-11 08:39:29 +00:00
/* There is no reason not to
* allow controller 0 !
*
* Hide problem from user :
*/
if ( unit = = 0 ) {
/* The ISDN4BSD kernel will modulo
* the controller number by
* " capi_num_controllers " , so this
* is equivalent to " 0 " :
*/
unit = capi_num_controllers ;
}
2008-03-23 13:04:30 +00:00
/* always range check user input */
if ( unit > CAPI_MAX_CONTROLLERS )
unit = CAPI_MAX_CONTROLLERS ;
if ( ( unit > capi_num_controllers ) | |
( ! ( capi_controllers [ unit ] ) ) ) {
2006-12-17 14:22:05 +00:00
free ( tmp ) ;
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " controller %d invalid, ignoring interface. \n " ,
unit ) ;
return 0 ;
}
2008-03-23 13:04:30 +00:00
capi_controllers [ unit ] - > used = 1 ;
2009-04-15 13:39:57 +00:00
capi_controllers [ unit ] - > ecPath = conf - > echocancelpath ;
2005-09-11 08:39:29 +00:00
2006-06-24 14:49:13 +00:00
tmp - > controller = unit ;
2005-07-17 19:01:14 +00:00
tmp - > doEC = conf - > echocancel ;
2006-11-25 16:13:40 +00:00
tmp - > doEC_global = conf - > echocancel ;
2005-07-17 19:01:14 +00:00
tmp - > ecOption = conf - > ecoption ;
2006-04-01 16:29:50 +00:00
if ( conf - > ecnlp ) tmp - > ecOption | = 0x01 ; /* bit 0 of ec-option is NLP */
2005-07-17 19:01:14 +00:00
tmp - > ecTail = conf - > ectail ;
tmp - > isdnmode = conf - > isdnmode ;
2005-08-25 19:00:55 +00:00
tmp - > ntmode = conf - > ntmode ;
2005-08-25 17:45:39 +00:00
tmp - > ES = conf - > es ;
2005-07-17 19:01:14 +00:00
tmp - > callgroup = conf - > callgroup ;
2006-07-08 16:29:27 +00:00
tmp - > pickupgroup = conf - > pickupgroup ;
2005-07-17 19:01:14 +00:00
tmp - > group = conf - > group ;
2007-09-30 21:09:15 +00:00
tmp - > transfergroup = conf - > transfergroup ;
2006-07-08 22:13:47 +00:00
tmp - > amaflags = conf - > amaflags ;
2005-08-13 09:31:07 +00:00
tmp - > immediate = conf - > immediate ;
2005-08-25 18:16:44 +00:00
tmp - > holdtype = conf - > holdtype ;
2005-08-29 19:06:19 +00:00
tmp - > ecSelector = conf - > ecSelector ;
2005-09-15 19:11:45 +00:00
tmp - > bridge = conf - > bridge ;
2006-05-27 12:49:57 +00:00
tmp - > FaxState = conf - > faxsetting ;
2008-06-29 11:33:46 +00:00
tmp - > faxdetecttime = conf - > faxdetecttime ;
2005-06-02 18:47:35 +00:00
2005-11-20 16:15:33 +00:00
tmp - > smoother = ast_smoother_new ( CAPI_MAX_B3_BLOCK_SIZE ) ;
2005-06-19 10:01:35 +00:00
2005-07-17 19:01:14 +00:00
tmp - > rxgain = conf - > rxgain ;
tmp - > txgain = conf - > txgain ;
capi_gains ( & tmp - > g , conf - > rxgain , conf - > txgain ) ;
2005-06-02 18:47:35 +00:00
2005-08-07 12:21:36 +00:00
tmp - > doDTMF = conf - > softdtmf ;
2006-01-30 23:40:28 +00:00
tmp - > capability = conf - > capability ;
2005-06-02 18:47:35 +00:00
2007-06-07 19:24:32 +00:00
/* Initialize QSIG code */
cc_qsig_interface_init ( conf , tmp ) ;
2007-04-29 22:28:30 +00:00
tmp - > next = capi_iflist ; /* prepend */
capi_iflist = tmp ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 CC_MESSAGE_NAME
" %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d \n " ,
2006-06-24 14:49:13 +00:00
( tmp - > channeltype = = CAPI_CHANNELTYPE_B ) ? ' B ' : ' D ' ,
tmp - > vname , tmp - > incomingmsn , tmp - > context , tmp - > controller ,
2005-07-17 19:01:14 +00:00
conf - > devices , tmp - > doEC , tmp - > ecOption , tmp - > ecTail ) ;
2005-06-02 18:47:35 +00:00
}
return 0 ;
}
/*
* eval supported services
*/
2005-11-20 16:15:33 +00:00
static void supported_sservices ( struct cc_capi_controller * cp )
2005-06-02 18:47:35 +00:00
{
MESSAGE_EXCHANGE_ERROR error ;
2007-04-28 20:59:44 +00:00
_cmsg CMSG2 ;
2005-06-02 18:47:35 +00:00
struct timeval tv ;
2005-08-19 17:18:10 +00:00
unsigned int services ;
2005-06-02 18:47:35 +00:00
2007-04-28 20:59:44 +00:00
capi_sendf ( NULL , 0 , CAPI_FACILITY_REQ , cp - > controller , get_capi_MessageNumber ( ) ,
" w(w()) " ,
FACILITYSELECTOR_SUPPLEMENTARY ,
0x0000 /* get supported services */
) ;
2005-06-02 18:47:35 +00:00
tv . tv_sec = 1 ;
tv . tv_usec = 0 ;
for ( /* for ever */ ; ; ) {
2005-11-20 16:15:33 +00:00
error = capi20_waitformessage ( capi_ApplID , & tv ) ;
error = capi_get_cmsg ( & CMSG2 , capi_ApplID ) ;
2005-06-02 18:47:35 +00:00
if ( error = = 0 ) {
if ( IS_FACILITY_CONF ( & CMSG2 ) ) {
2005-11-20 16:15:33 +00:00
cc_verbose ( 5 , 0 , VERBOSE_PREFIX_4 " FACILITY_CONF INFO = %#x \n " ,
2005-06-02 18:47:35 +00:00
FACILITY_CONF_INFO ( & CMSG2 ) ) ;
break ;
}
}
}
/* parse supported sservices */
2005-08-19 17:18:10 +00:00
if ( FACILITY_CONF_FACILITYSELECTOR ( & CMSG2 ) ! = FACILITYSELECTOR_SUPPLEMENTARY ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " unexpected FACILITY_SELECTOR = %#x \n " ,
2005-06-02 18:47:35 +00:00
FACILITY_CONF_FACILITYSELECTOR ( & CMSG2 ) ) ;
return ;
}
if ( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( & CMSG2 ) [ 4 ] ! = 0 ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " supplementary services info = %#x \n " ,
2005-06-02 18:47:35 +00:00
( short ) FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( & CMSG2 ) [ 1 ] ) ;
return ;
}
2005-08-19 17:18:10 +00:00
services = read_capi_dword ( & ( FACILITY_CONF_FACILITYCONFIRMATIONPARAMETER ( & CMSG2 ) [ 6 ] ) ) ;
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " supplementary services : 0x%08x \n " ,
2005-08-19 17:18:10 +00:00
services ) ;
2005-06-02 18:47:35 +00:00
/* success, so set the features we have */
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " " ) ;
2005-08-19 17:18:10 +00:00
if ( services & 0x0001 ) {
2005-06-02 18:47:35 +00:00
cp - > holdretrieve = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " HOLD/RETRIEVE " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0002 ) {
2005-06-02 18:47:35 +00:00
cp - > terminalportability = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " TERMINAL-PORTABILITY " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0004 ) {
2005-06-02 18:47:35 +00:00
cp - > ECT = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " ECT " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0008 ) {
2005-06-02 18:47:35 +00:00
cp - > threePTY = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " 3PTY " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0010 ) {
2005-06-02 18:47:35 +00:00
cp - > CF = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " CF " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0020 ) {
2005-06-02 18:47:35 +00:00
cp - > CD = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " CD " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0040 ) {
2005-06-02 18:47:35 +00:00
cp - > MCID = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " MCID " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0080 ) {
2005-06-02 18:47:35 +00:00
cp - > CCBS = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " CCBS " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0100 ) {
2005-06-02 18:47:35 +00:00
cp - > MWI = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " MWI " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0200 ) {
2005-06-02 18:47:35 +00:00
cp - > CCNR = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " CCNR " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-19 17:18:10 +00:00
if ( services & 0x0400 ) {
2005-06-02 18:47:35 +00:00
cp - > CONF = 1 ;
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " CONF " ) ;
2005-06-02 18:47:35 +00:00
}
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 0 , " \n " ) ;
2005-09-11 13:35:19 +00:00
return ;
2005-06-02 18:47:35 +00:00
}
2006-04-01 15:39:31 +00:00
/*
* helper functions to convert conf value to string
*/
static char * show_bproto ( int bproto )
{
switch ( bproto ) {
case CC_BPROTO_TRANSPARENT :
2006-05-18 14:36:09 +00:00
return " trans " ;
2006-04-01 15:39:31 +00:00
case CC_BPROTO_FAXG3 :
2009-08-05 22:25:53 +00:00
case CC_BPROTO_FAX3_BASIC :
2006-04-01 15:39:31 +00:00
return " fax " ;
case CC_BPROTO_RTP :
return " rtp " ;
2009-05-08 13:03:31 +00:00
case CC_BPROTO_VOCODER :
return " vocoder " ;
2006-04-01 15:39:31 +00:00
}
return " ??? " ;
}
static char * show_state ( int state )
{
switch ( state ) {
case CAPI_STATE_ALERTING :
return " Ring " ;
case CAPI_STATE_CONNECTED :
return " Conn " ;
case CAPI_STATE_DISCONNECTING :
return " discP " ;
case CAPI_STATE_DISCONNECTED :
return " Disc " ;
case CAPI_STATE_CONNECTPENDING :
return " Dial " ;
case CAPI_STATE_ANSWERING :
return " Answ " ;
case CAPI_STATE_DID :
return " DIDin " ;
case CAPI_STATE_INCALL :
return " icall " ;
case CAPI_STATE_ONHOLD :
return " Hold " ;
}
return " ----- " ;
}
2006-04-03 20:44:08 +00:00
static char * show_isdnstate ( unsigned int isdnstate , char * str )
{
str [ 0 ] = ' \0 ' ;
if ( isdnstate & CAPI_ISDN_STATE_PBX )
strcat ( str , " * " ) ;
if ( isdnstate & CAPI_ISDN_STATE_LI )
strcat ( str , " G " ) ;
if ( isdnstate & CAPI_ISDN_STATE_B3_UP )
strcat ( str , " B " ) ;
if ( isdnstate & CAPI_ISDN_STATE_B3_PEND )
strcat ( str , " b " ) ;
if ( isdnstate & CAPI_ISDN_STATE_PROGRESS )
strcat ( str , " P " ) ;
if ( isdnstate & CAPI_ISDN_STATE_HOLD )
strcat ( str , " H " ) ;
if ( isdnstate & CAPI_ISDN_STATE_ECT )
strcat ( str , " T " ) ;
2006-12-18 19:09:52 +00:00
if ( isdnstate & CAPI_ISDN_STATE_3PTY )
strcat ( str , " 3 " ) ;
2006-04-03 20:44:08 +00:00
if ( isdnstate & ( CAPI_ISDN_STATE_SETUP | CAPI_ISDN_STATE_SETUP_ACK ) )
strcat ( str , " S " ) ;
return str ;
}
2006-04-01 15:39:31 +00:00
2008-01-19 22:24:44 +00:00
/*
* usages
*/
static char info_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " info \n "
2008-01-19 22:24:44 +00:00
" Show info about B channels on controllers. \n " ;
static char show_channels_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " show channels \n "
2008-01-19 22:24:44 +00:00
" Show info about B channels. \n " ;
static char debug_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " debug \n "
" Enables dumping of " CC_MESSAGE_BIGNAME " packets for debugging purposes \n " ;
2008-01-19 22:24:44 +00:00
static char no_debug_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " no debug \n "
" Disables dumping of " CC_MESSAGE_BIGNAME " packets for debugging purposes \n " ;
2008-01-19 22:24:44 +00:00
static char qsig_debug_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " qsig debug \n "
" Enables dumping of QSIG facilities for debugging purposes \n " ;
2008-01-19 22:24:44 +00:00
static char qsig_no_debug_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " qsig no debug \n "
" Disables dumping of QSIG facilities for debugging purposes \n " ;
2008-01-19 22:24:44 +00:00
# ifndef CC_AST_HAS_VERSION_1_6
static
# endif
char chatinfo_usage [ ] =
2008-02-24 12:57:52 +00:00
" Usage: " CC_MESSAGE_NAME " chatinfo \n "
2008-01-19 22:24:44 +00:00
" Show info about chat status. \n " ;
2008-02-24 12:57:52 +00:00
# define CC_CLI_TEXT_INFO "Show " CC_MESSAGE_BIGNAME " info"
2008-01-19 22:24:44 +00:00
# define CC_CLI_TEXT_SHOW_CHANNELS "Show B-channel info"
2008-02-24 12:57:52 +00:00
# define CC_CLI_TEXT_DEBUG "Enable " CC_MESSAGE_BIGNAME " debugging"
# define CC_CLI_TEXT_NO_DEBUG "Disable " CC_MESSAGE_BIGNAME " debugging"
# define CC_CLI_TEXT_QSIG_DEBUG "Enable QSIG debugging"
# define CC_CLI_TEXT_QSIG_NO_DEBUG "Disable QSIG debugging"
# define CC_CLI_TEXT_CHATINFO "Show " CC_MESSAGE_BIGNAME " chat info"
2008-01-19 22:24:44 +00:00
2006-04-01 15:39:31 +00:00
/*
* do command capi show channels
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static char * pbxcli_capi_show_channels ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
# else
2006-06-09 21:48:24 +00:00
static int pbxcli_capi_show_channels ( int fd , int argc , char * argv [ ] )
2008-01-19 22:24:44 +00:00
# endif
2006-04-01 15:39:31 +00:00
{
struct capi_pvt * i ;
2006-04-03 20:44:08 +00:00
char iochar ;
char i_state [ 80 ] ;
2007-03-30 16:21:58 +00:00
char b3q [ 32 ] ;
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
int fd = a - > fd ;
if ( cmd = = CLI_INIT ) {
2008-02-24 12:57:52 +00:00
e - > command = CC_MESSAGE_NAME " show channels " ;
2008-01-19 22:24:44 +00:00
e - > usage = show_channels_usage ;
return NULL ;
} else if ( cmd = = CLI_GENERATE )
return NULL ;
if ( a - > argc ! = e - > args )
return CLI_SHOWUSAGE ;
# else
2006-04-01 15:39:31 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2008-01-19 22:24:44 +00:00
# endif
2006-04-01 15:39:31 +00:00
2008-02-24 12:57:52 +00:00
ast_cli ( fd , CC_MESSAGE_BIGNAME " B-channel information: \n " ) ;
2006-04-03 20:44:08 +00:00
ast_cli ( fd , " Line-Name NTmode state i/o bproto isdnstate ton number \n " ) ;
2006-04-01 15:39:31 +00:00
ast_cli ( fd , " ---------------------------------------------------------------- \n " ) ;
cc_mutex_lock ( & iflock ) ;
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i ; i = i - > next ) {
2006-04-01 15:39:31 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_B )
continue ;
2006-04-03 20:44:08 +00:00
if ( ( i - > state = = 0 ) | | ( i - > state = = CAPI_STATE_DISCONNECTED ) )
iochar = ' - ' ;
else if ( i - > outgoing )
iochar = ' O ' ;
else
iochar = ' I ' ;
2007-03-30 16:21:58 +00:00
if ( capidebug ) {
snprintf ( b3q , sizeof ( b3q ) , " B3q=%d B3count=%d " ,
i - > B3q , i - > B3count ) ;
} else {
2006-06-22 18:17:37 +00:00
b3q [ 0 ] = ' \0 ' ;
2007-03-30 16:21:58 +00:00
}
2006-06-22 18:17:37 +00:00
2006-04-01 15:39:31 +00:00
ast_cli ( fd ,
2006-06-22 18:17:37 +00:00
" %-16s %s %s %c %s %-10s 0x%02x '%s'->'%s'%s \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ,
2006-04-01 15:39:31 +00:00
i - > ntmode ? " yes " : " no " ,
show_state ( i - > state ) ,
2006-04-03 20:44:08 +00:00
iochar ,
2006-04-01 15:39:31 +00:00
show_bproto ( i - > bproto ) ,
2006-04-03 20:44:08 +00:00
show_isdnstate ( i - > isdnstate , i_state ) ,
2006-04-01 15:39:31 +00:00
i - > cid_ton ,
i - > cid ,
2006-06-22 18:17:37 +00:00
i - > dnid ,
b3q
2006-04-01 15:39:31 +00:00
) ;
}
cc_mutex_unlock ( & iflock ) ;
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
return CLI_SUCCESS ;
# else
2006-04-01 15:39:31 +00:00
return RESULT_SUCCESS ;
2008-01-19 22:24:44 +00:00
# endif
2006-04-01 15:39:31 +00:00
}
2005-06-02 18:47:35 +00:00
/*
* do command capi info
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static char * pbxcli_capi_info ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
# else
2006-06-09 21:48:24 +00:00
static int pbxcli_capi_info ( int fd , int argc , char * argv [ ] )
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
{
2006-04-01 15:39:31 +00:00
int i = 0 ;
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
int fd = a - > fd ;
if ( cmd = = CLI_INIT ) {
2008-02-24 12:57:52 +00:00
e - > command = CC_MESSAGE_NAME " info " ;
2008-01-19 22:24:44 +00:00
e - > usage = info_usage ;
return NULL ;
} else if ( cmd = = CLI_GENERATE )
return NULL ;
if ( a - > argc ! = e - > args )
return CLI_SHOWUSAGE ;
# else
2005-06-02 18:47:35 +00:00
if ( argc ! = 2 )
return RESULT_SHOWUSAGE ;
2008-01-19 22:24:44 +00:00
# endif
2007-04-24 08:35:44 +00:00
ast_cli ( fd , " %s www.chan-capi.org \n " , tdesc ) ;
2005-06-02 18:47:35 +00:00
for ( i = 1 ; i < = capi_num_controllers ; i + + ) {
if ( capi_controllers [ i ] ! = NULL ) {
2008-03-23 13:04:30 +00:00
ast_cli ( fd , " Contr%d: %d B channels total, %d B channels free.%s \n " ,
2006-04-01 15:39:31 +00:00
i , capi_controllers [ i ] - > nbchannels ,
2008-03-23 13:04:30 +00:00
capi_controllers [ i ] - > nfreebchannels ,
( capi_controllers [ i ] - > used ) ? " " : " (unused) " ) ;
2005-06-02 18:47:35 +00:00
}
}
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
return CLI_SUCCESS ;
# else
2005-06-02 18:47:35 +00:00
return RESULT_SUCCESS ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
}
/*
* enable debugging
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static char * pbxcli_capi_do_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
# else
2006-06-09 21:48:24 +00:00
static int pbxcli_capi_do_debug ( int fd , int argc , char * argv [ ] )
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
{
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
int fd = a - > fd ;
if ( cmd = = CLI_INIT ) {
2008-02-24 12:57:52 +00:00
e - > command = CC_MESSAGE_NAME " debug " ;
2008-01-19 22:24:44 +00:00
e - > usage = debug_usage ;
return NULL ;
} else if ( cmd = = CLI_GENERATE )
return NULL ;
if ( a - > argc ! = e - > args )
return CLI_SHOWUSAGE ;
# else
2005-06-02 18:47:35 +00:00
if ( argc ! = 2 )
return RESULT_SHOWUSAGE ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
capidebug = 1 ;
2008-02-24 12:57:52 +00:00
ast_cli ( fd , CC_MESSAGE_BIGNAME " Message Debugging Enabled \n " ) ;
2005-06-02 18:47:35 +00:00
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
return CLI_SUCCESS ;
# else
2005-06-02 18:47:35 +00:00
return RESULT_SUCCESS ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
}
/*
* disable debugging
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static char * pbxcli_capi_no_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
# else
2006-06-09 21:48:24 +00:00
static int pbxcli_capi_no_debug ( int fd , int argc , char * argv [ ] )
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
{
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
int fd = a - > fd ;
if ( cmd = = CLI_INIT ) {
2008-02-24 12:57:52 +00:00
e - > command = CC_MESSAGE_NAME " no debug " ;
2008-01-19 22:24:44 +00:00
e - > usage = no_debug_usage ;
return NULL ;
} else if ( cmd = = CLI_GENERATE )
return NULL ;
if ( a - > argc ! = e - > args )
return CLI_SHOWUSAGE ;
# else
2005-06-02 18:47:35 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-06 16:10:54 +00:00
2005-06-02 18:47:35 +00:00
capidebug = 0 ;
2008-02-24 12:57:52 +00:00
ast_cli ( fd , CC_MESSAGE_BIGNAME " Message Debugging Disabled \n " ) ;
2005-06-02 18:47:35 +00:00
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
return CLI_SUCCESS ;
# else
2005-06-02 18:47:35 +00:00
return RESULT_SUCCESS ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
}
2007-12-06 19:07:28 +00:00
/*
* enable QSIG debugging
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static char * pbxcli_capi_qsig_do_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
# else
2007-12-06 19:07:28 +00:00
static int pbxcli_capi_qsig_do_debug ( int fd , int argc , char * argv [ ] )
2008-01-19 22:24:44 +00:00
# endif
2007-12-06 19:07:28 +00:00
{
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
int fd = a - > fd ;
if ( cmd = = CLI_INIT ) {
2008-02-24 12:57:52 +00:00
e - > command = CC_MESSAGE_NAME " qsig debug " ;
2008-01-19 22:24:44 +00:00
e - > usage = qsig_debug_usage ;
return NULL ;
} else if ( cmd = = CLI_GENERATE )
return NULL ;
if ( a - > argc ! = e - > args )
return CLI_SHOWUSAGE ;
# else
2007-12-06 19:07:28 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2008-01-19 22:24:44 +00:00
# endif
2007-12-06 19:07:28 +00:00
capiqsigdebug = 1 ;
2008-02-24 12:57:52 +00:00
ast_cli ( fd , " QSIG Debugging Enabled \n " ) ;
2007-12-06 19:07:28 +00:00
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
return CLI_SUCCESS ;
# else
2007-12-06 19:07:28 +00:00
return RESULT_SUCCESS ;
2008-01-19 22:24:44 +00:00
# endif
2007-12-06 19:07:28 +00:00
}
/*
* disable QSIG debugging
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static char * pbxcli_capi_qsig_no_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
# else
2007-12-06 19:07:28 +00:00
static int pbxcli_capi_qsig_no_debug ( int fd , int argc , char * argv [ ] )
2008-01-19 22:24:44 +00:00
# endif
2007-12-06 19:07:28 +00:00
{
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
int fd = a - > fd ;
if ( cmd = = CLI_INIT ) {
2008-02-24 12:57:52 +00:00
e - > command = CC_MESSAGE_NAME " qsig no debug " ;
2008-01-19 22:24:44 +00:00
e - > usage = qsig_no_debug_usage ;
return NULL ;
} else if ( cmd = = CLI_GENERATE )
return NULL ;
if ( a - > argc ! = e - > args )
return CLI_SHOWUSAGE ;
# else
2007-12-06 19:07:28 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2008-01-19 22:24:44 +00:00
# endif
2007-12-06 19:07:28 +00:00
capiqsigdebug = 0 ;
2008-02-24 12:57:52 +00:00
ast_cli ( fd , " QSIG Debugging Disabled \n " ) ;
2007-12-06 19:07:28 +00:00
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
return CLI_SUCCESS ;
# else
2007-12-06 19:07:28 +00:00
return RESULT_SUCCESS ;
2008-01-19 22:24:44 +00:00
# endif
2007-12-06 19:07:28 +00:00
}
2005-06-02 18:47:35 +00:00
/*
* define commands
*/
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
static struct ast_cli_entry cc_cli_cmd [ ] = {
AST_CLI_DEFINE ( pbxcli_capi_info , CC_CLI_TEXT_INFO ) ,
AST_CLI_DEFINE ( pbxcli_capi_show_channels , CC_CLI_TEXT_SHOW_CHANNELS ) ,
AST_CLI_DEFINE ( pbxcli_capi_do_debug , CC_CLI_TEXT_DEBUG ) ,
AST_CLI_DEFINE ( pbxcli_capi_no_debug , CC_CLI_TEXT_NO_DEBUG ) ,
AST_CLI_DEFINE ( pbxcli_capi_qsig_do_debug , CC_CLI_TEXT_QSIG_DEBUG ) ,
AST_CLI_DEFINE ( pbxcli_capi_qsig_no_debug , CC_CLI_TEXT_QSIG_NO_DEBUG ) ,
AST_CLI_DEFINE ( pbxcli_capi_chatinfo , CC_CLI_TEXT_CHATINFO ) ,
} ;
# else
2005-06-02 18:47:35 +00:00
static struct ast_cli_entry cli_info =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " info " , NULL } , pbxcli_capi_info , CC_CLI_TEXT_INFO , info_usage } ;
2006-04-01 15:39:31 +00:00
static struct ast_cli_entry cli_show_channels =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " show " , " channels " , NULL } , pbxcli_capi_show_channels , CC_CLI_TEXT_SHOW_CHANNELS , show_channels_usage } ;
2005-06-02 18:47:35 +00:00
static struct ast_cli_entry cli_debug =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " debug " , NULL } , pbxcli_capi_do_debug , CC_CLI_TEXT_DEBUG , debug_usage } ;
2005-06-02 18:47:35 +00:00
static struct ast_cli_entry cli_no_debug =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " no " , " debug " , NULL } , pbxcli_capi_no_debug , CC_CLI_TEXT_NO_DEBUG , no_debug_usage } ;
2007-12-06 19:07:28 +00:00
static struct ast_cli_entry cli_qsig_debug =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " qsig " , " debug " , NULL } , pbxcli_capi_qsig_do_debug , CC_CLI_TEXT_QSIG_DEBUG , qsig_debug_usage } ;
2007-12-06 19:07:28 +00:00
static struct ast_cli_entry cli_qsig_no_debug =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " qsig " , " no " , " debug " , NULL } , pbxcli_capi_qsig_no_debug , CC_CLI_TEXT_QSIG_NO_DEBUG , qsig_no_debug_usage } ;
2007-04-30 14:02:22 +00:00
static struct ast_cli_entry cli_chatinfo =
2008-02-24 12:57:52 +00:00
{ { CC_MESSAGE_NAME , " chatinfo " , NULL } , pbxcli_capi_chatinfo , CC_CLI_TEXT_CHATINFO , chatinfo_usage } ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
2007-04-27 23:02:27 +00:00
const struct ast_channel_tech capi_tech = {
2005-08-16 10:11:43 +00:00
. type = channeltype ,
2005-06-02 18:47:35 +00:00
. description = tdesc ,
. capabilities = AST_FORMAT_ALAW ,
2006-06-09 21:48:24 +00:00
. requester = pbx_capi_request ,
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
. send_digit_begin = pbx_capi_send_digit_begin ,
. send_digit_end = pbx_capi_send_digit ,
# else
2006-06-09 21:48:24 +00:00
. send_digit = pbx_capi_send_digit ,
2006-11-11 20:07:19 +00:00
# endif
2007-07-10 17:44:09 +00:00
. send_text = pbx_capi_qsig_sendtext ,
2006-06-09 21:48:24 +00:00
. call = pbx_capi_call ,
. hangup = pbx_capi_hangup ,
. answer = pbx_capi_answer ,
. read = pbx_capi_read ,
. write = pbx_capi_write ,
. bridge = pbx_capi_bridge ,
2005-06-02 18:47:35 +00:00
. exception = NULL ,
2006-06-09 21:48:24 +00:00
. indicate = pbx_capi_indicate ,
. fixup = pbx_capi_fixup ,
2005-06-02 18:47:35 +00:00
. setoption = NULL ,
2006-06-09 21:48:24 +00:00
. devicestate = pbx_capi_devicestate ,
2005-06-02 18:47:35 +00:00
} ;
2006-02-06 19:21:38 +00:00
/*
* register at CAPI interface
*/
2007-03-05 20:00:35 +00:00
static int cc_register_capi ( unsigned blocksize , unsigned connections )
2006-02-06 19:21:38 +00:00
{
2006-02-06 20:00:56 +00:00
u_int16_t error = 0 ;
2007-04-08 21:31:23 +00:00
unsigned capi_ApplID_old = capi_ApplID ;
2006-02-06 20:00:56 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Registering at CAPI "
2007-03-24 12:41:33 +00:00
" (blocksize=%d maxlogicalchannels=%d) \n " , blocksize , connections ) ;
2006-02-06 20:00:56 +00:00
# if (CAPI_OS_HINT == 2)
2007-03-05 20:00:35 +00:00
error = capi20_register ( connections , CAPI_MAX_B3_BLOCKS ,
2006-02-06 20:00:56 +00:00
blocksize , & capi_ApplID , CAPI_STACK_VERSION ) ;
# else
2007-03-05 20:00:35 +00:00
error = capi20_register ( connections , CAPI_MAX_B3_BLOCKS ,
2006-02-06 20:00:56 +00:00
blocksize , & capi_ApplID ) ;
# endif
2007-04-08 21:31:23 +00:00
if ( capi_ApplID_old ! = CAPI_APPLID_UNUSED ) {
if ( capi20_release ( capi_ApplID_old ) ! = 0 )
cc_log ( LOG_WARNING , " Unable to unregister from CAPI! \n " ) ;
}
2006-02-06 20:00:56 +00:00
if ( error ! = 0 ) {
capi_ApplID = CAPI_APPLID_UNUSED ;
2006-02-06 19:21:38 +00:00
cc_log ( LOG_NOTICE , " unable to register application at CAPI! \n " ) ;
return - 1 ;
}
return 0 ;
}
2005-06-02 18:47:35 +00:00
/*
2005-07-17 19:01:14 +00:00
* init capi stuff
2005-06-02 18:47:35 +00:00
*/
2005-07-17 19:01:14 +00:00
static int cc_init_capi ( void )
2005-06-02 18:47:35 +00:00
{
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2005-07-17 19:01:14 +00:00
CAPIProfileBuffer_t profile ;
# else
2005-11-20 16:15:33 +00:00
struct cc_capi_profile profile ;
2005-07-17 19:01:14 +00:00
# endif
2005-11-20 16:15:33 +00:00
struct cc_capi_controller * cp ;
2005-07-17 19:01:14 +00:00
int controller ;
2006-01-30 23:40:28 +00:00
unsigned int privateoptions ;
2005-06-02 18:47:35 +00:00
if ( capi20_isinstalled ( ) ! = 0 ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_WARNING , " CAPI not installed, chan_capi disabled! \n " ) ;
2005-09-17 10:49:34 +00:00
return - 1 ;
2005-06-02 18:47:35 +00:00
}
2007-03-05 20:00:35 +00:00
if ( cc_register_capi ( CAPI_MAX_B3_BLOCK_SIZE , 2 ) )
2005-06-02 18:47:35 +00:00
return - 1 ;
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2005-06-02 18:47:35 +00:00
if ( capi20_get_profile ( 0 , & profile ) ! = 0 ) {
2005-09-11 08:39:29 +00:00
# elif (CAPI_OS_HINT == 2)
if ( capi20_get_profile ( 0 , & profile , sizeof ( profile ) ) ! = 0 ) {
2005-06-02 18:47:35 +00:00
# else
2006-01-03 20:03:00 +00:00
if ( capi20_get_profile ( 0 , ( unsigned char * ) & profile ) ! = 0 ) {
2005-06-02 18:47:35 +00:00
# endif
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " unable to get CAPI profile! \n " ) ;
2005-06-02 18:47:35 +00:00
return - 1 ;
}
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2008-01-21 10:40:42 +00:00
capi_num_controllers = read_capi_word ( & profile . wCtlr ) ;
2005-06-02 18:47:35 +00:00
# else
2008-01-21 10:40:42 +00:00
capi_num_controllers = read_capi_word ( & profile . ncontrollers ) ;
2005-06-02 18:47:35 +00:00
# endif
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " This box has %d capi controller(s). \n " ,
2005-06-02 18:47:35 +00:00
capi_num_controllers ) ;
for ( controller = 1 ; controller < = capi_num_controllers ; controller + + ) {
memset ( & profile , 0 , sizeof ( profile ) ) ;
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2005-06-02 18:47:35 +00:00
capi20_get_profile ( controller , & profile ) ;
2005-09-11 08:39:29 +00:00
# elif (CAPI_OS_HINT == 2)
capi20_get_profile ( controller , & profile , sizeof ( profile ) ) ;
2005-06-02 18:47:35 +00:00
# else
2006-01-03 20:03:00 +00:00
capi20_get_profile ( controller , ( unsigned char * ) & profile ) ;
2005-06-02 18:47:35 +00:00
# endif
2005-11-20 16:15:33 +00:00
cp = malloc ( sizeof ( struct cc_capi_controller ) ) ;
2005-06-02 18:47:35 +00:00
if ( ! cp ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Error allocating memory for struct cc_capi_controller \n " ) ;
2005-06-02 18:47:35 +00:00
return - 1 ;
}
2005-11-20 16:15:33 +00:00
memset ( cp , 0 , sizeof ( struct cc_capi_controller ) ) ;
2005-06-02 18:47:35 +00:00
cp - > controller = controller ;
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2008-01-21 10:40:42 +00:00
cp - > nbchannels = read_capi_word ( & profile . wNumBChannels ) ;
cp - > nfreebchannels = read_capi_word ( & profile . wNumBChannels ) ;
2005-06-02 18:47:35 +00:00
if ( profile . dwGlobalOptions & CAPI_PROFILE_DTMF_SUPPORT ) {
# else
2008-01-21 10:40:42 +00:00
cp - > nbchannels = read_capi_word ( & profile . nbchannels ) ;
cp - > nfreebchannels = read_capi_word ( & profile . nbchannels ) ;
2009-08-05 22:25:53 +00:00
cp - > fax_t30_extended = ( ( profile . b3protocols & ( 1U < < 5 ) ) ! = 0 ) ;
2005-09-15 19:11:45 +00:00
if ( profile . globaloptions & 0x08 ) {
2005-06-02 18:47:35 +00:00
# endif
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Contr%d supports DTMF \n " ,
2005-06-02 18:47:35 +00:00
controller ) ;
cp - > dtmf = 1 ;
}
2009-08-05 22:25:53 +00:00
2007-01-21 14:14:16 +00:00
# if (CAPI_OS_HINT == 1)
if ( profile . dwGlobalOptions & 0x01 ) {
# else
if ( profile . globaloptions2 & 0x01 ) {
# endif
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Contr%d supports broadband (or old echo-cancel) \n " ,
2007-01-21 14:14:16 +00:00
controller ) ;
cp - > broadband = 1 ;
}
2009-04-15 13:39:57 +00:00
cp - > ecPath = EC_ECHOCANCEL_PATH_IFC ;
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2005-06-02 18:47:35 +00:00
if ( profile . dwGlobalOptions & CAPI_PROFILE_ECHO_CANCELLATION ) {
# else
2006-05-19 09:51:45 +00:00
if ( profile . globaloptions2 & 0x02 ) {
2005-06-02 18:47:35 +00:00
# endif
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Contr%d supports echo cancellation \n " ,
2005-06-02 18:47:35 +00:00
controller ) ;
cp - > echocancel = 1 ;
}
2005-09-11 08:39:29 +00:00
# if (CAPI_OS_HINT == 1)
2005-06-02 18:47:35 +00:00
if ( profile . dwGlobalOptions & CAPI_PROFILE_SUPPLEMENTARY_SERVICES ) {
# else
2005-09-15 19:11:45 +00:00
if ( profile . globaloptions & 0x10 ) {
2005-06-02 18:47:35 +00:00
# endif
cp - > sservices = 1 ;
}
2005-09-15 19:11:45 +00:00
# if (CAPI_OS_HINT == 1)
if ( profile . dwGlobalOptions & 0x80 ) {
# else
if ( profile . globaloptions & 0x80 ) {
# endif
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Contr%d supports line interconnect \n " ,
2005-09-15 19:11:45 +00:00
controller ) ;
cp - > lineinterconnect = 1 ;
}
2005-06-02 18:47:35 +00:00
if ( cp - > sservices = = 1 ) {
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Contr%d supports supplementary services \n " ,
2005-06-02 18:47:35 +00:00
controller ) ;
supported_sservices ( cp ) ;
}
2008-02-05 10:57:54 +00:00
/* New profile options for e.g. RTP with Dialogic Diva */
2006-01-30 23:40:28 +00:00
privateoptions = read_capi_dword ( & profile . manufacturer [ 0 ] ) ;
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " Contr%d private options=0x%08x \n " ,
2006-01-30 23:40:28 +00:00
controller , privateoptions ) ;
if ( privateoptions & 0x02 ) {
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " VoIP/RTP is supported \n " ) ;
voice_over_ip_profile ( cp ) ;
}
if ( privateoptions & 0x04 ) {
2006-06-24 14:49:13 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " T.38 is supported (not implemented yet) \n " ) ;
2006-01-30 23:40:28 +00:00
}
2010-04-08 22:10:54 +00:00
# ifdef DIVA_STREAMING
/** \todo check CAPI profile */
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " Divaa streaming is supported \n " ) ;
cp - > divaStreaming = 1 ;
# endif
2005-06-02 18:47:35 +00:00
capi_controllers [ controller ] = cp ;
}
2005-10-01 11:31:05 +00:00
return 0 ;
}
/*
* final capi init
*/
static int cc_post_init_capi ( void )
{
2006-02-06 19:21:38 +00:00
struct capi_pvt * i ;
2005-10-01 11:31:05 +00:00
int controller ;
2006-01-28 19:42:44 +00:00
unsigned error ;
2007-03-05 20:00:35 +00:00
int rtp_ext_size = 0 ;
unsigned needchannels = 0 ;
2006-02-06 19:21:38 +00:00
2007-04-29 22:28:30 +00:00
for ( i = capi_iflist ; i & & ! rtp_ext_size ; i = i - > next ) {
2006-02-06 19:21:38 +00:00
/* if at least one line wants RTP, we need to re-register with
bigger block size for RTP - header */
2006-06-24 14:49:13 +00:00
if ( capi_controllers [ i - > controller ] - > rtpcodec & i - > capability ) {
2008-02-24 12:57:52 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " at least one controller wants RTP. \n " ) ;
2007-03-05 20:00:35 +00:00
rtp_ext_size = RTP_HEADER_SIZE ;
2006-02-06 19:21:38 +00:00
}
}
2007-03-05 20:00:35 +00:00
for ( controller = 1 ; controller < = capi_num_controllers ; controller + + ) {
2008-03-23 13:04:30 +00:00
if ( ( capi_controllers [ controller ] ! = NULL ) & &
( capi_controllers [ controller ] - > used ) ) {
2007-03-05 20:00:35 +00:00
needchannels + = ( capi_controllers [ controller ] - > nbchannels + 1 ) ;
}
2006-02-06 19:21:38 +00:00
}
2007-03-05 20:00:35 +00:00
if ( cc_register_capi ( CAPI_MAX_B3_BLOCK_SIZE + rtp_ext_size , needchannels ) )
return - 1 ;
2005-06-02 18:47:35 +00:00
2005-07-17 19:01:14 +00:00
for ( controller = 1 ; controller < = capi_num_controllers ; controller + + ) {
2008-03-23 13:04:30 +00:00
if ( capi_controllers [ controller ] - > used ) {
2007-04-29 22:28:30 +00:00
if ( ( error = capi_ListenOnController ( ALL_SERVICES , controller ) ) ! = 0 ) {
2006-01-28 19:42:44 +00:00
cc_log ( LOG_ERROR , " Unable to listen on contr%d (error=0x%x) \n " ,
controller , error ) ;
2005-07-17 19:01:14 +00:00
} else {
2005-11-20 16:15:33 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " listening on contr%d CIPmask = %#x \n " ,
2005-07-17 19:01:14 +00:00
controller , ALL_SERVICES ) ;
2009-02-14 20:56:14 +00:00
if ( capi_ManufacturerAllowOnController ( controller ) = = 0 ) {
capi_controllers [ controller ] - > divaExtendedFeaturesAvailable = 1 ;
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " enable extended voice features on contr%d \n " ,
controller ) ;
}
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
} else {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_NOTICE , " Unused contr%d \n " , controller ) ;
2005-07-17 19:01:14 +00:00
}
}
return 0 ;
}
/*
* build the interface according to configs
*/
2005-11-20 16:15:33 +00:00
static int conf_interface ( struct cc_capi_conf * conf , struct ast_variable * v )
2005-07-17 19:01:14 +00:00
{
2006-07-08 22:13:47 +00:00
int y ;
2005-07-17 19:01:14 +00:00
# define CONF_STRING(var, token) \
if ( ! strcasecmp ( v - > name , token ) ) { \
2006-01-28 19:42:44 +00:00
cc_copy_string ( var , v - > value , sizeof ( var ) ) ; \
2005-07-17 19:01:14 +00:00
continue ; \
2006-01-30 23:40:28 +00:00
} else
2005-07-17 19:01:14 +00:00
# define CONF_INTEGER(var, token) \
if ( ! strcasecmp ( v - > name , token ) ) { \
var = atoi ( v - > value ) ; \
continue ; \
2006-01-30 23:40:28 +00:00
} else
2005-09-26 11:35:13 +00:00
# define CONF_TRUE(var, token, val) \
if ( ! strcasecmp ( v - > name , token ) ) { \
if ( ast_true ( v - > value ) ) \
var = val ; \
continue ; \
2006-01-30 23:40:28 +00:00
} else
2005-07-17 19:01:14 +00:00
for ( ; v ; v = v - > next ) {
2007-02-10 23:18:57 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
/* handle jb conf */
if ( ! ast_jb_read_conf ( & conf - > jbconf , v - > name , v - > value ) ) {
continue ;
}
2007-02-11 14:34:10 +00:00
CONF_STRING ( conf - > mohinterpret , " mohinterpret " )
2007-02-10 23:18:57 +00:00
# endif
2006-01-30 23:40:28 +00:00
CONF_INTEGER ( conf - > devices , " devices " )
CONF_STRING ( conf - > context , " context " )
CONF_STRING ( conf - > incomingmsn , " incomingmsn " )
CONF_STRING ( conf - > defaultcid , " defaultcid " )
CONF_STRING ( conf - > controllerstr , " controller " )
CONF_STRING ( conf - > prefix , " prefix " )
CONF_STRING ( conf - > accountcode , " accountcode " )
CONF_STRING ( conf - > language , " language " )
2005-09-26 11:35:13 +00:00
2005-08-07 12:21:36 +00:00
if ( ! strcasecmp ( v - > name , " softdtmf " ) ) {
if ( ( ! conf - > softdtmf ) & & ( ast_true ( v - > value ) ) ) {
conf - > softdtmf = 1 ;
}
continue ;
2006-01-30 23:40:28 +00:00
} else
CONF_TRUE ( conf - > softdtmf , " relaxdtmf " , 2 )
2005-08-25 18:16:44 +00:00
if ( ! strcasecmp ( v - > name , " holdtype " ) ) {
if ( ! strcasecmp ( v - > value , " hold " ) ) {
conf - > holdtype = CC_HOLDTYPE_HOLD ;
} else if ( ! strcasecmp ( v - > value , " notify " ) ) {
conf - > holdtype = CC_HOLDTYPE_NOTIFY ;
} else {
conf - > holdtype = CC_HOLDTYPE_LOCAL ;
2005-08-21 10:28:43 +00:00
}
continue ;
2006-01-30 23:40:28 +00:00
} else
CONF_TRUE ( conf - > immediate , " immediate " , 1 )
CONF_TRUE ( conf - > es , " echosquelch " , 1 )
CONF_TRUE ( conf - > bridge , " bridge " , 1 )
CONF_TRUE ( conf - > ntmode , " ntmode " , 1 )
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
conf - > callgroup = ast_get_group ( v - > value ) ;
continue ;
2006-01-30 23:40:28 +00:00
} else
2006-07-08 16:29:27 +00:00
if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
conf - > pickupgroup = ast_get_group ( v - > value ) ;
continue ;
} else
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " group " ) ) {
conf - > group = ast_get_group ( v - > value ) ;
continue ;
2006-01-30 23:40:28 +00:00
} else
2007-09-30 21:09:15 +00:00
if ( ! strcasecmp ( v - > name , " transfergroup " ) ) {
conf - > transfergroup = ast_get_group ( v - > value ) ;
continue ;
} else
2006-07-08 22:13:47 +00:00
if ( ! strcasecmp ( v - > name , " amaflags " ) ) {
y = ast_cdr_amaflags2int ( v - > value ) ;
if ( y < 0 ) {
ast_log ( LOG_WARNING , " Invalid AMA flags: %s at line %d \n " ,
v - > value , v - > lineno ) ;
} else {
conf - > amaflags = y ;
}
} else
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " rxgain " ) ) {
if ( sscanf ( v - > value , " %f " , & conf - > rxgain ) ! = 1 ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " invalid rxgain \n " ) ;
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
continue ;
2006-01-30 23:40:28 +00:00
} else
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " txgain " ) ) {
if ( sscanf ( v - > value , " %f " , & conf - > txgain ) ! = 1 ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " invalid txgain \n " ) ;
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
continue ;
2006-01-30 23:40:28 +00:00
} else
2005-08-29 19:06:19 +00:00
if ( ! strcasecmp ( v - > name , " echocancelold " ) ) {
if ( ast_true ( v - > value ) ) {
conf - > ecSelector = 6 ;
}
continue ;
2006-01-30 23:40:28 +00:00
} else
2006-05-27 12:49:57 +00:00
if ( ! strcasecmp ( v - > name , " faxdetect " ) ) {
if ( ! strcasecmp ( v - > value , " incoming " ) ) {
conf - > faxsetting | = CAPI_FAX_DETECT_INCOMING ;
conf - > faxsetting & = ~ CAPI_FAX_DETECT_OUTGOING ;
} else if ( ! strcasecmp ( v - > value , " outgoing " ) ) {
conf - > faxsetting | = CAPI_FAX_DETECT_OUTGOING ;
conf - > faxsetting & = ~ CAPI_FAX_DETECT_INCOMING ;
} else if ( ! strcasecmp ( v - > value , " both " ) | | ast_true ( v - > value ) )
conf - > faxsetting | = ( CAPI_FAX_DETECT_OUTGOING | CAPI_FAX_DETECT_INCOMING ) ;
else
conf - > faxsetting & = ~ ( CAPI_FAX_DETECT_OUTGOING | CAPI_FAX_DETECT_INCOMING ) ;
} else
2008-06-29 11:33:46 +00:00
CONF_INTEGER ( conf - > faxdetecttime , " faxdetecttime " )
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " echocancel " ) ) {
2005-08-07 12:21:36 +00:00
if ( ast_true ( v - > value ) ) {
2005-07-17 19:01:14 +00:00
conf - > echocancel = 1 ;
conf - > ecoption = EC_OPTION_DISABLE_G165 ;
2005-06-02 18:47:35 +00:00
}
2005-08-07 12:21:36 +00:00
else if ( ast_false ( v - > value ) ) {
2005-07-17 19:01:14 +00:00
conf - > echocancel = 0 ;
conf - > ecoption = 0 ;
2005-06-02 18:47:35 +00:00
}
else if ( ! strcasecmp ( v - > value , " g165 " ) | | ! strcasecmp ( v - > value , " g.165 " ) ) {
2005-07-17 19:01:14 +00:00
conf - > echocancel = 1 ;
conf - > ecoption = EC_OPTION_DISABLE_G165 ;
2005-06-02 18:47:35 +00:00
}
else if ( ! strcasecmp ( v - > value , " g164 " ) | | ! strcasecmp ( v - > value , " g.164 " ) ) {
2005-07-17 19:01:14 +00:00
conf - > echocancel = 1 ;
conf - > ecoption = EC_OPTION_DISABLE_G164_OR_G165 ;
2005-06-02 18:47:35 +00:00
}
else if ( ! strcasecmp ( v - > value , " force " ) ) {
2005-07-17 19:01:14 +00:00
conf - > echocancel = 1 ;
conf - > ecoption = EC_OPTION_DISABLE_NEVER ;
2005-06-02 18:47:35 +00:00
}
else {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Unknown echocancel parameter \" %s \" -- ignoring \n " , v - > value ) ;
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
continue ;
2006-01-30 23:40:28 +00:00
} else
2006-04-01 16:29:50 +00:00
CONF_TRUE ( conf - > ecnlp , " echocancelnlp " , 1 )
2009-04-15 13:39:57 +00:00
if ( ! strcasecmp ( v - > name , " echocancelpath " ) ) {
conf - > echocancelpath = atoi ( v - > value ) ;
conf - > echocancelpath & = EC_ECHOCANCEL_PATH_BITS ;
if ( conf - > echocancelpath = = 0 )
conf - > echocancelpath = EC_ECHOCANCEL_PATH_BITS ;
}
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " echotail " ) ) {
conf - > ectail = atoi ( v - > value ) ;
if ( conf - > ectail > 255 ) {
conf - > ectail = 255 ;
}
continue ;
2006-01-30 23:40:28 +00:00
} else
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " isdnmode " ) ) {
2005-08-25 19:00:55 +00:00
if ( ! strcasecmp ( v - > value , " did " ) )
2005-11-20 16:15:33 +00:00
conf - > isdnmode = CAPI_ISDNMODE_DID ;
2005-08-25 19:00:55 +00:00
else if ( ! strcasecmp ( v - > value , " msn " ) )
2005-11-20 16:15:33 +00:00
conf - > isdnmode = CAPI_ISDNMODE_MSN ;
2005-06-02 18:47:35 +00:00
else
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Unknown isdnmode parameter \" %s \" -- ignoring \n " ,
2005-06-02 18:47:35 +00:00
v - > value ) ;
2006-01-30 23:40:28 +00:00
} else
if ( ! strcasecmp ( v - > name , " allow " ) ) {
ast_parse_allow_disallow ( & conf - > prefs , & conf - > capability , v - > value , 1 ) ;
} else
if ( ! strcasecmp ( v - > name , " disallow " ) ) {
ast_parse_allow_disallow ( & conf - > prefs , & conf - > capability , v - > value , 0 ) ;
2005-06-02 18:47:35 +00:00
}
2007-07-05 19:48:19 +00:00
cc_pbx_qsig_conf_interface_value ( conf , v ) ;
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
# undef CONF_STRING
# undef CONF_INTEGER
2005-11-20 16:15:33 +00:00
# undef CONF_TRUE
2005-07-17 19:01:14 +00:00
return 0 ;
}
2005-06-02 18:47:35 +00:00
2005-07-17 19:01:14 +00:00
/*
* load the config
*/
static int capi_eval_config ( struct ast_config * cfg )
{
2005-11-20 16:15:33 +00:00
struct cc_capi_conf conf ;
2005-07-17 19:01:14 +00:00
struct ast_variable * v ;
char * cat = NULL ;
float rxgain = 1.0 ;
float txgain = 1.0 ;
/* prefix defaults */
2006-01-28 19:42:44 +00:00
cc_copy_string ( capi_national_prefix , CAPI_NATIONAL_PREF , sizeof ( capi_national_prefix ) ) ;
cc_copy_string ( capi_international_prefix , CAPI_INTERNAT_PREF , sizeof ( capi_international_prefix ) ) ;
2008-07-07 20:29:19 +00:00
cc_copy_string ( capi_subscriber_prefix , CAPI_SUBSCRIBER_PREF , sizeof ( capi_subscriber_prefix ) ) ;
2005-07-17 19:01:14 +00:00
2007-02-10 23:18:57 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
/* Copy the default jb config over global_jbconf */
memcpy ( & global_jbconf , & default_jbconf , sizeof ( struct ast_jb_conf ) ) ;
# endif
2005-07-17 19:01:14 +00:00
/* read the general section */
for ( v = ast_variable_browse ( cfg , " general " ) ; v ; v = v - > next ) {
2007-02-10 23:18:57 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
/* handle global jb conf */
if ( ! ast_jb_read_conf ( & global_jbconf , v - > name , v - > value ) ) {
continue ;
}
2007-02-11 14:34:10 +00:00
if ( ! strcasecmp ( v - > name , " mohinterpret " ) ) {
cc_copy_string ( global_mohinterpret , v - > value , sizeof ( global_mohinterpret ) ) ;
} else
2007-02-10 23:18:57 +00:00
# endif
2005-07-17 19:01:14 +00:00
if ( ! strcasecmp ( v - > name , " nationalprefix " ) ) {
2006-01-28 19:42:44 +00:00
cc_copy_string ( capi_national_prefix , v - > value , sizeof ( capi_national_prefix ) ) ;
2005-07-17 19:01:14 +00:00
} else if ( ! strcasecmp ( v - > name , " internationalprefix " ) ) {
2006-01-28 19:42:44 +00:00
cc_copy_string ( capi_international_prefix , v - > value , sizeof ( capi_international_prefix ) ) ;
2008-07-07 20:29:19 +00:00
} else if ( ! strcasecmp ( v - > name , " subscriberprefix " ) ) {
cc_copy_string ( capi_subscriber_prefix , v - > value , sizeof ( capi_subscriber_prefix ) ) ;
2005-12-28 14:22:54 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
2006-01-28 19:42:44 +00:00
cc_copy_string ( default_language , v - > value , sizeof ( default_language ) ) ;
2005-07-17 19:01:14 +00:00
} else if ( ! strcasecmp ( v - > name , " rxgain " ) ) {
if ( sscanf ( v - > value , " %f " , & rxgain ) ! = 1 ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " invalid rxgain \n " ) ;
2005-07-17 19:01:14 +00:00
}
} else if ( ! strcasecmp ( v - > name , " txgain " ) ) {
if ( sscanf ( v - > value , " %f " , & txgain ) ! = 1 ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " invalid txgain \n " ) ;
2005-06-02 18:47:35 +00:00
}
2005-08-07 11:40:07 +00:00
} else if ( ! strcasecmp ( v - > name , " ulaw " ) ) {
2005-08-07 12:21:36 +00:00
if ( ast_true ( v - > value ) ) {
2005-08-07 11:40:07 +00:00
capi_capability = AST_FORMAT_ULAW ;
}
2007-02-10 23:23:03 +00:00
}
2005-06-02 18:47:35 +00:00
}
2005-07-17 19:01:14 +00:00
/* go through all other sections, which are our interfaces */
for ( cat = ast_category_browse ( cfg , NULL ) ; cat ; cat = ast_category_browse ( cfg , cat ) ) {
if ( ! strcasecmp ( cat , " general " ) )
continue ;
if ( ! strcasecmp ( cat , " interfaces " ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_WARNING , " Config file syntax has changed! Don't use 'interfaces' \n " ) ;
2005-07-17 19:01:14 +00:00
return - 1 ;
}
2005-11-20 16:15:33 +00:00
cc_verbose ( 4 , 0 , VERBOSE_PREFIX_2 " Reading config for %s \n " ,
2005-07-17 19:01:14 +00:00
cat ) ;
/* init the conf struct */
memset ( & conf , 0 , sizeof ( conf ) ) ;
conf . rxgain = rxgain ;
conf . txgain = txgain ;
conf . ecoption = EC_OPTION_DISABLE_G165 ;
conf . ectail = EC_DEFAULT_TAIL ;
2005-08-29 19:06:19 +00:00
conf . ecSelector = FACILITYSELECTOR_ECHO_CANCEL ;
2009-04-15 13:39:57 +00:00
conf . echocancelpath = EC_ECHOCANCEL_PATH_IFC ;
2006-01-28 19:42:44 +00:00
cc_copy_string ( conf . name , cat , sizeof ( conf . name ) ) ;
cc_copy_string ( conf . language , default_language , sizeof ( conf . language ) ) ;
2007-02-10 23:18:57 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2007-02-11 14:34:10 +00:00
cc_copy_string ( conf . mohinterpret , global_mohinterpret , sizeof ( conf . mohinterpret ) ) ;
2007-02-10 23:18:57 +00:00
/* Copy the global jb config into interface conf */
memcpy ( & conf . jbconf , & global_jbconf , sizeof ( struct ast_jb_conf ) ) ;
# endif
2005-07-17 19:01:14 +00:00
if ( conf_interface ( & conf , ast_variable_browse ( cfg , cat ) ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Error interface config. \n " ) ;
2005-07-17 19:01:14 +00:00
return - 1 ;
}
if ( mkif ( & conf ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Error creating interface list \n " ) ;
2005-07-17 19:01:14 +00:00
return - 1 ;
}
}
return 0 ;
}
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
static int reload ( void )
{
cc_log ( LOG_WARNING , " config reload is not supported yet. \n " ) ;
return 0 ;
}
# endif
2006-05-12 16:43:30 +00:00
/*
* unload the module
*/
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
static
# endif
int unload_module ( void )
2006-05-12 16:43:30 +00:00
{
struct capi_pvt * i , * itmp ;
int controller ;
ast_unregister_application ( commandapp ) ;
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
ast_cli_unregister_multiple ( cc_cli_cmd , sizeof ( cc_cli_cmd ) / sizeof ( struct ast_cli_entry ) ) ;
# else
2006-05-12 16:43:30 +00:00
ast_cli_unregister ( & cli_info ) ;
ast_cli_unregister ( & cli_show_channels ) ;
ast_cli_unregister ( & cli_debug ) ;
ast_cli_unregister ( & cli_no_debug ) ;
2007-12-06 19:07:28 +00:00
ast_cli_unregister ( & cli_qsig_debug ) ;
ast_cli_unregister ( & cli_qsig_no_debug ) ;
2007-04-30 14:02:22 +00:00
ast_cli_unregister ( & cli_chatinfo ) ;
2008-01-19 22:24:44 +00:00
# endif
2006-05-12 16:43:30 +00:00
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
ast_module_user_hangup_all ( ) ;
# endif
2007-10-21 16:00:18 +00:00
if ( capi_device_thread ! = ( pthread_t ) ( 0 - 1 ) ) {
pthread_cancel ( capi_device_thread ) ;
pthread_kill ( capi_device_thread , SIGURG ) ;
pthread_join ( capi_device_thread , NULL ) ;
2006-05-12 16:43:30 +00:00
}
cc_mutex_lock ( & iflock ) ;
if ( capi_ApplID ! = CAPI_APPLID_UNUSED ) {
if ( capi20_release ( capi_ApplID ) ! = 0 )
cc_log ( LOG_WARNING , " Unable to unregister from CAPI! \n " ) ;
}
2008-03-23 13:04:30 +00:00
for ( controller = 1 ; controller < = CAPI_MAX_CONTROLLERS ; controller + + ) {
if ( capi_controllers [ controller ] )
free ( capi_controllers [ controller ] ) ;
2006-05-12 16:43:30 +00:00
}
2007-04-29 22:28:30 +00:00
i = capi_iflist ;
2006-05-12 16:43:30 +00:00
while ( i ) {
2007-04-23 18:47:49 +00:00
if ( ( i - > owner ) | | ( i - > used ) )
cc_log ( LOG_WARNING , " On unload, interface still has owner or is used. \n " ) ;
2006-05-12 16:43:30 +00:00
if ( i - > smoother )
ast_smoother_free ( i - > smoother ) ;
2007-06-04 18:37:12 +00:00
2007-06-07 19:24:32 +00:00
pbx_capi_qsig_unload_module ( i ) ;
2007-06-04 18:37:12 +00:00
2006-05-21 14:42:17 +00:00
cc_mutex_destroy ( & i - > lock ) ;
2006-05-22 19:13:19 +00:00
ast_cond_destroy ( & i - > event_trigger ) ;
2006-05-12 16:43:30 +00:00
itmp = i ;
i = i - > next ;
free ( itmp ) ;
}
cc_mutex_unlock ( & iflock ) ;
ast_channel_unregister ( & capi_tech ) ;
2007-04-22 10:03:52 +00:00
cleanup_ccbsnr ( ) ;
2006-05-12 16:43:30 +00:00
return 0 ;
}
2005-07-17 19:01:14 +00:00
/*
* main : load the module
*/
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
static
# endif
2005-07-17 19:01:14 +00:00
int load_module ( void )
{
struct ast_config * cfg ;
char * config = " capi.conf " ;
int res = 0 ;
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
struct ast_flags config_flags = { 0 } ;
# endif
2005-07-17 19:01:14 +00:00
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
cfg = ast_config_load ( config , config_flags ) ;
# else
2005-07-17 19:01:14 +00:00
cfg = ast_config_load ( config ) ;
2008-01-19 22:24:44 +00:00
# endif
2005-07-17 19:01:14 +00:00
/* We *must* have a config file otherwise stop immediately, well no */
if ( ! cfg ) {
2008-02-24 12:57:52 +00:00
cc_log ( LOG_ERROR , " Unable to load config %s, chan_capi disabled \n " , config ) ;
2005-07-17 19:01:14 +00:00
return 0 ;
}
2005-11-27 14:47:54 +00:00
if ( cc_mutex_lock ( & iflock ) ) {
cc_log ( LOG_ERROR , " Unable to lock interface list??? \n " ) ;
2005-07-17 19:01:14 +00:00
return - 1 ;
}
2005-10-01 11:31:05 +00:00
if ( ( res = cc_init_capi ( ) ) ! = 0 ) {
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-10-01 11:31:05 +00:00
return ( res ) ;
}
2005-07-17 19:01:14 +00:00
res = capi_eval_config ( cfg ) ;
ast_config_destroy ( cfg ) ;
if ( res ! = 0 ) {
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-07-17 19:01:14 +00:00
return ( res ) ;
}
2005-10-01 11:31:05 +00:00
if ( ( res = cc_post_init_capi ( ) ) ! = 0 ) {
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2006-02-06 19:21:38 +00:00
unload_module ( ) ;
2005-07-17 19:01:14 +00:00
return ( res ) ;
}
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & iflock ) ;
2005-06-02 18:47:35 +00:00
if ( ast_channel_register ( & capi_tech ) ) {
2005-11-27 14:47:54 +00:00
cc_log ( LOG_ERROR , " Unable to register channel class %s \n " , channeltype ) ;
2005-06-02 18:47:35 +00:00
unload_module ( ) ;
return - 1 ;
}
2008-01-19 22:24:44 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
ast_cli_register_multiple ( cc_cli_cmd , sizeof ( cc_cli_cmd ) / sizeof ( struct ast_cli_entry ) ) ;
# else
2005-06-02 18:47:35 +00:00
ast_cli_register ( & cli_info ) ;
2006-04-01 15:39:31 +00:00
ast_cli_register ( & cli_show_channels ) ;
2005-06-02 18:47:35 +00:00
ast_cli_register ( & cli_debug ) ;
ast_cli_register ( & cli_no_debug ) ;
2007-12-06 19:07:28 +00:00
ast_cli_register ( & cli_qsig_debug ) ;
ast_cli_register ( & cli_qsig_no_debug ) ;
2007-04-30 14:02:22 +00:00
ast_cli_register ( & cli_chatinfo ) ;
2008-01-19 22:24:44 +00:00
# endif
2005-06-02 18:47:35 +00:00
2006-06-09 21:48:24 +00:00
ast_register_application ( commandapp , pbx_capicommand_exec , commandsynopsis , commandtdesc ) ;
2005-07-27 17:20:09 +00:00
2007-10-21 16:00:18 +00:00
if ( ast_pthread_create ( & capi_device_thread , NULL , capidev_loop , NULL ) < 0 ) {
capi_device_thread = ( pthread_t ) ( 0 - 1 ) ;
2008-02-24 12:57:52 +00:00
cc_log ( LOG_ERROR , " Unable to start CAPI device thread! \n " ) ;
2005-08-19 16:40:23 +00:00
return - 1 ;
}
2005-06-02 18:47:35 +00:00
2005-07-17 19:01:14 +00:00
return 0 ;
2005-06-02 18:47:35 +00:00
}
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_DEFAULT , tdesc ,
. load = load_module ,
. unload = unload_module ,
. reload = reload ,
) ;
# else
2005-06-02 18:47:35 +00:00
int usecount ( )
{
int res ;
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & usecnt_lock ) ;
2005-06-02 18:47:35 +00:00
res = usecnt ;
2005-11-27 14:47:54 +00:00
cc_mutex_unlock ( & usecnt_lock ) ;
2005-06-02 18:47:35 +00:00
return res ;
}
char * description ( )
{
2006-01-30 23:40:28 +00:00
return ccdesc ;
2005-06-02 18:47:35 +00:00
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}
2006-11-11 20:07:19 +00:00
# endif /* CC_AST_HAS_VERSION_1_4 */