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"
2010-08-13 20:41:23 +00:00
# ifdef CC_AST_HAS_VERSION_1_8
# include <asterisk/callerid.h>
# endif
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
# include "asterisk/smoother.h"
# include "asterisk/pickup.h"
# include "asterisk/features_config.h"
# endif
2010-05-26 14:40:57 +00:00
struct _diva_streaming_vector * vind ;
2010-05-07 22:28:56 +00:00
# ifdef DIVA_STREAMING
# include "platform.h"
# include "diva_streaming_result.h"
# include "diva_streaming_messages.h"
# include "diva_streaming_vector.h"
# include "diva_streaming_manager.h"
2010-06-30 08:33:41 +00:00
# include "chan_capi_divastreaming_utils.h"
2010-05-07 22:28:56 +00:00
# endif
2010-10-19 13:44:06 +00:00
# ifdef DIVA_STATUS
# include "divastatus_ifc.h"
# endif
2010-10-15 16:50:41 +00:00
# include "chan_capi_mwi.h"
2010-10-29 18:54:15 +00:00
# include "chan_capi_cli.h"
2010-11-03 22:04:22 +00:00
# include "chan_capi_ami.h"
2010-11-05 13:13:12 +00:00
# include "chan_capi_devstate.h"
2011-02-04 17:18:05 +00:00
# include "divaverbose.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 "
2010-12-21 19:14:27 +00:00
" \" proceeding \" send proceeding (for NT mode) \n "
2010-09-26 10:53:11 +00:00
" \" deflect,to_number \" forwards an unanswered call to number \n "
2006-07-10 17:40:03 +00:00
" \" malicous \" report a call of malicious nature \n "
2010-09-26 10:53:11 +00:00
" \" 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 "
" \" 3pty_begin,${MYHOLDVAR}) \" Three-Party-Conference (3PTY) with active and held call \n "
" \" receivefax,filename,stationID,headline,options \" receive a " CC_MESSAGE_BIGNAME " fax \n "
" \" sendfax,filename.sff,stationID,headline \" send a " CC_MESSAGE_BIGNAME " fax \n "
" \" 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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
struct ast_module * myself ;
# endif
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 ] = " " ;
2011-10-04 08:41:28 +00:00
cc_format_t capi_capability = CC_FORMAT_ALAW ;
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 */
2012-04-11 09:45:19 +00:00
# define CC_B_INTERFACE_NOT_FREE(__x__) (((__x__)->used) || ((__x__)->reserved) || \
2010-10-26 22:22:25 +00:00
( ( __x__ ) - > channeltype ! = CAPI_CHANNELTYPE_B ) | | \
( capi_controllers [ ( __x__ ) - > controller ] - > nfreebchannels < capi_controllers [ ( __x__ ) - > controller ] - > nfreebchannelsHardThr ) )
2010-10-22 22:44:50 +00:00
2010-11-02 14:14:43 +00:00
/*!
* \ brief Acquire lock in correct order . Called if locking from non
* ast_channel context ( thread , . . . )
*/
static struct ast_channel * capidev_acquire_locks_from_thread_context ( struct capi_pvt * i ) ;
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
2010-10-14 08:07:55 +00:00
static struct capi_pvt * get_active_plci ( struct ast_channel * c ) ;
static void clear_channel_fax_loop ( struct ast_channel * c , struct capi_pvt * i ) ;
static void pbx_capi_add_diva_protocol_independent_extension (
struct capi_pvt * i ,
unsigned char * facilityarray ,
struct ast_channel * c ,
const char * variable ) ;
2010-10-22 22:44:50 +00:00
# ifdef DIVA_STATUS
static void pbx_capi_interface_status_changed ( int controller , diva_status_interface_state_t newInterfaceState ) ;
2010-10-25 21:21:31 +00:00
static void pbx_capi_hw_status_changed ( int controller , diva_status_hardware_state_t newHwState ) ;
2010-10-22 22:44:50 +00:00
# endif
2010-10-26 22:22:25 +00:00
static int pbx_capi_check_controller_status ( int controller ) ;
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2006-07-08 16:29:27 +00:00
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_4 " %s: set channel task to %d \n " ,
2015-02-28 16:35:31 +00:00
cur_name , task ) ;
2006-07-08 16:29:27 +00:00
}
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
*/
2010-11-10 14:07:51 +00:00
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 ;
}
2010-10-09 08:29:39 +00:00
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & &
( capi_controllers [ i - > controller ] - > ecPath & EC_ECHOCANCEL_PATH_IP ) = = 0 ) {
2009-04-15 13:39:57 +00:00
return ;
}
2010-10-09 08:29:39 +00:00
if ( ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) & &
( capi_controllers [ i - > controller ] - > ecPath & EC_ECHOCANCEL_PATH_IFC ) = = 0 ) {
2009-04-15 13:39:57 +00:00
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 ;
}
2010-11-02 14:14:43 +00:00
static int capi_check_diva_tone_function_allowed ( struct capi_pvt * i , int useLinePLCI )
2009-02-14 20:56:14 +00:00
{
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
}
2010-11-02 14:14:43 +00:00
if ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & & ( useLinePLCI ! = 0 ) ) {
if ( ( i - > line_plci - > isdnstate & CAPI_ISDN_STATE_DISCONNECT ) )
return - 1 ;
if ( capi_verify_resource_plci ( i - > line_plci ) ! = 0 )
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
*/
2010-11-02 14:14:43 +00:00
static void capi_diva_audio_features ( struct capi_pvt * i , int useLinePLCI )
2009-02-13 21:58:19 +00:00
{
2010-11-02 14:14:43 +00:00
struct capi_pvt * effectiveIfc ;
2011-03-07 09:57:43 +00:00
unsigned short divaAudioFlags , divaDigitalTxGain , divaDigitalRxGain ;
const char * plciName ;
2010-11-02 14:14:43 +00:00
if ( capi_check_diva_tone_function_allowed ( i , useLinePLCI ) ! = 0 )
2009-02-13 21:58:19 +00:00
return ;
2010-11-02 14:14:43 +00:00
effectiveIfc = ( ( i - > channeltype = = CAPI_CHANNELTYPE_NULL ) & & ( useLinePLCI ! = 0 ) ) ? i - > line_plci : i ;
2011-03-07 09:57:43 +00:00
if ( i - > channeltype ! = CAPI_CHANNELTYPE_NULL ) {
/* ISDN connection */
divaAudioFlags = ( i - > divaAudioFlags | i - > divaDataStubAudioFlags ) ;
divaDigitalTxGain = i - > divaDigitalTxGain ;
divaDigitalRxGain = i - > divaDigitalRxGain ;
plciName = " " ;
} else {
/* Resource PLCI */
if ( useLinePLCI ! = 0 ) {
/* Command for line stub */
divaAudioFlags = i - > divaAudioFlags ;
divaDigitalTxGain = i - > divaDigitalTxGain ;
divaDigitalRxGain = i - > divaDigitalRxGain ;
plciName = " LINE- " ;
} else {
/* Command for data stub */
divaAudioFlags = i - > divaDataStubAudioFlags ;
divaDigitalTxGain = 0 ;
divaDigitalRxGain = 0 ;
plciName = " DATA- " ;
}
}
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_2 " %s: Setting up audio features (%sPLCI=%#x, function=%04x, rx=%u, tx=%u) \n " ,
i - > vname , plciName , i - > PLCI , divaAudioFlags , divaDigitalRxGain , divaDigitalTxGain ) ;
2009-02-13 21:58:19 +00:00
2010-11-02 14:14:43 +00:00
capi_sendf ( effectiveIfc , 0 , CAPI_MANUFACTURER_REQ , effectiveIfc - > PLCI , get_capi_MessageNumber ( ) ,
2009-02-13 21:58:19 +00:00
" dw(b(bwww)) " ,
_DI_MANU_ID ,
_DI_DSP_CTRL ,
0x1c ,
0x0b ,
2011-03-07 09:57:43 +00:00
divaAudioFlags ,
divaDigitalTxGain ,
divaDigitalRxGain ) ;
2009-02-13 21:58:19 +00:00
}
static void capi_diva_clamping ( struct capi_pvt * i , unsigned int duration )
{
2010-11-02 14:14:43 +00:00
if ( capi_check_diva_tone_function_allowed ( i , 0 ) ! = 0 )
2009-02-13 21:58:19 +00:00
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 )
{
2010-11-02 14:14:43 +00:00
if ( capi_check_diva_tone_function_allowed ( i , 0 ) ! = 0 )
2009-02-13 21:58:19 +00:00
return ;
2010-10-09 08:29:39 +00:00
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-02-13 21:58:19 +00:00
}
2009-04-10 07:23:20 +00:00
static void capi_diva_send_tone_function ( struct capi_pvt * i , unsigned char tone )
{
2010-11-02 14:14:43 +00:00
if ( capi_check_diva_tone_function_allowed ( i , 0 ) ! = 0 )
2009-02-13 21:58:19 +00:00
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
}
2010-10-09 08:29:39 +00:00
static void capi_diva_pitch_control_command (
struct capi_pvt * i ,
int enable ,
unsigned short rxpitch ,
unsigned short txpitch )
2009-02-14 20:56:14 +00:00
{
2010-11-02 14:14:43 +00:00
if ( capi_check_diva_tone_function_allowed ( i , 0 ) ! = 0 )
2009-02-13 21:58:19 +00:00
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 ) & &
2010-10-09 08:29:39 +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 ;
}
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const enum ast_channel_state cur_state = ast_channel_state ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const enum ast_channel_state cur_state = c - > _state ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2007-07-16 19:18:56 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: send_digit '%c' in state %d(%d) \n " ,
2015-02-28 16:35:31 +00:00
i - > vname , digit , i - > state , cur_state ) ;
2007-07-16 19:18:56 +00:00
2005-11-27 14:47:54 +00:00
cc_mutex_lock ( & i - > lock ) ;
2005-10-01 13:21:28 +00:00
2015-02-28 16:35:31 +00:00
if ( ( cur_state = = AST_STATE_DIALING ) & &
2005-07-17 19:01:14 +00:00
( 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 ) ;
2010-09-15 10:53:10 +00:00
facilityarray [ 0 ] = 0 ;
2007-08-09 07:53:12 +00:00
cc_qsig_add_call_alert_data ( facilityarray , i , c ) ;
2010-09-15 10:53:10 +00:00
pbx_capi_add_diva_protocol_independent_extension ( i , facilityarray , c , " CALLEDNAME " ) ;
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 ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_lock ( c ) ;
# endif
2005-07-17 19:01:14 +00:00
ast_setstate ( c , AST_STATE_RING ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_unlock ( c ) ;
# endif
2005-06-02 18:47:35 +00:00
return 0 ;
}
2010-12-21 19:14:27 +00:00
/*!
\ brief Send CALL PROCEEDING ( if supported by hardware )
\ note Sending of Proceeding is not defined by CAPI spec .
Diva hardware uses ALERT with sending complete set .
Other hardware can send alert only
*/
static int pbx_capi_signal_proceeding ( struct ast_channel * c , char * param )
{
static const unsigned char sending_complete [ ] = { 2 , 1 , 0 } ;
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
if ( ( i - > state ! = CAPI_STATE_INCALL ) & &
( i - > state ! = CAPI_STATE_DID ) ) {
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_3 " %s: attempting PROCEEDING in state %d \n " ,
i - > vname , i - > state ) ;
}
if ( ( i - > ntmode = = 0 )
/*! \todo || (capi_controllers[i->controlle]->mnufacturer != ManufacturerDiva) */ ) {
return ( pbx_capi_alert ( c ) ) ;
}
if ( ( ( i - > isdnstate2 & CAPI_ISDN_STATE2_PROCEEDING ) ! = 0 ) | |
( ( i - > isdnstate2 & CAPI_ISDN_STATE2_PROCEEDING_PENDING ) ! = 0 ) ) {
return 0 ;
}
if ( capi_sendf ( NULL , 0 , CAPI_ALERT_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" (()()()()s) " , sending_complete ) ! = 0 ) {
return - 1 ;
}
i - > isdnstate2 | = CAPI_ISDN_STATE2_PROCEEDING_PENDING ;
return 0 ;
}
2005-06-02 18:47:35 +00:00
/*
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
2010-06-11 11:21:40 +00:00
# ifdef DIVA_STREAMING
2010-06-25 13:49:15 +00:00
capi_DivaStreamingRemove ( i ) ;
2010-06-11 11:21:40 +00:00
# endif
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 ;
2010-12-21 19:14:27 +00:00
i - > isdnstate2 = 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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
ast_module_unref ( myself ) ;
# endif
2007-04-23 18:47:49 +00:00
i - > used = NULL ;
2012-04-11 09:45:19 +00:00
i - > reserved = 0 ;
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
}
}
/*
* 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
2016-07-11 14:32:43 +00:00
if ( i - > doB3 ! = CAPI_B3_DONT & &
! ( i - > fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL ) ) {
/* we do early B3 Connect */
cc_start_b3 ( i ) ;
}
2006-02-06 19:21:38 +00:00
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 ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
int hangupcause = ast_channel_hangupcause ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
int hangupcause = c - > hangupcause ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
i - > cause = hangupcause ;
2007-04-28 16:48:00 +00:00
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
ast_module_unref ( myself ) ;
# endif
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_tech_pvt_set ( c , NULL ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2006-06-27 08:20:19 +00:00
CC_CHANNEL_PVT ( c ) = NULL ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2007-04-23 18:47:49 +00:00
cc_mutex_unlock ( & i - > lock ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_lock ( c ) ;
# endif
2006-06-27 08:20:19 +00:00
ast_setstate ( c , AST_STATE_DOWN ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_unlock ( c ) ;
# endif
2006-06-27 08:20:19 +00:00
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 ;
}
2010-10-09 08:29:39 +00:00
static void pbx_capi_call_build_calling_party_number (
struct ast_channel * c ,
char * calling ,
int max_calling ,
int use_defaultcid ,
const char * ocid )
2010-08-13 20:41:23 +00:00
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
const char * ton ;
char callerid [ AST_MAX_EXTENSION ] ;
int CLIR ;
int callernplan ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
if ( ast_channel_connected ( c ) - > id . number . valid ) {
CLIR = ast_channel_connected ( c ) - > id . number . presentation ;
callernplan = ast_channel_connected ( c ) - > id . number . plan & 0x7f ;
} else {
CLIR = 0 ;
callernplan = 0 ;
}
if ( ast_channel_connected ( c ) - > id . number . valid & & ! ast_strlen_zero ( ast_channel_connected ( c ) - > id . number . str ) ) {
ast_copy_string ( callerid , ast_channel_connected ( c ) - > id . number . str , sizeof ( callerid ) ) ;
} else {
memset ( callerid , 0 , sizeof ( callerid ) ) ;
}
# elif defined(CC_AST_HAS_VERSION_1_8)
2010-08-13 20:41:23 +00:00
if ( c - > connected . id . number . valid ) {
CLIR = c - > connected . id . number . presentation ;
callernplan = c - > connected . id . number . plan & 0x7f ;
} else {
CLIR = 0 ;
callernplan = 0 ;
}
if ( c - > connected . id . number . valid & & ! ast_strlen_zero ( c - > connected . id . number . str ) ) {
ast_copy_string ( callerid , c - > connected . id . number . str , sizeof ( callerid ) ) ;
} else {
memset ( callerid , 0 , sizeof ( callerid ) ) ;
}
2015-02-28 16:35:31 +00:00
# else /* !(defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8)) */
2010-08-13 20:41:23 +00:00
CLIR = c - > cid . cid_pres ;
callernplan = c - > cid . cid_ton & 0x7f ;
if ( c - > cid . cid_num ) {
cc_copy_string ( callerid , c - > cid . cid_num , sizeof ( callerid ) ) ;
} else {
memset ( callerid , 0 , sizeof ( callerid ) ) ;
}
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8) */
2010-08-13 20:41:23 +00:00
if ( use_defaultcid ) {
cc_copy_string ( callerid , i - > defaultcid , sizeof ( callerid ) ) ;
} else if ( ocid ) {
cc_copy_string ( callerid , ocid , sizeof ( callerid ) ) ;
}
cc_copy_string ( i - > cid , callerid , sizeof ( i - > cid ) ) ;
if ( ( ton = pbx_builtin_getvar_helper ( c , " CALLERTON " ) ) ) {
callernplan = atoi ( ton ) & 0x7f ;
}
i - > cid_ton = callernplan ;
calling [ 0 ] = strlen ( callerid ) + 2 ;
calling [ 1 ] = callernplan ;
calling [ 2 ] = 0x80 | ( CLIR & 0x63 ) ;
strncpy ( & calling [ 3 ] , callerid , max_calling - 4 ) ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2010-08-13 20:41:23 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_2 " %s: Call %s %s%s (pres=0x%02x, ton=0x%02x) \n " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name , i - > doB3 ? " with B3 " : " " ,
2010-08-13 20:41:23 +00:00
i - > doOverlap ? " overlap " : " " , CLIR , callernplan ) ;
}
2005-06-02 18:47:35 +00:00
/*
2005-12-15 19:49:38 +00:00
* PBX tells us to make a call
2005-06-02 18:47:35 +00:00
*/
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
static int pbx_capi_call ( struct ast_channel * c , const char * idest , int timeout )
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
static int pbx_capi_call ( struct ast_channel * c , void * idest , int timeout )
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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-10-09 15:49:32 +00:00
int use_defaultcid = 0 ;
2009-03-25 12:38:46 +00:00
_cword cip ;
2010-08-13 20:41:23 +00:00
const char * 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 ;
2010-09-16 13:13:03 +00:00
unsigned char * facilityarray = NULL , * bc_s = NULL , * llc_s = 0 , * hlc_s = 0 ;
2011-04-21 20:44:45 +00:00
int no_sending_complete = 0 ;
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 ) ) ;
2010-09-15 09:14:51 +00:00
doqsig = i - > qsigfeat | | i - > divaqsig ;
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 ;
2016-07-11 14:32:43 +00:00
case ' t ' : /* enable B3 only on in-band tones available indication */
if ( ( i - > fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL ) )
cc_log ( LOG_WARNING ,
" B3 on in-band tones avail only already set in '%s' \n " ,
idest ) ;
i - > fsetting | = CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL ;
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 ;
2011-04-21 20:44:45 +00:00
case ' c ' : /* Do not send sending complete */
if ( no_sending_complete ! = 0 )
cc_log ( LOG_WARNING , " No sending complete already set in '%s' \n " , idest ) ;
no_sending_complete = 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
}
2016-07-11 14:32:43 +00:00
if ( ( ( ! dest ) | | ( ! dest [ 0 ] ) ) & &
i - > fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL )
cc_log ( LOG_WARNING ,
" dialtone request with B3 on in-band tones avail setting might not work on all exchanges in '%s' \n " ,
idest ) ;
if ( i - > doB3 = = CAPI_B3_DONT & &
i - > fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL )
cc_log ( LOG_WARNING ,
" B3 on in-band tones avail setting ignored when early B3 is disabled in '%s' \n " ,
idest ) ;
2007-04-24 20:21:04 +00:00
i - > peer = cc_get_peer_link_id ( pbx_builtin_getvar_helper ( c , " CAPIPEERLINKID " ) ) ;
i - > outgoing = 1 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
unsigned short cur_xfercap = ast_channel_transfercapability ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
unsigned short cur_xfercap = c - > transfercapability ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
i - > transfercapability = cur_xfercap ;
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-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 ) ;
}
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_G722) || defined(CC_FORMAT_SIREN7) || defined(CC_FORMAT_SIREN14) || defined(CC_FORMAT_SLINEAR16)
2010-09-16 13:13:03 +00:00
if ( capi_tcap_is_digital ( i - > transfercapability ) = = 0 & & i - > bproto = = CC_BPROTO_VOCODER ) {
static unsigned char llc_s_template [ ] = { 0x04 , 0x00 , 0xc0 , 0x90 , 0xa5 } ;
static unsigned char hlc_s_template [ ] = { 0x02 , 0x91 , 0x81 } ;
switch ( i - > codec ) {
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_G722)
case CC_FORMAT_G722 :
2010-09-16 13:13:03 +00:00
llc_s = llc_s_template ;
hlc_s = hlc_s_template ;
break ;
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SIREN7)
case CC_FORMAT_SIREN7 :
2010-09-16 13:13:03 +00:00
llc_s = llc_s_template ;
hlc_s = hlc_s_template ;
break ;
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SIREN14)
case CC_FORMAT_SIREN14 :
2010-09-16 13:13:03 +00:00
llc_s = llc_s_template ;
hlc_s = hlc_s_template ;
break ;
2010-09-30 22:27:39 +00:00
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SLINEAR16)
case CC_FORMAT_SLINEAR16 :
2010-09-30 22:27:39 +00:00
llc_s = llc_s_template ;
hlc_s = hlc_s_template ;
break ;
2010-09-16 13:13:03 +00:00
# endif
}
}
# endif
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 ;
2011-04-21 20:44:45 +00:00
sending_complete = ( no_sending_complete = = 0 ) ? " \x02 \x01 \x00 " : " \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
2010-10-09 08:29:39 +00:00
pbx_capi_call_build_calling_party_number ( c , calling , sizeof ( calling ) , use_defaultcid , ocid ) ;
2005-06-02 18:47:35 +00:00
2010-09-15 09:14:51 +00:00
if ( doqsig ! = 0 ) {
2010-09-15 10:53:10 +00:00
facilityarray = alloca ( CAPI_MAX_FACILITYDATAARRAY_SIZE ) ;
facilityarray [ 0 ] = 0 ;
if ( i - > qsigfeat ! = 0 )
2010-09-15 09:14:51 +00:00
cc_qsig_add_call_setup_data ( facilityarray , i , c ) ;
2010-09-15 10:53:10 +00:00
pbx_capi_add_diva_protocol_independent_extension ( i , facilityarray , NULL , " CALLED/CONNECTED NAME " ) ;
2007-02-11 16:01:32 +00:00
}
2010-06-28 21:37:56 +00:00
# ifdef DIVA_STREAMING
2010-10-09 08:29:39 +00:00
i - > diva_stream_entry = 0 ;
if ( pbx_capi_streaming_supported ( i ) ! = 0 ) {
capi_DivaStreamingOn ( i , 1 , i - > MessageNumber ) ;
}
2010-06-28 21:37:56 +00:00
# endif
2007-04-28 20:59:44 +00:00
error = capi_sendf ( NULL , 0 , CAPI_CONNECT_REQ , i - > controller , i - > MessageNumber ,
2010-09-16 13:13:03 +00:00
" wssss(wwwsss())sss((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 ,
2010-09-16 13:13:03 +00:00
bc_s , /* BC */
llc_s , /* LLC */
hlc_s , /* HLC */
2007-04-28 20:59:44 +00:00
/* 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 ;
}
2010-09-18 23:07:38 +00:00
_cstruct diva_get_b1_conf ( struct capi_pvt * i ) {
2009-05-08 13:03:31 +00:00
_cstruct b1conf = b_protocol_table [ i - > bproto ] . b1configuration ;
if ( i - > bproto = = CC_BPROTO_VOCODER ) {
switch ( i - > codec ) {
2011-10-04 08:41:28 +00:00
case CC_FORMAT_ALAW :
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x08 \x04 \x03 \x00 \xa0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
case CC_FORMAT_ULAW :
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x00 \x04 \x03 \x00 \xa0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
case CC_FORMAT_GSM :
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x03 \x04 \x0f \x00 \xa0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
case CC_FORMAT_G723_1 :
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x04 \x04 \x01 \x00 \xa0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
case CC_FORMAT_G726 :
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x02 \x04 \x0f \x00 \xa0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
case CC_FORMAT_ILBC : /* 30 mSec 240 samples */
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x1b \x04 \x03 \x00 \xf0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
case CC_FORMAT_G729A :
2009-05-08 13:03:31 +00:00
b1conf = ( _cstruct ) " \x06 \x12 \x04 \x0f \x00 \xa0 \x00 " ;
break ;
2011-10-04 08:41:28 +00:00
# ifdef CC_FORMAT_G722
case CC_FORMAT_G722 :
2010-09-16 13:13:03 +00:00
b1conf = ( _cstruct ) " \x06 \x09 \x04 \x03 \x00 \xa0 \x00 " ;
break ;
# endif
2011-10-04 08:41:28 +00:00
# ifdef CC_FORMAT_SIREN7
case CC_FORMAT_SIREN7 :
2010-09-16 13:13:03 +00:00
b1conf = ( _cstruct ) " \x06 \x24 \x04 \x0f \x02 \xa0 \x00 " ; /* 32 kBit/s */
break ;
# endif
2011-10-04 08:41:28 +00:00
# ifdef CC_FORMAT_SIREN14
case CC_FORMAT_SIREN14 :
2010-09-16 13:13:03 +00:00
b1conf = ( _cstruct ) " \x06 \x24 \x04 \x0f \x07 \xa0 \x00 " ; /* 48 kBit/s */
break ;
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SLINEAR)
case CC_FORMAT_SLINEAR :
2010-09-16 13:13:03 +00:00
b1conf = ( _cstruct ) " \x06 \x01 \x04 \x0f \x01 \xa0 \x00 " ;
break ;
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SLINEAR16)
case CC_FORMAT_SLINEAR16 :
2010-09-16 13:13:03 +00:00
b1conf = ( _cstruct ) " \x06 \x01 \x04 \x0f \x05 \xa0 \x00 " ;
break ;
# endif
2009-05-08 13:03:31 +00:00
default :
cc_log ( LOG_ERROR , " %s: format %s(%d) invalid. \n " ,
2011-10-04 08:41:28 +00:00
i - > vname , cc_getformatname ( i - > codec ) , i - > codec ) ;
2009-05-08 13:03:31 +00:00
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 ;
2010-09-16 13:13:03 +00:00
unsigned char * llc_s = NULL ;
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 ) ) {
2010-10-06 14:07:44 +00:00
const char * p = pbx_builtin_getvar_helper ( c , " CALLEDTON " ) ;
2005-08-18 07:25:17 +00:00
buf [ 0 ] = strlen ( dnid ) + 2 ;
2010-10-06 14:07:44 +00:00
buf [ 1 ] = ( p ! = 0 ) ? ( ( ( unsigned char ) atoi ( p ) ) & ~ 0x80 ) : 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 ) ;
2010-10-09 08:29:39 +00:00
pbx_capi_add_diva_protocol_independent_extension ( i , facilityarray , c , " CONNECTEDNAME " ) ;
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 ) ;
}
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_G722) || defined(CC_FORMAT_SIREN7) || defined(CC_FORMAT_SIREN14) || defined(CC_FORMAT_SLINEAR16)
2010-09-16 13:13:03 +00:00
if ( i - > bproto = = CC_BPROTO_VOCODER ) {
static unsigned char llc_s_template [ ] = { 0x03 , 0x91 , 0x90 , 0xa5 } ;
switch ( i - > codec ) {
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_G722)
case CC_FORMAT_G722 :
2010-09-16 13:13:03 +00:00
llc_s = llc_s_template ;
break ;
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SIREN7)
case CC_FORMAT_SIREN7 :
2010-09-16 13:13:03 +00:00
llc_s = llc_s_template ;
break ;
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SIREN14)
case CC_FORMAT_SIREN14 :
2010-09-16 13:13:03 +00:00
llc_s = llc_s_template ;
break ;
2010-09-30 22:27:39 +00:00
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SLINEAR16)
case CC_FORMAT_SLINEAR16 :
2010-09-30 22:27:39 +00:00
llc_s = llc_s_template ;
break ;
2010-09-16 13:13:03 +00:00
# endif
}
}
# endif
2007-04-28 20:59:44 +00:00
if ( capi_sendf ( NULL , 0 , CAPI_CONNECT_RESP , i - > PLCI , i - > MessageNumber ,
2010-09-16 13:13:03 +00:00
" w(wwwssss)s()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 */
2010-09-16 13:13:03 +00:00
llc_s , /* LLC */
2007-04-28 20:59:44 +00:00
/* 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
2011-04-21 21:04:29 +00:00
if ( f ! = NULL ) {
if ( f - > frametype = = AST_FRAME_VOICE ) {
if ( ( f - > datalen > 0 ) & & ( i - > doDTMF > 0 ) & & ( i - > vad ! = NULL ) ) {
f = ast_dsp_process ( c , i - > vad , f ) ;
}
2011-04-29 09:44:26 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2011-04-21 21:04:29 +00:00
} else if ( f - > frametype = = AST_FRAME_DTMF ) {
/* Work around problem with recognition of fast sequences of events,
* see main / channel . c for details
2015-02-28 16:35:31 +00:00
* . . . or better yet , get rid of this ugly hack alltogether .
2011-04-21 21:04:29 +00:00
*/
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
if ( ! ( ast_test_flag ( ast_channel_flags ( c ) , AST_FLAG_END_DTMF_ONLY ) | |
ast_test_flag ( ast_channel_flags ( c ) , AST_FLAG_EMULATE_DTMF ) | |
ast_test_flag ( ast_channel_flags ( c ) , AST_FLAG_IN_DTMF ) ) ) {
ast_set_flag ( ast_channel_flags ( c ) , AST_FLAG_IN_DTMF ) ;
struct timeval back_to_the_past = ast_tvsub ( ast_tvnow ( ) , ast_tv ( 0 , 250 * 1000 /* to msec */ ) ) ;
ast_channel_dtmf_tv_set ( c , & back_to_the_past ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0 */
2011-04-21 21:04:29 +00:00
if ( ! ( ast_test_flag ( c , AST_FLAG_END_DTMF_ONLY ) | |
ast_test_flag ( c , AST_FLAG_EMULATE_DTMF ) | |
ast_test_flag ( c , AST_FLAG_IN_DTMF ) ) ) {
ast_set_flag ( c , AST_FLAG_IN_DTMF ) ;
2011-04-29 09:44:26 +00:00
c - > dtmf_tv = ast_tvsub ( ast_tvnow ( ) , ast_tv ( 0 , 250 * 1000 ) ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2011-04-21 21:04:29 +00:00
if ( ! f - > len )
f - > len = 100 ;
}
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_1_4) */
2006-06-10 11:58:50 +00:00
}
}
2011-04-21 21:04:29 +00:00
2006-06-10 11:58:50 +00:00
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
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * old_name = ast_channel_name ( oldchan ) ;
const char * new_name = ast_channel_name ( newchan ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * old_name = oldchan - > name ;
const char * new_name = newchan - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: %s fixup now %s \n " ,
2015-02-28 16:35:31 +00:00
i - > vname , old_name , new_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 ;
}
2007-09-30 21:09:15 +00:00
/*
* try call transfer instead of bridge
*/
2017-01-15 17:12:14 +00:00
# ifndef CC_AST_HAS_VERSION_13_0
2007-09-30 21:09:15 +00:00
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 */
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * c0_name = ast_channel_name ( c0 ) ;
const char * c1_name = ast_channel_name ( c1 ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * c0_name = c0 - > name ;
const char * c1_name = c1 - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2007-09-30 21:09:15 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s:%s cancelled bridge (path replacement was sent) for %s and %s \n " ,
2015-02-28 16:35:31 +00:00
i0 - > vname , i1 - > vname , c0_name , c1_name ) ;
2007-09-30 21:09:15 +00:00
}
} 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 ;
}
2017-01-15 17:12:14 +00:00
# endif
2007-09-30 21:09:15 +00:00
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 ) ;
2010-07-17 23:17:49 +00:00
if ( ( capi_controllers [ i0 - > controller ] - > ecOnTransit & EC_ECHOCANCEL_TRANSIT_A ) = = 0 ) {
capi_echo_canceller ( i0 , EC_FUNCTION_DISABLE ) ;
}
if ( ( capi_controllers [ i1 - > controller ] - > ecOnTransit & EC_ECHOCANCEL_TRANSIT_B ) = = 0 ) {
capi_echo_canceller ( i1 , EC_FUNCTION_DISABLE ) ;
}
2008-08-30 09:58:27 +00:00
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
*/
2017-01-15 17:12:14 +00:00
# ifndef CC_AST_HAS_VERSION_13_0
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * c0_name = ast_channel_name ( c0 ) ;
const char * c1_name = ast_channel_name ( c1 ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * c0_name = c0 - > name ;
const char * c1_name = c1 - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 " ,
2015-02-28 16:35:31 +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 ;
}
2017-01-15 17:12:14 +00:00
# endif
2005-09-15 19:11:45 +00:00
2005-06-02 18:47:35 +00:00
/*
* a new channel is needed
*/
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
static struct ast_channel * capi_new ( struct capi_pvt * i , int state , const struct ast_channel * requestor )
# else
2009-07-24 20:30:47 +00:00
static struct ast_channel * capi_new ( struct capi_pvt * i , int state , const char * linkedid )
2017-01-15 17:12:14 +00:00
# endif
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 ,
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
NULL , requestor ,
# endif
2009-07-24 20:30:47 +00:00
# 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
2012-04-11 09:45:19 +00:00
cc_mutex_lock ( & iflock ) ;
i - > reserved = 0 ;
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 ;
}
2012-03-02 22:36:08 +00:00
# ifdef CC_AST_HAS_VERSION_1_6
ast_channel_set_fd ( tmp , 0 , i - > readerfd ) ;
# else
2006-06-10 11:58:50 +00:00
tmp - > fds [ 0 ] = i - > readerfd ;
2012-03-02 22:36:08 +00:00
# endif
2006-06-10 11:58:50 +00:00
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 ;
2011-03-07 09:57:43 +00:00
i - > divaDataStubAudioFlags = 0 ;
2009-02-13 21:58:19 +00:00
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
}
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_tech_pvt_set ( tmp , i ) ;
ast_channel_callgroup_set ( tmp , i - > callgroup ) ;
ast_channel_pickupgroup_set ( tmp , i - > pickupgroup ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
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 ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2011-10-04 08:41:28 +00:00
#if 0
2006-01-30 23:40:28 +00:00
i - > bproto = CC_BPROTO_TRANSPARENT ;
2011-10-04 08:41:28 +00:00
tmp - > nativeformats = capi_capability ;
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
tmp - > nativeformats = i - > rtpcodec ;
i - > bproto = CC_BPROTO_VOCODER ;
2006-01-30 23:40:28 +00:00
}
2011-10-04 08:41:28 +00:00
2005-06-02 18:47:35 +00:00
fmt = ast_best_codec ( tmp - > nativeformats ) ;
2011-10-04 08:41:28 +00:00
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 ;
tmp - > rawreadformat = fmt ;
tmp - > rawwriteformat = fmt ;
2011-10-04 08:41:28 +00:00
# else
if ( ( i - > rtpcodec = ( capi_controllers [ i - > controller ] - > rtpcodec & i - > capability ) ) ) {
i - > bproto = CC_BPROTO_VOCODER ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
struct ast_format_cap * cur_nativefmts = ast_channel_nativeformats ( tmp ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
struct ast_format_cap * cur_nativefmts = tmp - > nativeformats ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
cc_add_formats ( cur_nativefmts , i - > rtpcodec ) ;
2011-10-04 08:41:28 +00:00
} else {
i - > bproto = CC_BPROTO_TRANSPARENT ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
struct ast_format_cap * cur_nativefmts = ast_channel_nativeformats ( tmp ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
struct ast_format_cap * cur_nativefmts = tmp - > nativeformats ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
cc_add_formats ( cur_nativefmts , capi_capability ) ;
2011-10-04 08:41:28 +00:00
}
fmt = cc_set_best_codec ( tmp ) ;
i - > codec = fmt ;
# endif
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_tech_set ( tmp , & capi_tech ) ;
struct ast_format_cap * cur_nativefmts = ast_channel_nativeformats ( tmp ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2011-10-04 08:41:28 +00:00
tmp - > tech = & capi_tech ;
2015-02-28 16:35:31 +00:00
struct ast_format_cap * cur_nativefmts = tmp - > nativeformats ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2006-06-24 11:53:47 +00:00
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
struct ast_str * format_buf = ast_str_alloca ( AST_FORMAT_CAP_NAMES_LEN ) ;
# endif
2006-01-30 23:40:28 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: setting format %s - %s%s \n " ,
2011-10-04 08:41:28 +00:00
i - > vname , cc_getformatname ( fmt ) ,
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_format_cap_get_names ( cur_nativefmts , & format_buf ) ,
# else
ast_getformatname_multiple ( alloca ( 80 ) , 80 , cur_nativefmts ) ,
# endif
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 ) ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_free ( ast_channel_connected ( tmp ) - > id . number . str ) ;
ast_channel_connected ( tmp ) - > id . number . valid = 1 ;
ast_channel_connected ( tmp ) - > id . number . str = ast_strdup ( i - > cid ) ;
ast_channel_connected ( tmp ) - > id . number . plan = i - > cid_ton ;
# elif defined(CC_AST_HAS_VERSION_1_8)
2010-08-13 20:41:23 +00:00
ast_free ( tmp - > connected . id . number . str ) ;
tmp - > connected . id . number . valid = 1 ;
tmp - > connected . id . number . str = ast_strdup ( i - > cid ) ;
tmp - > connected . id . number . plan = i - > cid_ton ;
2015-02-28 16:35:31 +00:00
# else /* !(defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8)) */
2010-08-19 08:44:21 +00:00
ast_free ( tmp - > cid . cid_num ) ;
tmp - > cid . cid_num = ast_strdup ( i - > cid ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8) */
2006-08-06 18:44:56 +00:00
}
2006-02-12 20:58:02 +00:00
if ( ! ast_strlen_zero ( i - > dnid ) ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_free ( ast_channel_dialed ( tmp ) - > number . str ) ;
ast_channel_dialed ( tmp ) - > number . str = ast_strdup ( i - > dnid ) ;
# elif defined(CC_AST_HAS_VERSION_1_8)
2010-08-13 20:41:23 +00:00
ast_free ( tmp - > dialed . number . str ) ;
tmp - > dialed . number . str = ast_strdup ( i - > dnid ) ;
2015-02-28 16:35:31 +00:00
# else /* !(defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8)) */
2010-08-13 20:41:23 +00:00
ast_free ( tmp - > cid . cid_dnid ) ;
tmp - > cid . cid_dnid = ast_strdup ( i - > dnid ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8) */
2006-02-12 20:58:02 +00:00
}
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_dialed ( tmp ) - > number . plan = i - > cid_ton ;
# elif defined(CC_AST_HAS_VERSION_1_8)
2010-08-13 20:41:23 +00:00
tmp - > dialed . number . plan = i - > cid_ton ;
2015-02-28 16:35:31 +00:00
# else /* !(defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8)) */
2006-03-07 21:17:58 +00:00
tmp - > cid . cid_ton = i - > cid_ton ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8) */
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_context_set ( tmp , i - > context ) ;
ast_channel_exten_set ( tmp , i - > dnid ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_9) */
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 ) ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2006-02-04 12:48:10 +00:00
# ifdef CC_AST_HAS_STRINGFIELD_IN_CHANNEL
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_accountcode_set ( tmp , i - > accountcode ) ;
ast_channel_language_set ( tmp , i - > language ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_9) */
2006-02-04 12:48:10 +00:00
ast_string_field_set ( tmp , accountcode , i - > accountcode ) ;
ast_string_field_set ( tmp , language , i - > language ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2006-02-04 12:48:10 +00:00
# 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
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 ) ;
2015-02-28 16:35:31 +00:00
ast_module_ref ( myself ) ;
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
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_unlock ( tmp ) ;
# endif
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
*/
2011-10-04 08:41:28 +00:00
# ifdef CC_AST_HAS_REQUEST_REQUESTOR /* { */
# 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 */
2011-10-04 08:41:28 +00:00
# elif !defined(CC_AST_HAS_VERSION_10_0) /* } { */
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 )
2015-02-28 16:35:31 +00:00
# elif !defined(CC_AST_HAS_VERSION_11_0) /* } { */
2011-10-04 08:41:28 +00:00
static struct ast_channel *
pbx_capi_request ( const char * type , struct ast_format_cap * format , const struct ast_channel * requestor , void * data , int * cause )
2017-01-15 17:12:14 +00:00
# elif !defined(CC_AST_HAS_VERSION_13_0) /* } { */
2015-02-28 16:35:31 +00:00
static struct ast_channel *
pbx_capi_request ( const char * type , struct ast_format_cap * format , const struct ast_channel * requestor , const char * data , int * cause )
2017-01-15 17:12:14 +00:00
# else /* } { */
static struct ast_channel *
pbx_capi_request ( const char * type , struct ast_format_cap * format , const struct ast_assigned_ids * assignedids , const struct ast_channel * requestor , const char * data , int * cause )
2011-10-04 08:41:28 +00:00
# endif /* } */
# else /* } { */
2010-03-01 17:59:31 +00:00
static struct ast_channel *
2006-06-09 21:48:24 +00:00
pbx_capi_request ( const char * type , int format , void * data , int * cause )
2011-10-04 08:41:28 +00:00
# endif /* } */
2005-06-02 18:47:35 +00:00
{
2010-10-26 22:22:25 +00:00
struct capi_pvt * i , * bestChannel ;
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 ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
struct ast_str * format_buf = ast_str_alloca ( AST_FORMAT_CAP_NAMES_LEN ) ;
# endif
2005-06-02 18:47:35 +00:00
2011-10-04 08:41:28 +00:00
cc_verbose ( 1 , 1 , VERBOSE_PREFIX_4 " data = %s format=%s \n " ,
( char * ) data ,
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_format_cap_get_names ( format , & format_buf )
# else
ast_getformatname_multiple ( alloca ( 80 ) , 80 , format )
# endif
) ;
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
2010-10-26 22:22:25 +00:00
for ( i = capi_iflist , bestChannel = 0 ; i ; i = i - > next ) {
2010-10-22 22:44:50 +00:00
if ( CC_B_INTERFACE_NOT_FREE ( i ) ) {
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 ;
2010-10-26 22:22:25 +00:00
} else if ( pbx_capi_check_controller_status ( i - > controller ) < 0 ) {
2010-10-22 22:44:50 +00:00
break ;
2005-06-02 18:47:35 +00:00
}
} else {
/* DIAL(CAPI/gX/...) */
2010-10-22 22:44:50 +00:00
if ( interface [ 0 ] = = ' g ' ) {
if ( ( i - > group & capigroup ) = = 0 )
continue ; /* not in group, keep on running! */
2010-10-26 22:22:25 +00:00
if ( pbx_capi_check_controller_status ( i - > controller ) < 0 )
2010-10-22 22:44:50 +00:00
continue ; /* not active or better interface found, keep on running! */
2010-10-26 22:22:25 +00:00
if ( capi_controllers [ i - > controller ] - > nfreebchannelsSoftThr ! = 0 ) {
if ( bestChannel = = 0 ) {
bestChannel = i ;
} else if ( i - > controller ! = bestChannel - > controller ) {
int idiff = capi_controllers [ i - > controller ] - > nfreebchannels - capi_controllers [ i - > controller ] - > nfreebchannelsSoftThr ;
int bdiff = capi_controllers [ bestChannel - > controller ] - > nfreebchannels - capi_controllers [ bestChannel - > controller ] - > nfreebchannelsSoftThr ;
int c = ( i - > controller < bestChannel - > controller ) ;
if ( ( c & & ( idiff > = 0 ) ) | | ( ( bdiff < 0 ) & & ( idiff > = 0 ) ) | | ( ( bdiff < 0 ) & & ( idiff > bdiff ) ) ) {
bestChannel = i ;
}
}
continue ; /* Continue search for best channel */
}
2010-10-22 22:44:50 +00:00
} else if ( strcmp ( interface , i - > name ) ! = 0 ) {
2005-07-27 18:17:41 +00:00
/* DIAL(CAPI/<interface-name>/...) */
2005-06-02 18:47:35 +00:00
/* keep on running! */
continue ;
2010-10-26 22:22:25 +00:00
} else if ( pbx_capi_check_controller_status ( i - > controller ) < 0 ) {
2010-10-22 22:44:50 +00:00
break ;
2005-06-02 18:47:35 +00:00
}
}
2010-10-26 22:22:25 +00:00
found_best_channel :
2005-06-02 18:47:35 +00:00
/* 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 ) ) ;
2012-04-11 09:45:19 +00:00
i - > reserved = 1 ;
cc_mutex_unlock ( & iflock ) ;
2009-07-24 20:30:47 +00:00
tmp = capi_new ( i , AST_STATE_RESERVED ,
# ifdef CC_AST_HAS_REQUEST_REQUESTOR
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
requestor
# elif defined(CC_AST_HAS_VERSION_11_0)
2015-02-28 16:35:31 +00:00
requestor ? ast_channel_linkedid ( requestor ) : NULL
2017-01-15 17:12:14 +00:00
# else /* !defined(CC_AST_HAS_VERSION_13_0) */
2009-07-24 20:30:47 +00:00
requestor ? requestor - > linkedid : NULL
2017-01-15 17:12:14 +00:00
# endif /* defined(CC_AST_HAS_REQUEST_REQUESTOR) */
2009-07-24 20:30:47 +00:00
# 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 ;
}
2010-10-26 22:22:25 +00:00
if ( bestChannel ! = 0 ) {
i = bestChannel ;
goto found_best_channel ;
}
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 ;
2010-06-25 13:49:15 +00:00
# ifdef DIVA_STREAMING
capi_DivaStreamingRemoveInfo ( i ) ;
# endif
2006-02-06 19:21:38 +00:00
cc_disconnect_b3 ( i , 1 ) ;
2010-06-25 13:49:15 +00:00
# ifdef DIVA_STREAMING
capi_DivaStreamingRemove ( i ) ;
# endif
2006-02-06 19:21:38 +00:00
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
2010-09-26 10:51:45 +00:00
filename = strsep ( & data , COMMANDSEPARATOR ) ;
stationid = strsep ( & data , COMMANDSEPARATOR ) ;
headline = strsep ( & data , COMMANDSEPARATOR ) ;
2007-04-05 19:33:01 +00:00
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 :
2010-06-25 14:58:04 +00:00
# ifdef DIVA_STREAMING
capi_DivaStreamingRemoveInfo ( i ) ;
capi_DivaStreamingRemove ( i ) ;
# endif
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 ] ;
2010-09-26 10:51:45 +00:00
filename = strsep ( & data , COMMANDSEPARATOR ) ;
stationid = strsep ( & data , COMMANDSEPARATOR ) ;
headline = strsep ( & data , COMMANDSEPARATOR ) ;
2009-08-05 22:25:53 +00:00
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 :
2010-06-25 14:58:04 +00:00
# ifdef DIVA_STREAMING
capi_DivaStreamingRemoveInfo ( i ) ;
capi_DivaStreamingRemove ( i ) ;
# endif
2009-08-05 22:25:53 +00:00
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 ;
}
2010-08-19 08:44:21 +00:00
ldata_mem = ldata = ast_strdup ( data ) ;
2009-08-05 22:25:53 +00:00
if ( ! ldata_mem ) {
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " out of memory \n " ) ;
capi_remove_nullif ( i ) ;
return - 1 ;
}
2010-09-26 10:51:45 +00:00
( void ) strsep ( & ldata , COMMANDSEPARATOR ) ;
( void ) strsep ( & ldata , COMMANDSEPARATOR ) ;
( void ) strsep ( & ldata , COMMANDSEPARATOR ) ;
2009-08-05 22:25:53 +00:00
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 + + ;
}
2010-08-19 08:44:21 +00:00
ast_free ( ldata_mem ) ;
2009-08-05 22:25:53 +00:00
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 ;
2011-10-04 08:41:28 +00:00
cc_set_read_format ( chan , capi_capability ) ;
cc_set_write_format ( chan , capi_capability ) ;
2009-05-02 13:21:17 +00:00
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 */
2010-07-20 13:00:54 +00:00
cc_verbose ( 5 , 1 , VERBOSE_PREFIX_3 " %s: clear channel fax: NULL frame, ignoring. \n " ,
2009-05-02 13:21:17 +00:00
i - > vname ) ;
} else {
2010-07-20 13:00:54 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: clear 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 ) {
2010-07-20 13:00:54 +00:00
cc_verbose ( 1 , 0 , VERBOSE_PREFIX_3 " %s: clear channel fax: exception on readerfd \n " ,
2009-05-02 13:21:17 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_name ( chan ) ,
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
chan - > name ,
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
strerror ( errno ) ) ;
2009-05-02 13:21:17 +00:00
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
2010-09-26 10:51:45 +00:00
filename = strsep ( & data , COMMANDSEPARATOR ) ;
stationid = strsep ( & data , COMMANDSEPARATOR ) ;
headline = strsep ( & data , COMMANDSEPARATOR ) ;
2009-04-08 22:44:14 +00:00
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 :
2010-06-25 14:58:04 +00:00
# ifdef DIVA_STREAMING
capi_DivaStreamingRemoveInfo ( i ) ;
capi_DivaStreamingRemove ( i ) ;
# endif
2006-06-27 14:54:03 +00:00
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 ] ;
2010-09-26 10:51:45 +00:00
filename = strsep ( & data , COMMANDSEPARATOR ) ;
stationid = strsep ( & data , COMMANDSEPARATOR ) ;
headline = strsep ( & data , COMMANDSEPARATOR ) ;
2009-08-06 08:49:25 +00:00
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 :
2010-06-25 14:58:04 +00:00
# ifdef DIVA_STREAMING
capi_DivaStreamingRemoveInfo ( i ) ;
capi_DivaStreamingRemove ( i ) ;
# endif
2009-08-06 08:49:25 +00:00
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 ;
}
2010-08-19 08:44:21 +00:00
ldata_mem = ldata = ast_strdup ( data ) ;
2009-08-06 08:49:25 +00:00
if ( ! ldata_mem ) {
cc_log ( LOG_WARNING , CC_MESSAGE_NAME " out of memory \n " ) ;
capi_remove_nullif ( i ) ;
return - 1 ;
}
2010-09-26 10:51:45 +00:00
( void ) strsep ( & ldata , COMMANDSEPARATOR ) ;
( void ) strsep ( & ldata , COMMANDSEPARATOR ) ;
( void ) strsep ( & ldata , COMMANDSEPARATOR ) ;
2009-08-06 08:49:25 +00:00
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 + + ;
}
2010-08-19 08:44:21 +00:00
ast_free ( ldata_mem ) ;
2009-08-06 08:49:25 +00:00
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 ;
2015-02-28 16:35:31 +00:00
const char * faxcontext ;
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 ;
}
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
struct ast_cdr * cur_cdr = ast_channel_cdr ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
struct ast_cdr * cur_cdr = c - > cdr ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( ( i - > faxdetecttime > 0 ) & & cur_cdr ) {
2008-06-29 11:33:46 +00:00
struct timeval now ;
gettimeofday ( & now , NULL ) ;
2015-02-28 16:35:31 +00:00
if ( ( cur_cdr - > start . tv_sec + i - > faxdetecttime ) < now . tv_sec ) {
2008-06-29 11:33:46 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3
" %s: Fax detected after %ld seconds, limit %u - ignored \n " ,
2015-02-28 16:35:31 +00:00
i - > vname , ( long ) ( now . tv_sec - cur_cdr - > start . tv_sec ) ,
2008-06-29 11:33:46 +00:00
i - > faxdetecttime ) ;
return ;
}
}
2010-09-24 19:20:28 +00:00
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_context = ast_channel_context ( c ) ;
const char * cur_exten = ast_channel_exten ( c ) ;
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_context = c - > context ;
const char * cur_exten = c - > exten ;
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
faxcontext = cur_context ;
2010-09-24 19:20:28 +00:00
if ( strlen ( i - > faxcontext ) > 0 )
faxcontext = i - > faxcontext ;
2005-06-04 14:28:52 +00:00
2015-02-28 16:35:31 +00:00
if ( ( ! strcmp ( cur_exten , i - > faxexten ) ) & &
( ! strcmp ( cur_context , faxcontext ) ) ) {
2010-09-24 19:20:28 +00:00
cc_log ( LOG_DEBUG , " Already in fax context/extension, not redirecting \n " ) ;
2005-06-04 14:28:52 +00:00
return ;
}
2005-09-27 17:52:13 +00:00
2010-09-24 19:20:28 +00:00
if ( ! ast_exists_extension ( c , faxcontext , i - > faxexten , i - > faxpriority , i - > cid ) ) {
2008-03-19 18:29:37 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3
2010-09-24 19:20:28 +00:00
" Fax tone detected, but no extension '%s' for %s in context '%s' \n " ,
2015-02-28 16:35:31 +00:00
i - > faxexten , cur_name , faxcontext ) ;
2005-06-04 14:28:52 +00:00
return ;
}
2010-09-26 13:20:38 +00:00
cc_verbose ( 2 , 0 , VERBOSE_PREFIX_3 " %s: Redirecting %s for fax to %s,%s,%d \n " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name , faxcontext , i - > faxexten , i - > faxpriority ) ;
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_context = ast_channel_context ( c ) ;
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_context = c - > context ;
char * cur_exten = ( char * ) c - > exten ;
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name , exten , cur_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
2015-02-28 16:35:31 +00:00
if ( ast_exists_extension ( NULL , cur_context , exten , 1 , i - > cid ) ) {
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_priority_set ( c , 1 ) ;
ast_channel_exten_set ( c , exten ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2005-06-02 18:47:35 +00:00
c - > priority = 1 ;
2015-02-28 16:35:31 +00:00
cc_copy_string ( cur_exten , exten , sizeof ( cur_exten ) ) ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2005-11-20 16:15:33 +00:00
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: %s: %s matches in context %s \n " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name , exten , cur_context ) ;
2005-06-02 18:47:35 +00:00
return 0 ;
}
2015-02-28 16:35:31 +00:00
if ( ast_canmatch_extension ( NULL , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name , exten , cur_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
{
2016-07-11 14:32:43 +00:00
int inband_info = 0 ;
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 ;
}
2016-07-11 14:32:43 +00:00
if ( ( INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] & 0x60 ) ! = 0x00 ) {
cc_verbose ( 3 , 1 ,
VERBOSE_PREFIX_4 " %s: Progress description has unsupported coding \n " ,
i - > vname ) ;
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 ) ;
2016-07-11 14:32:43 +00:00
inband_info = 1 ;
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 ) ;
2016-07-11 14:32:43 +00:00
inband_info = 1 ;
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
}
2016-07-11 14:32:43 +00:00
if ( inband_info & & i - > doB3 ! = CAPI_B3_DONT & &
i - > fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL )
cc_start_b3 ( i ) ;
2005-09-04 13:51:50 +00:00
send_progress ( i ) ;
2016-07-11 14:32:43 +00:00
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
char * cur_exten = ( char * ) c - > exten ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name ) ;
2006-07-08 16:29:27 +00:00
return ;
}
/* check for internal pickup extension first */
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
RAII_VAR ( struct ast_features_pickup_config * , pickup_cfg , NULL , ao2_cleanup ) ;
const char * pickupexten ;
pickup_cfg = ast_get_chan_features_pickup_config ( c ) ;
pickupexten = ast_strdupa ( pickup_cfg - > pickupexten ) ;
if ( ! strcmp ( i - > dnid , pickupexten ) ) {
# else
2006-07-08 16:29:27 +00:00
if ( ! strcmp ( i - > dnid , ast_pickup_ext ( ) ) ) {
2017-01-15 17:12:14 +00:00
# endif
2006-07-08 16:29:27 +00:00
i - > isdnstate | = CAPI_ISDN_STATE_PBX ;
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_2 " %s: Pickup extension '%s' found. \n " ,
i - > vname , i - > dnid ) ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_exten_set ( c , i - > dnid ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
cc_copy_string ( cur_exten , i - > dnid , sizeof ( cur_exten ) ) ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2006-07-08 16:29:27 +00:00
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 ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_lock ( c ) ;
# endif
2006-07-08 16:29:27 +00:00
ast_setstate ( c , AST_STATE_RING ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_unlock ( c ) ;
# endif
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 " ,
2015-02-28 16:35:31 +00:00
cur_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 ) ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const struct ast_pbx * owner_pbx = ast_channel_pbx ( i - > owner ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const struct ast_pbx * owner_pbx = i - > owner - > pbx ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( 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 ) ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
int cause = ast_channel_hangupcause ( i - > owner ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2005-07-17 19:01:14 +00:00
int cause = i - > owner - > hangupcause ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 ;
}
2016-07-11 14:32:43 +00:00
/* at this point the call is either incoming or we are always doing B3 */
2005-06-02 18:47:35 +00:00
/* case 2: we are doing B3, and receive the 0x8045 after a successful call */
2016-07-11 14:32:43 +00:00
if ( ( 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 ) ;
2016-07-11 14:32:43 +00:00
/*
* FIXME : is this right ? if this is just a normal hangup of
* a successful call shouldn ' t it be the same as case 1 ?
*/
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 ;
}
2016-07-11 14:32:43 +00:00
/* case 4 (a.k.a. the italian case): always doing B3 and call is unsuccessful */
cc_verbose ( 4 , 1 , VERBOSE_PREFIX_3 " %s: Disconnect case 4 \n " ,
2006-06-18 16:32:32 +00:00
i - > vname ) ;
2016-07-11 14:32:43 +00:00
/* play audio and wait for a timeout from the network */
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const struct ast_channel_tech * peer_tech = ast_channel_tech ( i - > peer ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const struct ast_channel_tech * peer_tech = i - > peer - > tech ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( peer_tech ! = & capi_tech )
2007-09-01 22:11:48 +00:00
return ;
i2 = CC_CHANNEL_PVT ( i - > peer ) ;
2011-05-11 09:03:17 +00:00
if ( ( i2 = = NULL ) | | ( ! ( i2 - > ntmode ) ) )
2007-09-01 22:11:48 +00:00
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 ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
2016-10-30 18:57:44 +00:00
ast_channel_hangupcause_set ( i - > owner , INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] & 0x7f ) ;
2015-02-28 16:35:31 +00:00
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2005-07-17 19:01:14 +00:00
i - > owner - > hangupcause = INFO_IND_INFOELEMENT ( CMSG ) [ 2 ] & 0x7f ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 ] ) ;
2016-07-11 14:32:43 +00:00
if ( i - > doB3 ! = CAPI_B3_DONT & &
! ( i - > fsetting & CAPI_FSETTING_EARLYB3_ONLY_WHEN_TONES_AVAIL ) ) {
2007-05-28 08:46:01 +00:00
/* 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 ;
2013-10-22 10:25:45 +00:00
case 0xc2 :
desc = " Conference established " ;
pbx_builtin_setvar_helper ( i - > owner , " THREEWAYESTABLISHED " , " YES " ) ;
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 ) ;
2010-08-13 20:41:23 +00:00
# ifdef CC_AST_HAS_VERSION_1_8
{
/*! \todo Set correctly redirecting to and reason */
struct ast_party_redirecting redirecting ;
struct ast_set_party_redirecting update_redirecting ;
memset ( & redirecting , 0 , sizeof ( redirecting ) ) ;
memset ( & update_redirecting , 0 , sizeof ( update_redirecting ) ) ;
update_redirecting . from . number = 1 ;
redirecting . from . number . valid = 1 ;
redirecting . from . number . str = ( char * ) p ;
redirecting . from . number . plan = 0 ;
redirecting . from . number . presentation = 0 ;
redirecting . from . tag = 0 ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
redirecting . reason . code = AST_REDIRECTING_REASON_UNKNOWN ;
# else
2010-08-13 20:41:23 +00:00
redirecting . reason = AST_REDIRECTING_REASON_UNKNOWN ;
2017-01-15 17:12:14 +00:00
# endif
2010-08-13 20:41:23 +00:00
redirecting . count = 1 ;
ast_channel_set_redirecting ( i - > owner , & redirecting , & update_redirecting ) ;
}
# else
2010-08-19 08:44:21 +00:00
ast_free ( i - > owner - > cid . cid_rdnis ) ;
i - > owner - > cid . cid_rdnis = ast_strdup ( p ) ;
2010-08-13 20:41:23 +00:00
# endif
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 )
2017-01-15 17:12:14 +00:00
{
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_lock ( i - > owner ) ;
# endif
2006-06-27 20:29:15 +00:00
ast_setstate ( i - > owner , AST_STATE_RINGING ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_unlock ( i - > owner ) ;
# endif
}
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 ) {
2015-02-28 16:35:31 +00:00
if ( i - > owner ) {
# ifdef CC_AST_HAS_VERSION_11_0
int owner_hangupcause = ast_channel_hangupcause ( i - > owner ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
int owner_hangupcause = i - > owner - > hangupcause ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( owner_hangupcause = = AST_CAUSE_USER_BUSY ) {
capi_queue_cause_control ( i , 1 ) ;
break ;
}
2005-08-28 14:14:23 +00:00
}
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
}
2010-10-09 08:29:39 +00:00
static int pbx_capi_get_samples ( struct capi_pvt * i , int length )
{
2010-09-16 13:13:03 +00:00
switch ( i - > codec ) {
2011-10-04 08:41:28 +00:00
case CC_FORMAT_SLINEAR :
# if defined(CC_FORMAT_SLINEAR16)
case CC_FORMAT_SLINEAR16 :
2010-09-25 10:26:24 +00:00
# endif
2010-10-09 08:29:39 +00:00
return ( length / 2 ) ;
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_G722)
case CC_FORMAT_G722 :
2010-10-09 08:29:39 +00:00
return ( length * 2 ) ;
2011-02-04 17:18:05 +00:00
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SIREN7)
case CC_FORMAT_SIREN7 :
2010-10-09 08:29:39 +00:00
return ( length * ( 320 / 80 ) ) ;
2010-09-25 10:26:24 +00:00
# endif
2011-10-04 08:41:28 +00:00
# if defined(CC_FORMAT_SIREN14)
case CC_FORMAT_SIREN14 :
2010-10-09 08:29:39 +00:00
return ( ( typeof ( length ) ) length * ( ( float ) 640 / 120 ) ) ;
2010-09-25 10:26:24 +00:00
# endif
2010-09-16 13:13:03 +00:00
}
return ( length ) ;
}
2005-06-02 18:47:35 +00:00
/*
* CAPI DATA_B3_IND
*/
2010-10-09 08:29:39 +00:00
static void capidev_handle_data_b3_indication (
_cmsg * CMSG ,
unsigned int PLCI ,
unsigned int NCCI ,
struct capi_pvt * i ,
struct _diva_streaming_vector * vind ,
int vind_nr )
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 ;
2006-01-30 23:40:28 +00:00
b3buf = & ( i - > rec_buffer [ AST_FRIENDLY_OFFSET - rtpoffset ] ) ;
2010-05-07 22:28:56 +00:00
if ( CMSG ! = 0 ) {
b3len = DATA_B3_IND_DATALENGTH ( CMSG ) ;
memcpy ( b3buf , ( char * ) DATA_B3_IND_DATA ( CMSG ) , b3len ) ;
} else {
# ifdef DIVA_STREAMING
2010-05-26 14:40:57 +00:00
dword i = 0 , k = 0 ;
2010-10-09 08:29:39 +00:00
b3len = ( int ) diva_streaming_read_vector_data ( vind ,
vind_nr , & i , & k , b3buf , CAPI_MAX_B3_BLOCK_SIZE ) ;
2010-05-07 22:28:56 +00:00
# endif
}
2005-12-16 11:21:57 +00:00
}
2005-06-19 10:01:35 +00:00
2010-05-07 22:28:56 +00:00
if ( CMSG ! = 0 ) { /* send a DATA_B3_RESP very quickly to free the buffer in capi */
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
2010-12-14 16:28:18 +00:00
if ( i - > virtualBridgePeer ! = 0 ) {
if ( ( i - > bridgePeer ! = NULL )
2010-11-24 21:44:22 +00:00
# ifdef DIVA_STREAMING
2010-12-14 16:28:18 +00:00
& & ( i - > diva_stream_entry = = 0 )
& & ( i - > bridgePeer - > diva_stream_entry = = 0 )
2010-11-24 21:44:22 +00:00
# endif
2010-12-14 16:28:18 +00:00
) {
if ( i - > bridgePeer - > NCCI ! = 0 ) {
i - > bridgePeer - > send_buffer_handle + + ;
capi_sendf ( NULL , 0 , CAPI_DATA_B3_REQ , i - > bridgePeer - > NCCI , get_capi_MessageNumber ( ) ,
" dwww " , b3buf , b3len , i - > bridgePeer - > send_buffer_handle , 0 ) ;
}
2010-11-24 21:44:22 +00:00
}
return ;
}
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 ) ] ;
2011-10-04 08:41:28 +00:00
if ( capi_capability = = CC_FORMAT_ULAW ) {
2009-05-08 13:03:31 +00:00
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 ) {
2011-10-04 08:41:28 +00:00
if ( capi_capability = = CC_FORMAT_ULAW ) {
2009-05-08 13:03:31 +00:00
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
}
2011-10-04 08:41:28 +00:00
SET_FRAME_SUBCLASS_CODEC ( fr . subclass , capi_capability ) ;
2009-05-08 13:03:31 +00:00
} else {
2011-10-04 08:41:28 +00:00
SET_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 ;
2010-09-16 13:13:03 +00:00
fr . samples = ( i - > bproto = = CC_BPROTO_VOCODER ) ? pbx_capi_get_samples ( i , b3len ) : b3len ;
2005-06-02 18:47:35 +00:00
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 " ,
2011-10-04 08:41:28 +00:00
i - > vname , b3len , fr . datalen , GET_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
}
2010-05-26 14:40:57 +00:00
# if defined(DIVA_STREAMING)
2010-10-09 08:29:39 +00:00
void capidev_handle_data_b3_indication_vector (
struct capi_pvt * i ,
struct _diva_streaming_vector * vind ,
int vind_nr )
2010-05-07 22:28:56 +00:00
{
capidev_handle_data_b3_indication ( 0 , 0 , 0 , i , vind , vind_nr ) ;
}
# endif
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
}
2010-10-09 08:29:39 +00:00
static void capidev_read_name_from_diva_manufacturer_infications (
const unsigned char * src ,
const unsigned char * end ,
char * dst ,
int max_length ,
unsigned char * octet3a ,
const char * channelname ,
const char * nametype )
{
2010-09-14 19:54:25 +00:00
int length ;
* dst = 0 ;
* octet3a = * src + + ;
if ( src < end ) {
length = MIN ( max_length - 1 , ( end - src ) ) ;
memcpy ( dst , src , length ) ;
dst [ length ] = 0 ;
}
2010-10-09 08:29:39 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: received %s Name %02x '%s' \n " ,
channelname , nametype , * octet3a , dst ) ;
2010-09-14 19:54:25 +00:00
}
2010-11-09 09:03:41 +00:00
static void capidev_read_connected_number_from_diva_manufacturer_infications (
const unsigned char * src ,
const unsigned char * end ,
char * dst ,
int max_length ,
unsigned char * presentation ,
unsigned char * plan ,
const char * channelname ,
const char * numbertype )
{
int length ;
* dst = 0 ;
* presentation = 0 ;
* plan = * src + + ;
if ( src < end )
* presentation = * src + + ;
presentation [ 0 ] & = 0x7f ;
if ( src < end ) {
length = MIN ( max_length - 1 , ( end - src ) ) ;
memcpy ( dst , src , length ) ;
dst [ length ] = 0 ;
}
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: received %s Number %02x/%02x '%s' \n " ,
channelname , numbertype , * presentation , * plan , dst ) ;
}
# ifdef CC_AST_HAS_VERSION_1_8
static void pbx_capi_update_connected_number ( struct ast_channel * c ,
unsigned char presentation ,
unsigned char plan ,
const char * number ,
enum AST_CONNECTED_LINE_UPDATE_SOURCE source )
{
struct ast_party_connected_line connected ;
struct ast_set_party_connected_line update_connected ;
ast_party_connected_line_init ( & connected ) ;
memset ( & update_connected , 0 , sizeof ( update_connected ) ) ;
update_connected . id . number = 1 ;
connected . id . number . valid = 1 ;
connected . id . number . str = ( char * ) number ;
connected . id . number . plan = plan ;
connected . id . number . presentation = presentation ;
connected . id . tag = NULL ;
connected . source = source ;
ast_channel_queue_connected_line_update ( c , & connected , & update_connected ) ;
}
static void pbx_capi_update_connected_name ( struct ast_channel * c ,
const char * name ,
unsigned char presentation ,
enum AST_CONNECTED_LINE_UPDATE_SOURCE source )
{
struct ast_party_connected_line connected ;
struct ast_set_party_connected_line update_connected ;
ast_party_connected_line_init ( & connected ) ;
memset ( & update_connected , 0 , sizeof ( update_connected ) ) ;
update_connected . id . name = 1 ;
connected . id . name . valid = 1 ;
connected . id . name . str = ( char * ) name ;
connected . id . name . presentation = presentation ;
connected . id . tag = NULL ;
connected . source = source ;
ast_channel_queue_connected_line_update ( c , & connected , & update_connected ) ;
}
# endif
2010-10-09 08:29:39 +00:00
static void capidev_handle_diva_signaling_manufacturer_infications ( struct capi_pvt * i , const unsigned char * data )
{
2010-09-14 19:54:25 +00:00
int length = * data + + ;
char buffer [ CAPI_MAX_STRING ] ;
unsigned char octet3a ;
/*
Bits : 7 : set to 1
6 - 5 : Presentation indicator , 00 - Presentation allowed , 01 - Presentation restricted , 10 - Number not available due to internetworking , 11 - Reserved
4 - 2 : Set to zeero
1 - 0 : Screening indicator , 00 - User provided not screened , 01 - User provided , verified and passed , 10 - User provided verified and failed , 11 - Nnetwork provided
*/
if ( length > = 2 ) {
unsigned short command = read_capi_word ( data ) ;
data + = 2 ;
length - = 2 ;
switch ( command ) {
2010-10-09 08:29:39 +00:00
case 0x0005 : /* Display */
break ;
case 0x0006 : /* CalledPartyName */
if ( length ! = 0 ) {
capidev_read_name_from_diva_manufacturer_infications ( data , & data [ length ] , buffer , sizeof ( buffer ) , & octet3a , i - > vname , " Called Party " ) ;
2010-11-09 09:20:29 +00:00
# ifdef CC_AST_HAS_VERSION_1_8
if ( buffer [ 0 ] ! = 0 ) {
pbx_capi_update_connected_name ( i - > owner , buffer , octet3a & 0x7f , AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN ) ;
}
# endif
2010-10-09 08:29:39 +00:00
}
break ;
case 0x0007 : /* CallingPartyName */
if ( length ! = 0 ) {
capidev_read_name_from_diva_manufacturer_infications ( data , & data [ length ] , buffer , sizeof ( buffer ) , & octet3a , i - > vname , " Calling Party " ) ;
2010-09-14 19:54:25 +00:00
# ifdef CC_AST_HAS_VERSION_1_8
2015-02-28 16:35:31 +00:00
/* ast_set_callerid updates CDR, but __ast_pbx_run updates CDR too.
2011-10-05 09:09:23 +00:00
__ast_pbx_run does not uses the channel lock and this results in destruction
of CDR list
Do notcall this function until problem resolved
ast_set_callerid ( i - > owner , NULL , buffer , NULL ) ;
Use code from ast_set_callerid but do not update CDR
2015-02-28 16:35:31 +00:00
*/
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_caller ( i - > owner ) - > id . name . valid = 1 ;
ast_free ( ast_channel_caller ( i - > owner ) - > id . name . str ) ;
ast_channel_caller ( i - > owner ) - > id . name . str = ast_strdup ( buffer ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2011-10-05 09:09:23 +00:00
i - > owner - > caller . id . name . valid = 1 ;
ast_free ( i - > owner - > caller . id . name . str ) ;
i - > owner - > caller . id . name . str = ast_strdup ( buffer ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2010-09-14 19:54:25 +00:00
# else
2010-10-09 08:29:39 +00:00
ast_free ( i - > owner - > cid . cid_name ) ;
i - > owner - > cid . cid_name = ast_strdup ( buffer ) ; /* Save name to callerid */
2010-09-14 19:54:25 +00:00
# endif
2010-10-09 08:29:39 +00:00
}
break ;
case 0x0008 : /* ConnectedPartyName */
if ( length ! = 0 ) {
capidev_read_name_from_diva_manufacturer_infications ( data , & data [ length ] , buffer , sizeof ( buffer ) , & octet3a , i - > vname , " Connected Party " ) ;
2010-11-09 09:03:41 +00:00
# ifdef CC_AST_HAS_VERSION_1_8
if ( buffer [ 0 ] ! = 0 ) {
pbx_capi_update_connected_name ( i - > owner , buffer , octet3a & 0x7f , AST_CONNECTED_LINE_UPDATE_SOURCE_UNKNOWN ) ;
}
# endif
2010-10-09 08:29:39 +00:00
}
break ;
case 0x000a : /* BusyPartyName */
if ( length ! = 0 ) {
capidev_read_name_from_diva_manufacturer_infications ( data , & data [ length ] , buffer , sizeof ( buffer ) , & octet3a , i - > vname , " Busy Party " ) ;
}
break ;
case 0x0009 : /* CQ_Events */
2010-11-09 09:03:41 +00:00
if ( data [ 0 ] = = 0 ) { /* CQ_RemoteTransfer */
if ( data [ 1 ] > 2 ) {
unsigned char presentation ;
unsigned char plan ;
capidev_read_connected_number_from_diva_manufacturer_infications ( & data [ 2 ] ,
& data [ length ] , buffer , sizeof ( buffer ) , & presentation , & plan , i - > vname , " Changed Called Party " ) ;
# ifdef CC_AST_HAS_VERSION_1_8
if ( buffer [ 0 ] ! = 0 ) {
pbx_capi_update_connected_number ( i - > owner , presentation , plan , buffer ,
( i - > state = = CAPI_STATE_CONNECTPENDING ) ? \
AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER_ALERTING : AST_CONNECTED_LINE_UPDATE_SOURCE_TRANSFER ) ;
}
# endif
}
}
2010-10-09 08:29:39 +00:00
break ;
2010-09-14 19:54:25 +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 " ) ;
2010-09-14 19:54:25 +00:00
if ( MANUFACTURER_IND_MANUID ( CMSG ) = = _DI_MANU_ID ) {
if ( CMSG - > Info = = 0x000a & & i - > owner ! = 0 ) {
2010-10-09 08:29:39 +00:00
capidev_handle_diva_signaling_manufacturer_infications ( i , MANUFACTURER_IND_MANUDATA ( CMSG ) ) ;
2010-09-14 19:54:25 +00:00
} else {
2010-10-09 08:29:39 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: Ignored Diva MANUFACTURER_IND Id=0x%04x \n " ,
i - > vname , CMSG - > Info ) ;
2010-09-14 19:54:25 +00:00
}
} else {
cc_verbose ( 3 , 1 , VERBOSE_PREFIX_3 " %s: Ignored MANUFACTURER_IND Id=0x%x \n " ,
i - > vname , MANUFACTURER_IND_MANUID ( CMSG ) ) ;
}
2006-09-24 10:44:40 +00:00
}
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 ) ) {
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_lock ( i - > owner ) ;
# endif
2006-08-12 15:40:32 +00:00
ast_setstate ( i - > owner , AST_STATE_UP ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ast_channel_unlock ( i - > owner ) ;
# endif
# ifndef CC_AST_HAS_VERSION_13_0
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
struct ast_cdr * owner_cdr = ast_channel_cdr ( i - > owner ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
struct ast_cdr * owner_cdr = i - > owner - > cdr ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( owner_cdr )
ast_cdr_answer ( owner_cdr ) ;
2017-01-15 17:12:14 +00:00
# endif
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 ) {
2015-02-28 16:35:31 +00:00
if ( i - > peer ! = NULL ) {
# ifdef CC_AST_HAS_VERSION_11_0
const struct ast_channel_tech * peer_tech = ast_channel_tech ( i - > peer ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const struct ast_channel_tech * peer_tech = i - > peer - > tech ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( 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 ) ;
}
2008-08-30 09:58:27 +00:00
}
}
}
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 + + ;
2010-11-05 21:58:49 +00:00
pbx_capi_ifc_state_event ( capi_controllers [ i - > controller ] , 1 ) ;
2007-04-29 14:00:32 +00:00
}
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 - - ;
2010-11-05 21:58:49 +00:00
pbx_capi_ifc_state_event ( capi_controllers [ i - > controller ] , - 1 ) ;
2008-08-08 08:13:29 +00:00
}
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 ;
2010-07-22 05:31:51 +00:00
char buffer [ CAPI_MAX_STRING ] ;
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
2010-06-25 13:49:15 +00:00
if ( i ! = 0 )
2010-04-08 22:10:54 +00:00
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
2010-07-22 05:31:51 +00:00
if ( i - > owner ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
int owner_hangupcause = ast_channel_hangupcause ( i - > owner ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
int owner_hangupcause = i - > owner - > hangupcause ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( owner_hangupcause = = 0 ) {
2010-07-22 05:31:51 +00:00
/* set hangupcause, in case there is no
* " cause " information element :
*/
2015-02-28 16:35:31 +00:00
owner_hangupcause =
2010-07-22 05:31:51 +00:00
( ( i - > reason & 0xFF00 ) = = 0x3400 ) ?
i - > reason & 0x7F : AST_CAUSE_NORMAL_CLEARING ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_hangupcause_set ( i - > owner , owner_hangupcause ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
i - > owner - > hangupcause = owner_hangupcause ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2010-07-22 05:31:51 +00:00
}
/* the real reason could be != 0x34xx, so provide this value in variable */
sprintf ( buffer , " %d " , i - > reason ) ;
pbx_builtin_setvar_helper ( i - > owner , " DISCONNECT_IND_REASON " , buffer ) ;
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
*/
2010-10-09 08:29:39 +00:00
static void capidev_handle_connect_indication (
_cmsg * CMSG ,
unsigned int PLCI ,
unsigned int NCCI ,
struct capi_pvt * * interface ,
struct ast_channel * * interface_owner )
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 ' ;
2013-08-09 10:56:22 +00:00
if ( ( bchannelinfo [ 0 ] = = ' 4 ' ) & & ( CONNECT_IND_BCHANNELINFORMATION ( CMSG ) [ 0 ] > = 4 ) & & ( CONNECT_IND_BCHANNELINFORMATION ( CMSG ) [ 3 ] > 0 ) ) {
if ( CONNECT_IND_BCHANNELINFORMATION ( CMSG ) [ 4 ] & 4 ) {
bchannelinfo [ 0 ] = ' 1 ' ;
} else {
bchannelinfo [ 0 ] = ' 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 ) {
2012-04-11 09:45:19 +00:00
if ( i - > used | | i - > reserved ) {
2007-04-23 18:47:49 +00:00
/* 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
2012-04-11 09:45:19 +00:00
i - > reserved = 1 ;
cc_mutex_unlock ( & iflock ) ;
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 ) ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_transfercapability_set ( i - > owner , i - > transfercapability ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2007-05-01 14:26:39 +00:00
i - > owner - > transfercapability = i - > transfercapability ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2007-05-01 14:26:39 +00:00
if ( capi_tcap_is_digital ( i - > transfercapability ) ) {
2006-05-22 11:04:33 +00:00
i - > bproto = CC_BPROTO_TRANSPARENT ;
}
2010-08-13 20:41:23 +00:00
# ifdef CC_AST_HAS_VERSION_1_8
if ( CID ! = NULL ) {
const char * effective_cid = i - > cid ;
/*
Preserve original plan if translation is not required or done in dial plan
*/
if ( capi_national_prefix [ 0 ] = = 0 & &
capi_international_prefix [ 0 ] = = 0 & &
capi_subscriber_prefix [ 0 ] = = 0 ) {
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_caller ( i - > owner ) - > id . number . plan = callernplan ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2010-08-13 20:41:23 +00:00
i - > owner - > caller . id . number . plan = callernplan ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2010-08-13 20:41:23 +00:00
effective_cid = CID ;
}
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_caller ( i - > owner ) - > id . number . presentation = callpres ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2010-08-13 20:41:23 +00:00
i - > owner - > caller . id . number . presentation = callpres ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2010-08-13 20:41:23 +00:00
2011-10-05 09:09:23 +00:00
/* Don't use ast_set_callerid() here because it will
generate a needless NewCallerID event
ast_set_callerid ( i - > owner , effective_cid , NULL , effective_cid ) ;
*/
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_caller ( i - > owner ) - > id . number . valid = 1 ;
ast_free ( ast_channel_caller ( i - > owner ) - > id . number . str ) ;
ast_channel_caller ( i - > owner ) - > id . number . str = ast_strdup ( effective_cid ) ;
ast_channel_caller ( i - > owner ) - > ani . number . valid = 1 ;
ast_free ( ast_channel_caller ( i - > owner ) - > ani . number . str ) ;
ast_channel_caller ( i - > owner ) - > ani . number . str = ast_strdup ( effective_cid ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2011-10-05 09:09:23 +00:00
i - > owner - > caller . id . number . valid = 1 ;
ast_free ( i - > owner - > caller . id . number . str ) ;
i - > owner - > caller . id . number . str = ast_strdup ( effective_cid ) ;
i - > owner - > caller . ani . number . valid = 1 ;
ast_free ( i - > owner - > caller . ani . number . str ) ;
i - > owner - > caller . ani . number . str = ast_strdup ( effective_cid ) ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2010-08-13 20:41:23 +00:00
}
# else
2005-07-18 18:50:43 +00:00
i - > owner - > cid . cid_pres = callpres ;
2010-08-13 20:41:23 +00:00
# endif
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 ) ;
2010-09-12 08:52:18 +00:00
* interface_owner = capidev_acquire_locks_from_thread_context ( i ) ;
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 ;
2010-08-23 12:14:03 +00:00
if ( pbx_capi_streaming_supported ( i ) ! = 0 ) {
2010-06-28 21:37:56 +00:00
capi_DivaStreamingOn ( i , 0 , 0 ) ;
2010-04-08 22:10:54 +00:00
}
# 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
*/
2010-10-09 08:29:39 +00:00
static void capidev_handle_facility_confirmation (
_cmsg * CMSG ,
unsigned int PLCI ,
unsigned int NCCI ,
struct capi_pvt * * i ,
struct ast_channel * * interface_owner )
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 ) {
2010-09-12 08:52:18 +00:00
handle_facility_confirmation_supplementary ( CMSG , PLCI , NCCI , i , interface_owner ) ;
2007-04-20 16:42:20 +00:00
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
*/
2010-10-09 08:29:39 +00:00
static void show_capi_conf_error (
struct capi_pvt * i ,
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 ,
2010-09-12 08:52:18 +00:00
unsigned short wInfo , unsigned short wMsgNum , struct ast_channel * * interface_owner )
2007-04-24 20:21:04 +00:00
{
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 ) ;
2010-09-12 08:52:18 +00:00
2010-09-24 19:20:28 +00:00
* interface_owner = capidev_acquire_locks_from_thread_context ( ii ) ;
2010-09-12 08:52:18 +00:00
2007-04-24 20:21:04 +00:00
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
}
}
2010-09-12 08:52:18 +00:00
/*! \brief acquire locks in the correct order
*/
2010-09-24 19:20:28 +00:00
static struct ast_channel * capidev_acquire_locks_from_thread_context ( struct capi_pvt * i )
2010-09-12 08:52:18 +00:00
{
struct ast_channel * owner = 0 ;
if ( unlikely ( i = = 0 ) )
return ( 0 ) ;
# ifdef CC_AST_HAS_VERSION_1_8
cc_mutex_lock ( & i - > lock ) ;
owner = i - > owner ;
if ( likely ( owner ! = 0 ) ) {
2011-10-05 09:56:42 +00:00
struct ast_channel * ref_owner = owner ;
2010-09-12 08:52:18 +00:00
ast_channel_ref ( owner ) ;
cc_mutex_unlock ( & i - > lock ) ;
ast_channel_lock ( owner ) ;
cc_mutex_lock ( & i - > lock ) ;
if ( unlikely ( i - > owner = = 0 ) ) {
cc_mutex_unlock ( & i - > lock ) ;
ast_channel_unlock ( owner ) ;
cc_mutex_lock ( & i - > lock ) ;
owner = 0 ;
}
2011-10-05 09:56:42 +00:00
ast_channel_unref ( ref_owner ) ;
2010-09-12 08:52:18 +00:00
}
# else
for ( ; ; ) {
cc_mutex_lock ( & i - > lock ) ;
owner = i - > owner ;
if ( unlikely ( owner = = 0 ) )
break ;
if ( likely ( ast_channel_trylock ( owner ) = = 0 ) )
break ;
cc_mutex_unlock ( & i - > lock ) ;
usleep ( 100 ) ;
}
# endif
return ( owner ) ;
}
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 ) ;
2010-09-12 08:52:18 +00:00
struct ast_channel * owner ;
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
}
2010-09-12 08:52:18 +00:00
owner = capidev_acquire_locks_from_thread_context ( i ) ;
2006-01-28 19:42:44 +00:00
2005-09-11 13:35:19 +00:00
/* main switch table */
switch ( wCmd ) {
/*
* CAPI indications
*/
case CAPI_P_IND ( CONNECT ) :
2010-09-12 08:52:18 +00:00
capidev_handle_connect_indication ( CMSG , PLCI , NCCI , & i , & owner ) ;
2005-09-11 13:35:19 +00:00
break ;
case CAPI_P_IND ( DATA_B3 ) :
2010-05-07 22:28:56 +00:00
capidev_handle_data_b3_indication ( CMSG , PLCI , NCCI , i , 0 , 0 ) ;
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 ) ;
2010-09-12 08:52:18 +00:00
capidev_handle_facility_confirmation ( CMSG , PLCI , NCCI , & i , & owner ) ;
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 ) ;
2010-09-12 08:52:18 +00:00
capidev_handle_connection_conf ( & i , PLCI , wInfo , wMsgNum , & owner ) ;
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 - - ;
2010-11-05 21:58:49 +00:00
pbx_capi_ifc_state_event ( capi_controllers [ i - > controller ] , - 1 ) ;
2008-08-08 08:13:29 +00:00
}
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 ) ;
2010-12-21 19:14:27 +00:00
if ( i = = NULL ) break ;
if ( ( i - > isdnstate2 & CAPI_ISDN_STATE2_PROCEEDING_PENDING ) ! = 0 ) {
if ( ( wInfo & 0xff00 ) = = 0 ) {
i - > isdnstate2 | = CAPI_ISDN_STATE2_PROCEEDING ;
}
i - > isdnstate2 & = ~ CAPI_ISDN_STATE2_PROCEEDING_PENDING ;
break ;
}
2005-09-11 13:35:19 +00:00
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
enum ast_channel_state owner_state = ast_channel_state ( i - > owner ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
enum ast_channel_state owner_state = i - > owner - > _state ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( owner_state = = AST_STATE_RING ) {
# ifdef CC_AST_HAS_VERSION_11_0
ast_channel_rings_set ( i - > owner , 1 ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
2005-07-17 19:01:14 +00:00
i - > owner - > rings = 1 ;
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 ) ;
2010-09-12 08:52:18 +00:00
capidev_handle_connection_conf ( & i , PLCI , wInfo , wMsgNum , & owner ) ;
2009-04-09 21:13:43 +00:00
break ;
2010-05-07 22:28:56 +00:00
# ifdef DIVA_STREAMING
case _DI_STREAM_CTRL :
2010-06-29 10:21:31 +00:00
wInfo = ( unsigned short ) ( CMSG - > Class > > 16 ) ;
if ( wInfo ! = 0 ) {
int do_lock = ( i = = 0 ) ;
struct capi_pvt * ii = ( i ! = 0 ) ? i : capi_find_interface_by_msgnum ( wMsgNum ) ;
2010-09-12 08:52:18 +00:00
struct ast_channel * streaming_interface_owner = 0 ;
2010-06-29 10:21:31 +00:00
cc_log ( LOG_ERROR , " stream error %04x for %s=%#x \n " , wInfo , PLCI ! = 0 ? " PLCI " : " MsgNr " , PLCI ! = 0 ? PLCI : wMsgNum ) ;
if ( ii ! = 0 ) {
if ( do_lock ) {
2010-09-24 19:20:28 +00:00
streaming_interface_owner = capidev_acquire_locks_from_thread_context ( ii ) ;
2010-06-29 10:21:31 +00:00
}
capi_DivaStreamingRemove ( ii ) ;
if ( do_lock ) {
cc_mutex_unlock ( & ii - > lock ) ;
2010-09-12 08:52:18 +00:00
if ( streaming_interface_owner ! = 0 ) {
ast_channel_unlock ( streaming_interface_owner ) ;
}
2010-06-29 10:21:31 +00:00
}
} else {
cc_log ( LOG_ERROR , " stream error %04x for MsgNr %04x, unexpected " , wInfo , wMsgNum ) ;
}
}
2010-05-07 22:28:56 +00:00
break ;
# endif
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
2010-09-12 08:52:18 +00:00
if ( owner ! = 0 ) {
ast_channel_unlock ( owner ) ;
}
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
2010-10-09 08:29:39 +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 ;
2015-02-28 16:35:31 +00:00
const struct ast_channel_tech * cur_tech ;
# ifdef CC_AST_HAS_VERSION_11_0
cur_tech = ast_channel_tech ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
cur_tech = c - > tech ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2009-04-15 12:28:40 +00:00
2015-02-28 16:35:31 +00:00
if ( cur_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
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 ;
}
2010-09-26 10:51:45 +00:00
number = strsep ( & param , COMMANDSEPARATOR ) ;
2006-06-09 21:48:24 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2007-04-17 21:04:42 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
cur_name ) ;
2007-04-18 11:48:07 +00:00
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const struct ast_channel_tech * cur_tech = ast_channel_tech ( c ) ;
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const struct ast_channel_tech * cur_tech = c - > tech ;
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( cur_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 " ,
2015-02-28 16:35:31 +00:00
cur_name ) ;
2005-08-28 14:14:23 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2005-08-21 15:35:44 +00:00
if ( ( id = pbx_builtin_getvar_helper ( c , " CALLERHOLDID " ) ) ) {
plci = ( unsigned int ) strtoul ( id , NULL , 0 ) ;
}
2010-09-26 10:51:45 +00:00
holdid = strsep ( & param , COMMANDSEPARATOR ) ;
2007-04-22 11:24:25 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 ;
}
2010-07-23 08:08:40 +00:00
/*
* send keypad facility
*/
static int pbx_capi_keypad ( struct ast_channel * c , char * param )
{
struct capi_pvt * i = CC_CHANNEL_PVT ( c ) ;
unsigned char buffer [ 32 ] ;
int length ;
if ( ( ! param ) | | ( ! ( * param ) ) ) {
cc_log ( LOG_WARNING , " Parameter for keypad missing. \n " ) ;
return - 1 ;
}
length = strlen ( param ) ;
if ( length > ( sizeof ( buffer ) - 1 ) )
length = sizeof ( buffer ) - 1 ;
buffer [ 0 ] = length ;
memcpy ( & buffer [ 1 ] , param , length ) ;
capi_sendf ( NULL , 0 , CAPI_INFO_REQ , i - > PLCI , get_capi_MessageNumber ( ) ,
" ()(()s()()()) " ,
buffer
) ;
cc_verbose ( 2 , 1 , VERBOSE_PREFIX_4 " %s: sent KEYPAD [%s] for PLCI=%#x \n " ,
i - > vname , param , i - > PLCI ) ;
return 0 ;
}
2005-08-16 18:25:03 +00:00
/*
* 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
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 ) ) {
2012-05-22 12:52:08 +00:00
i - > divaDataStubAudioFlags | = 0x0080 /* Use to activate in Tx direction 0x0040 */ ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 0 ) ;
2009-02-13 21:58:19 +00:00
} else if ( ast_false ( param ) ) {
2012-05-22 12:52:08 +00:00
i - > divaDataStubAudioFlags & = ~ 0x0080 /* Use to activate in Tx direction ~0x0040 */ ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 0 ) ;
2009-02-13 21:58:19 +00:00
} 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 " ,
2011-03-07 09:57:43 +00:00
i - > vname , ( i - > divaDataStubAudioFlags & 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 ) ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
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 ) ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
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 ) ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
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 ) ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
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 ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
} else if ( ast_false ( param ) ) {
i - > divaAudioFlags & = ~ 0x0008 ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
} 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 ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
} else if ( ast_false ( param ) ) {
i - > divaAudioFlags & = ~ 0x0004 ;
2010-11-02 14:14:43 +00:00
capi_diva_audio_features ( i , 1 ) ;
2009-02-13 21:58:19 +00:00
} 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
}
2010-10-09 08:29:39 +00:00
static const char * pbx_capi_map_detected_tone ( unsigned char tone )
2009-02-14 20:56:14 +00:00
{
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 ;
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
2006-12-18 19:09:52 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name ) ;
2006-12-18 19:09:52 +00:00
return 0 ;
}
if ( ! ( capi_controllers [ i - > controller ] - > threePTY ) ) {
2015-02-28 16:35:31 +00:00
cc_log ( LOG_NOTICE , " %s: 3PTY for %s not supported by controller. \n " ,
i - > vname , cur_name ) ;
2006-12-18 19:09:52 +00:00
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 ;
2010-11-24 17:08:11 +00:00
int notchannelrelated ;
2005-08-28 14:14:23 +00:00
} capicommands [ ] = {
2010-11-24 17:08:11 +00:00
{ " getid " , pbx_capi_get_id , 0 , 0 , 0 } ,
{ " peerlink " , pbx_capi_peer_link , 0 , 0 , 0 } ,
{ " progress " , pbx_capi_signal_progress , 1 , 0 , 0 } ,
2010-12-21 19:14:27 +00:00
{ " proceeding " , pbx_capi_signal_proceeding , 1 , 0 , 0 } ,
2010-11-24 17:08:11 +00:00
{ " deflect " , pbx_capi_call_deflect , 1 , 0 , 0 } ,
{ " receivefax " , pbx_capi_receive_fax , 1 , 1 , 0 } ,
{ " sendfax " , pbx_capi_send_fax , 1 , 1 , 0 } ,
{ " echosquelch " , pbx_capi_echosquelch , 1 , 0 , 0 } ,
{ " echocancel " , pbx_capi_echocancel , 1 , 1 , 0 } ,
{ " noisesuppressor " , pbx_capi_noisesuppressor , 1 , 1 , 0 } ,
{ " rxagc " , pbx_capi_rxagc , 1 , 1 , 0 } ,
{ " txagc " , pbx_capi_txagc , 1 , 1 , 0 } ,
{ " rxdgain " , pbx_capi_rxdgain , 1 , 1 , 0 } ,
{ " incrxdgain " , pbx_capi_incrxdgain , 1 , 1 , 0 } ,
{ " txdgain " , pbx_capi_txdgain , 1 , 1 , 0 } ,
{ " inctxdgain " , pbx_capi_inctxdgain , 1 , 1 , 0 } ,
{ " clamping " , pbx_capi_clamping , 1 , 1 , 0 } ,
{ " mftonedetection " , pbx_capi_mftonedetection , 1 , 1 , 0 } ,
{ " pulsedetection " , pbx_capi_pulsedetection , 1 , 1 , 0 } ,
{ " sendtone " , pbx_capi_sendtone , 1 , 1 , 0 } ,
{ " stoptone " , pbx_capi_stoptone , 1 , 1 , 0 } ,
{ " starttonedetection " , pbx_capi_starttonedetection , 1 , 1 , 0 } ,
{ " stoptonedetection " , pbx_capi_stoptonedetection , 1 , 1 , 0 } ,
{ " pitchcontrol " , pbx_capi_pitchcontrol , 1 , 1 , 0 } ,
{ " incpitchcontrol " , pbx_capi_incpitchcontrol , 1 , 1 , 0 } ,
{ " vc " , pbx_capi_voicecommand , 1 , 1 , 0 } ,
{ " vctransparency " , pbx_capi_voicecommand_transparency , 1 , 1 , 0 } ,
{ " getplci " , pbx_capi_getplci , 1 , 0 , 0 } ,
{ " malicious " , pbx_capi_malicious , 1 , 0 , 0 } ,
{ " keypad " , pbx_capi_keypad , 1 , 0 , 0 } ,
{ " hold " , pbx_capi_hold , 1 , 0 , 0 } ,
{ " holdtype " , pbx_capi_holdtype , 1 , 0 , 0 } ,
{ " retrieve " , pbx_capi_retrieve , 0 , 0 , 0 } ,
{ " ect " , pbx_capi_ect , 1 , 0 , 0 } ,
{ " 3pty_begin " , pbx_capi_3pty_begin , 1 , 0 , 0 } ,
{ " ccbs " , pbx_capi_ccbs , 0 , 0 , 0 } ,
{ " ccbsstop " , pbx_capi_ccbsstop , 0 , 0 , 0 } ,
{ " ccpartybusy " , pbx_capi_ccpartybusy , 0 , 0 , 0 } ,
{ " chat " , pbx_capi_chat , 0 , 0 , 0 } ,
{ " chat_command " , pbx_capi_chat_command , 0 , 0 , 0 } ,
{ " chat_mute " , pbx_capi_chat_mute , 0 , 0 , 0 } ,
{ " chat_play " , pbx_capi_chat_play , 0 , 0 , 0 } ,
{ " chat_connect " , pbx_capi_chat_connect , 0 , 0 , 1 } ,
{ " resource " , pbx_capi_chat_associate_resource_plci , 0 , 0 , 0 } ,
{ " mwi " , pbx_capi_mwi , 1 , 0 , 0 } ,
{ " hangup " , pbx_capi_realhangup , 0 , 0 , 0 } ,
2015-02-28 16:35:31 +00:00
{ " qsig_ssct " , pbx_capi_qsig_ssct , 1 , 0 , 0 } ,
{ " qsig_ct " , pbx_capi_qsig_ct , 1 , 0 , 0 } ,
{ " qsig_callmark " , pbx_capi_qsig_callmark , 1 , 0 , 0 } ,
2010-11-24 17:08:11 +00:00
{ " qsig_getplci " , pbx_capi_qsig_getplci , 1 , 0 , 0 } ,
2015-02-28 16:35:31 +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
2010-11-24 17:08:11 +00:00
if ( chan ! = NULL ) {
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2010-11-24 17:08:11 +00:00
u = ast_module_user_add ( chan ) ;
2006-11-11 20:07:19 +00:00
# else
2010-11-24 17:08:11 +00:00
LOCAL_USER_ADD ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2010-11-24 17:08:11 +00:00
} else {
u = NULL ;
}
2005-08-28 14:14:23 +00:00
2006-01-28 19:42:44 +00:00
s = ast_strdupa ( data ) ;
stringp = s ;
2010-09-26 10:51:45 +00:00
command = strsep ( & stringp , COMMANDSEPARATOR ) ;
2005-08-13 18:21:20 +00:00
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 + + ;
}
2010-11-24 17:08:11 +00:00
if ( ( capicmd - > cmd = = NULL ) | |
( ( chan = = NULL ) & & ( capicmd - > notchannelrelated = = 0 ) ) ) {
if ( chan ! = NULL ) {
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2010-11-24 17:08:11 +00:00
ast_module_user_remove ( u ) ;
2006-11-11 20:07:19 +00:00
# else
2010-11-24 17:08:11 +00:00
LOCAL_USER_REMOVE ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2010-11-24 17:08:11 +00:00
}
cc_log ( LOG_WARNING , " %s command '%s' for capicommand \n " ,
( capicmd - > cmd = = NULL ) ? " Unknown " : " Channel required for " , command ) ;
2005-08-28 14:14:23 +00:00
return - 1 ;
}
2015-02-28 16:35:31 +00:00
if ( chan ! = NULL ) {
# ifdef CC_AST_HAS_VERSION_11_0
const struct ast_channel_tech * cur_tech = ast_channel_tech ( chan ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const struct ast_channel_tech * cur_tech = chan - > tech ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
if ( cur_tech ! = & capi_tech ) {
if ( capicmd - > capionly ! = 0 ) {
struct capi_pvt * resource_plci = pbx_check_resource_plci ( chan ) ;
if ( ( capicmd - > resourceplcisupported = = 0 ) | |
( resource_plci = = NULL ) | |
( resource_plci - > line_plci = = NULL ) ) {
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2015-02-28 16:35:31 +00:00
ast_module_user_remove ( u ) ;
2006-11-11 20:07:19 +00:00
# else
2015-02-28 16:35:31 +00:00
LOCAL_USER_REMOVE ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2015-02-28 16:35:31 +00:00
cc_log ( LOG_WARNING , " This capicommand works on " CC_MESSAGE_NAME
" channels only, check your extensions.conf! \n " ) ;
return - 1 ;
}
2009-04-15 12:28:40 +00:00
}
}
2005-07-27 17:20:09 +00:00
}
2005-08-28 14:14:23 +00:00
res = ( capicmd - > cmd ) ( chan , params ) ;
2010-11-24 17:08:11 +00:00
if ( chan ! = NULL ) {
2006-11-11 20:07:19 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
2010-11-24 17:08:11 +00:00
ast_module_user_remove ( u ) ;
2006-11-11 20:07:19 +00:00
# else
2010-11-24 17:08:11 +00:00
LOCAL_USER_REMOVE ( u ) ;
2006-11-11 20:07:19 +00:00
# endif
2010-11-24 17:08:11 +00:00
}
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
2010-11-02 14:14:43 +00:00
int pbx_capi_cli_exec_capicommand ( struct ast_channel * chan , const char * data )
{
2010-11-03 22:04:22 +00:00
# ifdef CC_AST_HAS_CONST_CHAR_IN_REGAPPL
2010-11-02 14:14:43 +00:00
return ( pbx_capicommand_exec ( chan , data ) ) ;
2010-11-03 22:04:22 +00:00
# else
return ( pbx_capicommand_exec ( chan , ( void * ) data ) ) ;
# endif
2010-11-02 14:14:43 +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
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
const char * cur_name = ast_channel_name ( c ) ;
# else /* !defined(CC_AST_HAS_VERSION_11_0) */
const char * cur_name = c - > name ;
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_name ) ;
2010-12-21 19:14:27 +00:00
pbx_capi_signal_proceeding ( 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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , cur_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 " ,
2015-02-28 16:35:31 +00:00
i - > vname , condition , cur_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
*/
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
static int pbx_capi_devicestate ( const char * data )
# else /* !defined(CC_AST_HAS_VERSIOM_11_0) */
2006-06-09 21:48:24 +00:00
static int pbx_capi_devicestate ( void * data )
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) */
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 ;
2010-11-05 21:58:49 +00:00
struct capi_pvt * i = NULL ;
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 , " / " ) ;
2010-11-05 21:58:49 +00:00
if ( target ! = NULL ) {
cc_mutex_lock ( & iflock ) ;
for ( i = capi_iflist ; i ; i = i - > next ) {
if ( ! ( strcmp ( target , i - > vname ) ) )
break ;
}
cc_mutex_unlock ( & iflock ) ;
2007-10-20 14:07:01 +00:00
}
if ( ! i ) {
2010-11-05 21:58:49 +00:00
const char * interfaceEvent = strsep ( & s , " / " ) ;
if ( ( target ! = NULL ) & & ( * target = = ' I ' ) & &
( interfaceEvent ! = NULL ) & & ( strcmp ( interfaceEvent , " congestion " ) = = 0 ) ) {
const struct cc_capi_controller * capiController ;
capiController = pbx_capi_get_controller ( atoi ( & target [ 1 ] ) ) ;
if ( capiController ! = NULL ) {
if ( pbx_capi_check_controller_status ( capiController - > controller ) < 0 ) {
res = AST_DEVICE_UNAVAILABLE ;
} else {
if ( capiController - > nbchannels = = capiController - > nfreebchannels ) {
res = AST_DEVICE_NOT_INUSE ;
} else if ( ( capiController - > nfreebchannels = = 0 ) | |
( capiController - > nfreebchannels < capiController - > nfreebchannelsHardThr ) ) {
res = AST_DEVICE_BUSY ;
} else {
res = AST_DEVICE_INUSE ;
}
}
} else {
cc_log ( LOG_WARNING , " Unknown controller '%s' for devicestate. \n " ,
target ) ;
}
} else {
cc_log ( LOG_WARNING , " Unknown target '%s' for devicestate. \n " ,
target ) ;
}
2007-10-20 14:07:01 +00:00
} 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 )
{
2010-09-24 19:20:28 +00:00
struct capi_pvt * i ;
2006-07-08 16:29:27 +00:00
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 " ,
2015-02-28 16:35:31 +00:00
ast_channel_name ( chan_for_task ) ) ;
2006-07-08 16:29:27 +00:00
}
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 */
2015-02-28 16:35:31 +00:00
pbx_builtin_setvar_helper ( chan_for_task , " FAXEXTEN " , ast_channel_exten ( chan_for_task ) ) ;
2010-09-24 19:20:28 +00:00
i = CC_CHANNEL_PVT ( chan_for_task ) ;
if ( i ) {
if ( ast_async_goto ( chan_for_task , i - > faxcontext , i - > faxexten , i - > faxpriority ) ) {
cc_log ( LOG_WARNING , " Failed to async goto '%s,%s,%d' for '%s' \n " ,
2015-02-28 16:35:31 +00:00
i - > faxcontext , i - > faxexten , i - > faxpriority , ast_channel_name ( chan_for_task ) ) ;
2010-09-24 19:20:28 +00:00
}
2007-04-08 21:20:47 +00:00
}
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-10-22 22:44:50 +00:00
# ifdef DIVA_STATUS
diva_status_process_events ( ) ;
# endif
2007-04-23 18:47:49 +00:00
}
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 + + ) {
2011-10-04 08:41:28 +00:00
if ( capi_capability = = CC_FORMAT_ULAW ) {
2005-08-10 19:19:16 +00:00
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 ;
2011-10-04 08:41:28 +00:00
if ( capi_capability = = CC_FORMAT_ULAW ) {
2005-08-10 19:19:16 +00:00
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 + + ) {
2011-10-04 08:41:28 +00:00
if ( capi_capability = = CC_FORMAT_ULAW ) {
2005-08-10 19:19:16 +00:00
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 ;
2011-10-04 08:41:28 +00:00
if ( capi_capability = = CC_FORMAT_ULAW ) {
2005-08-10 19:19:16 +00:00
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 ;
2010-10-13 23:17:33 +00:00
struct cc_capi_controller * mwiController = 0 ;
2005-06-02 18:47:35 +00:00
2005-10-01 15:17:10 +00:00
for ( i = 0 ; i < = conf - > devices ; i + + ) {
2010-08-19 08:44:21 +00:00
tmp = ast_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 ] ) ) ) {
2010-08-19 08:44:21 +00:00
ast_free ( tmp ) ;
2006-12-17 14:22:05 +00:00
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 ;
2010-07-17 23:17:49 +00:00
capi_controllers [ unit ] - > ecOnTransit = conf - > econtransitconn ;
2010-10-26 22:22:25 +00:00
capi_controllers [ unit ] - > nfreebchannelsHardThr = conf - > hlimit ;
capi_controllers [ unit ] - > nfreebchannelsSoftThr = conf - > slimit ;
2010-10-13 23:17:33 +00:00
mwiController = capi_controllers [ unit ] ;
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 ;
2010-09-24 19:20:28 +00:00
cc_copy_string ( tmp - > faxcontext , conf - > faxcontext , sizeof ( tmp - > faxcontext ) ) ;
cc_copy_string ( tmp - > faxexten , conf - > faxexten , sizeof ( tmp - > faxexten ) ) ;
tmp - > faxpriority = conf - > faxpriority ;
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 ) ;
2010-09-15 09:14:51 +00:00
tmp - > divaqsig = conf - > divaqsig ;
2007-06-07 19:24:32 +00:00
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
}
2010-10-13 23:17:33 +00:00
/*
Init MWI subscriptions
2010-10-14 08:07:55 +00:00
*/
2010-10-15 16:50:41 +00:00
pbx_capi_init_mwi_server ( mwiController , conf ) ;
2010-10-13 23:17:33 +00:00
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
}
2011-10-04 08:41:28 +00:00
# ifndef CC_AST_HAS_VERSION_10_0
const
# endif
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 ,
2011-10-04 08:41:28 +00:00
# ifndef CC_AST_HAS_VERSION_10_0
2005-06-02 18:47:35 +00:00
. capabilities = AST_FORMAT_ALAW ,
2011-10-04 08:41:28 +00:00
# endif
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 ,
2017-01-15 17:12:14 +00:00
# ifndef CC_AST_HAS_VERSION_13_0
2006-06-09 21:48:24 +00:00
. bridge = pbx_capi_bridge ,
2017-01-15 17:12:14 +00:00
# endif
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
2010-08-19 08:44:21 +00:00
cp = ast_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
2010-06-28 21:37:56 +00:00
cp - > divaStreaming = capi_DivaStreamingSupported ( cp - > controller ) ;
2010-05-07 22:28:56 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_4 " CAPI %d Diva streaming is supported \n " , cp - > controller ) ;
2010-04-08 22:10:54 +00:00
# endif
2010-10-13 23:17:33 +00:00
AST_LIST_HEAD_INIT_NOLOCK ( & cp - > mwiSubscribtions ) ;
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 ) ;
}
2010-10-22 22:44:50 +00:00
# ifdef DIVA_STATUS
2010-10-25 21:21:31 +00:00
{
diva_status_hardware_state_t hwState = DivaStatusHardwareStateUnknown ;
capi_controllers [ controller ] - > interfaceState = diva_status_init_interface ( controller ,
& hwState ,
pbx_capi_interface_status_changed ,
pbx_capi_hw_status_changed ) ;
capi_controllers [ controller ] - > hwState = hwState ;
}
2010-10-22 22:44:50 +00:00
# endif
2010-10-13 23:17:33 +00:00
/*
Register MWI mailboxes and refresh MWI info
*/
2010-10-14 08:07:55 +00:00
pbx_capi_register_mwi ( capi_controllers [ controller ] ) ;
pbx_capi_refresh_mwi ( capi_controllers [ 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 ;
2010-09-24 19:20:28 +00:00
char faxcontext [ AST_MAX_EXTENSION + 1 ] ;
char faxexten [ AST_MAX_EXTENSION + 1 ] ;
int faxpriority = 1 ;
char faxdest [ AST_MAX_EXTENSION + 1 ] ;
char * p , * q ;
2011-10-04 08:41:28 +00:00
# ifdef CC_AST_HAS_VERSION_10_0
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
struct ast_format_cap * cap = ast_format_cap_alloc ( AST_FORMAT_CAP_FLAG_DEFAULT ) ;
# else
2011-10-04 08:41:28 +00:00
struct ast_format_cap * cap = ast_format_cap_alloc ( ) ;
2017-01-15 17:12:14 +00:00
# endif
2011-10-04 08:41:28 +00:00
# endif
2010-09-24 19:20:28 +00:00
memset ( faxdest , 0 , sizeof ( faxdest ) ) ;
cc_copy_string ( faxcontext , " " , sizeof ( faxcontext ) ) ;
cc_copy_string ( faxexten , " fax " , sizeof ( faxexten ) ) ;
2006-07-08 22:13:47 +00:00
2010-10-13 23:17:33 +00:00
/*
Default values for MWI subscribtion
*/
conf - > mwifacptynrtype = 0 ;
conf - > mwifacptynrton = 0 ;
conf - > mwifacptynrpres = 0 ;
conf - > mwibasicservice = 1 ;
conf - > mwiinvocation = 2 ;
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
2010-10-13 23:17:33 +00:00
# define CONF_INTEGER_SAFE(var, token, lower, upper) \
if ( ! strcasecmp ( v - > name , token ) ) { \
typeof ( ( var ) ) vi = ( typeof ( ( var ) ) ) atoi ( v - > value ) ; if ( var < = upper & & var > = lower ) var = vi ; \
continue ; \
} 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 " )
2010-09-24 19:20:28 +00:00
CONF_STRING ( faxdest , " faxdestination " )
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 )
2010-10-13 23:17:33 +00:00
CONF_INTEGER_SAFE ( conf - > mwifacptynrtype , " mwifacptynrtype " , 0 , 1 )
CONF_INTEGER_SAFE ( conf - > mwifacptynrton , " mwifacptynrton " , 0 , 0x7f )
CONF_INTEGER_SAFE ( conf - > mwifacptynrpres , " mwifacptynrpres " , 0 , 0x7f )
CONF_INTEGER_SAFE ( conf - > mwibasicservice , " mwibasicservice " , 0 , 0xff )
CONF_INTEGER_SAFE ( conf - > mwiinvocation , " mwiinvocation " , 0 , 0xffff )
2010-10-26 22:22:25 +00:00
CONF_INTEGER_SAFE ( conf - > hlimit , " hlimit " , 0 , 0xff )
CONF_INTEGER_SAFE ( conf - > slimit , " slimit " , 0 , 0xff )
2010-10-13 23:17:33 +00:00
if ( ! strcasecmp ( v - > name , " mwimailbox " ) ) {
conf - > mwimailbox = ast_strdup ( v - > value ) ;
continue ;
} else
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 " ) ) {
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
y = ast_channel_string2amaflag ( v - > value ) ;
# else
2006-07-08 22:13:47 +00:00
y = ast_cdr_amaflags2int ( v - > value ) ;
2017-01-15 17:12:14 +00:00
# endif
2006-07-08 22:13:47 +00:00
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 ;
}
2010-07-17 23:17:49 +00:00
if ( ! strcasecmp ( v - > name , " econtransitconn " ) ) {
conf - > econtransitconn = atoi ( v - > value ) ;
conf - > econtransitconn & = EC_ECHOCANCEL_TRANSIT_BITS ;
}
2009-04-15 13:39:57 +00:00
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 " ) ) {
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
cc_parse_allow_disallow ( conf - > capability , v - > value , 1 , cap ) ;
# else
2011-10-04 08:41:28 +00:00
cc_parse_allow_disallow ( & conf - > prefs , & conf - > capability , v - > value , 1 , cap ) ;
2017-01-15 17:12:14 +00:00
# endif
2006-01-30 23:40:28 +00:00
} else
if ( ! strcasecmp ( v - > name , " disallow " ) ) {
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
cc_parse_allow_disallow ( conf - > capability , v - > value , 0 , cap ) ;
# else
2011-10-04 08:41:28 +00:00
cc_parse_allow_disallow ( & conf - > prefs , & conf - > capability , v - > value , 0 , cap ) ;
2017-01-15 17:12:14 +00:00
# endif
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
2010-10-13 23:17:33 +00:00
# undef CONF_INTEGER_SAFE
2005-11-20 16:15:33 +00:00
# undef CONF_TRUE
2010-09-24 19:20:28 +00:00
/* faxdestination */
if ( strlen ( faxdest ) > 0 ) {
p = faxdest ;
q = strsep ( & p , " , " ) ;
cc_copy_string ( faxcontext , q , sizeof ( faxcontext ) ) ;
if ( p ) {
q = strsep ( & p , " , " ) ;
cc_copy_string ( faxexten , q , sizeof ( faxexten ) ) ;
}
if ( p ) {
faxpriority = atoi ( p ) ;
}
}
cc_copy_string ( conf - > faxcontext , faxcontext , sizeof ( conf - > faxcontext ) ) ;
cc_copy_string ( conf - > faxexten , faxexten , sizeof ( conf - > faxexten ) ) ;
if ( faxpriority < 1 ) faxpriority = 1 ;
conf - > faxpriority = faxpriority ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ao2_ref ( cap , - 1 ) ;
# elif defined(CC_AST_HAS_VERSION_10_0)
2011-10-04 08:41:28 +00:00
ast_format_cap_destroy ( cap ) ;
# endif
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 ) ) {
2011-10-04 08:41:28 +00:00
capi_capability = CC_FORMAT_ULAW ;
2005-08-07 11:40:07 +00:00
}
2010-06-30 09:17:09 +00:00
# ifdef DIVA_STREAMING
} else if ( ! strcasecmp ( v - > name , " nodivastreaming " ) ) {
if ( ast_true ( v - > value ) ) {
capi_DivaStreamingDisable ( ) ;
}
# endif
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 ) ) ) {
2010-10-14 08:07:55 +00:00
ast_free ( conf . mwimailbox ) ;
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 ) ) {
2010-10-14 08:07:55 +00:00
ast_free ( conf . mwimailbox ) ;
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 ;
}
2010-10-14 08:07:55 +00:00
ast_free ( conf . mwimailbox ) ;
2005-07-17 19:01:14 +00:00
}
return 0 ;
}
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 ) ;
2010-11-05 13:13:12 +00:00
pbx_capi_unregister_device_state_providers ( ) ;
2010-11-03 22:04:22 +00:00
pbx_capi_ami_unregister ( ) ;
2010-10-29 18:54:15 +00:00
pbx_capi_cli_unregister ( ) ;
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 ) ;
2011-11-16 21:43:04 +00:00
capi_device_thread = ( pthread_t ) ( 0 - 1 ) ;
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 + + ) {
2010-10-13 23:17:33 +00:00
if ( capi_controllers [ controller ] ) {
2010-10-14 08:07:55 +00:00
pbx_capi_cleanup_mwi ( capi_controllers [ controller ] ) ;
2010-10-22 22:44:50 +00:00
# ifdef DIVA_STATUS
diva_status_cleanup_interface ( controller ) ;
# endif
2010-08-19 08:44:21 +00:00
ast_free ( capi_controllers [ controller ] ) ;
2011-11-16 21:43:04 +00:00
capi_controllers [ controller ] = 0 ;
2010-10-13 23:17:33 +00:00
}
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 " ) ;
2011-11-16 21:43:04 +00:00
if ( i - > smoother ) {
2006-05-12 16:43:30 +00:00
ast_smoother_free ( i - > smoother ) ;
2011-11-16 21:43:04 +00:00
i - > smoother = 0 ;
}
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 ;
2010-08-19 08:44:21 +00:00
ast_free ( itmp ) ;
2006-05-12 16:43:30 +00:00
}
2011-11-16 21:43:04 +00:00
capi_iflist = NULL ;
2006-05-12 16:43:30 +00:00
cc_mutex_unlock ( & iflock ) ;
ast_channel_unregister ( & capi_tech ) ;
2007-04-22 10:03:52 +00:00
cleanup_ccbsnr ( ) ;
2011-02-04 17:18:05 +00:00
diva_verbose_unload ( ) ;
2006-05-12 16:43:30 +00:00
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ao2_ref ( capi_tech . capabilities , - 1 ) ;
# elif defined(CC_AST_HAS_VERSION_10_0)
2011-10-04 08:41:28 +00:00
capi_tech . capabilities = ast_format_cap_destroy ( capi_tech . capabilities ) ;
# endif
2011-11-16 21:43:04 +00:00
capi_num_controllers = 0 ;
capi_counter = 0 ;
2011-10-04 08:41:28 +00:00
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
2011-10-04 08:41:28 +00:00
# ifdef CC_AST_HAS_VERSION_10_0
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
if ( ! ( capi_tech . capabilities = ast_format_cap_alloc ( AST_FORMAT_CAP_FLAG_DEFAULT ) ) ) {
# else
2011-10-04 08:41:28 +00:00
if ( ! ( capi_tech . capabilities = ast_format_cap_alloc ( ) ) ) {
2017-01-15 17:12:14 +00:00
# endif
2011-10-04 08:41:28 +00:00
return AST_MODULE_LOAD_DECLINE ;
} else {
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
struct ast_format * fmt = ast_format_alaw ;
2019-01-22 08:03:48 +00:00
ast_format_cap_remove_by_type ( capi_tech . capabilities , AST_MEDIA_TYPE_AUDIO ) ;
2017-01-15 17:12:14 +00:00
ast_format_cap_append ( capi_tech . capabilities , fmt , 0 ) ;
# else
2011-10-04 08:41:28 +00:00
struct ast_format fmt ;
ast_format_clear ( & fmt ) ;
ast_format_set ( & fmt , AST_FORMAT_ALAW , 0 ) ;
ast_format_cap_add ( capi_tech . capabilities , & fmt ) ;
2017-01-15 17:12:14 +00:00
# endif
2011-10-04 08:41:28 +00:00
}
# endif
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
myself = ast_module_info - > self ;
# endif
2011-02-04 17:18:05 +00:00
diva_verbose_load ( ) ;
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 ) ;
2011-02-04 17:18:05 +00:00
diva_verbose_unload ( ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ao2_ref ( capi_tech . capabilities , - 1 ) ;
# elif defined(CC_AST_HAS_VERSION_10_0)
2011-10-04 08:41:28 +00:00
capi_tech . capabilities = ast_format_cap_destroy ( capi_tech . capabilities ) ;
# endif
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 " ) ;
2011-02-04 17:18:05 +00:00
diva_verbose_unload ( ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ao2_ref ( capi_tech . capabilities , - 1 ) ;
# elif defined(CC_AST_HAS_VERSION_10_0)
2011-10-04 08:41:28 +00:00
capi_tech . capabilities = ast_format_cap_destroy ( capi_tech . capabilities ) ;
# endif
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 ) ;
2011-02-04 17:18:05 +00:00
diva_verbose_unload ( ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ao2_ref ( capi_tech . capabilities , - 1 ) ;
# elif defined(CC_AST_HAS_VERSION_10_0)
2011-10-04 08:41:28 +00:00
capi_tech . capabilities = ast_format_cap_destroy ( capi_tech . capabilities ) ;
# endif
2011-11-16 10:01:28 +00:00
return 0 ;
2005-10-01 11:31:05 +00:00
}
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 ) ;
2011-02-04 17:18:05 +00:00
diva_verbose_unload ( ) ;
2017-01-15 17:12:14 +00:00
# ifdef CC_AST_HAS_VERSION_13_0
ao2_ref ( capi_tech . capabilities , - 1 ) ;
# elif defined(CC_AST_HAS_VERSION_10_0)
2011-10-04 08:41:28 +00:00
capi_tech . capabilities = ast_format_cap_destroy ( capi_tech . capabilities ) ;
# endif
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 ;
}
2010-10-29 18:54:15 +00:00
pbx_capi_cli_register ( ) ;
2015-02-28 16:35:31 +00:00
pbx_capi_ami_register ( myself ) ;
2010-11-05 13:13:12 +00:00
pbx_capi_register_device_state_providers ( ) ;
2010-12-10 22:46:01 +00:00
pbx_capi_chat_init_module ( ) ;
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 " ) ;
2011-10-04 08:41:28 +00:00
unload_module ( ) ;
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
}
2011-11-16 21:43:04 +00:00
# ifdef CC_AST_HAS_VERSION_1_4
static int reload ( void )
{
2012-11-15 10:37:50 +00:00
int ret = 0 ;
2011-11-16 21:43:04 +00:00
2012-11-15 10:37:50 +00:00
if ( usecnt ) {
cc_verbose ( 1 , 0 , VERBOSE_PREFIX_1 " chan_capi refused reload because of active channels \n " ) ;
} else {
cc_verbose ( 1 , 0 , VERBOSE_PREFIX_1 " chan_capi reload \n " ) ;
2011-11-16 21:43:04 +00:00
2012-11-15 10:37:50 +00:00
unload_module ( ) ;
ret = load_module ( ) ;
}
2011-11-16 21:43:04 +00:00
return ret ;
}
# endif
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 */
2010-08-23 12:14:03 +00:00
# ifdef DIVA_STREAMING
int pbx_capi_streaming_supported ( struct capi_pvt * i )
{
2010-11-26 17:11:07 +00:00
return ( ( i ! = 0 ) & & ( i - > controller < = CAPI_MAX_CONTROLLERS ) & &
( capi_controllers [ i - > controller ] ! = NULL ) & &
( capi_controllers [ i - > controller ] - > divaStreaming ! = 0 ) ) ;
2010-08-23 12:14:03 +00:00
}
# endif
2010-09-15 09:14:51 +00:00
2010-09-15 10:53:10 +00:00
/*!
* \ brief Used to provide ' Name ' info element to network . Name is provided in generoc format and is automatically converted by Diva protocol code
* to required format with respect to call state ( automatic name type ) . If name is not supported by protocol then information element is silently discarded .
* Can be used with QSIG and any other protocol which supports names .
*/
static void pbx_capi_add_diva_protocol_independent_extension ( struct capi_pvt * i , unsigned char * facilityarray , struct ast_channel * c , const char * variable )
2010-09-15 09:14:51 +00:00
{
2010-09-15 10:53:10 +00:00
const char * cid_name = 0 ;
2010-09-15 09:14:51 +00:00
2010-09-15 10:53:10 +00:00
if ( i - > qsigfeat ! = 0 | | i - > divaqsig = = 0 )
return ;
if ( c ! = 0 & & variable ! = 0 ) {
cid_name = pbx_builtin_getvar_helper ( c , variable ) ;
if ( cid_name ! = 0 & & * cid_name = = 0 )
cid_name = 0 ;
}
2010-09-15 09:14:51 +00:00
2015-02-28 16:35:31 +00:00
# ifdef CC_AST_HAS_VERSION_11_0
if ( cid_name = = 0 & & ast_channel_connected ( i - > owner ) - > id . name . valid ) {
cid_name = ast_strdupa ( S_COR ( ast_channel_connected ( i - > owner ) - > id . name . valid , ast_channel_connected ( i - > owner ) - > id . name . str , " " ) ) ;
}
# elif defined(CC_AST_HAS_VERSION_1_8)
2010-09-15 10:53:10 +00:00
if ( cid_name = = 0 & & i - > owner - > connected . id . name . valid ) {
2010-09-15 09:14:51 +00:00
cid_name = ast_strdupa ( S_COR ( i - > owner - > connected . id . name . valid , i - > owner - > connected . id . name . str , " " ) ) ;
}
2015-02-28 16:35:31 +00:00
# else /* !(defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8)) */
2010-09-15 10:53:10 +00:00
if ( cid_name = = 0 & & i - > owner - > cid . cid_name & & * i - > owner - > cid . cid_name ) {
2010-09-15 09:14:51 +00:00
cid_name = ast_strdupa ( i - > owner - > cid . cid_name ) ;
}
2015-02-28 16:35:31 +00:00
# endif /* defined(CC_AST_HAS_VERSION_11_0) || defined(CC_AST_HAS_VERSION_1_8) */
2010-09-15 10:53:10 +00:00
if ( cid_name ! = 0 & & * cid_name = = 0 )
cid_name = i - > name ;
if ( cid_name ! = 0 & & * cid_name ! = 0 ) {
2010-09-15 09:14:51 +00:00
unsigned char * p ;
int length = strlen ( cid_name ) ;
const unsigned char t [ ] =
{ 0x0d /* 0 - len */ , 0x1c , 0x0b /* 2 - len */ , 0x9f , 0xa1 , 0x08 /* 5 - len */ , 0x02 , 0x01 , 0x01 , 0x02 , 0x01 , 0x00 , 0x80 , 0x00 /* 12+1 - len */ } ;
2010-09-15 10:53:10 +00:00
p = facilityarray ;
2010-09-15 09:14:51 +00:00
memcpy ( p , t , sizeof ( t ) ) ;
memcpy ( p + sizeof ( t ) , cid_name , MIN ( length , ( CAPI_MAX_FACILITYDATAARRAY_SIZE - sizeof ( t ) ) ) ) ;
p [ 0 ] + = length ;
p [ 2 ] + = length ;
p [ 5 ] + = length ;
p [ 12 + 1 ] + = length ;
2010-09-15 10:53:10 +00:00
cc_verbose ( 3 , 0 , VERBOSE_PREFIX_3 " %s: * Sending %s %02x '%s' \n " , i - > vname , variable , 0x80 , cid_name ) ;
2010-09-15 09:14:51 +00:00
}
2010-09-15 10:53:10 +00:00
return ;
2010-09-15 09:14:51 +00:00
}
2010-10-09 08:29:39 +00:00
cc_format_t pbx_capi_get_controller_codecs ( int controller )
{
2010-09-18 23:07:38 +00:00
return ( capi_controllers [ controller ] - > rtpcodec ) ;
}
2010-10-29 18:54:15 +00:00
const struct cc_capi_controller * pbx_capi_get_controller ( int controller )
{
2010-10-15 16:50:41 +00:00
return ( ( controller > 0 & & controller < = capi_num_controllers ) ? capi_controllers [ controller ] : 0 ) ;
2010-10-13 23:17:33 +00:00
}
2010-10-29 18:54:15 +00:00
int pbx_capi_get_num_controllers ( void )
{
return capi_num_controllers ;
}
2010-10-22 22:44:50 +00:00
# ifdef DIVA_STATUS
/*!
\ brief Notify about interface state change
\ note No locks are taken at time this function is called
\ note called from the context of CAPI thread
*/
static void pbx_capi_interface_status_changed ( int controller , diva_status_interface_state_t newInterfaceState )
{
int currentInterfaceState ;
2010-11-05 21:58:49 +00:00
int originalControllerStatus = ( pbx_capi_check_controller_status ( controller ) ! = - 1 ) ;
int newControllerStatus ;
2010-10-22 22:44:50 +00:00
cc_mutex_lock ( & iflock ) ;
currentInterfaceState = capi_controllers [ controller ] - > interfaceState ;
capi_controllers [ controller ] - > interfaceState = newInterfaceState ;
cc_mutex_unlock ( & iflock ) ;
2010-11-05 21:58:49 +00:00
newControllerStatus = ( pbx_capi_check_controller_status ( controller ) ! = - 1 ) ;
2010-10-22 22:44:50 +00:00
cc_verbose ( 1 , 0 , VERBOSE_PREFIX_1 " CAPI%d: interface state changed %s -> %s \n " ,
controller ,
diva_status_interface_state_name ( ( diva_status_interface_state_t ) currentInterfaceState ) ,
diva_status_interface_state_name ( ( diva_status_interface_state_t ) newInterfaceState ) ) ;
2010-11-05 21:58:49 +00:00
if ( originalControllerStatus ! = newControllerStatus )
pbx_capi_ifc_state_event ( capi_controllers [ controller ] , 0 ) ;
2010-10-22 22:44:50 +00:00
}
2010-10-25 21:21:31 +00:00
static void pbx_capi_hw_status_changed ( int controller , diva_status_hardware_state_t newHwState )
{
int currentHwState ;
cc_mutex_lock ( & iflock ) ;
currentHwState = capi_controllers [ controller ] - > hwState ;
capi_controllers [ controller ] - > hwState = newHwState ;
cc_mutex_unlock ( & iflock ) ;
cc_verbose ( 1 , 0 , VERBOSE_PREFIX_1 " CAPI%d: hardware state changed %s -> %s \n " ,
controller ,
diva_status_hw_state_name ( ( diva_status_hardware_state_t ) currentHwState ) ,
diva_status_hw_state_name ( ( diva_status_hardware_state_t ) newHwState ) ) ;
}
2010-10-22 22:44:50 +00:00
# endif
/*! \brief Check interface is operational. If the state of the interface
is not known then check if one with known state is available .
\ note Called with iflock taken
\ note The core runs twice over the interface list , but this allows to preserve
the structure of the original code which uses this function .
*/
2010-10-26 22:22:25 +00:00
static int pbx_capi_check_controller_status ( int capiController )
2010-10-22 22:44:50 +00:00
{
# ifdef DIVA_STATUS
if ( capi_controllers [ capiController ] - > interfaceState = = ( int ) DivaStatusInterfaceStateOK ) /* known, OK */
return 0 ;
if ( capi_controllers [ capiController ] - > interfaceState = = ( int ) DivaStatusInterfaceStateERROR ) /* known, not OK */
return - 1 ;
/*
2010-10-26 22:22:25 +00:00
Unknown interface state
2010-10-22 22:44:50 +00:00
*/
# endif
2010-10-26 22:22:25 +00:00
return 1 ;
2010-10-22 22:44:50 +00:00
}
2010-10-29 18:54:15 +00:00
const char * pbx_capi_get_module_description ( void )
{
return tdesc ;
}
void pbx_capi_lock_interfaces ( void )
{
cc_mutex_lock ( & iflock ) ;
}
void pbx_capi_unlock_interfaces ( void )
{
cc_mutex_unlock ( & iflock ) ;
}