2001-10-09 02:06:21 +00:00
/*
* Asterisk - - A telephony toolkit for Linux .
*
2003-02-24 06:00:18 +00:00
* Zaptel Pseudo TDM interface
2001-10-09 02:06:21 +00:00
*
2003-02-24 06:00:18 +00:00
* Copyright ( C ) 2003 Digium
2001-10-09 02:06:21 +00:00
*
2003-02-24 06:00:18 +00:00
* Mark Spencer < markster @ digium . com >
2001-10-09 02:06:21 +00:00
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
# include <stdio.h>
# include <string.h>
2002-06-24 17:59:56 +00:00
# include <asterisk/lock.h>
2001-10-09 02:06:21 +00:00
# include <asterisk/channel.h>
# include <asterisk/channel_pvt.h>
# include <asterisk/config.h>
# include <asterisk/logger.h>
# include <asterisk/module.h>
# include <asterisk/pbx.h>
# include <asterisk/options.h>
# include <asterisk/file.h>
# include <asterisk/ulaw.h>
2003-02-07 19:23:19 +00:00
# include <asterisk/alaw.h>
2001-10-09 02:06:21 +00:00
# include <asterisk/callerid.h>
2001-12-29 18:04:21 +00:00
# include <asterisk/adsi.h>
2001-10-09 02:06:21 +00:00
# include <asterisk/cli.h>
2001-12-29 18:04:21 +00:00
# include <asterisk/cdr.h>
# include <asterisk/parking.h>
2002-06-24 17:59:56 +00:00
# include <asterisk/musiconhold.h>
2003-02-07 19:23:19 +00:00
# include <asterisk/say.h>
2001-12-29 18:04:21 +00:00
# include <asterisk/tdd.h>
2003-02-07 19:23:19 +00:00
# include <asterisk/app.h>
# include <asterisk/dsp.h>
2003-03-07 06:00:13 +00:00
# include <asterisk/astdb.h>
2001-10-09 02:06:21 +00:00
# include <sys/signal.h>
# include <sys/select.h>
# include <errno.h>
# include <stdlib.h>
2003-02-07 19:23:19 +00:00
# include <stdint.h>
2001-10-09 02:06:21 +00:00
# include <unistd.h>
# include <sys/ioctl.h>
# include <linux/zaptel.h>
# include <math.h>
# include <tonezone.h>
2003-02-07 19:23:19 +00:00
# include <ctype.h>
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
# include <libpri.h>
# endif
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
# include <libmfcr2.h>
# endif
2001-10-09 02:06:21 +00:00
2002-03-08 23:48:42 +00:00
# include "../asterisk.h"
2001-10-09 02:06:21 +00:00
/*
XXX
XXX We definitely need to lock the private structure in zt_read and such
XXX
*/
2002-06-24 17:59:56 +00:00
/*
* Define ZHONE_HACK to cause us to go off hook and then back on hook when
* the user hangs up to reset the state machine so ring works properly .
* This is used to be able to support kewlstart by putting the zhone in
* groundstart mode since their forward disconnect supervision is entirely
* broken even though their documentation says it isn ' t and their support
* is entirely unwilling to provide any assistance with their channel banks
* even though their web site says they support their products for life .
*/
2003-02-07 19:23:19 +00:00
/* #define ZHONE_HACK */
2002-06-24 17:59:56 +00:00
2003-04-15 17:09:34 +00:00
/* Typically, how many rings before we should send Caller*ID */
# define DEFAULT_CIDRINGS 1
2002-06-24 17:59:56 +00:00
# define CHANNEL_PSEUDO -12
2003-02-07 19:23:19 +00:00
# define AST_LAW(p) (((p)->law == ZT_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
static char * desc = " Zapata Telephony "
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
2003-02-07 19:23:19 +00:00
" w/PRI "
# endif
# ifdef ZAPATA_R2
" w/R2 "
# endif
;
static char * tdesc = " Zapata Telephony Driver "
# ifdef ZAPATA_PRI
" w/PRI "
# endif
# ifdef ZAPATA_R2
" w/R2 "
2001-10-09 02:06:21 +00:00
# endif
2003-02-07 19:23:19 +00:00
;
2001-10-09 02:06:21 +00:00
static char * type = " Zap " ;
static char * typecompat = " Tor " ; /* Retain compatibility with chan_tor */
static char * config = " zapata.conf " ;
# define SIG_EM ZT_SIG_EM
# define SIG_EMWINK (0x10000 | ZT_SIG_EM)
# define SIG_FEATD (0x20000 | ZT_SIG_EM)
2002-06-24 17:59:56 +00:00
# define SIG_FEATDMF (0x40000 | ZT_SIG_EM)
# define SIG_FEATB (0x80000 | ZT_SIG_EM)
2001-10-09 02:06:21 +00:00
# define SIG_FXSLS ZT_SIG_FXSLS
# define SIG_FXSGS ZT_SIG_FXSGS
# define SIG_FXSKS ZT_SIG_FXSKS
# define SIG_FXOLS ZT_SIG_FXOLS
# define SIG_FXOGS ZT_SIG_FXOGS
# define SIG_FXOKS ZT_SIG_FXOKS
# define SIG_PRI ZT_SIG_CLEAR
2003-02-07 19:23:19 +00:00
# define SIG_R2 ZT_SIG_CAS
2003-03-17 18:11:33 +00:00
# define SIG_SF ZT_SIG_SF
2003-03-17 20:04:36 +00:00
# define SIG_SFWINK (0x10000 | ZT_SIG_SF)
# define SIG_SF_FEATD (0x20000 | ZT_SIG_SF)
# define SIG_SF_FEATDMF (0x40000 | ZT_SIG_SF)
# define SIG_SF_FEATB (0x80000 | ZT_SIG_SF)
2001-10-09 02:06:21 +00:00
2001-12-29 18:04:21 +00:00
# define NUM_SPANS 32
2002-06-24 17:59:56 +00:00
# define RESET_INTERVAL 3600 /* How often (in seconds) to reset unused channels */
# define CHAN_PSEUDO -2
2001-10-09 02:06:21 +00:00
static char context [ AST_MAX_EXTENSION ] = " default " ;
static char callerid [ 256 ] = " " ;
static char language [ MAX_LANGUAGE ] = " " ;
2002-06-24 17:59:56 +00:00
static char musicclass [ MAX_LANGUAGE ] = " " ;
2001-10-09 02:06:21 +00:00
static int use_callerid = 1 ;
static int cur_signalling = - 1 ;
2003-04-09 04:00:43 +00:00
static unsigned int cur_group = 0 ;
static unsigned int cur_callergroup = 0 ;
static unsigned int cur_pickupgroup = 0 ;
2003-02-07 19:23:19 +00:00
static int relaxdtmf = 0 ;
2001-10-09 02:06:21 +00:00
static int immediate = 0 ;
static int stripmsd = 0 ;
static int callwaiting = 0 ;
static int callwaitingcallerid = 0 ;
static int hidecallerid = 0 ;
2003-02-07 19:23:19 +00:00
static int callreturn = 0 ;
2001-10-09 02:06:21 +00:00
static int threewaycalling = 0 ;
static int transfer = 0 ;
2002-03-08 23:48:42 +00:00
static int cancallforward = 0 ;
2001-10-09 02:06:21 +00:00
static float rxgain = 0.0 ;
static float txgain = 0.0 ;
static int echocancel ;
2002-09-10 04:45:51 +00:00
static int echocanbridged = 0 ;
2003-02-07 19:23:19 +00:00
static int busydetect = 0 ;
2003-03-06 06:00:17 +00:00
static int busycount = 3 ;
2003-02-07 19:23:19 +00:00
static int callprogress = 0 ;
2001-12-29 18:04:21 +00:00
static char accountcode [ 20 ] = " " ;
2002-03-08 23:48:42 +00:00
static char mailbox [ AST_MAX_EXTENSION ] ;
2001-12-29 18:04:21 +00:00
static int amaflags = 0 ;
static int adsi = 0 ;
2002-06-24 17:59:56 +00:00
# ifdef ZAPATA_PRI
static int minunused = 2 ;
static int minidle = 0 ;
static char idleext [ AST_MAX_EXTENSION ] ;
static char idledial [ AST_MAX_EXTENSION ] ;
2003-05-19 23:33:41 +00:00
static int overlapdial = 0 ;
2002-06-24 17:59:56 +00:00
# endif
2001-10-09 02:06:21 +00:00
/* Wait up to 16 seconds for first digit (FXO logic) */
static int firstdigittimeout = 16000 ;
/* How long to wait for following digits (FXO logic) */
static int gendigittimeout = 8000 ;
2003-02-07 19:23:19 +00:00
/* How long to wait for an extra digit, if there is an ambiguous match */
static int matchdigittimeout = 3000 ;
2001-10-09 02:06:21 +00:00
static int usecnt = 0 ;
2002-06-24 17:59:56 +00:00
static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER ;
2001-10-09 02:06:21 +00:00
/* Protect the interface list (of zt_pvt's) */
2002-06-24 17:59:56 +00:00
static pthread_mutex_t iflock = AST_MUTEX_INITIALIZER ;
2001-10-09 02:06:21 +00:00
/* Protect the monitoring thread, so only one process can kill or start it, and not
when it ' s doing something critical . */
2002-06-24 17:59:56 +00:00
static pthread_mutex_t monlock = AST_MUTEX_INITIALIZER ;
2001-10-09 02:06:21 +00:00
/* This is the thread for the monitor which checks for input on the channels
which are not currently in use . */
static pthread_t monitor_thread = 0 ;
static int restart_monitor ( void ) ;
static int zt_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , int flags , struct ast_frame * * fo , struct ast_channel * * rc ) ;
2001-12-29 18:04:21 +00:00
static int zt_sendtext ( struct ast_channel * c , char * text ) ;
2001-10-09 02:06:21 +00:00
static inline int zt_get_event ( int fd )
{
/* Avoid the silly zt_getevent which ignores a bunch of events */
int j ;
if ( ioctl ( fd , ZT_GETEVENT , & j ) = = - 1 ) return - 1 ;
return j ;
}
static inline int zt_wait_event ( int fd )
{
/* Avoid the silly zt_waitevent which ignores a bunch of events */
int i , j = 0 ;
i = ZT_IOMUX_SIGEVENT ;
if ( ioctl ( fd , ZT_IOMUX , & i ) = = - 1 ) return - 1 ;
if ( ioctl ( fd , ZT_GETEVENT , & j ) = = - 1 ) return - 1 ;
return j ;
}
2003-02-07 19:23:19 +00:00
/* Chunk size to read -- we use 20ms chunks to make things happy. */
# define READ_SIZE 160
2001-10-09 02:06:21 +00:00
# define MASK_AVAIL (1 << 0) /* Channel available for PRI use */
# define MASK_INUSE (1 << 1) /* Channel currently in use */
# define CALLWAITING_SILENT_SAMPLES ( (300 * 8) / READ_SIZE) /* 300 ms */
# define CALLWAITING_REPEAT_SAMPLES ( (10000 * 8) / READ_SIZE) /* 300 ms */
2003-02-07 19:23:19 +00:00
# define CIDCW_EXPIRE_SAMPLES ( (500 * 8) / READ_SIZE) /* 500 ms */
2003-04-11 04:31:33 +00:00
# define MIN_MS_SINCE_FLASH ( (2000) ) /* 2000 ms */
2003-02-07 19:23:19 +00:00
# define RINGT ( (8000 * 8) / READ_SIZE)
2001-10-09 02:06:21 +00:00
struct zt_pvt ;
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
static int r2prot = - 1 ;
# endif
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
struct zt_pri {
pthread_t master ; /* Thread of master */
pthread_mutex_t lock ; /* Mutex */
2002-06-24 17:59:56 +00:00
char idleext [ AST_MAX_EXTENSION ] ; /* Where to idle extra calls */
char idlecontext [ AST_MAX_EXTENSION ] ; /* What context to use for idle */
char idledial [ AST_MAX_EXTENSION ] ; /* What to dial before dumping */
int minunused ; /* Min # of channels to keep empty */
int minidle ; /* Min # of "idling" calls to keep active */
2001-10-09 02:06:21 +00:00
int nodetype ; /* Node type */
int switchtype ; /* Type of switch to emulate */
2003-02-07 19:23:19 +00:00
int dialplan ; /* Dialing plan */
2001-12-29 18:04:21 +00:00
int dchannel ; /* What channel the dchannel is on */
int channels ; /* Num of chans in span (31 or 24) */
2003-05-19 23:33:41 +00:00
int overlapdial ; /* In overlap dialing mode */
2001-10-09 02:06:21 +00:00
struct pri * pri ;
int debug ;
int fd ;
int up ;
int offset ;
int span ;
2003-02-07 19:23:19 +00:00
int chanmask [ 32 ] ; /* Channel status */
2002-06-24 17:59:56 +00:00
int resetting ;
int resetchannel ;
time_t lastreset ;
2003-02-07 19:23:19 +00:00
struct zt_pvt * pvt [ 32 ] ; /* Member channel pvt structs */
struct zt_channel * chan [ 32 ] ; /* Channels on each line */
2001-10-09 02:06:21 +00:00
} ;
static struct zt_pri pris [ NUM_SPANS ] ;
static int pritype = PRI_CPE ;
#if 0
2001-12-29 18:04:21 +00:00
# define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
2001-10-09 02:06:21 +00:00
# else
# define DEFAULT_PRI_DEBUG 0
# endif
static inline void pri_rel ( struct zt_pri * pri )
{
ast_pthread_mutex_unlock ( & pri - > lock ) ;
}
static int switchtype = PRI_SWITCH_NI2 ;
2003-02-07 19:23:19 +00:00
static int dialplan = PRI_NATIONAL_ISDN + 1 ;
2001-10-09 02:06:21 +00:00
# endif
2003-02-07 19:23:19 +00:00
# define SUB_REAL 0 /* Active call */
# define SUB_CALLWAIT 1 /* Call-Waiting call on hold */
# define SUB_THREEWAY 2 /* Three-way call */
static char * subnames [ ] = {
" Real " ,
" Callwait " ,
" Threeway "
} ;
struct zt_subchannel {
int zfd ;
struct ast_channel * owner ;
int chan ;
short buffer [ AST_FRIENDLY_OFFSET / 2 + READ_SIZE ] ;
struct ast_frame f ; /* One frame for each channel. How did this ever work before? */
int needringing ;
int needcallerid ;
int needanswer ;
int linear ;
int inthreeway ;
int curconfno ; /* What conference we're currently in */
} ;
# define CONF_USER_REAL (1 << 0)
# define CONF_USER_THIRDCALL (1 << 1)
# define MAX_SLAVES 4
2001-10-09 02:06:21 +00:00
static struct zt_pvt {
pthread_mutex_t lock ;
2003-02-07 19:23:19 +00:00
struct ast_channel * owner ; /* Our current active owner (if applicable) */
2001-10-09 02:06:21 +00:00
/* Up to three channels can be associated with this call */
2003-02-07 19:23:19 +00:00
struct zt_subchannel sub_unused ; /* Just a safety precaution */
struct zt_subchannel subs [ 3 ] ; /* Sub-channels */
struct zt_confinfo saveconf ; /* Saved conference info */
struct zt_pvt * slaves [ MAX_SLAVES ] ; /* Slave to us (follows our conferencing) */
struct zt_pvt * master ; /* Master to us (we follow their conferencing) */
int inconference ; /* If our real should be in the conference */
2001-10-09 02:06:21 +00:00
int sig ; /* Signalling style */
2003-02-07 19:23:19 +00:00
int radio ; /* radio type */
int firstradio ; /* first radio flag */
2001-10-09 02:06:21 +00:00
float rxgain ;
float txgain ;
struct zt_pvt * next ; /* Next channel in list */
char context [ AST_MAX_EXTENSION ] ;
char exten [ AST_MAX_EXTENSION ] ;
char language [ MAX_LANGUAGE ] ;
2002-06-24 17:59:56 +00:00
char musicclass [ MAX_LANGUAGE ] ;
2001-10-09 02:06:21 +00:00
char callerid [ AST_MAX_EXTENSION ] ;
2003-02-07 19:23:19 +00:00
char lastcallerid [ AST_MAX_EXTENSION ] ;
2001-10-09 02:06:21 +00:00
char callwaitcid [ AST_MAX_EXTENSION ] ;
2003-02-07 19:23:19 +00:00
char rdnis [ AST_MAX_EXTENSION ] ;
2003-04-09 04:00:43 +00:00
unsigned int group ;
2001-12-29 18:04:21 +00:00
int law ;
2003-02-07 19:23:19 +00:00
int confno ; /* Our conference */
int confusers ; /* Who is using our conference */
int propconfno ; /* Propagated conference number */
2003-04-09 04:00:43 +00:00
unsigned int callgroup ;
unsigned int pickupgroup ;
2001-10-09 02:06:21 +00:00
int immediate ; /* Answer before getting digits? */
int channel ; /* Channel Number */
int span ; /* Span number */
int dialing ;
2001-12-29 18:04:21 +00:00
int dialednone ;
2001-10-09 02:06:21 +00:00
int use_callerid ; /* Whether or not to use caller id on this channel */
int hidecallerid ;
2003-02-07 19:23:19 +00:00
int callreturn ;
2001-10-09 02:06:21 +00:00
int permhidecallerid ; /* Whether to hide our outgoing caller ID or not */
int callwaitingrepeat ; /* How many samples to wait before repeating call waiting */
2003-02-07 19:23:19 +00:00
int cidcwexpire ; /* When to expire our muting for CID/CW */
2001-10-09 02:06:21 +00:00
unsigned char * cidspill ;
int cidpos ;
int cidlen ;
int ringt ;
int stripmsd ;
int callwaiting ;
int callwaitcas ;
int callwaitrings ;
int echocancel ;
2002-09-10 04:45:51 +00:00
int echocanbridged ;
2003-02-07 19:23:19 +00:00
int echocanon ;
2001-10-09 02:06:21 +00:00
int permcallwaiting ;
int callwaitingcallerid ;
int threewaycalling ;
int transfer ;
2003-02-07 19:23:19 +00:00
int digital ;
int outgoing ;
2002-09-10 04:45:51 +00:00
int dnd ;
2003-02-07 19:23:19 +00:00
int busydetect ;
2003-03-06 06:00:17 +00:00
int busycount ;
2003-02-07 19:23:19 +00:00
int callprogress ;
2003-03-21 16:26:50 +00:00
struct timeval flashtime ; /* Last flash-hook time */
2003-02-07 19:23:19 +00:00
struct ast_dsp * dsp ;
2001-10-09 02:06:21 +00:00
int cref ; /* Call reference number */
ZT_DIAL_OPERATION dop ;
int destroy ;
int ignoredtmf ;
int inalarm ;
2001-12-29 18:04:21 +00:00
char accountcode [ 20 ] ; /* Account code */
int amaflags ; /* AMA Flags */
char didtdd ; /* flag to say its done it once */
struct tdd_state * tdd ; /* TDD flag */
int adsi ;
2002-03-08 23:48:42 +00:00
int cancallforward ;
char call_forward [ AST_MAX_EXTENSION ] ;
char mailbox [ AST_MAX_EXTENSION ] ;
2003-02-07 19:23:19 +00:00
int onhooktime ;
int msgstate ;
2002-06-24 17:59:56 +00:00
int confirmanswer ; /* Wait for '#' to confirm answer */
int distinctivering ; /* Which distinctivering to use */
int cidrings ; /* Which ring to deliver CID on */
2003-02-07 19:23:19 +00:00
int faxhandled ; /* Has a fax tone already been handled? */
2002-06-24 17:59:56 +00:00
char mate ; /* flag to say its in MATE mode */
2003-02-07 19:23:19 +00:00
int pulsedial ; /* whether a pulse dial phone is detected */
int dtmfrelax ; /* whether to run in relaxed DTMF mode */
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
struct zt_pri * pri ;
q931_call * call ;
2002-06-24 17:59:56 +00:00
int isidlecall ;
int resetting ;
2003-02-07 19:23:19 +00:00
int prioffset ;
int alreadyhungup ;
2003-04-18 15:55:50 +00:00
# ifdef PRI_EVENT_PROCEEDING
int proceeding ;
# endif
2003-05-19 23:33:41 +00:00
int setup_ack ; /* wheter we received SETUP_ACKNOWLEDGE or not */
2003-02-07 19:23:19 +00:00
# endif
# ifdef ZAPATA_R2
int r2prot ;
mfcr2_t * r2 ;
int hasr2call ;
int r2blocked ;
int sigchecked ;
2001-10-09 02:06:21 +00:00
# endif
} * iflist = NULL ;
2003-04-22 18:47:49 +00:00
# ifdef ZAPATA_PRI
static inline int pri_grab ( struct zt_pvt * pvt , struct zt_pri * pri )
{
int res ;
/* Grab the lock first */
do {
res = pthread_mutex_trylock ( & pri - > lock ) ;
if ( res ) {
ast_pthread_mutex_unlock ( & pvt - > lock ) ;
/* Release the lock and try again */
usleep ( 1 ) ;
ast_pthread_mutex_lock ( & pvt - > lock ) ;
}
} while ( res ) ;
/* Then break the select */
pthread_kill ( pri - > master , SIGURG ) ;
return 0 ;
}
# endif
2002-06-24 17:59:56 +00:00
static struct zt_ring_cadence cadences [ ] = {
{ { 125 , 125 , 2000 , 4000 } } , /* Quick chirp followed by normal ring */
{ { 250 , 250 , 500 , 1000 , 250 , 250 , 500 , 4000 } } , /* British style ring */
{ { 125 , 125 , 125 , 125 , 125 , 4000 } } , /* Three short bursts */
{ { 1000 , 500 , 2500 , 5000 } } , /* Long ring */
} ;
static int cidrings [ ] = {
2 , /* Right after first long ring */
4 , /* Right after long part */
3 , /* After third chirp */
2 , /* Second spell */
} ;
# define NUM_CADENCE (sizeof(cadences) / sizeof(cadences[0]))
2001-10-09 02:06:21 +00:00
# define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
2003-02-07 19:23:19 +00:00
( p - > sig = = SIG_FXSGS ) | | ( p - > sig = = SIG_PRI ) )
2001-10-09 02:06:21 +00:00
2003-03-17 20:04:36 +00:00
# define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */ )
# define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */ )
2001-10-09 02:06:21 +00:00
2003-02-07 19:23:19 +00:00
static int zt_get_index ( struct ast_channel * ast , struct zt_pvt * p , int nullok )
2001-10-09 02:06:21 +00:00
{
int res ;
2003-02-07 19:23:19 +00:00
if ( p - > subs [ 0 ] . owner = = ast )
res = 0 ;
else if ( p - > subs [ 1 ] . owner = = ast )
res = 1 ;
else if ( p - > subs [ 2 ] . owner = = ast )
res = 2 ;
else {
res = - 1 ;
if ( ! nullok )
ast_log ( LOG_WARNING , " Unable to get index, and nullok is not asserted \n " ) ;
}
return res ;
}
static void swap_subs ( struct zt_pvt * p , int a , int b )
{
int tchan ;
int tinthreeway ;
struct ast_channel * towner ;
2003-04-11 04:31:33 +00:00
struct ast_frame null = { AST_FRAME_NULL , } ;
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Swapping %d and %d \n " , a , b ) ;
tchan = p - > subs [ a ] . chan ;
towner = p - > subs [ a ] . owner ;
tinthreeway = p - > subs [ a ] . inthreeway ;
p - > subs [ a ] . chan = p - > subs [ b ] . chan ;
p - > subs [ a ] . owner = p - > subs [ b ] . owner ;
p - > subs [ a ] . inthreeway = p - > subs [ b ] . inthreeway ;
p - > subs [ b ] . chan = tchan ;
p - > subs [ b ] . owner = towner ;
p - > subs [ b ] . inthreeway = tinthreeway ;
2003-04-11 04:31:33 +00:00
if ( p - > subs [ a ] . owner ) {
2003-02-07 19:23:19 +00:00
p - > subs [ a ] . owner - > fds [ 0 ] = p - > subs [ a ] . zfd ;
2003-04-11 04:31:33 +00:00
ast_queue_frame ( p - > subs [ a ] . owner , & null , 0 ) ;
}
if ( p - > subs [ b ] . owner ) {
2003-02-07 19:23:19 +00:00
p - > subs [ b ] . owner - > fds [ 0 ] = p - > subs [ b ] . zfd ;
2003-04-11 04:31:33 +00:00
ast_queue_frame ( p - > subs [ b ] . owner , & null , 0 ) ;
}
2003-02-07 19:23:19 +00:00
}
static int zt_open ( char * fn )
{
int fd ;
int isnum ;
int chan = 0 ;
int bs ;
int x ;
isnum = 1 ;
for ( x = 0 ; x < strlen ( fn ) ; x + + ) {
if ( ! isdigit ( fn [ x ] ) ) {
isnum = 0 ;
break ;
}
}
if ( isnum ) {
chan = atoi ( fn ) ;
if ( chan < 1 ) {
ast_log ( LOG_WARNING , " Invalid channel number '%s' \n " , fn ) ;
return - 1 ;
}
fn = " /dev/zap/channel " ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
fd = open ( fn , O_RDWR | O_NONBLOCK ) ;
if ( fd < 0 ) {
ast_log ( LOG_WARNING , " Unable to open '%s': %s \n " , fn , strerror ( errno ) ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
2003-02-07 19:23:19 +00:00
}
if ( chan ) {
if ( ioctl ( fd , ZT_SPECIFY , & chan ) ) {
x = errno ;
close ( fd ) ;
errno = x ;
ast_log ( LOG_WARNING , " Unable to specify channel %d: %s \n " , chan , strerror ( errno ) ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
}
2003-02-07 19:23:19 +00:00
bs = READ_SIZE ;
if ( ioctl ( fd , ZT_SET_BLOCKSIZE , & bs ) = = - 1 ) return - 1 ;
return fd ;
}
static void zt_close ( int fd )
{
close ( fd ) ;
}
int zt_setlinear ( int zfd , int linear )
{
int res ;
res = ioctl ( zfd , ZT_SETLINEAR , & linear ) ;
if ( res )
return res ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
2003-02-07 19:23:19 +00:00
int zt_setlaw ( int zfd , int law )
2001-10-09 02:06:21 +00:00
{
2003-02-07 19:23:19 +00:00
int res ;
res = ioctl ( zfd , ZT_SETLAW , & law ) ;
if ( res )
return res ;
return 0 ;
}
static int alloc_sub ( struct zt_pvt * p , int x )
{
ZT_BUFFERINFO bi ;
int res ;
if ( p - > subs [ x ] . zfd < 0 ) {
p - > subs [ x ] . zfd = zt_open ( " /dev/zap/pseudo " ) ;
if ( p - > subs [ x ] . zfd > - 1 ) {
res = ioctl ( p - > subs [ x ] . zfd , ZT_GET_BUFINFO , & bi ) ;
if ( ! res ) {
bi . txbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . rxbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . numbufs = 4 ;
res = ioctl ( p - > subs [ x ] . zfd , ZT_SET_BUFINFO , & bi ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to set buffer policy on channel %d \n " , x ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to check buffer policy on channel %d \n " , x ) ;
if ( ioctl ( p - > subs [ x ] . zfd , ZT_CHANNO , & p - > subs [ x ] . chan ) = = 1 ) {
ast_log ( LOG_WARNING , " Unable to get channel number for pseudo channel on FD %d \n " , p - > subs [ x ] . zfd ) ;
zt_close ( p - > subs [ x ] . zfd ) ;
p - > subs [ x ] . zfd = - 1 ;
return - 1 ;
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Allocated %s subchannel on FD %d channel %d \n " , subnames [ x ] , p - > subs [ x ] . zfd , p - > subs [ x ] . chan ) ;
return 0 ;
} else
ast_log ( LOG_WARNING , " Unable to open pseudo channel: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
ast_log ( LOG_WARNING , " %s subchannel of %d already in use \n " , subnames [ x ] , p - > channel ) ;
return - 1 ;
}
static int unalloc_sub ( struct zt_pvt * p , int x )
{
if ( ! x ) {
ast_log ( LOG_WARNING , " Trying to unalloc the real channel %d?!? \n " , p - > channel ) ;
return - 1 ;
}
ast_log ( LOG_DEBUG , " Released sub %d of channel %d \n " , x , p - > channel ) ;
if ( p - > subs [ x ] . zfd > - 1 ) {
zt_close ( p - > subs [ x ] . zfd ) ;
}
p - > subs [ x ] . zfd = - 1 ;
p - > subs [ x ] . linear = 0 ;
p - > subs [ x ] . chan = 0 ;
p - > subs [ x ] . owner = NULL ;
p - > subs [ x ] . inthreeway = 0 ;
p - > subs [ x ] . curconfno = - 1 ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
static int zt_digit ( struct ast_channel * ast , char digit )
{
ZT_DIAL_OPERATION zo ;
struct zt_pvt * p ;
2003-02-07 19:23:19 +00:00
int res = 0 ;
int index ;
2001-10-09 02:06:21 +00:00
p = ast - > pvt - > pvt ;
2003-02-07 19:23:19 +00:00
index = zt_get_index ( ast , p , 0 ) ;
if ( index = = SUB_REAL ) {
2003-03-25 19:08:46 +00:00
# ifdef ZAPATA_PRI
2003-05-19 23:33:41 +00:00
# ifdef PRI_EVENT_SETUP_ACK
if ( p - > sig = = SIG_PRI & & ast - > _state = = AST_STATE_DIALING & & p - > setup_ack & & ! p - > proceeding ) {
# else
2003-04-18 15:55:50 +00:00
# ifdef PRI_EVENT_PROCEEDING
if ( p - > sig = = SIG_PRI & & ast - > _state = = AST_STATE_DIALING & & ! p - > proceeding ) {
# else
2003-03-24 22:12:11 +00:00
if ( p - > sig = = SIG_PRI & & ast - > _state = = AST_STATE_DIALING ) {
2003-05-15 22:16:26 +00:00
# endif
2003-05-19 23:33:41 +00:00
# endif
if ( ! pri_grab ( p , p - > pri ) )
pri_information ( p - > pri - > pri , p - > call , digit ) ;
else
ast_log ( LOG_WARNING , " Unable to grab PRI on span %d \n " , p - > span ) ;
pri_rel ( p - > pri ) ;
2003-03-24 22:12:11 +00:00
} else {
2003-03-25 19:08:46 +00:00
# else
{
# endif
2003-03-24 22:12:11 +00:00
zo . op = ZT_DIAL_OP_APPEND ;
zo . dialstr [ 0 ] = ' T ' ;
zo . dialstr [ 1 ] = digit ;
zo . dialstr [ 2 ] = 0 ;
if ( ( res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_DIAL , & zo ) ) )
ast_log ( LOG_WARNING , " Couldn't dial digit %c \n " , digit ) ;
else
p - > dialing = 1 ;
}
2003-02-07 19:23:19 +00:00
}
2001-10-09 02:06:21 +00:00
return res ;
}
static char * events [ ] = {
" No event " ,
" On hook " ,
" Ring/Answered " ,
" Wink/Flash " ,
" Alarm " ,
" No more alarm " ,
" HDLC Abort " ,
" HDLC Overrun " ,
" HDLC Bad FCS " ,
" Dial Complete " ,
" Ringer On " ,
" Ringer Off " ,
2003-02-07 19:23:19 +00:00
" Hook Transition Complete " ,
" Bits Changed " ,
" Pulse Start "
2001-10-09 02:06:21 +00:00
} ;
2003-02-28 06:00:18 +00:00
static struct {
int alarm ;
char * name ;
} alarms [ ] = {
{ ZT_ALARM_RED , " Red Alarm " } ,
{ ZT_ALARM_YELLOW , " Yellow Alarm " } ,
{ ZT_ALARM_BLUE , " Blue Alarm " } ,
{ ZT_ALARM_RECOVER , " Recovering " } ,
{ ZT_ALARM_LOOPBACK , " Loopback " } ,
{ ZT_ALARM_NOTOPEN , " Not Open " } ,
{ ZT_ALARM_NONE , " None " } ,
} ;
static char * alarm2str ( int alarm )
{
int x ;
for ( x = 0 ; x < sizeof ( alarms ) / sizeof ( alarms [ 0 ] ) ; x + + ) {
if ( alarms [ x ] . alarm & alarm )
return alarms [ x ] . name ;
}
return alarm ? " Unknown Alarm " : " No Alarm " ;
}
2001-10-09 02:06:21 +00:00
static char * event2str ( int event )
{
static char buf [ 256 ] ;
2003-02-07 19:23:19 +00:00
if ( ( event < 15 ) & & ( event > - 1 ) )
2001-10-09 02:06:21 +00:00
return events [ event ] ;
sprintf ( buf , " Event %d " , event ) ;
return buf ;
}
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
static int str2r2prot ( char * swtype )
{
if ( ! strcasecmp ( swtype , " ar " ) )
return MFCR2_PROT_ARGENTINA ;
/*endif*/
if ( ! strcasecmp ( swtype , " cn " ) )
return MFCR2_PROT_CHINA ;
/*endif*/
if ( ! strcasecmp ( swtype , " kr " ) )
return MFCR2_PROT_KOREA ;
/*endif*/
return - 1 ;
}
# endif
2001-10-09 02:06:21 +00:00
static char * sig2str ( int sig )
{
static char buf [ 256 ] ;
switch ( sig ) {
case SIG_EM :
return " E & M Immediate " ;
case SIG_EMWINK :
return " E & M Wink " ;
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
return " Feature Group D (DTMF) " ;
case SIG_FEATDMF :
return " Feature Group D (MF) " ;
case SIG_FEATB :
return " Feature Group B (MF) " ;
2001-10-09 02:06:21 +00:00
case SIG_FXSLS :
return " FXS Loopstart " ;
case SIG_FXSGS :
return " FXS Groundstart " ;
case SIG_FXSKS :
return " FXS Kewlstart " ;
case SIG_FXOLS :
return " FXO Loopstart " ;
case SIG_FXOGS :
return " FXO Groundstart " ;
case SIG_FXOKS :
return " FXO Kewlstart " ;
case SIG_PRI :
return " PRI Signalling " ;
2003-02-07 19:23:19 +00:00
case SIG_R2 :
return " R2 Signalling " ;
2003-03-17 18:11:33 +00:00
case SIG_SF :
2003-03-17 20:04:36 +00:00
return " SF (Tone) Signalling Immediate " ;
case SIG_SFWINK :
return " SF (Tone) Signalling Wink " ;
case SIG_SF_FEATD :
return " SF (Tone) Signalling with Feature Group D (DTMF) " ;
case SIG_SF_FEATDMF :
return " SF (Tone) Signallong with Feature Group D (MF) " ;
case SIG_SF_FEATB :
return " SF (Tone) Signalling with Feature Group B (MF) " ;
2002-06-24 17:59:56 +00:00
case 0 :
return " Pseudo Signalling " ;
2001-10-09 02:06:21 +00:00
default :
2002-06-24 17:59:56 +00:00
snprintf ( buf , sizeof ( buf ) , " Unknown signalling %d " , sig ) ;
2001-10-09 02:06:21 +00:00
return buf ;
}
}
2003-02-07 19:23:19 +00:00
static int conf_add ( int * confno , struct zt_subchannel * c , int index )
2001-10-09 02:06:21 +00:00
{
2003-02-07 19:23:19 +00:00
/* If the conference already exists, and we're already in it
don ' t bother doing anything */
ZT_CONFINFO zi ;
if ( ( * confno > 0 ) & & ( c - > curconfno = = * confno ) )
return 0 ;
if ( c - > curconfno > 0 ) {
ast_log ( LOG_WARNING , " Subchannel %d is already in conference %d, moving to %d \n " , c - > zfd , c - > curconfno , * confno ) ;
}
if ( c - > zfd < 0 )
return 0 ;
memset ( & zi , 0 , sizeof ( zi ) ) ;
zi . chan = 0 ;
zi . confno = * confno ;
if ( ! index ) {
/* Real-side and pseudo-side both participate in conference */
zi . confmode = ZT_CONF_REALANDPSEUDO | ZT_CONF_TALKER | ZT_CONF_LISTENER |
ZT_CONF_PSEUDO_TALKER | ZT_CONF_PSEUDO_LISTENER ;
} else
zi . confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER ;
if ( ioctl ( c - > zfd , ZT_SETCONF , & zi ) ) {
ast_log ( LOG_WARNING , " Failed to add %d to conference %d \n " , c - > zfd , * confno ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
2003-02-07 19:23:19 +00:00
c - > curconfno = zi . confno ;
* confno = zi . confno ;
ast_log ( LOG_DEBUG , " Added %d to conference %d \n " , c - > zfd , * confno ) ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
2003-02-07 19:23:19 +00:00
static int conf_del ( int * confno , struct zt_subchannel * c , int index )
2001-10-09 02:06:21 +00:00
{
2003-02-07 19:23:19 +00:00
ZT_CONFINFO zi ;
/* Can't delete from this conference if it's not 0 */
if ( ( * confno < 1 ) | |
/* Can't delete if there's no zfd */
( c - > zfd < 0 ) | |
/* Don't delete from the conference if it's not our conference */
( * confno ! = c - > curconfno )
/* Don't delete if we don't think it's conferenced at all (implied) */
) return 0 ;
memset ( & zi , 0 , sizeof ( zi ) ) ;
zi . chan = 0 ;
zi . confno = 0 ;
zi . confmode = 0 ;
if ( ioctl ( c - > zfd , ZT_SETCONF , & zi ) ) {
ast_log ( LOG_WARNING , " Failed to drop %d from conference %d \n " , c - > zfd , * confno ) ;
return - 1 ;
}
c - > curconfno = - 1 ;
ast_log ( LOG_DEBUG , " Removed %d from conference %d \n " , c - > zfd , * confno ) ;
return 0 ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
static int update_conf ( struct zt_pvt * p )
2001-10-09 02:06:21 +00:00
{
2003-02-07 19:23:19 +00:00
int needconf = 0 ;
int x ;
/* Update conference state in a stateless fashion */
/* Start with the obvious, general stuff */
for ( x = 0 ; x < 3 ; x + + ) {
if ( ( p - > subs [ x ] . zfd > - 1 ) & & p - > subs [ x ] . inthreeway ) {
conf_add ( & p - > confno , & p - > subs [ x ] , x ) ;
needconf + + ;
} else {
conf_del ( & p - > confno , & p - > subs [ x ] , x ) ;
}
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
/* If we have a slave, add him to our conference now */
for ( x = 0 ; x < MAX_SLAVES ; x + + ) {
if ( p - > slaves [ x ] ) {
conf_add ( & p - > confno , & p - > slaves [ x ] - > subs [ SUB_REAL ] , SUB_REAL ) ;
needconf + + ;
}
}
/* If we're supposed to be in there, do so now */
if ( p - > inconference & & ! p - > subs [ SUB_REAL ] . inthreeway ) {
conf_add ( & p - > confno , & p - > subs [ SUB_REAL ] , SUB_REAL ) ;
needconf + + ;
}
/* If we have a master, add ourselves to his conference */
if ( p - > master )
conf_add ( & p - > master - > confno , & p - > subs [ SUB_REAL ] , SUB_REAL ) ;
if ( ! needconf ) {
/* Nobody is left (or should be left) in our conference.
Kill it . */
p - > confno = - 1 ;
}
ast_log ( LOG_DEBUG , " Updated conferencing on %d, with %d conference users \n " , p - > channel , needconf ) ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
static void zt_enable_ec ( struct zt_pvt * p )
{
int x ;
int res ;
2003-02-07 19:23:19 +00:00
if ( p - > echocanon ) {
ast_log ( LOG_DEBUG , " Echo cancellation already on \n " ) ;
return ;
}
2001-12-29 18:04:21 +00:00
if ( p & & p - > echocancel ) {
2003-05-19 23:33:41 +00:00
if ( p - > sig = = SIG_PRI ) {
x = 1 ;
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_AUDIOMODE , & x ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to enable echo cancellation on channel %d \n " , p - > channel ) ;
}
2002-03-08 23:48:42 +00:00
x = p - > echocancel ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_ECHOCANCEL , & x ) ;
2001-10-09 02:06:21 +00:00
if ( res )
ast_log ( LOG_WARNING , " Unable to enable echo cancellation on channel %d \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
else {
p - > echocanon = 1 ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_DEBUG , " Enabled echo cancellation on channel %d \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
}
2002-03-08 23:48:42 +00:00
} else
ast_log ( LOG_DEBUG , " No echocancellation requested \n " ) ;
2001-10-09 02:06:21 +00:00
}
static void zt_disable_ec ( struct zt_pvt * p )
{
int x ;
int res ;
if ( p - > echocancel ) {
x = 0 ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_ECHOCANCEL , & x ) ;
2001-10-09 02:06:21 +00:00
if ( res )
ast_log ( LOG_WARNING , " Unable to disable echo cancellation on channel %d \n " , p - > channel ) ;
else
ast_log ( LOG_DEBUG , " disabled echo cancellation on channel %d \n " , p - > channel ) ;
}
2003-02-07 19:23:19 +00:00
p - > echocanon = 0 ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
int set_actual_gain ( int fd , int chan , float rxgain , float txgain , int law )
2001-10-09 02:06:21 +00:00
{
struct zt_gains g ;
float ltxgain ;
float lrxgain ;
int j , k ;
g . chan = chan ;
2003-03-20 16:58:45 +00:00
if ( ( rxgain ! = 0.0 ) | | ( txgain ! = 0.0 ) ) {
/* caluculate linear value of tx gain */
ltxgain = pow ( 10.0 , txgain / 20.0 ) ;
/* caluculate linear value of rx gain */
lrxgain = pow ( 10.0 , rxgain / 20.0 ) ;
if ( law = = ZT_LAW_ALAW ) {
for ( j = 0 ; j < 256 ; j + + ) {
k = ( int ) ( ( ( float ) AST_ALAW ( j ) ) * lrxgain ) ;
if ( k > 32767 ) k = 32767 ;
if ( k < - 32767 ) k = - 32767 ;
g . rxgain [ j ] = AST_LIN2A ( k ) ;
k = ( int ) ( ( ( float ) AST_ALAW ( j ) ) * ltxgain ) ;
if ( k > 32767 ) k = 32767 ;
if ( k < - 32767 ) k = - 32767 ;
g . txgain [ j ] = AST_LIN2A ( k ) ;
}
} else {
for ( j = 0 ; j < 256 ; j + + ) {
k = ( int ) ( ( ( float ) AST_MULAW ( j ) ) * lrxgain ) ;
if ( k > 32767 ) k = 32767 ;
if ( k < - 32767 ) k = - 32767 ;
g . rxgain [ j ] = AST_LIN2MU ( k ) ;
k = ( int ) ( ( ( float ) AST_MULAW ( j ) ) * ltxgain ) ;
if ( k > 32767 ) k = 32767 ;
if ( k < - 32767 ) k = - 32767 ;
g . txgain [ j ] = AST_LIN2MU ( k ) ;
}
2003-02-07 19:23:19 +00:00
}
} else {
for ( j = 0 ; j < 256 ; j + + ) {
2003-03-20 16:58:45 +00:00
g . rxgain [ j ] = j ;
g . txgain [ j ] = j ;
2003-02-07 19:23:19 +00:00
}
2001-10-09 02:06:21 +00:00
}
2003-03-20 16:58:45 +00:00
2001-10-09 02:06:21 +00:00
/* set 'em */
return ( ioctl ( fd , ZT_SETGAINS , & g ) ) ;
}
static inline int zt_set_hook ( int fd , int hs )
{
int x , res ;
x = hs ;
res = ioctl ( fd , ZT_HOOK , & x ) ;
if ( res < 0 )
2003-02-07 19:23:19 +00:00
{
if ( errno = = EINPROGRESS ) return 0 ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " zt hook failed: %s \n " , strerror ( errno ) ) ;
2003-02-07 19:23:19 +00:00
}
return res ;
}
static inline int zt_confmute ( struct zt_pvt * p , int muted )
{
2003-05-19 23:33:41 +00:00
int x , y , res ;
2003-02-07 19:23:19 +00:00
x = muted ;
2003-05-19 23:33:41 +00:00
if ( p - > sig = = SIG_PRI ) {
y = 1 ;
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_AUDIOMODE , & y ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to set audio mode on '%d' \n " , p - > channel ) ;
}
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_CONFMUTE , & x ) ;
if ( res < 0 )
ast_log ( LOG_WARNING , " zt confmute(%d) failed on channel %d: %s \n " , muted , p - > channel , strerror ( errno ) ) ;
2001-10-09 02:06:21 +00:00
return res ;
}
static int save_conference ( struct zt_pvt * p )
{
struct zt_confinfo c ;
int res ;
2003-02-07 19:23:19 +00:00
if ( p - > saveconf . confmode ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Can't save conference -- already in use \n " ) ;
return - 1 ;
}
2003-02-07 19:23:19 +00:00
p - > saveconf . chan = 0 ;
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GETCONF , & p - > saveconf ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to get conference info: %s \n " , strerror ( errno ) ) ;
2003-02-07 19:23:19 +00:00
p - > saveconf . confmode = 0 ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
c . chan = 0 ;
c . confno = 0 ;
c . confmode = ZT_CONF_NORMAL ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SETCONF , & c ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to set conference info: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Disabled conferencing \n " ) ;
return 0 ;
}
static int restore_conference ( struct zt_pvt * p )
{
int res ;
2003-02-07 19:23:19 +00:00
if ( p - > saveconf . confmode ) {
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SETCONF , & p - > saveconf ) ;
p - > saveconf . confmode = 0 ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to restore conference info: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Restored conferencing \n " ) ;
return 0 ;
}
static int send_callerid ( struct zt_pvt * p ) ;
int send_cwcidspill ( struct zt_pvt * p )
{
p - > callwaitcas = 0 ;
2003-02-07 19:23:19 +00:00
p - > cidcwexpire = 0 ;
2001-10-09 02:06:21 +00:00
p - > cidspill = malloc ( MAX_CALLERID_SIZE ) ;
if ( p - > cidspill ) {
memset ( p - > cidspill , 0x7f , MAX_CALLERID_SIZE ) ;
2003-02-07 19:23:19 +00:00
p - > cidlen = ast_callerid_callwaiting_generate ( p - > cidspill , p - > callwaitcid , AST_LAW ( p ) ) ;
2001-10-09 02:06:21 +00:00
/* Make sure we account for the end */
p - > cidlen + = READ_SIZE * 4 ;
p - > cidpos = 0 ;
send_callerid ( p ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " CPE supports Call Waiting Caller*ID. Sending '%s' \n " , p - > callwaitcid ) ;
} else return - 1 ;
return 0 ;
}
2002-03-08 23:48:42 +00:00
static int has_voicemail ( struct zt_pvt * p )
{
2003-02-07 19:23:19 +00:00
return ast_app_has_voicemail ( p - > mailbox ) ;
2002-03-08 23:48:42 +00:00
}
2001-10-09 02:06:21 +00:00
static int send_callerid ( struct zt_pvt * p )
{
/* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
int res ;
2003-02-07 19:23:19 +00:00
/* Take out of linear mode if necessary */
if ( p - > subs [ SUB_REAL ] . linear ) {
p - > subs [ SUB_REAL ] . linear = 0 ;
zt_setlinear ( p - > subs [ SUB_REAL ] . zfd , 0 ) ;
}
2001-10-09 02:06:21 +00:00
while ( p - > cidpos < p - > cidlen ) {
2003-02-07 19:23:19 +00:00
res = write ( p - > subs [ SUB_REAL ] . zfd , p - > cidspill + p - > cidpos , p - > cidlen - p - > cidpos ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
if ( errno = = EAGAIN )
return 0 ;
else {
ast_log ( LOG_WARNING , " write failed: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
}
if ( ! res )
return 0 ;
p - > cidpos + = res ;
}
free ( p - > cidspill ) ;
2003-02-07 19:23:19 +00:00
p - > cidspill = NULL ;
2001-10-09 02:06:21 +00:00
if ( p - > callwaitcas ) {
2003-02-07 19:23:19 +00:00
/* Wait for CID/CW to expire */
p - > cidcwexpire = CIDCW_EXPIRE_SAMPLES ;
2001-10-09 02:06:21 +00:00
} else
restore_conference ( p ) ;
return 0 ;
}
static int zt_callwait ( struct ast_channel * ast )
{
struct zt_pvt * p = ast - > pvt - > pvt ;
p - > callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES ;
if ( p - > cidspill ) {
ast_log ( LOG_WARNING , " Spill already exists?!? \n " ) ;
free ( p - > cidspill ) ;
}
p - > cidspill = malloc ( 2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4 ) ;
if ( p - > cidspill ) {
save_conference ( p ) ;
/* Silence */
memset ( p - > cidspill , 0x7f , 2400 + 600 + READ_SIZE * 4 ) ;
if ( ! p - > callwaitrings & & p - > callwaitingcallerid ) {
2003-02-07 19:23:19 +00:00
ast_gen_cas ( p - > cidspill , 1 , 2400 + 680 , AST_LAW ( p ) ) ;
2001-10-09 02:06:21 +00:00
p - > callwaitcas = 1 ;
p - > cidlen = 2400 + 680 + READ_SIZE * 4 ;
} else {
2003-02-07 19:23:19 +00:00
ast_gen_cas ( p - > cidspill , 1 , 2400 , AST_LAW ( p ) ) ;
2001-10-09 02:06:21 +00:00
p - > callwaitcas = 0 ;
p - > cidlen = 2400 + READ_SIZE * 4 ;
}
p - > cidpos = 0 ;
send_callerid ( p ) ;
} else {
ast_log ( LOG_WARNING , " Unable to create SAS/CAS spill \n " ) ;
return - 1 ;
}
return 0 ;
}
2003-02-07 19:23:19 +00:00
static int zt_call ( struct ast_channel * ast , char * rdest , int timeout )
2001-10-09 02:06:21 +00:00
{
struct zt_pvt * p = ast - > pvt - > pvt ;
int x , res , index ;
char * c , * n , * l ;
2003-02-07 19:23:19 +00:00
char * s ;
2001-10-09 02:06:21 +00:00
char callerid [ 256 ] ;
2003-02-07 19:23:19 +00:00
char dest [ 256 ] ;
strncpy ( dest , rdest , sizeof ( dest ) - 1 ) ;
2002-09-10 04:45:51 +00:00
if ( ( ast - > _state ! = AST_STATE_DOWN ) & & ( ast - > _state ! = AST_STATE_RESERVED ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " zt_call called on %s, neither down nor reserved \n " , ast - > name ) ;
return - 1 ;
}
2001-12-29 18:04:21 +00:00
p - > dialednone = 0 ;
2003-02-07 19:23:19 +00:00
if ( p - > radio ) /* if a radio channel, up immediately */
{
/* Special pseudo -- automatically up */
ast_setstate ( ast , AST_STATE_UP ) ;
return 0 ;
}
x = ZT_FLUSH_READ | ZT_FLUSH_WRITE ;
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_FLUSH , & x ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to flush input on channel %d \n " , p - > channel ) ;
p - > outgoing = 1 ;
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
if ( p - > owner = = ast ) {
/* Normal ring, on hook */
2002-09-10 04:45:51 +00:00
/* Don't send audio while on hook, until the call is answered */
p - > dialing = 1 ;
2001-10-09 02:06:21 +00:00
if ( p - > use_callerid ) {
/* Generate the Caller-ID spill if desired */
if ( p - > cidspill ) {
ast_log ( LOG_WARNING , " cidspill already exists?? \n " ) ;
free ( p - > cidspill ) ;
}
p - > cidspill = malloc ( MAX_CALLERID_SIZE ) ;
p - > callwaitcas = 0 ;
if ( p - > cidspill ) {
2003-02-07 19:23:19 +00:00
p - > cidlen = ast_callerid_generate ( p - > cidspill , ast - > callerid , AST_LAW ( p ) ) ;
2001-10-09 02:06:21 +00:00
p - > cidpos = 0 ;
send_callerid ( p ) ;
} else
ast_log ( LOG_WARNING , " Unable to generate CallerID spill \n " ) ;
}
2002-06-24 17:59:56 +00:00
/* Select proper cadence */
if ( ( p - > distinctivering > 0 ) & & ( p - > distinctivering < = NUM_CADENCE ) ) {
2003-02-07 19:23:19 +00:00
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SETCADENCE , & cadences [ p - > distinctivering - 1 ] ) )
2002-06-24 17:59:56 +00:00
ast_log ( LOG_WARNING , " Unable to set distinctive ring cadence %d on '%s' \n " , p - > distinctivering , ast - > name ) ;
p - > cidrings = cidrings [ p - > distinctivering - 1 ] ;
} else {
2003-02-07 19:23:19 +00:00
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SETCADENCE , NULL ) )
2002-06-24 17:59:56 +00:00
ast_log ( LOG_WARNING , " Unable to reset default ring on '%s' \n " , ast - > name ) ;
2003-04-15 17:09:34 +00:00
p - > cidrings = DEFAULT_CIDRINGS ;
2002-06-24 17:59:56 +00:00
}
2003-04-10 21:14:54 +00:00
/* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
c = strchr ( dest , ' / ' ) ;
if ( c )
c + + ;
if ( c & & ( strlen ( c ) < p - > stripmsd ) ) {
ast_log ( LOG_WARNING , " Number '%s' is shorter than stripmsd (%d) \n " , c , p - > stripmsd ) ;
c = NULL ;
}
if ( c ) {
p - > dop . op = ZT_DIAL_OP_REPLACE ;
2003-04-11 18:03:59 +00:00
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " Tw%s " , c ) ;
2003-04-10 21:14:54 +00:00
ast_log ( LOG_DEBUG , " FXO: setup deferred dialstring: %s \n " , c ) ;
} else {
strcpy ( p - > dop . dialstr , " " ) ;
}
2001-10-09 02:06:21 +00:00
x = ZT_RING ;
2003-02-07 19:23:19 +00:00
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_HOOK , & x ) & & ( errno ! = EINPROGRESS ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to ring phone: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
p - > dialing = 1 ;
} else {
/* Call waiting call */
p - > callwaitrings = 0 ;
if ( ast - > callerid )
2001-12-29 18:04:21 +00:00
strncpy ( p - > callwaitcid , ast - > callerid , sizeof ( p - > callwaitcid ) - 1 ) ;
2001-10-09 02:06:21 +00:00
else
strcpy ( p - > callwaitcid , " " ) ;
/* Call waiting tone instead */
if ( zt_callwait ( ast ) )
return - 1 ;
2003-02-07 19:23:19 +00:00
/* Make ring-back */
if ( tone_zone_play_tone ( p - > subs [ SUB_CALLWAIT ] . zfd , ZT_TONE_RINGTONE ) )
ast_log ( LOG_WARNING , " Unable to generate call-wait ring-back on channel %s \n " , ast - > name ) ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
if ( ast - > callerid )
strncpy ( callerid , ast - > callerid , sizeof ( callerid ) - 1 ) ;
else
strcpy ( callerid , " " ) ;
ast_callerid_parse ( callerid , & n , & l ) ;
if ( l ) {
ast_shrink_phone_number ( l ) ;
if ( ! ast_isphonenumber ( l ) )
l = NULL ;
}
if ( l )
strcpy ( p - > lastcallerid , l ) ;
else
strcpy ( p - > lastcallerid , " " ) ;
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_RINGING ) ;
2001-10-09 02:06:21 +00:00
index = zt_get_index ( ast , p , 0 ) ;
if ( index > - 1 ) {
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . needringing = 1 ;
2001-10-09 02:06:21 +00:00
}
break ;
case SIG_FXSLS :
case SIG_FXSGS :
case SIG_FXSKS :
case SIG_EMWINK :
case SIG_EM :
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2003-03-17 20:04:36 +00:00
case SIG_SFWINK :
case SIG_SF :
case SIG_SF_FEATD :
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
2001-10-09 02:06:21 +00:00
c = strchr ( dest , ' / ' ) ;
if ( c )
c + + ;
else
c = dest ;
if ( strlen ( c ) < p - > stripmsd ) {
ast_log ( LOG_WARNING , " Number '%s' is shorter than stripmsd (%d) \n " , c , p - > stripmsd ) ;
return - 1 ;
}
x = ZT_START ;
/* Start the trunk */
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_HOOK , & x ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
if ( errno ! = EINPROGRESS ) {
ast_log ( LOG_WARNING , " Unable to start channel: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
}
ast_log ( LOG_DEBUG , " Dialing '%s' \n " , c ) ;
p - > dop . op = ZT_DIAL_OP_REPLACE ;
if ( p - > sig = = SIG_FEATD ) {
if ( ast - > callerid ) {
2001-12-29 18:04:21 +00:00
strncpy ( callerid , ast - > callerid , sizeof ( callerid ) - 1 ) ;
2001-10-09 02:06:21 +00:00
ast_callerid_parse ( callerid , & n , & l ) ;
if ( l ) {
ast_shrink_phone_number ( l ) ;
if ( ! ast_isphonenumber ( l ) )
l = NULL ;
}
} else
l = NULL ;
if ( l )
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " T*%s*%s* " , l , c + p - > stripmsd ) ;
else
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " T**%s* " , c + p - > stripmsd ) ;
2002-06-24 17:59:56 +00:00
} else
if ( p - > sig = = SIG_FEATDMF ) {
if ( ast - > callerid ) {
strncpy ( callerid , ast - > callerid , sizeof ( callerid ) - 1 ) ;
ast_callerid_parse ( callerid , & n , & l ) ;
if ( l ) {
ast_shrink_phone_number ( l ) ;
if ( ! ast_isphonenumber ( l ) )
l = NULL ;
}
} else
l = NULL ;
if ( l )
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " M*00%s#*%s# " , l , c + p - > stripmsd ) ;
else
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " M*02#*%s# " , c + p - > stripmsd ) ;
} else
if ( p - > sig = = SIG_FEATB ) {
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " M*%s# " , c + p - > stripmsd ) ;
2001-10-09 02:06:21 +00:00
} else
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " T%s " , c + p - > stripmsd ) ;
if ( ! res ) {
2003-02-07 19:23:19 +00:00
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_DIAL , & p - > dop ) ) {
2001-10-09 02:06:21 +00:00
x = ZT_ONHOOK ;
2003-02-07 19:23:19 +00:00
ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_HOOK , & x ) ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Dialing failed on channel %d: %s \n " , p - > channel , strerror ( errno ) ) ;
return - 1 ;
}
} else
ast_log ( LOG_DEBUG , " Deferring dialing... \n " ) ;
p - > dialing = 1 ;
2001-12-29 18:04:21 +00:00
if ( strlen ( c + p - > stripmsd ) < 1 ) p - > dialednone = 1 ;
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_DIALING ) ;
2001-10-09 02:06:21 +00:00
break ;
# ifdef ZAPATA_PRI
case SIG_PRI :
c = strchr ( dest , ' / ' ) ;
if ( c )
c + + ;
else
c = dest ;
2003-05-19 23:33:41 +00:00
if ( ast - > callerid & & ! p - > hidecallerid ) {
2001-12-29 18:04:21 +00:00
strncpy ( callerid , ast - > callerid , sizeof ( callerid ) - 1 ) ;
2001-10-09 02:06:21 +00:00
ast_callerid_parse ( callerid , & n , & l ) ;
if ( l ) {
ast_shrink_phone_number ( l ) ;
if ( ! ast_isphonenumber ( l ) )
l = NULL ;
}
} else
l = NULL ;
if ( strlen ( c ) < p - > stripmsd ) {
ast_log ( LOG_WARNING , " Number '%s' is shorter than stripmsd (%d) \n " , c , p - > stripmsd ) ;
return - 1 ;
}
2003-02-07 19:23:19 +00:00
p - > dop . op = ZT_DIAL_OP_REPLACE ;
s = strchr ( c + p - > stripmsd , ' w ' ) ;
if ( s ) {
snprintf ( p - > dop . dialstr , sizeof ( p - > dop . dialstr ) , " T%s " , s ) ;
* s = ' \0 ' ;
} else {
strcpy ( p - > dop . dialstr , " " ) ;
}
2003-03-16 06:00:11 +00:00
if ( ! ( p - > call = pri_new_call ( p - > pri - > pri ) ) ) {
ast_log ( LOG_WARNING , " Unable to create call on channel %d \n " , p - > channel ) ;
return - 1 ;
}
2003-02-07 19:23:19 +00:00
if ( pri_call ( p - > pri - > pri , p - > call , p - > digital ? PRI_TRANS_CAP_DIGITAL : PRI_TRANS_CAP_SPEECH ,
p - > prioffset , p - > pri - > nodetype = = PRI_NETWORK ? 0 : 1 , 1 , l , p - > pri - > dialplan - 1 , n ,
2001-10-09 02:06:21 +00:00
l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE ,
2003-02-07 19:23:19 +00:00
c + p - > stripmsd , p - > pri - > dialplan - 1 ,
2001-12-29 18:04:21 +00:00
( ( p - > law = = ZT_LAW_ALAW ) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW ) ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to setup call to %s \n " , c + p - > stripmsd ) ;
return - 1 ;
}
2003-02-07 19:23:19 +00:00
ast_setstate ( ast , AST_STATE_DIALING ) ;
2001-10-09 02:06:21 +00:00
break ;
2002-06-24 17:59:56 +00:00
# endif
case 0 :
/* Special pseudo -- automatically up*/
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
2002-06-24 17:59:56 +00:00
break ;
2001-10-09 02:06:21 +00:00
default :
ast_log ( LOG_DEBUG , " not yet implemented \n " ) ;
return - 1 ;
}
return 0 ;
}
static int destroy_channel ( struct zt_pvt * prev , struct zt_pvt * cur , int now )
{
int owned = 0 ;
int i = 0 ;
if ( ! now ) {
if ( cur - > owner ) {
owned = 1 ;
}
for ( i = 0 ; i < 3 ; i + + ) {
2003-02-07 19:23:19 +00:00
if ( cur - > subs [ i ] . owner ) {
2001-10-09 02:06:21 +00:00
owned = 1 ;
}
}
if ( ! owned ) {
if ( prev ) {
prev - > next = cur - > next ;
} else {
iflist = cur - > next ;
}
2003-02-07 19:23:19 +00:00
if ( cur - > subs [ SUB_REAL ] . zfd > - 1 ) {
zt_close ( cur - > subs [ SUB_REAL ] . zfd ) ;
2001-10-09 02:06:21 +00:00
}
free ( cur ) ;
}
} else {
if ( prev ) {
prev - > next = cur - > next ;
} else {
iflist = cur - > next ;
}
2003-02-07 19:23:19 +00:00
if ( cur - > subs [ SUB_REAL ] . zfd > - 1 ) {
zt_close ( cur - > subs [ SUB_REAL ] . zfd ) ;
2001-10-09 02:06:21 +00:00
}
free ( cur ) ;
}
return 0 ;
}
static int zt_hangup ( struct ast_channel * ast )
{
int res ;
2001-12-29 18:04:21 +00:00
int index , x , law ;
2001-10-09 02:06:21 +00:00
static int restore_gains ( struct zt_pvt * p ) ;
struct zt_pvt * p = ast - > pvt - > pvt ;
struct zt_pvt * tmp = NULL ;
struct zt_pvt * prev = NULL ;
ZT_PARAMS par ;
if ( option_debug )
ast_log ( LOG_DEBUG , " zt_hangup(%s) \n " , ast - > name ) ;
if ( ! ast - > pvt - > pvt ) {
ast_log ( LOG_WARNING , " Asked to hangup channel not connected \n " ) ;
return 0 ;
}
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_lock ( & p - > lock ) ;
2001-10-09 02:06:21 +00:00
index = zt_get_index ( ast , p , 1 ) ;
2003-03-26 00:35:52 +00:00
if ( p - > sig = = SIG_PRI ) {
2003-05-19 23:33:41 +00:00
x = 1 ;
2003-03-26 00:35:52 +00:00
ast_channel_setoption ( ast , AST_OPTION_AUDIO_MODE , & x , sizeof ( char ) , 0 ) ;
}
2003-03-23 18:55:52 +00:00
2003-05-19 23:33:41 +00:00
x = 0 ;
zt_confmute ( p , 0 ) ;
2001-10-09 02:06:21 +00:00
restore_gains ( p ) ;
2003-02-07 19:23:19 +00:00
2003-04-24 20:13:23 +00:00
if ( p - > dsp )
ast_dsp_digitmode ( p - > dsp , DSP_DIGITMODE_DTMF | p - > dtmfrelax ) ;
2002-06-24 17:59:56 +00:00
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d \n " ,
p - > channel , index , p - > subs [ SUB_REAL ] . zfd , p - > subs [ SUB_CALLWAIT ] . zfd , p - > subs [ SUB_THREEWAY ] . zfd ) ;
2001-10-09 02:06:21 +00:00
p - > ignoredtmf = 0 ;
if ( index > - 1 ) {
/* Real channel, do some fixup */
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . owner = NULL ;
p - > subs [ index ] . needanswer = 0 ;
p - > subs [ index ] . needringing = 0 ;
p - > subs [ index ] . linear = 0 ;
p - > subs [ index ] . needcallerid = 0 ;
zt_setlinear ( p - > subs [ index ] . zfd , 0 ) ;
if ( index = = SUB_REAL ) {
if ( ( p - > subs [ SUB_CALLWAIT ] . zfd > - 1 ) & & ( p - > subs [ SUB_THREEWAY ] . zfd > - 1 ) ) {
ast_log ( LOG_DEBUG , " Normal call hung up with both three way call and a call waiting call in place? \n " ) ;
if ( p - > subs [ SUB_CALLWAIT ] . inthreeway ) {
/* We had flipped over to answer a callwait and now it's gone */
ast_log ( LOG_DEBUG , " We were flipped over to the callwait, moving back and unowning. \n " ) ;
/* Move to the call-wait, but un-own us until they flip back. */
swap_subs ( p , SUB_CALLWAIT , SUB_REAL ) ;
unalloc_sub ( p , SUB_CALLWAIT ) ;
p - > owner = NULL ;
} else {
/* The three way hung up, but we still have a call wait */
ast_log ( LOG_DEBUG , " We were in the threeway and have a callwait still. Ditching the threeway. \n " ) ;
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
if ( p - > subs [ SUB_REAL ] . inthreeway ) {
/* This was part of a three way call. Immediately make way for
another call */
ast_log ( LOG_DEBUG , " Call was complete, setting owner to former third call \n " ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
} else {
/* This call hasn't been completed yet... Set owner to NULL */
ast_log ( LOG_DEBUG , " Call was incomplete, setting owner to NULL \n " ) ;
p - > owner = NULL ;
}
p - > subs [ SUB_REAL ] . inthreeway = 0 ;
}
} else if ( p - > subs [ SUB_CALLWAIT ] . zfd > - 1 ) {
/* Move to the call-wait and switch back to them. */
swap_subs ( p , SUB_CALLWAIT , SUB_REAL ) ;
unalloc_sub ( p , SUB_CALLWAIT ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
if ( p - > subs [ SUB_REAL ] . owner - > bridge )
ast_moh_stop ( p - > subs [ SUB_REAL ] . owner - > bridge ) ;
} else if ( p - > subs [ SUB_THREEWAY ] . zfd > - 1 ) {
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
if ( p - > subs [ SUB_REAL ] . inthreeway ) {
/* This was part of a three way call. Immediately make way for
another call */
ast_log ( LOG_DEBUG , " Call was complete, setting owner to former third call \n " ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
} else {
/* This call hasn't been completed yet... Set owner to NULL */
ast_log ( LOG_DEBUG , " Call was incomplete, setting owner to NULL \n " ) ;
p - > owner = NULL ;
}
p - > subs [ SUB_REAL ] . inthreeway = 0 ;
}
} else if ( index = = SUB_CALLWAIT ) {
/* Ditch the holding callwait call, and immediately make it availabe */
if ( p - > subs [ SUB_CALLWAIT ] . inthreeway ) {
/* This is actually part of a three way, placed on hold. Place the third part
on music on hold now */
if ( p - > subs [ SUB_THREEWAY ] . owner & & p - > subs [ SUB_THREEWAY ] . owner - > bridge )
ast_moh_start ( p - > subs [ SUB_THREEWAY ] . owner - > bridge , NULL ) ;
p - > subs [ SUB_THREEWAY ] . inthreeway = 0 ;
/* Make it the call wait now */
swap_subs ( p , SUB_CALLWAIT , SUB_THREEWAY ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
} else
unalloc_sub ( p , SUB_CALLWAIT ) ;
} else if ( index = = SUB_THREEWAY ) {
if ( p - > subs [ SUB_CALLWAIT ] . inthreeway ) {
/* The other party of the three way call is currently in a call-wait state.
Start music on hold for them , and take the main guy out of the third call */
if ( p - > subs [ SUB_CALLWAIT ] . owner & & p - > subs [ SUB_CALLWAIT ] . owner - > bridge )
ast_moh_start ( p - > subs [ SUB_CALLWAIT ] . owner - > bridge , NULL ) ;
p - > subs [ SUB_CALLWAIT ] . inthreeway = 0 ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_REAL ] . inthreeway = 0 ;
2001-10-09 02:06:21 +00:00
/* If this was part of a three way call index, let us make
another three way call */
2003-02-07 19:23:19 +00:00
unalloc_sub ( p , SUB_THREEWAY ) ;
2001-10-09 02:06:21 +00:00
} else {
/* This wasn't any sort of call, but how are we an index? */
ast_log ( LOG_WARNING , " Index found but not any type of call? \n " ) ;
}
}
2002-06-24 17:59:56 +00:00
2003-02-07 19:23:19 +00:00
if ( ! p - > subs [ SUB_REAL ] . owner & & ! p - > subs [ SUB_CALLWAIT ] . owner & & ! p - > subs [ SUB_THREEWAY ] . owner ) {
2001-10-09 02:06:21 +00:00
p - > owner = NULL ;
p - > ringt = 0 ;
2002-06-24 17:59:56 +00:00
p - > distinctivering = 0 ;
p - > confirmanswer = 0 ;
p - > cidrings = 1 ;
2003-02-07 19:23:19 +00:00
p - > outgoing = 0 ;
p - > digital = 0 ;
p - > faxhandled = 0 ;
p - > pulsedial = 0 ;
p - > onhooktime = time ( NULL ) ;
2003-04-19 00:27:31 +00:00
# ifdef PRI_EVENT_PROCEEDING
2003-04-18 15:55:50 +00:00
p - > proceeding = 0 ;
2003-05-19 23:33:41 +00:00
# endif
# ifdef PRI_EVENT_SETUP_ACK
p - > setup_ack = 0 ;
2003-04-19 00:27:31 +00:00
# endif
2003-02-07 19:23:19 +00:00
if ( p - > dsp ) {
ast_dsp_free ( p - > dsp ) ;
p - > dsp = NULL ;
}
2003-05-19 23:33:41 +00:00
2001-12-29 18:04:21 +00:00
law = ZT_LAW_DEFAULT ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SETLAW , & law ) ;
2001-12-29 18:04:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to set law on channel %d to default \n " , p - > channel ) ;
2001-10-09 02:06:21 +00:00
/* Perform low level hangup if no owner left */
# ifdef ZAPATA_PRI
if ( p - > sig = = SIG_PRI ) {
if ( p - > call ) {
2003-04-22 18:47:49 +00:00
if ( ! pri_grab ( p , p - > pri ) ) {
2003-05-19 23:33:41 +00:00
if ( ! p - > alreadyhungup ) {
res = pri_disconnect ( p - > pri - > pri , p - > call , PRI_CAUSE_NORMAL_CLEARING ) ;
} else {
pri_release ( p - > pri - > pri , p - > call , - 1 ) ;
2003-02-07 19:23:19 +00:00
p - > call = NULL ;
p - > alreadyhungup = 0 ;
}
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " pri_disconnect failed \n " ) ;
pri_rel ( p - > pri ) ;
} else {
ast_log ( LOG_WARNING , " Unable to grab PRI on span %d \n " , p - > span ) ;
res = - 1 ;
}
} else
res = 0 ;
2002-03-08 23:48:42 +00:00
2002-06-24 17:59:56 +00:00
} else
2001-10-09 02:06:21 +00:00
# endif
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
if ( p - > sig = = SIG_R2 ) {
if ( p - > hasr2call ) {
mfcr2_DropCall ( p - > r2 , NULL , UC_NORMAL_CLEARING ) ;
p - > hasr2call = 0 ;
res = 0 ;
} else
res = 0 ;
} else
# endif
if ( p - > sig )
res = zt_set_hook ( p - > subs [ SUB_REAL ] . zfd , ZT_ONHOOK ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to hangup line %s \n " , ast - > name ) ;
}
switch ( p - > sig ) {
case SIG_FXOGS :
case SIG_FXOLS :
case SIG_FXOKS :
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GET_PARAMS , & par ) ;
2001-10-09 02:06:21 +00:00
if ( ! res ) {
#if 0
ast_log ( LOG_DEBUG , " Hanging up channel %d, offhook = %d \n " , p - > channel , par . rxisoffhook ) ;
# endif
/* If they're off hook, try playing congestion */
if ( par . rxisoffhook )
2003-02-07 19:23:19 +00:00
tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
else
2003-02-07 19:23:19 +00:00
tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , - 1 ) ;
2001-10-09 02:06:21 +00:00
}
break ;
default :
2003-02-07 19:23:19 +00:00
tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , - 1 ) ;
2001-10-09 02:06:21 +00:00
}
if ( p - > cidspill )
free ( p - > cidspill ) ;
2002-06-24 17:59:56 +00:00
if ( p - > sig )
zt_disable_ec ( p ) ;
2001-10-09 02:06:21 +00:00
x = 0 ;
ast_channel_setoption ( ast , AST_OPTION_TONE_VERIFY , & x , sizeof ( char ) , 0 ) ;
2001-12-29 18:04:21 +00:00
ast_channel_setoption ( ast , AST_OPTION_TDD , & x , sizeof ( char ) , 0 ) ;
p - > didtdd = 0 ;
2001-10-09 02:06:21 +00:00
p - > cidspill = NULL ;
p - > callwaitcas = 0 ;
p - > callwaiting = p - > permcallwaiting ;
p - > hidecallerid = p - > permhidecallerid ;
p - > dialing = 0 ;
2003-02-07 19:23:19 +00:00
strcpy ( p - > rdnis , " " ) ;
update_conf ( p ) ;
2003-05-19 23:33:41 +00:00
/* Restore data mode */
if ( p - > sig = = SIG_PRI ) {
x = 0 ;
ast_channel_setoption ( ast , AST_OPTION_AUDIO_MODE , & x , sizeof ( char ) , 0 ) ;
}
2001-10-09 02:06:21 +00:00
restart_monitor ( ) ;
}
2002-06-24 17:59:56 +00:00
2001-10-09 02:06:21 +00:00
p - > callwaitingrepeat = 0 ;
2003-02-07 19:23:19 +00:00
p - > cidcwexpire = 0 ;
2001-10-09 02:06:21 +00:00
ast - > pvt - > pvt = NULL ;
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_unlock ( & p - > lock ) ;
2001-10-09 02:06:21 +00:00
ast_pthread_mutex_lock ( & usecnt_lock ) ;
usecnt - - ;
if ( usecnt < 0 )
ast_log ( LOG_WARNING , " Usecnt < 0??? \n " ) ;
ast_pthread_mutex_unlock ( & usecnt_lock ) ;
ast_update_use_count ( ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Hungup '%s' \n " , ast - > name ) ;
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_lock ( & iflock ) ;
2001-10-09 02:06:21 +00:00
tmp = iflist ;
prev = NULL ;
if ( p - > destroy ) {
while ( tmp ) {
2002-06-24 17:59:56 +00:00
if ( tmp = = p ) {
2001-10-09 02:06:21 +00:00
destroy_channel ( prev , tmp , 0 ) ;
break ;
} else {
prev = tmp ;
tmp = tmp - > next ;
}
}
}
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_unlock ( & iflock ) ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
static int zt_answer ( struct ast_channel * ast )
{
struct zt_pvt * p = ast - > pvt - > pvt ;
int res = 0 ;
2003-02-07 19:23:19 +00:00
int index ;
int oldstate = ast - > _state ;
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
2003-04-22 18:47:49 +00:00
ast_pthread_mutex_lock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
index = zt_get_index ( ast , p , 0 ) ;
if ( index < 0 )
index = SUB_REAL ;
/* nothing to do if a radio channel */
2003-04-22 18:47:49 +00:00
if ( p - > radio ) {
ast_pthread_mutex_unlock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
return 0 ;
2003-04-22 18:47:49 +00:00
}
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FXSLS :
case SIG_FXSGS :
case SIG_FXSKS :
p - > ringt = 0 ;
/* Fall through */
case SIG_EM :
case SIG_EMWINK :
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2003-03-17 20:04:36 +00:00
case SIG_SF :
case SIG_SFWINK :
case SIG_SF_FEATD :
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
2001-10-09 02:06:21 +00:00
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
/* Pick up the line */
ast_log ( LOG_DEBUG , " Took %s off hook \n " , ast - > name ) ;
2003-02-07 19:23:19 +00:00
res = zt_set_hook ( p - > subs [ SUB_REAL ] . zfd , ZT_OFFHOOK ) ;
tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
2001-10-09 02:06:21 +00:00
p - > dialing = 0 ;
2003-02-07 19:23:19 +00:00
if ( ( index = = SUB_REAL ) & & p - > subs [ SUB_THREEWAY ] . inthreeway ) {
if ( oldstate = = AST_STATE_RINGING ) {
ast_log ( LOG_DEBUG , " Finally swapping real and threeway \n " ) ;
tone_zone_play_tone ( p - > subs [ SUB_THREEWAY ] . zfd , - 1 ) ;
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
}
}
2001-10-09 02:06:21 +00:00
break ;
# ifdef ZAPATA_PRI
case SIG_PRI :
/* Send a pri acknowledge */
2003-04-22 18:47:49 +00:00
if ( ! pri_grab ( p , p - > pri ) ) {
2001-10-09 02:06:21 +00:00
res = pri_answer ( p - > pri - > pri , p - > call , 0 , 1 ) ;
pri_rel ( p - > pri ) ;
} else {
ast_log ( LOG_WARNING , " Unable to grab PRI on span %d \n " , p - > span ) ;
res = - 1 ;
}
break ;
2003-02-07 19:23:19 +00:00
# endif
# ifdef ZAPATA_R2
case SIG_R2 :
res = mfcr2_AnswerCall ( p - > r2 , NULL ) ;
if ( res )
ast_log ( LOG_WARNING , " R2 Answer call failed :( on %s \n " , ast - > name ) ;
break ;
# endif
case 0 :
return 0 ;
2001-10-09 02:06:21 +00:00
default :
ast_log ( LOG_WARNING , " Don't know how to answer signalling %d (channel %d) \n " , p - > sig , p - > channel ) ;
2003-04-22 18:47:49 +00:00
res = - 1 ;
2001-10-09 02:06:21 +00:00
}
2003-04-22 18:47:49 +00:00
ast_pthread_mutex_unlock ( & p - > lock ) ;
2001-10-09 02:06:21 +00:00
return res ;
}
static int zt_setoption ( struct ast_channel * chan , int option , void * data , int datalen )
{
char * cp ;
2003-02-07 19:23:19 +00:00
int x ;
2001-10-09 02:06:21 +00:00
struct zt_pvt * p = chan - > pvt - > pvt ;
2001-12-29 18:04:21 +00:00
2003-03-23 17:14:29 +00:00
if ( ( option ! = AST_OPTION_TONE_VERIFY ) & & ( option ! = AST_OPTION_AUDIO_MODE ) & &
2003-02-07 19:23:19 +00:00
( option ! = AST_OPTION_TDD ) & & ( option ! = AST_OPTION_RELAXDTMF ) )
2001-10-09 02:06:21 +00:00
{
errno = ENOSYS ;
return - 1 ;
}
cp = ( char * ) data ;
if ( ( ! cp ) | | ( datalen < 1 ) )
{
errno = EINVAL ;
return - 1 ;
}
2001-12-29 18:04:21 +00:00
switch ( option ) {
case AST_OPTION_TONE_VERIFY :
2003-02-07 19:23:19 +00:00
if ( ! p - > dsp )
break ;
2001-12-29 18:04:21 +00:00
switch ( * cp ) {
case 1 :
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Set option TONE VERIFY, mode: MUTECONF(1) on %s \n " , chan - > name ) ;
ast_dsp_digitmode ( p - > dsp , DSP_DIGITMODE_MUTECONF | p - > dtmfrelax ) ; /* set mute mode if desired */
2001-12-29 18:04:21 +00:00
break ;
case 2 :
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s \n " , chan - > name ) ;
ast_dsp_digitmode ( p - > dsp , DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p - > dtmfrelax ) ; /* set mute mode if desired */
2001-12-29 18:04:21 +00:00
break ;
default :
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Set option TONE VERIFY, mode: OFF(0) on %s \n " , chan - > name ) ;
ast_dsp_digitmode ( p - > dsp , DSP_DIGITMODE_DTMF | p - > dtmfrelax ) ; /* set mute mode if desired */
2001-12-29 18:04:21 +00:00
break ;
}
2001-10-09 02:06:21 +00:00
break ;
2001-12-29 18:04:21 +00:00
case AST_OPTION_TDD : /* turn on or off TDD */
if ( ! * cp ) { /* turn it off */
ast_log ( LOG_DEBUG , " Set option TDD MODE, value: OFF(0) on %s \n " , chan - > name ) ;
if ( p - > tdd ) tdd_free ( p - > tdd ) ;
p - > tdd = 0 ;
2002-06-24 17:59:56 +00:00
p - > mate = 0 ;
2001-12-29 18:04:21 +00:00
break ;
}
2002-06-24 17:59:56 +00:00
if ( * cp = = 2 )
ast_log ( LOG_DEBUG , " Set option TDD MODE, value: MATE(2) on %s \n " , chan - > name ) ;
else ast_log ( LOG_DEBUG , " Set option TDD MODE, value: ON(1) on % s \ n " ,chan->name) ;
p - > mate = 0 ;
zt_disable_ec ( p ) ;
2001-12-29 18:04:21 +00:00
/* otherwise, turn it on */
if ( ! p - > didtdd ) { /* if havent done it yet */
unsigned char mybuf [ 41000 ] , * buf ;
int size , res , fd , len ;
2003-02-07 19:23:19 +00:00
int index ;
2001-12-29 18:04:21 +00:00
fd_set wfds , efds ;
buf = mybuf ;
memset ( buf , 0x7f , sizeof ( mybuf ) ) ; /* set to silence */
ast_tdd_gen_ecdisa ( buf + 16000 , 16000 ) ; /* put in tone */
len = 40000 ;
2003-02-07 19:23:19 +00:00
index = zt_get_index ( chan , p , 0 ) ;
if ( index < 0 ) {
ast_log ( LOG_WARNING , " No index in TDD? \n " ) ;
return - 1 ;
}
fd = p - > subs [ index ] . zfd ;
2001-12-29 18:04:21 +00:00
while ( len ) {
if ( ast_check_hangup ( chan ) ) return - 1 ;
size = len ;
if ( size > READ_SIZE )
size = READ_SIZE ;
FD_ZERO ( & wfds ) ;
FD_ZERO ( & efds ) ;
FD_SET ( fd , & wfds ) ;
FD_SET ( fd , & efds ) ;
2003-05-19 23:33:41 +00:00
res = ast_select ( fd + 1 , NULL , & wfds , & efds , NULL ) ;
2001-12-29 18:04:21 +00:00
if ( ! res ) {
ast_log ( LOG_DEBUG , " select (for write) ret. 0 on channel %d \n " , p - > channel ) ;
continue ;
}
/* if got exception */
if ( FD_ISSET ( fd , & efds ) ) return - 1 ;
if ( ! FD_ISSET ( fd , & wfds ) ) {
ast_log ( LOG_DEBUG , " write fd not ready on channel %d \n " , p - > channel ) ;
continue ;
}
res = write ( fd , buf , size ) ;
if ( res ! = size ) {
if ( res = = - 1 ) return - 1 ;
ast_log ( LOG_DEBUG , " Write returned %d (%s) on channel %d \n " , res , strerror ( errno ) , p - > channel ) ;
break ;
}
len - = size ;
buf + = size ;
}
p - > didtdd = 1 ; /* set to have done it now */
}
2002-06-24 17:59:56 +00:00
if ( * cp = = 2 ) { /* Mate mode */
if ( p - > tdd ) tdd_free ( p - > tdd ) ;
p - > tdd = 0 ;
p - > mate = 1 ;
break ;
}
2001-12-29 18:04:21 +00:00
if ( ! p - > tdd ) { /* if we dont have one yet */
p - > tdd = tdd_new ( ) ; /* allocate one */
}
2001-10-09 02:06:21 +00:00
break ;
2003-02-07 19:23:19 +00:00
case AST_OPTION_RELAXDTMF : /* Relax DTMF decoding (or not) */
if ( ! * cp )
{
ast_log ( LOG_DEBUG , " Set option RELAX DTMF, value: OFF(0) on %s \n " , chan - > name ) ;
x = 0 ;
}
else
{
ast_log ( LOG_DEBUG , " Set option RELAX DTMF, value: ON(1) on %s \n " , chan - > name ) ;
x = 1 ;
}
ast_dsp_digitmode ( p - > dsp , x ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF | p - > dtmfrelax ) ;
break ;
2003-03-23 17:14:29 +00:00
case AST_OPTION_AUDIO_MODE : /* Set AUDIO mode (or not) */
if ( ! * cp )
{
ast_log ( LOG_DEBUG , " Set option AUDIO MODE, value: OFF(0) on %s \n " , chan - > name ) ;
x = 0 ;
2003-03-23 18:55:52 +00:00
zt_disable_ec ( p ) ;
2003-03-23 17:14:29 +00:00
}
else
{
ast_log ( LOG_DEBUG , " Set option AUDIO MODE, value: ON(1) on %s \n " , chan - > name ) ;
x = 1 ;
}
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_AUDIOMODE , & x ) = = - 1 )
2003-03-26 00:25:09 +00:00
ast_log ( LOG_WARNING , " Unable to set audio mode on channel %d to %d \n " , p - > channel , x ) ;
2003-03-23 17:14:29 +00:00
break ;
2001-10-09 02:06:21 +00:00
}
errno = 0 ;
return 0 ;
}
2003-02-07 19:23:19 +00:00
static void zt_unlink ( struct zt_pvt * slave , struct zt_pvt * master )
{
/* Unlink a specific slave or all slaves/masters from a given master */
int x ;
int hasslaves ;
if ( ! master )
return ;
hasslaves = 0 ;
for ( x = 0 ; x < MAX_SLAVES ; x + + ) {
if ( master - > slaves [ x ] ) {
if ( ! slave | | ( master - > slaves [ x ] = = slave ) ) {
/* Take slave out of the conference */
ast_log ( LOG_DEBUG , " Unlinking slave %d from %d \n " , master - > slaves [ x ] - > channel , master - > channel ) ;
conf_del ( & master - > confno , & master - > slaves [ x ] - > subs [ SUB_REAL ] , SUB_REAL ) ;
master - > slaves [ x ] - > master = NULL ;
master - > slaves [ x ] = NULL ;
} else
hasslaves = 1 ;
}
if ( ! hasslaves )
master - > inconference = 0 ;
}
if ( ! slave ) {
if ( master - > master ) {
/* Take master out of the conference */
conf_del ( & master - > master - > confno , & master - > subs [ SUB_REAL ] , SUB_REAL ) ;
hasslaves = 0 ;
for ( x = 0 ; x < MAX_SLAVES ; x + + ) {
if ( master - > master - > slaves [ x ] = = master )
master - > master - > slaves [ x ] = NULL ;
else if ( master - > master - > slaves [ x ] )
hasslaves = 1 ;
}
if ( ! hasslaves )
master - > master - > inconference = 0 ;
}
master - > master = NULL ;
}
update_conf ( master ) ;
}
static void zt_link ( struct zt_pvt * slave , struct zt_pvt * master ) {
int x ;
if ( ! slave | | ! master ) {
ast_log ( LOG_WARNING , " Tried to link to/from NULL?? \n " ) ;
return ;
}
for ( x = 0 ; x < MAX_SLAVES ; x + + ) {
if ( ! master - > slaves [ x ] ) {
master - > slaves [ x ] = slave ;
break ;
}
}
if ( x > = MAX_SLAVES ) {
ast_log ( LOG_WARNING , " Replacing slave %d with new slave, %d \n " , master - > slaves [ MAX_SLAVES - 1 ] - > channel , slave - > channel ) ;
master - > slaves [ MAX_SLAVES - 1 ] = slave ;
}
if ( slave - > master )
ast_log ( LOG_WARNING , " Replacing master %d with new master, %d \n " , slave - > master - > channel , master - > channel ) ;
slave - > master = master ;
ast_log ( LOG_DEBUG , " Making %d slave to master %d at %d \n " , slave - > channel , master - > channel , x ) ;
}
2001-10-09 02:06:21 +00:00
static int zt_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , int flags , struct ast_frame * * fo , struct ast_channel * * rc )
{
struct ast_channel * who = NULL , * cs [ 3 ] ;
2003-02-07 19:23:19 +00:00
struct zt_pvt * p0 , * p1 , * op0 , * op1 ;
struct zt_pvt * master = NULL , * slave = NULL ;
2001-10-09 02:06:21 +00:00
struct ast_frame * f ;
2003-02-07 19:23:19 +00:00
int to ;
int inconf = 0 ;
int nothingok = 0 ;
int ofd1 , ofd2 ;
int oi1 , oi2 , i1 = - 1 , i2 = - 1 , t1 , t2 ;
int os1 = - 1 , os2 = - 1 ;
struct ast_channel * oc1 , * oc2 ;
/* if need DTMF, cant native bridge */
2001-10-09 02:06:21 +00:00
if ( flags & ( AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1 ) )
return - 2 ;
2003-02-07 19:23:19 +00:00
p0 = c0 - > pvt - > pvt ;
p1 = c1 - > pvt - > pvt ;
/* cant do pseudo-channels here */
if ( ( ! p0 - > sig ) | | ( ! p1 - > sig ) ) return - 2 ;
2003-05-19 23:33:41 +00:00
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_lock ( & c0 - > lock ) ;
ast_pthread_mutex_lock ( & c1 - > lock ) ;
2003-02-07 19:23:19 +00:00
op0 = p0 = c0 - > pvt - > pvt ;
op1 = p1 = c1 - > pvt - > pvt ;
ofd1 = c0 - > fds [ 0 ] ;
ofd2 = c1 - > fds [ 0 ] ;
oi1 = zt_get_index ( c0 , p0 , 0 ) ;
oi2 = zt_get_index ( c1 , p1 , 0 ) ;
oc1 = p0 - > owner ;
oc2 = p1 - > owner ;
if ( ( oi1 < 0 ) | | ( oi2 < 0 ) )
return - 1 ;
ast_pthread_mutex_lock ( & p0 - > lock ) ;
if ( pthread_mutex_trylock ( & p1 - > lock ) ) {
/* Don't block, due to potential for deadlock */
ast_pthread_mutex_unlock ( & p0 - > lock ) ;
ast_pthread_mutex_unlock ( & c0 - > lock ) ;
ast_pthread_mutex_unlock ( & c1 - > lock ) ;
ast_log ( LOG_NOTICE , " Avoiding deadlock... \n " ) ;
2001-10-09 02:06:21 +00:00
return - 3 ;
}
2003-02-07 19:23:19 +00:00
if ( ( oi1 = = SUB_REAL ) & & ( oi2 = = SUB_REAL ) ) {
if ( ! p0 - > owner | | ! p1 - > owner ) {
/* Currently unowned -- Do nothing. */
nothingok = 1 ;
} else {
/* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
if ( ! p0 - > subs [ SUB_CALLWAIT ] . inthreeway & & ! p1 - > subs [ SUB_REAL ] . inthreeway ) {
master = p0 ;
slave = p1 ;
inconf = 1 ;
} else if ( ! p1 - > subs [ SUB_CALLWAIT ] . inthreeway & & ! p0 - > subs [ SUB_REAL ] . inthreeway ) {
master = p1 ;
slave = p0 ;
inconf = 1 ;
} else {
ast_log ( LOG_WARNING , " Huh? Both calls are callwaits or 3-ways? That's clever...? \n " ) ;
ast_log ( LOG_WARNING , " p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d \n " , p0 - > channel , oi1 , ( p0 - > subs [ SUB_CALLWAIT ] . zfd > - 1 ) ? 1 : 0 , p0 - > subs [ SUB_REAL ] . inthreeway ,
p0 - > channel , oi1 , ( p1 - > subs [ SUB_CALLWAIT ] . zfd > - 1 ) ? 1 : 0 , p1 - > subs [ SUB_REAL ] . inthreeway ) ;
}
}
} else if ( ( oi1 = = SUB_REAL ) & & ( oi2 = = SUB_THREEWAY ) ) {
if ( p1 - > subs [ SUB_THREEWAY ] . inthreeway ) {
master = p1 ;
slave = p0 ;
} else {
nothingok = 1 ;
}
} else if ( ( oi1 = = SUB_THREEWAY ) & & ( oi2 = = SUB_REAL ) ) {
if ( p0 - > subs [ SUB_THREEWAY ] . inthreeway ) {
master = p0 ;
slave = p1 ;
} else {
nothingok = 1 ;
}
} else if ( ( oi1 = = SUB_REAL ) & & ( oi2 = = SUB_CALLWAIT ) ) {
/* We have a real and a call wait. If we're in a three way call, put us in it, otherwise,
don ' t put us in anything */
if ( p1 - > subs [ SUB_CALLWAIT ] . inthreeway ) {
master = p1 ;
slave = p0 ;
} else {
nothingok = 1 ;
}
} else if ( ( oi1 = = SUB_CALLWAIT ) & & ( oi2 = = SUB_REAL ) ) {
/* Same as previous */
if ( p0 - > subs [ SUB_CALLWAIT ] . inthreeway ) {
master = p0 ;
slave = p1 ;
} else {
nothingok = 1 ;
}
}
ast_log ( LOG_DEBUG , " master: %d, slave: %d, nothingok: %d \n " ,
master ? master - > channel : 0 , slave ? slave - > channel : 0 , nothingok ) ;
if ( master & & slave ) {
/* Stop any tones, or play ringtone as appropriate. If they're bridged
in an active threeway call with a channel that is ringing , we should
indicate ringing . */
if ( ( oi2 = = SUB_THREEWAY ) & &
p1 - > subs [ SUB_THREEWAY ] . inthreeway & &
p1 - > subs [ SUB_REAL ] . owner & &
p1 - > subs [ SUB_REAL ] . inthreeway & &
( p1 - > subs [ SUB_REAL ] . owner - > _state = = AST_STATE_RINGING ) ) {
ast_log ( LOG_DEBUG , " Playing ringback on %s since %s is in a ringing three-way \n " , c0 - > name , c1 - > name ) ;
tone_zone_play_tone ( p0 - > subs [ oi1 ] . zfd , ZT_TONE_RINGTONE ) ;
os2 = p1 - > subs [ SUB_REAL ] . owner - > _state ;
} else {
ast_log ( LOG_DEBUG , " Stoping tones on %d/%d talking to %d/%d \n " , p0 - > channel , oi1 , p1 - > channel , oi2 ) ;
tone_zone_play_tone ( p0 - > subs [ oi1 ] . zfd , - 1 ) ;
}
if ( ( oi1 = = SUB_THREEWAY ) & &
p0 - > subs [ SUB_THREEWAY ] . inthreeway & &
p0 - > subs [ SUB_REAL ] . owner & &
p0 - > subs [ SUB_REAL ] . inthreeway & &
( p0 - > subs [ SUB_REAL ] . owner - > _state = = AST_STATE_RINGING ) ) {
ast_log ( LOG_DEBUG , " Playing ringback on %s since %s is in a ringing three-way \n " , c1 - > name , c0 - > name ) ;
tone_zone_play_tone ( p1 - > subs [ oi2 ] . zfd , ZT_TONE_RINGTONE ) ;
os1 = p0 - > subs [ SUB_REAL ] . owner - > _state ;
} else {
ast_log ( LOG_DEBUG , " Stoping tones on %d/%d talking to %d/%d \n " , p1 - > channel , oi2 , p0 - > channel , oi1 ) ;
tone_zone_play_tone ( p1 - > subs [ oi1 ] . zfd , - 1 ) ;
}
if ( ( oi1 = = SUB_REAL ) & & ( oi2 = = SUB_REAL ) ) {
if ( ! p0 - > echocanbridged | | ! p1 - > echocanbridged ) {
/* Disable echo cancellation if appropriate */
zt_disable_ec ( p0 ) ;
zt_disable_ec ( p1 ) ;
}
}
zt_link ( slave , master ) ;
master - > inconference = inconf ;
} else if ( ! nothingok )
ast_log ( LOG_WARNING , " Can't link %d/%s with %d/%s \n " , p0 - > channel , subnames [ oi1 ] , p1 - > channel , subnames [ oi2 ] ) ;
update_conf ( p0 ) ;
update_conf ( p1 ) ;
t1 = p0 - > subs [ SUB_REAL ] . inthreeway ;
t2 = p1 - > subs [ SUB_REAL ] . inthreeway ;
ast_pthread_mutex_unlock ( & p0 - > lock ) ;
ast_pthread_mutex_unlock ( & p1 - > lock ) ;
2001-10-09 02:06:21 +00:00
2003-02-07 19:23:19 +00:00
ast_pthread_mutex_unlock ( & c0 - > lock ) ;
ast_pthread_mutex_unlock ( & c1 - > lock ) ;
/* Native bridge failed */
if ( ( ! master | | ! slave ) & & ! nothingok ) {
if ( op0 = = p0 )
zt_enable_ec ( p0 ) ;
if ( op1 = = p1 )
zt_enable_ec ( p1 ) ;
return - 1 ;
}
2001-10-09 02:06:21 +00:00
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
2003-02-07 19:23:19 +00:00
cs [ 2 ] = NULL ;
2001-10-09 02:06:21 +00:00
for ( ; ; ) {
2003-02-07 19:23:19 +00:00
/* Here's our main loop... Start by locking things, looking for private parts,
and then balking if anything is wrong */
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_lock ( & c0 - > lock ) ;
ast_pthread_mutex_lock ( & c1 - > lock ) ;
2001-10-09 02:06:21 +00:00
p0 = c0 - > pvt - > pvt ;
p1 = c1 - > pvt - > pvt ;
2003-02-07 19:23:19 +00:00
if ( op0 = = p0 )
i1 = zt_get_index ( c0 , p0 , 1 ) ;
if ( op1 = = p1 )
i2 = zt_get_index ( c1 , p1 , 1 ) ;
ast_pthread_mutex_unlock ( & c0 - > lock ) ;
ast_pthread_mutex_unlock ( & c1 - > lock ) ;
if ( ( op0 ! = p0 ) | | ( op1 ! = p1 ) | |
( ofd1 ! = c0 - > fds [ 0 ] ) | |
( ofd2 ! = c1 - > fds [ 0 ] ) | |
( p0 - > subs [ SUB_REAL ] . owner & & ( os1 > - 1 ) & & ( os1 ! = p0 - > subs [ SUB_REAL ] . owner - > _state ) ) | |
( p1 - > subs [ SUB_REAL ] . owner & & ( os2 > - 1 ) & & ( os2 ! = p1 - > subs [ SUB_REAL ] . owner - > _state ) ) | |
( oc1 ! = p0 - > owner ) | |
( oc2 ! = p1 - > owner ) | |
( t1 ! = p0 - > subs [ SUB_REAL ] . inthreeway ) | |
( t2 ! = p1 - > subs [ SUB_REAL ] . inthreeway ) | |
( oi1 ! = i1 ) | |
( oi2 ! = i2 ) ) {
if ( slave & & master )
zt_unlink ( slave , master ) ;
ast_log ( LOG_DEBUG , " Something changed out on %d/%d to %d/%d, returning -3 to restart \n " ,
op0 - > channel , oi1 , op1 - > channel , oi2 ) ;
if ( op0 = = p0 )
2002-09-10 04:45:51 +00:00
zt_enable_ec ( p0 ) ;
2003-02-07 19:23:19 +00:00
if ( op1 = = p1 )
2002-09-10 04:45:51 +00:00
zt_enable_ec ( p1 ) ;
2003-02-07 19:23:19 +00:00
return - 3 ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
to = - 1 ;
2001-10-09 02:06:21 +00:00
who = ast_waitfor_n ( cs , 2 , & to ) ;
if ( ! who ) {
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Ooh, empty read... \n " ) ;
2001-10-09 02:06:21 +00:00
continue ;
}
2003-02-07 19:23:19 +00:00
if ( who - > pvt - > pvt = = op0 )
op0 - > ignoredtmf = 1 ;
else if ( who - > pvt - > pvt = = op1 )
op1 - > ignoredtmf = 1 ;
2001-10-09 02:06:21 +00:00
f = ast_read ( who ) ;
2003-02-07 19:23:19 +00:00
if ( who - > pvt - > pvt = = op0 )
op0 - > ignoredtmf = 0 ;
else if ( who - > pvt - > pvt = = op1 )
op1 - > ignoredtmf = 0 ;
2001-10-09 02:06:21 +00:00
if ( ! f ) {
* fo = NULL ;
* rc = who ;
2003-02-07 19:23:19 +00:00
if ( slave & & master )
zt_unlink ( slave , master ) ;
if ( op0 = = p0 )
zt_enable_ec ( p0 ) ;
if ( op1 = = p1 )
zt_enable_ec ( p1 ) ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
2003-02-07 19:23:19 +00:00
if ( f - > frametype = = AST_FRAME_DTMF ) {
if ( ( ( who = = c0 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) | |
( ( who = = c1 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) ) {
* fo = f ;
* rc = who ;
if ( slave & & master )
zt_unlink ( slave , master ) ;
return 0 ;
} else if ( ( who = = c0 ) & & p0 - > pulsedial ) {
ast_write ( c1 , f ) ;
} else if ( ( who = = c1 ) & & p1 - > pulsedial ) {
ast_write ( c0 , f ) ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
}
ast_frfree ( f ) ;
2001-10-09 02:06:21 +00:00
/* Swap who gets priority */
cs [ 2 ] = cs [ 0 ] ;
cs [ 0 ] = cs [ 1 ] ;
cs [ 1 ] = cs [ 2 ] ;
}
}
static int zt_indicate ( struct ast_channel * chan , int condition ) ;
static int zt_fixup ( struct ast_channel * oldchan , struct ast_channel * newchan )
{
struct zt_pvt * p = newchan - > pvt - > pvt ;
int x ;
ast_log ( LOG_DEBUG , " New owner for channel %d is %s \n " , p - > channel , newchan - > name ) ;
2003-02-07 19:23:19 +00:00
if ( p - > owner = = oldchan )
p - > owner = newchan ;
2001-10-09 02:06:21 +00:00
for ( x = 0 ; x < 3 ; x + + )
2003-02-07 19:23:19 +00:00
if ( p - > subs [ x ] . owner = = oldchan ) {
if ( ! x )
zt_unlink ( NULL , p ) ;
p - > subs [ x ] . owner = newchan ;
}
2002-09-10 04:45:51 +00:00
if ( newchan - > _state = = AST_STATE_RINGING )
2001-10-09 02:06:21 +00:00
zt_indicate ( newchan , AST_CONTROL_RINGING ) ;
2003-02-07 19:23:19 +00:00
update_conf ( p ) ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
static int zt_ring_phone ( struct zt_pvt * p )
{
int x ;
int res ;
/* Make sure our transmit state is on hook */
x = 0 ;
x = ZT_ONHOOK ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_HOOK , & x ) ;
2001-10-09 02:06:21 +00:00
do {
x = ZT_RING ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_HOOK , & x ) ;
2001-10-09 02:06:21 +00:00
#if 0
printf ( " Res: %d, error: %s \n " , res , strerror ( errno ) ) ;
# endif
if ( res ) {
switch ( errno ) {
case EBUSY :
case EINTR :
/* Wait just in case */
usleep ( 10000 ) ;
continue ;
case EINPROGRESS :
res = 0 ;
break ;
default :
ast_log ( LOG_WARNING , " Couldn't ring the phone: %s \n " , strerror ( errno ) ) ;
res = 0 ;
}
}
} while ( res ) ;
return res ;
}
static void * ss_thread ( void * data ) ;
static struct ast_channel * zt_new ( struct zt_pvt * , int , int , int , int ) ;
static int attempt_transfer ( struct zt_pvt * p )
{
/* In order to transfer, we need at least one of the channels to
actually be in a call bridge . We can ' t conference two applications
together ( but then , why would we want to ? ) */
2003-02-07 19:23:19 +00:00
if ( p - > subs [ SUB_REAL ] . owner - > bridge ) {
/* The three-way person we're about to transfer to could still be in MOH, so
stop if now if appropriate */
if ( p - > subs [ SUB_THREEWAY ] . owner - > bridge )
ast_moh_stop ( p - > subs [ SUB_THREEWAY ] . owner - > bridge ) ;
if ( p - > subs [ SUB_THREEWAY ] . owner - > _state = = AST_STATE_RINGING ) {
ast_indicate ( p - > subs [ SUB_REAL ] . owner - > bridge , AST_CONTROL_RINGING ) ;
}
if ( ast_channel_masquerade ( p - > subs [ SUB_THREEWAY ] . owner , p - > subs [ SUB_REAL ] . owner - > bridge ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to masquerade %s as %s \n " ,
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_REAL ] . owner - > bridge - > name , p - > subs [ SUB_THREEWAY ] . owner - > name ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
/* Orphan the channel */
2003-02-07 19:23:19 +00:00
unalloc_sub ( p , SUB_THREEWAY ) ;
} else if ( p - > subs [ SUB_THREEWAY ] . owner - > bridge ) {
if ( p - > subs [ SUB_REAL ] . owner - > _state = = AST_STATE_RINGING ) {
ast_indicate ( p - > subs [ SUB_THREEWAY ] . owner - > bridge , AST_CONTROL_RINGING ) ;
}
ast_moh_stop ( p - > subs [ SUB_THREEWAY ] . owner - > bridge ) ;
if ( ast_channel_masquerade ( p - > subs [ SUB_REAL ] . owner , p - > subs [ SUB_THREEWAY ] . owner - > bridge ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to masquerade %s as %s \n " ,
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_THREEWAY ] . owner - > bridge - > name , p - > subs [ SUB_REAL ] . owner - > name ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
2003-02-07 19:23:19 +00:00
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
/* Tell the caller not to hangup */
return 1 ;
2001-10-09 02:06:21 +00:00
} else {
ast_log ( LOG_DEBUG , " Neither %s nor %s are in a bridge, nothing to transfer \n " ,
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_REAL ] . owner - > name , p - > subs [ SUB_THREEWAY ] . owner - > name ) ;
p - > subs [ SUB_THREEWAY ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2001-10-09 02:06:21 +00:00
}
return 0 ;
}
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
static struct ast_frame * handle_r2_event ( struct zt_pvt * p , mfcr2_event_t * e , int index )
{
struct ast_frame * f ;
f = & p - > subs [ index ] . f ;
if ( ! p - > r2 ) {
ast_log ( LOG_WARNING , " Huh? No R2 structure :( \n " ) ;
return NULL ;
}
switch ( e - > e ) {
case MFCR2_EVENT_BLOCKED :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Channel %d blocked \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_UNBLOCKED :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Channel %d unblocked \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_CONFIG_ERR :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Config error on channel %d \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_RING :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Ring on channel %d \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_HANGUP :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Hangup on channel %d \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_RINGING :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Ringing on channel %d \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_ANSWER :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Answer on channel %d \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_HANGUP_ACK :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Hangup ACK on channel %d \n " , p - > channel ) ;
break ;
case MFCR2_EVENT_IDLE :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Idle on channel %d \n " , p - > channel ) ;
break ;
default :
ast_log ( LOG_WARNING , " Unknown MFC/R2 event %d \n " , e - > e ) ;
break ;
}
return f ;
}
static mfcr2_event_t * r2_get_event_bits ( struct zt_pvt * p )
{
int x ;
int res ;
mfcr2_event_t * e ;
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GETRXBITS , & x ) ;
if ( res ) {
ast_log ( LOG_WARNING , " Unable to check received bits \n " ) ;
return NULL ;
}
if ( ! p - > r2 ) {
ast_log ( LOG_WARNING , " Odd, no R2 structure on channel %d \n " , p - > channel ) ;
return NULL ;
}
e = mfcr2_cas_signaling_event ( p - > r2 , x ) ;
return e ;
}
# endif
2003-02-24 06:00:18 +00:00
static int check_for_conference ( struct zt_pvt * p )
{
ZT_CONFINFO ci ;
/* Fine if we already have a master, etc */
if ( p - > master | | ( p - > confno > - 1 ) )
return 0 ;
memset ( & ci , 0 , sizeof ( ci ) ) ;
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GETCONF , & ci ) ) {
ast_log ( LOG_WARNING , " Failed to get conference info on channel %d \n " , p - > channel ) ;
return 0 ;
}
/* If we have no master and don't have a confno, then
if we ' re in a conference , it ' s probably a MeetMe room or
some such , so don ' t let us 3 - way out ! */
if ( ci . confno ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Avoiding 3-way call when in an external conference \n " ) ;
return 1 ;
}
return 0 ;
}
2003-02-28 06:00:18 +00:00
static int get_alarms ( struct zt_pvt * p )
{
int res ;
ZT_SPANINFO zi ;
memset ( & zi , 0 , sizeof ( zi ) ) ;
zi . spanno = p - > span ;
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SPANSTAT , & zi ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to determine alarm on channel %d \n " , p - > channel ) ;
return 0 ;
}
return zi . alarms ;
}
2003-02-24 06:00:18 +00:00
2003-02-07 19:23:19 +00:00
static struct ast_frame * zt_handle_event ( struct ast_channel * ast )
2001-10-09 02:06:21 +00:00
{
int res , x ;
int index ;
struct zt_pvt * p = ast - > pvt - > pvt ;
pthread_t threadid ;
pthread_attr_t attr ;
struct ast_channel * chan ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
index = zt_get_index ( ast , p , 0 ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . datalen = 0 ;
p - > subs [ index ] . f . samples = 0 ;
p - > subs [ index ] . f . mallocd = 0 ;
p - > subs [ index ] . f . offset = 0 ;
p - > subs [ index ] . f . src = " zt_handle_event " ;
p - > subs [ index ] . f . data = NULL ;
2001-10-09 02:06:21 +00:00
if ( index < 0 )
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
res = zt_get_event ( p - > subs [ index ] . zfd ) ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_DEBUG , " Got event %s(%d) on channel %d (index %d) \n " , event2str ( res ) , res , p - > channel , index ) ;
2003-02-07 19:23:19 +00:00
if ( res & ( ZT_EVENT_PULSEDIGIT | ZT_EVENT_DTMFDIGIT ) ) {
if ( res & ZT_EVENT_PULSEDIGIT )
p - > pulsedial = 1 ;
else
p - > pulsedial = 0 ;
ast_log ( LOG_DEBUG , " Pulse dial '%c' \n " , res & 0xff ) ;
p - > subs [ index ] . f . frametype = AST_FRAME_DTMF ;
p - > subs [ index ] . f . subclass = res & 0xff ;
/* Return the captured digit */
return & p - > subs [ index ] . f ;
}
2001-10-09 02:06:21 +00:00
switch ( res ) {
2003-02-07 19:23:19 +00:00
case ZT_EVENT_BITSCHANGED :
if ( p - > sig = = SIG_R2 ) {
# ifdef ZAPATA_R2
struct ast_frame * f = & p - > subs [ index ] . f ;
mfcr2_event_t * e ;
e = r2_get_event_bits ( p ) ;
if ( e )
f = handle_r2_event ( p , e , index ) ;
return f ;
# else
break ;
# endif
}
ast_log ( LOG_WARNING , " Recieved bits changed on %s signalling? \n " , sig2str ( p - > sig ) ) ;
case ZT_EVENT_PULSE_START :
/* Stop tone if there's a pulse start and the PBX isn't started */
if ( ! ast - > pbx )
tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
break ;
2001-10-09 02:06:21 +00:00
case ZT_EVENT_DIALCOMPLETE :
if ( p - > inalarm ) break ;
2003-02-07 19:23:19 +00:00
if ( p - > radio ) break ;
if ( ioctl ( p - > subs [ index ] . zfd , ZT_DIALING , & x ) = = - 1 ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_DEBUG , " ZT_DIALING ioctl failed on %s \n " , ast - > name ) ;
return NULL ;
}
2001-12-29 18:04:21 +00:00
if ( ! x ) { /* if not still dialing in driver */
2001-10-09 02:06:21 +00:00
zt_enable_ec ( p ) ;
p - > dialing = 0 ;
2002-09-10 04:45:51 +00:00
if ( ast - > _state = = AST_STATE_DIALING ) {
2003-02-07 19:23:19 +00:00
if ( p - > callprogress & & CANPROGRESSDETECT ( p ) & & p - > dsp ) {
ast_log ( LOG_DEBUG , " Done dialing, but waiting for progress detection before doing more... \n " ) ;
2003-03-17 20:04:36 +00:00
} else if ( p - > confirmanswer | | ( ! p - > dialednone & & ( ( p - > sig = = SIG_EM ) | | ( p - > sig = = SIG_EMWINK ) | | ( p - > sig = = SIG_FEATD ) | | ( p - > sig = = SIG_FEATDMF ) | | ( p - > sig = = SIG_FEATB ) | | ( p - > sig = = SIG_SF ) | | ( p - > sig = = SIG_SFWINK ) | | ( p - > sig = = SIG_SF_FEATD ) | | ( p - > sig = = SIG_SF_FEATDMF ) | | ( p - > sig = = SIG_SF_FEATB ) ) ) ) {
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_RINGING ) ;
2001-12-29 18:04:21 +00:00
} else {
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_ANSWER ;
2001-12-29 18:04:21 +00:00
}
2001-10-09 02:06:21 +00:00
}
}
break ;
case ZT_EVENT_ALARM :
p - > inalarm = 1 ;
2003-02-28 06:00:18 +00:00
res = get_alarms ( p ) ;
ast_log ( LOG_WARNING , " Detected alarm on channel %d: %s \n " , p - > channel , alarm2str ( res ) ) ;
2001-10-09 02:06:21 +00:00
/* fall through intentionally */
case ZT_EVENT_ONHOOK :
2003-02-07 19:23:19 +00:00
if ( p - > radio )
{
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_RADIO_UNKEY ;
break ;
}
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
2003-02-07 19:23:19 +00:00
p - > onhooktime = time ( NULL ) ;
p - > msgstate = - 1 ;
2001-10-09 02:06:21 +00:00
/* Check for some special conditions regarding call waiting */
2003-02-07 19:23:19 +00:00
if ( index = = SUB_REAL ) {
2001-10-09 02:06:21 +00:00
/* The normal line was hung up */
2003-02-07 19:23:19 +00:00
if ( p - > subs [ SUB_CALLWAIT ] . owner ) {
/* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
swap_subs ( p , SUB_CALLWAIT , SUB_REAL ) ;
2001-10-09 02:06:21 +00:00
if ( option_verbose > 2 )
2003-02-07 19:23:19 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Channel %d still has (callwait) call, ringing phone \n " , p - > channel ) ;
unalloc_sub ( p , SUB_CALLWAIT ) ;
#if 0
p - > subs [ index ] . needanswer = 0 ;
p - > subs [ index ] . needringing = 0 ;
# endif
2001-10-09 02:06:21 +00:00
p - > callwaitingrepeat = 0 ;
2003-02-07 19:23:19 +00:00
p - > cidcwexpire = 0 ;
p - > owner = NULL ;
2001-10-09 02:06:21 +00:00
zt_ring_phone ( p ) ;
2003-02-07 19:23:19 +00:00
} else if ( p - > subs [ SUB_THREEWAY ] . owner ) {
2003-03-21 16:26:50 +00:00
struct timeval tv ;
unsigned int mssinceflash ;
gettimeofday ( & tv , NULL ) ;
mssinceflash = ( tv . tv_sec - p - > flashtime . tv_sec ) * 1000 + ( tv . tv_usec - p - > flashtime . tv_usec ) / 1000 ;
2003-04-11 04:31:33 +00:00
ast_log ( LOG_DEBUG , " Last flash was %d ms ago \n " , mssinceflash ) ;
2003-03-21 16:26:50 +00:00
if ( mssinceflash < MIN_MS_SINCE_FLASH ) {
/* It hasn't been long enough since the last flashook. This is probably a bounce on
hanging up . Hangup both channels now */
2003-04-11 04:31:33 +00:00
if ( p - > subs [ SUB_THREEWAY ] . owner )
ast_queue_hangup ( p - > subs [ SUB_THREEWAY ] . owner , 0 ) ;
2003-03-21 16:26:50 +00:00
p - > subs [ SUB_THREEWAY ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
ast_log ( LOG_DEBUG , " Looks like a bounced flash, hanging up both calls on %d \n " , p - > channel ) ;
} else if ( ( ast - > pbx ) | |
2003-02-07 19:23:19 +00:00
( ast - > _state = = AST_STATE_UP ) ) {
if ( p - > transfer ) {
/* In any case this isn't a threeway call anymore */
p - > subs [ SUB_REAL ] . inthreeway = 0 ;
p - > subs [ SUB_THREEWAY ] . inthreeway = 0 ;
if ( ( res = attempt_transfer ( p ) ) < 0 )
p - > subs [ SUB_THREEWAY ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
else if ( res ) {
/* Don't actually hang up at this point */
break ;
}
} else
p - > subs [ SUB_THREEWAY ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
} else {
/* Swap subs and dis-own channel */
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
p - > owner = NULL ;
/* Ring the phone */
zt_ring_phone ( p ) ;
2001-10-09 02:06:21 +00:00
}
}
2003-02-07 19:23:19 +00:00
} else {
ast_log ( LOG_WARNING , " Got a hangup and my index is %d? \n " , index ) ;
2001-10-09 02:06:21 +00:00
}
/* Fall through */
default :
zt_disable_ec ( p ) ;
return NULL ;
}
break ;
case ZT_EVENT_RINGOFFHOOK :
if ( p - > inalarm ) break ;
2003-02-07 19:23:19 +00:00
if ( p - > radio )
{
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_RADIO_KEY ;
break ;
}
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
2002-09-10 04:45:51 +00:00
switch ( ast - > _state ) {
2001-10-09 02:06:21 +00:00
case AST_STATE_RINGING :
zt_enable_ec ( p ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_ANSWER ;
2001-10-09 02:06:21 +00:00
/* Make sure it stops ringing */
2003-02-07 19:23:19 +00:00
zt_set_hook ( p - > subs [ index ] . zfd , ZT_OFFHOOK ) ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_DEBUG , " channel %d answered \n " , p - > channel ) ;
if ( p - > cidspill ) {
/* Cancel any running CallerID spill */
free ( p - > cidspill ) ;
p - > cidspill = NULL ;
}
p - > dialing = 0 ;
2003-02-07 19:23:19 +00:00
p - > callwaitcas = 0 ;
2002-06-24 17:59:56 +00:00
if ( p - > confirmanswer ) {
/* Ignore answer if "confirm answer" is selected */
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
2003-04-11 18:03:59 +00:00
} else if ( strlen ( p - > dop . dialstr ) ) {
2003-04-10 21:14:54 +00:00
/* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_DIAL , & p - > dop ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to initiate dialing on trunk channel %d \n " , p - > channel ) ;
p - > dop . dialstr [ 0 ] = ' \0 ' ;
return NULL ;
2003-04-11 18:03:59 +00:00
} else {
ast_log ( LOG_DEBUG , " Sent FXO deferred digit string: %s \n " , p - > dop . dialstr ) ;
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
p - > dialing = 1 ;
}
2003-04-10 21:14:54 +00:00
p - > dop . dialstr [ 0 ] = ' \0 ' ;
2003-04-11 18:03:59 +00:00
ast_setstate ( ast , AST_STATE_DIALING ) ;
} else
ast_setstate ( ast , AST_STATE_UP ) ;
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
2001-10-09 02:06:21 +00:00
case AST_STATE_DOWN :
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_RING ) ;
2001-10-09 02:06:21 +00:00
ast - > rings = 1 ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_OFFHOOK ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_DEBUG , " channel %d picked up \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
2001-10-09 02:06:21 +00:00
case AST_STATE_UP :
/* Make sure it stops ringing */
2003-02-07 19:23:19 +00:00
zt_set_hook ( p - > subs [ index ] . zfd , ZT_OFFHOOK ) ;
2001-10-09 02:06:21 +00:00
/* Okay -- probably call waiting*/
2002-06-24 17:59:56 +00:00
if ( p - > owner - > bridge )
ast_moh_stop ( p - > owner - > bridge ) ;
2001-10-09 02:06:21 +00:00
break ;
default :
2002-09-10 04:45:51 +00:00
ast_log ( LOG_WARNING , " FXO phone off hook in weird state %d?? \n " , ast - > _state ) ;
2001-10-09 02:06:21 +00:00
}
break ;
case SIG_FXSLS :
case SIG_FXSGS :
case SIG_FXSKS :
2002-09-10 04:45:51 +00:00
if ( ast - > _state = = AST_STATE_RING ) {
2001-10-09 02:06:21 +00:00
p - > ringt = RINGT ;
}
/* Fall through */
case SIG_EM :
case SIG_EMWINK :
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2003-03-17 20:04:36 +00:00
case SIG_SF :
case SIG_SFWINK :
case SIG_SF_FEATD :
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
2003-05-26 23:10:08 +00:00
if ( ( ast - > _state = = AST_STATE_DOWN ) | | ( ast - > _state = = AST_STATE_RING ) ) {
2001-10-09 02:06:21 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Ring detected \n " ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_RING ;
2003-04-11 03:03:41 +00:00
} else if ( p - > outgoing & & ( ( ast - > _state = = AST_STATE_RINGING ) | | ( ast - > _state = = AST_STATE_DIALING ) ) ) {
2001-10-09 02:06:21 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Line answered \n " ) ;
2002-06-24 17:59:56 +00:00
if ( p - > confirmanswer ) {
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
2002-06-24 17:59:56 +00:00
} else {
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_ANSWER ;
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_UP ) ;
2002-06-24 17:59:56 +00:00
}
2002-09-10 04:45:51 +00:00
} else if ( ast - > _state ! = AST_STATE_RING )
ast_log ( LOG_WARNING , " Ring/Off-hook in strange state %d on channel %d \n " , ast - > _state , p - > channel ) ;
2001-10-09 02:06:21 +00:00
break ;
default :
ast_log ( LOG_WARNING , " Don't know how to handle ring/off hoook for signalling %d \n " , p - > sig ) ;
}
break ;
case ZT_EVENT_RINGEROFF :
if ( p - > inalarm ) break ;
2003-02-07 19:23:19 +00:00
if ( p - > radio ) break ;
2001-10-09 02:06:21 +00:00
ast - > rings + + ;
2002-06-24 17:59:56 +00:00
if ( ( ast - > rings > p - > cidrings ) & & ( p - > cidspill ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Didn't finish Caller-ID spill. Cancelling. \n " ) ;
free ( p - > cidspill ) ;
p - > cidspill = NULL ;
p - > callwaitcas = 0 ;
}
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_RINGING ;
2001-10-09 02:06:21 +00:00
break ;
case ZT_EVENT_RINGERON :
break ;
case ZT_EVENT_NOALARM :
p - > inalarm = 0 ;
2003-02-28 06:00:18 +00:00
ast_log ( LOG_NOTICE , " Alarm cleared on channel %d \n " , p - > channel ) ;
2001-10-09 02:06:21 +00:00
break ;
case ZT_EVENT_WINKFLASH :
if ( p - > inalarm ) break ;
2003-02-07 19:23:19 +00:00
if ( p - > radio ) break ;
2003-03-21 16:26:50 +00:00
/* Remember last time we got a flash-hook */
gettimeofday ( & p - > flashtime , NULL ) ;
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
ast_log ( LOG_DEBUG , " Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d \n " ,
2003-02-07 19:23:19 +00:00
index , p - > subs [ SUB_REAL ] . zfd , p - > subs [ SUB_CALLWAIT ] . zfd , p - > subs [ SUB_THREEWAY ] . zfd ) ;
p - > callwaitcas = 0 ;
if ( index = = SUB_REAL ) {
if ( p - > subs [ SUB_CALLWAIT ] . owner ) {
/* Swap to call-wait */
swap_subs ( p , SUB_REAL , SUB_CALLWAIT ) ;
tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , - 1 ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
ast_log ( LOG_DEBUG , " Making %s the new owner \n " , p - > owner - > name ) ;
2002-09-10 04:45:51 +00:00
if ( p - > owner - > _state = = AST_STATE_RINGING ) {
ast_setstate ( p - > owner , AST_STATE_UP ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_REAL ] . needanswer = 1 ;
2001-10-09 02:06:21 +00:00
}
p - > callwaitingrepeat = 0 ;
2003-02-07 19:23:19 +00:00
p - > cidcwexpire = 0 ;
2002-06-24 17:59:56 +00:00
/* Start music on hold if appropriate */
2003-02-07 19:23:19 +00:00
if ( ! p - > subs [ SUB_CALLWAIT ] . inthreeway & & p - > subs [ SUB_CALLWAIT ] . owner - > bridge )
ast_moh_start ( p - > subs [ SUB_CALLWAIT ] . owner - > bridge , NULL ) ;
if ( p - > subs [ SUB_REAL ] . owner - > bridge )
ast_moh_stop ( p - > subs [ SUB_REAL ] . owner - > bridge ) ;
} else if ( ! p - > subs [ SUB_THREEWAY ] . owner ) {
2003-02-24 06:00:18 +00:00
if ( p - > threewaycalling & & ! check_for_conference ( p ) ) {
2003-02-07 19:23:19 +00:00
/* XXX This section needs much more error checking!!! XXX */
/* Start a 3-way call if feasible */
if ( ( ast - > pbx ) | |
2002-09-10 04:45:51 +00:00
( ast - > _state = = AST_STATE_UP ) | |
( ast - > _state = = AST_STATE_RING ) ) {
2003-02-07 19:23:19 +00:00
if ( ! alloc_sub ( p , SUB_THREEWAY ) ) {
/* Make new channel */
chan = zt_new ( p , AST_STATE_RESERVED , 0 , SUB_THREEWAY , 0 ) ;
/* Swap things around between the three-way and real call */
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
2002-03-08 23:48:42 +00:00
/* Disable echo canceller for better dialing */
zt_disable_ec ( p ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , ZT_TONE_DIALRECALL ) ;
2001-10-09 02:06:21 +00:00
if ( res )
ast_log ( LOG_WARNING , " Unable to start dial recall tone on channel %d \n " , p - > channel ) ;
p - > owner = chan ;
if ( pthread_create ( & threadid , & attr , ss_thread , chan ) ) {
ast_log ( LOG_WARNING , " Unable to start simple switch on channel %d \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , ZT_TONE_CONGESTION ) ;
2002-03-08 23:48:42 +00:00
zt_enable_ec ( p ) ;
2001-10-09 02:06:21 +00:00
ast_hangup ( chan ) ;
} else {
if ( option_verbose > 2 )
2003-02-07 19:23:19 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Started three way call on channel %d \n " , p - > channel ) ;
2002-06-24 17:59:56 +00:00
/* Start music on hold if appropriate */
2003-02-07 19:23:19 +00:00
if ( p - > subs [ SUB_THREEWAY ] . owner - > bridge )
ast_moh_start ( p - > subs [ SUB_THREEWAY ] . owner - > bridge , NULL ) ;
2001-10-09 02:06:21 +00:00
}
} else
2003-02-07 19:23:19 +00:00
ast_log ( LOG_WARNING , " Unable to allocate three-way subchannel \n " ) ;
2001-10-09 02:06:21 +00:00
} else
ast_log ( LOG_DEBUG , " Flash when call not up or ringing \n " ) ;
}
} else {
2003-02-07 19:23:19 +00:00
/* Already have a 3 way call */
if ( p - > subs [ SUB_THREEWAY ] . inthreeway ) {
/* Call is already up, drop the last person */
if ( option_debug )
ast_log ( LOG_DEBUG , " Got flash with three way call up, dropping last call on %d \n " , p - > channel ) ;
/* If the primary call isn't answered yet, use it */
if ( ( p - > subs [ SUB_REAL ] . owner - > _state ! = AST_STATE_UP ) & & ( p - > subs [ SUB_THREEWAY ] . owner - > _state = = AST_STATE_UP ) ) {
/* Swap back -- we're droppign the real 3-way that isn't finished yet*/
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
}
/* Drop the last call and stop the conference */
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Dropping three-way call on %s \n " , p - > subs [ SUB_THREEWAY ] . owner - > name ) ;
p - > subs [ SUB_THREEWAY ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
p - > subs [ SUB_REAL ] . inthreeway = 0 ;
p - > subs [ SUB_THREEWAY ] . inthreeway = 0 ;
} else {
/* Lets see what we're up to */
if ( ( ast - > pbx ) | |
( ast - > _state = = AST_STATE_UP ) ) {
int otherindex = SUB_THREEWAY ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Building conference on call on %s and %s \n " , p - > subs [ SUB_THREEWAY ] . owner - > name , p - > subs [ SUB_REAL ] . owner - > name ) ;
/* Put them in the threeway, and flip */
p - > subs [ SUB_THREEWAY ] . inthreeway = 1 ;
p - > subs [ SUB_REAL ] . inthreeway = 1 ;
if ( ast - > _state = = AST_STATE_UP ) {
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
otherindex = SUB_REAL ;
}
if ( p - > subs [ otherindex ] . owner & & p - > subs [ otherindex ] . owner - > bridge )
ast_moh_stop ( p - > subs [ otherindex ] . owner - > bridge ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
if ( ast - > _state = = AST_STATE_RINGING ) {
ast_log ( LOG_DEBUG , " Enabling ringtone on real and threeway \n " ) ;
res = tone_zone_play_tone ( p - > subs [ SUB_REAL ] . zfd , ZT_TONE_RINGTONE ) ;
res = tone_zone_play_tone ( p - > subs [ SUB_THREEWAY ] . zfd , ZT_TONE_RINGTONE ) ;
}
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Dumping incomplete call on on %s \n " , p - > subs [ SUB_THREEWAY ] . owner - > name ) ;
swap_subs ( p , SUB_THREEWAY , SUB_REAL ) ;
p - > subs [ SUB_THREEWAY ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
if ( p - > subs [ SUB_REAL ] . owner & & p - > subs [ SUB_REAL ] . owner - > bridge )
ast_moh_stop ( p - > subs [ SUB_REAL ] . owner - > bridge ) ;
2003-03-18 06:00:18 +00:00
zt_enable_ec ( p ) ;
2003-02-07 19:23:19 +00:00
}
2001-10-09 02:06:21 +00:00
}
}
2003-02-07 19:23:19 +00:00
} else {
ast_log ( LOG_WARNING , " Got flash hook with index %d on channel %d?!? \n " , index , p - > channel ) ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
update_conf ( p ) ;
2001-10-09 02:06:21 +00:00
break ;
case SIG_EM :
case SIG_EMWINK :
case SIG_FEATD :
2003-03-17 20:04:36 +00:00
case SIG_SF :
case SIG_SFWINK :
case SIG_SF_FEATD :
2001-10-09 02:06:21 +00:00
case SIG_FXSLS :
case SIG_FXSGS :
if ( p - > dialing )
ast_log ( LOG_DEBUG , " Ignoring wink on channel %d \n " , p - > channel ) ;
else
2002-09-10 04:45:51 +00:00
ast_log ( LOG_DEBUG , " Got wink in weird state %d on channel %d \n " , ast - > _state , p - > channel ) ;
2001-10-09 02:06:21 +00:00
break ;
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
2002-06-24 17:59:56 +00:00
/* FGD MF *Must* wait for wink */
2003-05-19 23:45:46 +00:00
if ( strlen ( p - > dop . dialstr ) )
2003-05-19 23:43:44 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_DIAL , & p - > dop ) ;
else if ( res < 0 ) {
2002-06-24 17:59:56 +00:00
ast_log ( LOG_WARNING , " Unable to initiate dialing on trunk channel %d \n " , p - > channel ) ;
p - > dop . dialstr [ 0 ] = ' \0 ' ;
return NULL ;
} else
ast_log ( LOG_DEBUG , " Sent deferred digit string: %s \n " , p - > dop . dialstr ) ;
p - > dop . dialstr [ 0 ] = ' \0 ' ;
break ;
2001-10-09 02:06:21 +00:00
default :
ast_log ( LOG_WARNING , " Don't know how to handle ring/off hoook for signalling %d \n " , p - > sig ) ;
}
break ;
case ZT_EVENT_HOOKCOMPLETE :
if ( p - > inalarm ) break ;
2003-02-07 19:23:19 +00:00
if ( p - > radio ) break ;
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FXSLS : /* only interesting for FXS */
case SIG_FXSGS :
case SIG_FXSKS :
case SIG_EM :
case SIG_EMWINK :
2001-12-29 18:04:21 +00:00
case SIG_FEATD :
2003-03-17 20:04:36 +00:00
case SIG_SF :
case SIG_SFWINK :
case SIG_SF_FEATD :
2003-05-19 23:49:15 +00:00
if ( strlen ( p - > dop . dialstr ) )
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_DIAL , & p - > dop ) ;
else if ( res < 0 ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to initiate dialing on trunk channel %d \n " , p - > channel ) ;
p - > dop . dialstr [ 0 ] = ' \0 ' ;
return NULL ;
} else
ast_log ( LOG_DEBUG , " Sent deferred digit string: %s \n " , p - > dop . dialstr ) ;
p - > dop . dialstr [ 0 ] = ' \0 ' ;
2003-05-19 23:33:41 +00:00
p - > dop . op = ZT_DIAL_OP_REPLACE ;
2001-10-09 02:06:21 +00:00
break ;
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
2002-06-24 17:59:56 +00:00
ast_log ( LOG_DEBUG , " Got hook complete in MF FGD, waiting for wink now on channel %d \n " , p - > channel ) ;
break ;
2001-10-09 02:06:21 +00:00
default :
break ;
}
break ;
default :
ast_log ( LOG_DEBUG , " Dunno what to do with event %d on channel %d \n " , res , p - > channel ) ;
}
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
2001-10-09 02:06:21 +00:00
}
struct ast_frame * zt_exception ( struct ast_channel * ast )
{
struct zt_pvt * p = ast - > pvt - > pvt ;
int res ;
int usedindex = - 1 ;
int index ;
2003-05-19 23:33:41 +00:00
struct ast_frame * f ;
ast_pthread_mutex_lock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
2001-10-09 02:06:21 +00:00
index = zt_get_index ( ast , p , 1 ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . datalen = 0 ;
p - > subs [ index ] . f . samples = 0 ;
p - > subs [ index ] . f . mallocd = 0 ;
p - > subs [ index ] . f . offset = 0 ;
p - > subs [ index ] . f . subclass = 0 ;
p - > subs [ index ] . f . src = " zt_exception " ;
p - > subs [ index ] . f . data = NULL ;
if ( ( ! p - > owner ) & & ( ! p - > radio ) ) {
2001-10-09 02:06:21 +00:00
/* If nobody owns us, absorb the event appropriately, otherwise
we loop indefinitely . This occurs when , during call waiting , the
other end hangs up our channel so that it no longer exists , but we
have neither FLASH ' d nor ONHOOK ' d to signify our desire to
change to the other channel . */
2003-02-07 19:23:19 +00:00
res = zt_get_event ( p - > subs [ SUB_REAL ] . zfd ) ;
/* Switch to real if there is one and this isn't something really silly... */
if ( ( res ! = ZT_EVENT_RINGEROFF ) & & ( res ! = ZT_EVENT_RINGERON ) & &
( res ! = ZT_EVENT_HOOKCOMPLETE ) ) {
ast_log ( LOG_DEBUG , " Restoring owner of channel %d on event %d \n " , p - > channel , res ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
if ( p - > owner & & p - > owner - > bridge )
ast_moh_stop ( p - > owner - > bridge ) ;
2001-10-09 02:06:21 +00:00
}
switch ( res ) {
case ZT_EVENT_ONHOOK :
zt_disable_ec ( p ) ;
if ( p - > owner ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Channel %s still has call, ringing phone \n " , p - > owner - > name ) ;
zt_ring_phone ( p ) ;
p - > callwaitingrepeat = 0 ;
2003-02-07 19:23:19 +00:00
p - > cidcwexpire = 0 ;
2001-10-09 02:06:21 +00:00
} else
ast_log ( LOG_WARNING , " Absorbed on hook, but nobody is left!?!? \n " ) ;
2003-02-07 19:23:19 +00:00
update_conf ( p ) ;
break ;
case ZT_EVENT_RINGOFFHOOK :
zt_set_hook ( p - > subs [ SUB_REAL ] . zfd , ZT_OFFHOOK ) ;
if ( p - > owner & & ( p - > owner - > _state = = AST_STATE_RINGING ) ) {
p - > subs [ SUB_REAL ] . needanswer = 1 ;
}
break ;
case ZT_EVENT_HOOKCOMPLETE :
case ZT_EVENT_RINGERON :
case ZT_EVENT_RINGEROFF :
/* Do nothing */
2001-10-09 02:06:21 +00:00
break ;
case ZT_EVENT_WINKFLASH :
2003-03-21 16:26:50 +00:00
gettimeofday ( & p - > flashtime , NULL ) ;
2001-10-09 02:06:21 +00:00
if ( p - > owner ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Channel %d flashed to other channel %s \n " , p - > channel , p - > owner - > name ) ;
2003-02-07 19:23:19 +00:00
if ( p - > owner - > _state ! = AST_STATE_UP ) {
/* Answer if necessary */
usedindex = zt_get_index ( p - > owner , p , 0 ) ;
if ( usedindex > - 1 ) {
p - > subs [ usedindex ] . needanswer = 1 ;
}
2002-09-10 04:45:51 +00:00
ast_setstate ( p - > owner , AST_STATE_UP ) ;
2001-10-09 02:06:21 +00:00
}
p - > callwaitingrepeat = 0 ;
2003-02-07 19:23:19 +00:00
p - > cidcwexpire = 0 ;
2002-06-24 17:59:56 +00:00
if ( p - > owner - > bridge )
2003-02-07 19:23:19 +00:00
ast_moh_stop ( p - > owner - > bridge ) ;
2001-10-09 02:06:21 +00:00
} else
ast_log ( LOG_WARNING , " Absorbed on hook, but nobody is left!?!? \n " ) ;
2003-02-07 19:23:19 +00:00
update_conf ( p ) ;
2001-10-09 02:06:21 +00:00
break ;
default :
ast_log ( LOG_WARNING , " Don't know how to absorb event %s \n " , event2str ( res ) ) ;
}
2003-05-19 23:33:41 +00:00
f = & p - > subs [ index ] . f ;
ast_pthread_mutex_unlock ( & p - > lock ) ;
return f ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
if ( ! p - > radio ) ast_log ( LOG_DEBUG , " Exception on %d, channel %d \n " , ast - > fds [ 0 ] , p - > channel ) ;
2001-10-09 02:06:21 +00:00
/* If it's not us, return NULL immediately */
2003-02-07 19:23:19 +00:00
if ( ast ! = p - > owner ) {
ast_log ( LOG_WARNING , " We're %s, not %s \n " , ast - > name , p - > owner - > name ) ;
2003-05-19 23:33:41 +00:00
f = & p - > subs [ index ] . f ;
ast_pthread_mutex_unlock ( & p - > lock ) ;
return f ;
2003-02-07 19:23:19 +00:00
}
2003-05-19 23:33:41 +00:00
f = zt_handle_event ( ast ) ;
ast_pthread_mutex_unlock ( & p - > lock ) ;
return f ;
2001-10-09 02:06:21 +00:00
}
struct ast_frame * zt_read ( struct ast_channel * ast )
{
struct zt_pvt * p = ast - > pvt - > pvt ;
2001-12-29 18:04:21 +00:00
int res ;
2001-10-09 02:06:21 +00:00
int index ;
2001-12-29 18:04:21 +00:00
void * readbuf ;
2003-02-07 19:23:19 +00:00
struct ast_frame * f ;
2001-10-09 02:06:21 +00:00
2003-02-07 19:23:19 +00:00
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_lock ( & p - > lock ) ;
2001-10-09 02:06:21 +00:00
index = zt_get_index ( ast , p , 0 ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . datalen = 0 ;
p - > subs [ index ] . f . samples = 0 ;
p - > subs [ index ] . f . mallocd = 0 ;
p - > subs [ index ] . f . offset = 0 ;
p - > subs [ index ] . f . subclass = 0 ;
p - > subs [ index ] . f . src = " zt_read " ;
p - > subs [ index ] . f . data = NULL ;
2001-10-09 02:06:21 +00:00
/* Hang up if we don't really exist */
if ( index < 0 ) {
ast_log ( LOG_WARNING , " We dont exist? \n " ) ;
pthread_mutex_unlock ( & p - > lock ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
/* make sure it sends initial key state as first frame */
if ( p - > radio & & ( ! p - > firstradio ) )
{
ZT_PARAMS ps ;
ps . channo = p - > channel ;
if ( ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GET_PARAMS , & ps ) < 0 )
return NULL ;
p - > firstradio = 1 ;
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
if ( ps . rxisoffhook )
{
p - > subs [ index ] . f . subclass = AST_CONTROL_RADIO_KEY ;
}
else
{
p - > subs [ index ] . f . subclass = AST_CONTROL_RADIO_UNKEY ;
}
pthread_mutex_unlock ( & p - > lock ) ;
return & p - > subs [ index ] . f ;
}
2001-10-09 02:06:21 +00:00
if ( p - > ringt = = 1 ) {
pthread_mutex_unlock ( & p - > lock ) ;
return NULL ;
}
else if ( p - > ringt > 0 )
p - > ringt - - ;
2003-02-07 19:23:19 +00:00
if ( p - > subs [ index ] . needringing ) {
2001-10-09 02:06:21 +00:00
/* Send ringing frame if requested */
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . needringing = 0 ;
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_RINGING ;
2002-09-10 04:45:51 +00:00
ast_setstate ( ast , AST_STATE_RINGING ) ;
2001-10-09 02:06:21 +00:00
pthread_mutex_unlock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
2002-06-24 17:59:56 +00:00
}
2001-10-09 02:06:21 +00:00
2003-02-07 19:23:19 +00:00
if ( p - > subs [ index ] . needcallerid ) {
ast_set_callerid ( ast , strlen ( p - > lastcallerid ) ? p - > lastcallerid : NULL , 1 ) ;
p - > subs [ index ] . needcallerid = 0 ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
if ( p - > subs [ index ] . needanswer ) {
/* Send ringing frame if requested */
p - > subs [ index ] . needanswer = 0 ;
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_ANSWER ;
ast_setstate ( ast , AST_STATE_UP ) ;
2001-10-09 02:06:21 +00:00
pthread_mutex_unlock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
}
2001-10-09 02:06:21 +00:00
if ( ast - > pvt - > rawreadformat = = AST_FORMAT_SLINEAR ) {
2003-02-07 19:23:19 +00:00
if ( ! p - > subs [ index ] . linear ) {
p - > subs [ index ] . linear = 1 ;
res = zt_setlinear ( p - > subs [ index ] . zfd , p - > subs [ index ] . linear ) ;
2001-12-29 18:04:21 +00:00
if ( res )
2003-02-07 19:23:19 +00:00
ast_log ( LOG_WARNING , " Unable to set channel %d (index %d) to linear mode. \n " , p - > channel , index ) ;
2001-12-29 18:04:21 +00:00
}
} else if ( ( ast - > pvt - > rawreadformat = = AST_FORMAT_ULAW ) | |
( ast - > pvt - > rawreadformat = = AST_FORMAT_ALAW ) ) {
2003-02-07 19:23:19 +00:00
if ( p - > subs [ index ] . linear ) {
p - > subs [ index ] . linear = 0 ;
res = zt_setlinear ( p - > subs [ index ] . zfd , p - > subs [ index ] . linear ) ;
2001-12-29 18:04:21 +00:00
if ( res )
2003-02-07 19:23:19 +00:00
ast_log ( LOG_WARNING , " Unable to set channel %d (index %d) to campanded mode. \n " , p - > channel , index ) ;
2001-12-29 18:04:21 +00:00
}
2001-10-09 02:06:21 +00:00
} else {
ast_log ( LOG_WARNING , " Don't know how to read frames in format %d \n " , ast - > pvt - > rawreadformat ) ;
pthread_mutex_unlock ( & p - > lock ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
readbuf = ( ( unsigned char * ) p - > subs [ index ] . buffer ) + AST_FRIENDLY_OFFSET ;
2001-10-09 02:06:21 +00:00
CHECK_BLOCKING ( ast ) ;
2003-02-07 19:23:19 +00:00
res = read ( p - > subs [ index ] . zfd , readbuf , p - > subs [ index ] . linear ? READ_SIZE * 2 : READ_SIZE ) ;
2001-10-09 02:06:21 +00:00
ast - > blocking = 0 ;
/* Check for hangup */
if ( res < 0 ) {
2003-02-07 19:23:19 +00:00
if ( res = = - 1 ) {
if ( errno = = EAGAIN ) {
/* Return "NULL" frame if there is nobody there */
pthread_mutex_unlock ( & p - > lock ) ;
return & p - > subs [ index ] . f ;
} else
ast_log ( LOG_WARNING , " zt_rec: %s \n " , strerror ( errno ) ) ;
}
2001-10-09 02:06:21 +00:00
pthread_mutex_unlock ( & p - > lock ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
if ( res ! = ( p - > subs [ index ] . linear ? READ_SIZE * 2 : READ_SIZE ) ) {
ast_log ( LOG_DEBUG , " Short read (%d/%d), must be an event... \n " , res , p - > subs [ index ] . linear ? READ_SIZE * 2 : READ_SIZE ) ;
2003-05-19 23:33:41 +00:00
f = zt_handle_event ( ast ) ;
2001-10-09 02:06:21 +00:00
pthread_mutex_unlock ( & p - > lock ) ;
2003-05-19 23:33:41 +00:00
return f ;
2001-10-09 02:06:21 +00:00
}
2001-12-29 18:04:21 +00:00
if ( p - > tdd ) { /* if in TDD mode, see if we receive that */
int c ;
c = tdd_feed ( p - > tdd , readbuf , READ_SIZE ) ;
if ( c < 0 ) {
ast_log ( LOG_DEBUG , " tdd_feed failed \n " ) ;
return NULL ;
}
if ( c ) { /* if a char to return */
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . subclass = 0 ;
p - > subs [ index ] . f . frametype = AST_FRAME_TEXT ;
p - > subs [ index ] . f . mallocd = 0 ;
p - > subs [ index ] . f . offset = AST_FRIENDLY_OFFSET ;
p - > subs [ index ] . f . data = p - > subs [ index ] . buffer + AST_FRIENDLY_OFFSET ;
p - > subs [ index ] . f . datalen = 1 ;
* ( ( char * ) p - > subs [ index ] . f . data ) = c ;
2001-12-29 18:04:21 +00:00
pthread_mutex_unlock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
return & p - > subs [ index ] . f ;
2001-12-29 18:04:21 +00:00
}
}
2001-10-09 02:06:21 +00:00
if ( p - > callwaitingrepeat )
p - > callwaitingrepeat - - ;
2003-02-07 19:23:19 +00:00
if ( p - > cidcwexpire )
p - > cidcwexpire - - ;
2001-10-09 02:06:21 +00:00
/* Repeat callwaiting */
if ( p - > callwaitingrepeat = = 1 ) {
p - > callwaitrings + + ;
zt_callwait ( ast ) ;
}
2003-02-07 19:23:19 +00:00
/* Expire CID/CW */
if ( p - > cidcwexpire = = 1 ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " CPE does not support Call Waiting Caller*ID. \n " ) ;
restore_conference ( p ) ;
}
if ( p - > subs [ index ] . linear ) {
p - > subs [ index ] . f . datalen = READ_SIZE * 2 ;
2001-10-09 02:06:21 +00:00
} else
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . datalen = READ_SIZE ;
2001-10-09 02:06:21 +00:00
/* Handle CallerID Transmission */
2003-02-07 19:23:19 +00:00
if ( ( p - > owner = = ast ) & & p - > cidspill & & ( ( ast - > _state = = AST_STATE_UP ) | | ( ast - > rings = = p - > cidrings ) ) ) {
2001-10-09 02:06:21 +00:00
send_callerid ( p ) ;
2002-06-24 17:59:56 +00:00
}
2001-10-09 02:06:21 +00:00
2003-02-07 19:23:19 +00:00
p - > subs [ index ] . f . frametype = AST_FRAME_VOICE ;
p - > subs [ index ] . f . subclass = ast - > pvt - > rawreadformat ;
p - > subs [ index ] . f . samples = READ_SIZE ;
p - > subs [ index ] . f . mallocd = 0 ;
p - > subs [ index ] . f . offset = AST_FRIENDLY_OFFSET ;
p - > subs [ index ] . f . data = p - > subs [ index ] . buffer + AST_FRIENDLY_OFFSET / 2 ;
2001-10-09 02:06:21 +00:00
#if 0
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Read %d of voice on %s \n " , p - > subs [ index ] . f . datalen , ast - > name ) ;
2001-10-09 02:06:21 +00:00
# endif
2003-02-07 19:23:19 +00:00
if ( p - > dialing | | /* Transmitting something */
( index & & ( ast - > _state ! = AST_STATE_UP ) ) | | /* Three-way or callwait that isn't up */
( ( index = = SUB_CALLWAIT ) & & ! p - > subs [ SUB_CALLWAIT ] . inthreeway ) /* Inactive and non-confed call-wait */
) {
/* Whoops, we're still dialing, or in a state where we shouldn't transmit....
don ' t send anything */
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
p - > subs [ index ] . f . samples = 0 ;
p - > subs [ index ] . f . mallocd = 0 ;
p - > subs [ index ] . f . offset = 0 ;
p - > subs [ index ] . f . data = NULL ;
p - > subs [ index ] . f . datalen = 0 ;
}
if ( p - > dsp & & ! p - > ignoredtmf & & ! index ) {
/* Perform busy detection. etc on the zap line */
f = ast_dsp_process ( ast , p - > dsp , & p - > subs [ index ] . f , 0 ) ;
if ( f ) {
if ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ( f - > subclass = = AST_CONTROL_BUSY ) ) {
if ( ( ast - > _state = = AST_STATE_UP ) & & ! p - > outgoing ) {
/* Treat this as a "hangup" instead of a "busy" on the assumption that
a busy */
f = NULL ;
}
} else if ( f - > frametype = = AST_FRAME_DTMF ) {
/* DSP clears us of being pulse */
p - > pulsedial = 0 ;
}
}
} else
f = & p - > subs [ index ] . f ;
if ( f & & ( f - > frametype = = AST_FRAME_DTMF ) ) {
ast_log ( LOG_DEBUG , " DTMF digit: %c on %s \n " , f - > subclass , ast - > name ) ;
if ( p - > confirmanswer ) {
ast_log ( LOG_DEBUG , " Confirm answer on %s! \n " , ast - > name ) ;
/* Upon receiving a DTMF digit, consider this an answer confirmation instead
of a DTMF digit */
p - > subs [ index ] . f . frametype = AST_FRAME_CONTROL ;
p - > subs [ index ] . f . subclass = AST_CONTROL_ANSWER ;
ast_setstate ( ast , AST_STATE_UP ) ;
f = & p - > subs [ index ] . f ;
} else if ( p - > callwaitcas ) {
if ( ( f - > subclass = = ' A ' ) | | ( f - > subclass = = ' D ' ) ) {
ast_log ( LOG_DEBUG , " Got some DTMF, but it's for the CAS \n " ) ;
if ( p - > cidspill )
free ( p - > cidspill ) ;
send_cwcidspill ( p ) ;
}
p - > callwaitcas = 0 ;
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
f = & p - > subs [ index ] . f ;
} else if ( f - > subclass = = ' f ' ) {
/* Fax tone -- Handle and return NULL */
if ( ! p - > faxhandled ) {
p - > faxhandled + + ;
if ( strcmp ( ast - > exten , " fax " ) ) {
if ( ast_exists_extension ( ast , ast - > context , " fax " , 1 , ast - > callerid ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Redirecting %s to fax extension \n " , ast - > name ) ;
2003-05-29 20:18:45 +00:00
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
pbx_builtin_setvar_helper ( ast , " FAXEXTEN " , ast - > exten ) ;
2003-02-07 19:23:19 +00:00
if ( ast_async_goto ( ast , ast - > context , " fax " , 1 , 0 ) )
ast_log ( LOG_WARNING , " Failed to async goto '%s' into fax of '%s' \n " , ast - > name , ast - > context ) ;
} else
ast_log ( LOG_NOTICE , " Fax detected, but no fax extension \n " ) ;
} else
ast_log ( LOG_DEBUG , " Already in a fax extension, not redirecting \n " ) ;
} else
ast_log ( LOG_DEBUG , " Fax already handled \n " ) ;
zt_confmute ( p , 0 ) ;
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
f = & p - > subs [ index ] . f ;
} else if ( f - > subclass = = ' m ' ) {
/* Confmute request */
zt_confmute ( p , 1 ) ;
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
f = & p - > subs [ index ] . f ;
} else if ( f - > subclass = = ' u ' ) {
/* Unmute */
zt_confmute ( p , 0 ) ;
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
f = & p - > subs [ index ] . f ;
} else
zt_confmute ( p , 0 ) ;
}
#if 0
if ( f - > frametype = = AST_FRAME_VOICE & & ( ast - > _state = = AST_STATE_UP ) ) {
p - > subs [ index ] . f . frametype = AST_FRAME_NULL ;
p - > subs [ index ] . f . subclass = 0 ;
f = & p - > subs [ index ] . f ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
# endif
2001-10-09 02:06:21 +00:00
pthread_mutex_unlock ( & p - > lock ) ;
2003-02-07 19:23:19 +00:00
return f ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
static int my_zt_write ( struct zt_pvt * p , unsigned char * buf , int len , int index , int linear )
2001-10-09 02:06:21 +00:00
{
int sent = 0 ;
int size ;
int res ;
int fd ;
2003-02-07 19:23:19 +00:00
fd = p - > subs [ index ] . zfd ;
2001-10-09 02:06:21 +00:00
while ( len ) {
size = len ;
2003-02-07 19:23:19 +00:00
if ( size > ( linear ? READ_SIZE * 2 : READ_SIZE ) )
size = ( linear ? READ_SIZE * 2 : READ_SIZE ) ;
2001-10-09 02:06:21 +00:00
res = write ( fd , buf , size ) ;
if ( res ! = size ) {
2001-12-29 18:04:21 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Write returned %d (%s) on channel %d \n " , res , strerror ( errno ) , p - > channel ) ;
2001-10-09 02:06:21 +00:00
return sent ;
}
len - = size ;
buf + = size ;
}
return sent ;
}
static int zt_write ( struct ast_channel * ast , struct ast_frame * frame )
{
struct zt_pvt * p = ast - > pvt - > pvt ;
int res ;
unsigned char outbuf [ 4096 ] ;
2003-02-07 19:23:19 +00:00
int index ;
2001-10-09 02:06:21 +00:00
2003-02-07 19:23:19 +00:00
index = zt_get_index ( ast , p , 0 ) ;
if ( index < 0 ) {
ast_log ( LOG_WARNING , " %s doesn't really exist? \n " , ast - > name ) ;
return - 1 ;
2001-10-09 02:06:21 +00:00
}
/* Write a frame of (presumably voice) data */
if ( frame - > frametype ! = AST_FRAME_VOICE ) {
2002-06-24 17:59:56 +00:00
if ( frame - > frametype ! = AST_FRAME_IMAGE )
ast_log ( LOG_WARNING , " Don't know what to do with frame type '%d' \n " , frame - > frametype ) ;
return 0 ;
2001-10-09 02:06:21 +00:00
}
2001-12-29 18:04:21 +00:00
if ( ( frame - > subclass ! = AST_FORMAT_SLINEAR ) & &
( frame - > subclass ! = AST_FORMAT_ULAW ) & &
( frame - > subclass ! = AST_FORMAT_ALAW ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Cannot handle frames in %d format \n " , frame - > subclass ) ;
return - 1 ;
}
if ( p - > dialing ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Dropping frame since I'm still dialing on %s... \n " , ast - > name ) ;
return 0 ;
}
if ( p - > cidspill ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Dropping frame since I've still got a callerid spill \n " ) ;
return 0 ;
}
/* Return if it's not valid data */
if ( ! frame - > data | | ! frame - > datalen )
return 0 ;
if ( frame - > datalen > sizeof ( outbuf ) * 2 ) {
ast_log ( LOG_WARNING , " Frame too large \n " ) ;
return 0 ;
}
2003-02-07 19:23:19 +00:00
2001-10-09 02:06:21 +00:00
if ( frame - > subclass = = AST_FORMAT_SLINEAR ) {
2003-02-07 19:23:19 +00:00
if ( ! p - > subs [ index ] . linear ) {
p - > subs [ index ] . linear = 1 ;
res = zt_setlinear ( p - > subs [ index ] . zfd , p - > subs [ index ] . linear ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to set linear mode on channel %d \n " , p - > channel ) ;
2001-12-29 18:04:21 +00:00
}
2003-02-07 19:23:19 +00:00
res = my_zt_write ( p , ( unsigned char * ) frame - > data , frame - > datalen , index , 1 ) ;
2001-10-09 02:06:21 +00:00
} else {
2001-12-29 18:04:21 +00:00
/* x-law already */
2003-02-07 19:23:19 +00:00
if ( p - > subs [ index ] . linear ) {
p - > subs [ index ] . linear = 0 ;
res = zt_setlinear ( p - > subs [ index ] . zfd , p - > subs [ index ] . linear ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to set companded mode on channel %d \n " , p - > channel ) ;
2001-12-29 18:04:21 +00:00
}
2003-02-07 19:23:19 +00:00
res = my_zt_write ( p , ( unsigned char * ) frame - > data , frame - > datalen , index , 0 ) ;
2001-10-09 02:06:21 +00:00
}
if ( res < 0 ) {
ast_log ( LOG_WARNING , " write failed: %s \n " , strerror ( errno ) ) ;
return - 1 ;
2001-12-29 18:04:21 +00:00
}
2001-10-09 02:06:21 +00:00
return 0 ;
}
static int zt_indicate ( struct ast_channel * chan , int condition )
{
struct zt_pvt * p = chan - > pvt - > pvt ;
int res = - 1 ;
2003-02-07 19:23:19 +00:00
int index = zt_get_index ( chan , p , 0 ) ;
if ( index = = SUB_REAL ) {
switch ( condition ) {
case AST_CONTROL_BUSY :
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_BUSY ) ;
break ;
case AST_CONTROL_RINGING :
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_RINGTONE ) ;
if ( chan - > _state ! = AST_STATE_UP ) {
if ( ( chan - > _state ! = AST_STATE_RING ) | |
( ( p - > sig ! = SIG_FXSKS ) & &
( p - > sig ! = SIG_FXSLS ) & &
( p - > sig ! = SIG_FXSGS ) ) )
ast_setstate ( chan , AST_STATE_RINGING ) ;
}
2003-05-19 23:33:41 +00:00
#if 0
break ;
# endif
/* Fall through */
case AST_CONTROL_PROGRESS :
ast_log ( LOG_DEBUG , " Received AST_CONTROL_PROGRESS on %s \n " , chan - > name ) ;
# ifdef ZAPATA_PRI
# ifdef PRI_EVENT_PROCEEDING
if ( ! p - > proceeding & & p - > sig = = SIG_PRI & & p - > pri & & p - > pri - > overlapdial ) {
if ( p - > pri - > pri ) {
if ( ! pri_grab ( p , p - > pri ) ) {
pri_acknowledge ( p - > pri - > pri , p - > call , p - > prioffset , 1 ) ;
pri_rel ( p - > pri ) ;
}
else
ast_log ( LOG_WARNING , " Unable to grab PRI on span %d \n " , p - > span ) ;
}
p - > proceeding = 1 ;
}
# else
ast_log ( LOG_WARNING , " Please update your libpri package if you want to use overlap sending \n " ) ;
# endif
# endif
/* don't continue in ast_indicate */
res = 0 ;
2003-02-07 19:23:19 +00:00
break ;
case AST_CONTROL_CONGESTION :
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
break ;
case AST_CONTROL_RADIO_KEY :
if ( p - > radio )
res = zt_set_hook ( p - > subs [ index ] . zfd , ZT_OFFHOOK ) ;
res = 0 ;
break ;
case AST_CONTROL_RADIO_UNKEY :
if ( p - > radio )
res = zt_set_hook ( p - > subs [ index ] . zfd , ZT_RINGOFF ) ;
res = 0 ;
break ;
case - 1 :
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
break ;
default :
ast_log ( LOG_WARNING , " Don't know how to set condition %d on channel %s \n " , condition , chan - > name ) ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
} else
res = 0 ;
2001-10-09 02:06:21 +00:00
return res ;
}
2003-02-07 19:23:19 +00:00
static struct ast_channel * zt_new ( struct zt_pvt * i , int state , int startpbx , int index , int law )
2001-10-09 02:06:21 +00:00
{
struct ast_channel * tmp ;
2001-12-29 18:04:21 +00:00
int deflaw ;
int res ;
2003-02-07 19:23:19 +00:00
int x , y ;
int features ;
2001-12-29 18:04:21 +00:00
ZT_PARAMS ps ;
2002-06-24 17:59:56 +00:00
tmp = ast_channel_alloc ( 0 ) ;
2001-10-09 02:06:21 +00:00
if ( tmp ) {
2001-12-29 18:04:21 +00:00
ps . channo = i - > channel ;
2003-02-07 19:23:19 +00:00
res = ioctl ( i - > subs [ SUB_REAL ] . zfd , ZT_GET_PARAMS , & ps ) ;
2001-12-29 18:04:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to get parameters, assuming MULAW \n " ) ;
ps . curlaw = ZT_LAW_MULAW ;
}
if ( ps . curlaw = = ZT_LAW_ALAW )
deflaw = AST_FORMAT_ALAW ;
else
deflaw = AST_FORMAT_ULAW ;
2003-02-07 19:23:19 +00:00
if ( law ) {
if ( law = = ZT_LAW_ALAW )
deflaw = AST_FORMAT_ALAW ;
else
deflaw = AST_FORMAT_ULAW ;
}
y = 1 ;
do {
snprintf ( tmp - > name , sizeof ( tmp - > name ) , " Zap/%d-%d " , i - > channel , y ) ;
for ( x = 0 ; x < 3 ; x + + ) {
if ( ( index ! = x ) & & i - > subs [ x ] . owner & & ! strcasecmp ( tmp - > name , i - > subs [ x ] . owner - > name ) )
break ;
}
y + + ;
} while ( x < 3 ) ;
2001-10-09 02:06:21 +00:00
tmp - > type = type ;
2003-02-07 19:23:19 +00:00
tmp - > fds [ 0 ] = i - > subs [ index ] . zfd ;
2001-12-29 18:04:21 +00:00
tmp - > nativeformats = AST_FORMAT_SLINEAR | deflaw ;
2001-10-09 02:06:21 +00:00
/* Start out assuming ulaw since it's smaller :) */
2001-12-29 18:04:21 +00:00
tmp - > pvt - > rawreadformat = deflaw ;
tmp - > readformat = deflaw ;
tmp - > pvt - > rawwriteformat = deflaw ;
tmp - > writeformat = deflaw ;
2003-02-07 19:23:19 +00:00
i - > subs [ index ] . linear = 0 ;
zt_setlinear ( i - > subs [ index ] . zfd , i - > subs [ index ] . linear ) ;
features = 0 ;
if ( i - > busydetect & & CANBUSYDETECT ( i ) ) {
features | = DSP_FEATURE_BUSY_DETECT ;
}
2003-04-11 03:47:19 +00:00
if ( i - > callprogress & & CANPROGRESSDETECT ( i ) & & i - > outgoing ) {
2003-02-07 19:23:19 +00:00
features | = DSP_FEATURE_CALL_PROGRESS ;
}
features | = DSP_FEATURE_DTMF_DETECT ;
if ( features ) {
if ( i - > dsp ) {
ast_log ( LOG_DEBUG , " Already have a dsp on %s? \n " , tmp - > name ) ;
} else {
i - > dsp = ast_dsp_new ( ) ;
if ( i - > dsp ) {
ast_dsp_set_features ( i - > dsp , features ) ;
ast_dsp_digitmode ( i - > dsp , DSP_DIGITMODE_DTMF | i - > dtmfrelax ) ;
2003-03-06 06:00:17 +00:00
if ( i - > busydetect & & CANBUSYDETECT ( i ) ) {
ast_dsp_set_busy_count ( i - > dsp , i - > busycount ) ;
}
2003-02-07 19:23:19 +00:00
}
}
}
2001-10-09 02:06:21 +00:00
if ( state = = AST_STATE_RING )
tmp - > rings = 1 ;
tmp - > pvt - > pvt = i ;
tmp - > pvt - > send_digit = zt_digit ;
2001-12-29 18:04:21 +00:00
tmp - > pvt - > send_text = zt_sendtext ;
2001-10-09 02:06:21 +00:00
tmp - > pvt - > call = zt_call ;
tmp - > pvt - > hangup = zt_hangup ;
tmp - > pvt - > answer = zt_answer ;
tmp - > pvt - > read = zt_read ;
tmp - > pvt - > write = zt_write ;
tmp - > pvt - > bridge = zt_bridge ;
tmp - > pvt - > exception = zt_exception ;
tmp - > pvt - > indicate = zt_indicate ;
tmp - > pvt - > fixup = zt_fixup ;
tmp - > pvt - > setoption = zt_setoption ;
2003-04-09 04:00:43 +00:00
if ( ( i - > sig = = SIG_FXOKS ) | | ( i - > sig = = SIG_FXOGS ) | | ( i - > sig = = SIG_FXOLS ) ) {
/* Only FXO signalled stuff can be picked up */
tmp - > callgroup = i - > callgroup ;
tmp - > pickupgroup = i - > pickupgroup ;
}
2001-10-09 02:06:21 +00:00
if ( strlen ( i - > language ) )
2001-12-29 18:04:21 +00:00
strncpy ( tmp - > language , i - > language , sizeof ( tmp - > language ) - 1 ) ;
2002-06-24 17:59:56 +00:00
if ( strlen ( i - > musicclass ) )
strncpy ( tmp - > musicclass , i - > musicclass , sizeof ( tmp - > musicclass ) - 1 ) ;
2001-10-09 02:06:21 +00:00
if ( ! i - > owner )
i - > owner = tmp ;
2001-12-29 18:04:21 +00:00
if ( strlen ( i - > accountcode ) )
strncpy ( tmp - > accountcode , i - > accountcode , sizeof ( tmp - > accountcode ) - 1 ) ;
if ( i - > amaflags )
tmp - > amaflags = i - > amaflags ;
2003-02-07 19:23:19 +00:00
if ( i - > subs [ index ] . owner ) {
ast_log ( LOG_WARNING , " Channel %d already has a %s call \n " , i - > channel , subnames [ index ] ) ;
2001-10-09 02:06:21 +00:00
}
2003-02-07 19:23:19 +00:00
i - > subs [ index ] . owner = tmp ;
2002-09-10 04:45:51 +00:00
ast_setstate ( tmp , state ) ;
2001-10-09 02:06:21 +00:00
ast_pthread_mutex_lock ( & usecnt_lock ) ;
usecnt + + ;
ast_pthread_mutex_unlock ( & usecnt_lock ) ;
ast_update_use_count ( ) ;
2001-12-29 18:04:21 +00:00
strncpy ( tmp - > context , i - > context , sizeof ( tmp - > context ) - 1 ) ;
2002-03-08 23:48:42 +00:00
/* Copy call forward info */
strncpy ( tmp - > call_forward , i - > call_forward , sizeof ( tmp - > call_forward ) ) ;
2001-12-29 18:04:21 +00:00
/* If we've been told "no ADSI" then enforce it */
if ( ! i - > adsi )
tmp - > adsicpe = AST_ADSI_UNAVAILABLE ;
2001-10-09 02:06:21 +00:00
if ( strlen ( i - > exten ) )
2001-12-29 18:04:21 +00:00
strncpy ( tmp - > exten , i - > exten , sizeof ( tmp - > exten ) - 1 ) ;
2003-02-07 19:23:19 +00:00
if ( strlen ( i - > rdnis ) )
tmp - > rdnis = strdup ( i - > rdnis ) ;
2002-06-24 17:59:56 +00:00
if ( strlen ( i - > callerid ) ) {
tmp - > callerid = strdup ( i - > callerid ) ;
tmp - > ani = strdup ( i - > callerid ) ;
}
# ifdef ZAPATA_PRI
/* Assume calls are not idle calls unless we're told differently */
i - > isidlecall = 0 ;
# endif
2003-02-12 13:59:15 +00:00
/* Assure there is no confmute on this channel */
zt_confmute ( i , 0 ) ;
2001-10-09 02:06:21 +00:00
if ( startpbx ) {
if ( ast_pbx_start ( tmp ) ) {
ast_log ( LOG_WARNING , " Unable to start PBX on %s \n " , tmp - > name ) ;
ast_hangup ( tmp ) ;
tmp = NULL ;
}
}
} else
ast_log ( LOG_WARNING , " Unable to allocate channel structure \n " ) ;
return tmp ;
}
static int bump_gains ( struct zt_pvt * p )
{
int res ;
/* Bump receive gain by 9.0db */
2003-02-07 19:23:19 +00:00
res = set_actual_gain ( p - > subs [ SUB_REAL ] . zfd , 0 , p - > rxgain + 5.0 , p - > txgain , p - > law ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to bump gain \n " ) ;
return - 1 ;
}
return 0 ;
}
static int restore_gains ( struct zt_pvt * p )
{
int res ;
/* Bump receive gain by 9.0db */
2003-02-07 19:23:19 +00:00
res = set_actual_gain ( p - > subs [ SUB_REAL ] . zfd , 0 , p - > rxgain , p - > txgain , p - > law ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to restore gains: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
return 0 ;
}
2003-02-07 19:23:19 +00:00
static int my_getsigstr ( struct ast_channel * chan , char * str , char term , int ms )
{
char c ;
* str = 0 ; /* start with empty output buffer */
for ( ; ; )
{
/* Wait for the first digit (up to specified ms). */
c = ast_waitfordigit ( chan , ms ) ;
/* if timeout, hangup or error, return as such */
if ( c < 1 ) return ( c ) ;
* str + + = c ;
* str = 0 ;
if ( c = = term ) return ( 1 ) ;
}
}
2003-05-29 16:03:53 +00:00
static int zt_wink ( struct zt_pvt * p , int index )
{
int j ;
zt_set_hook ( p - > subs [ index ] . zfd , ZT_WINK ) ;
for ( ; ; )
{
/* set bits of interest */
j = ZT_IOMUX_SIGEVENT ;
/* wait for some happening */
if ( ioctl ( p - > subs [ index ] . zfd , ZT_IOMUX , & j ) = = - 1 ) return ( - 1 ) ;
/* exit loop if we have it */
if ( j & ZT_IOMUX_SIGEVENT ) break ;
}
/* get the event info */
if ( ioctl ( p - > subs [ index ] . zfd , ZT_GETEVENT , & j ) = = - 1 ) return ( - 1 ) ;
return 0 ;
}
2001-10-09 02:06:21 +00:00
static void * ss_thread ( void * data )
{
struct ast_channel * chan = data ;
struct zt_pvt * p = chan - > pvt - > pvt ;
char exten [ AST_MAX_EXTENSION ] ;
char exten2 [ AST_MAX_EXTENSION ] ;
unsigned char buf [ 256 ] ;
char cid [ 256 ] ;
2003-02-07 19:23:19 +00:00
char dtmfbuf [ 300 ] ;
2001-10-09 02:06:21 +00:00
struct callerid_state * cs ;
char * name = NULL , * number = NULL ;
int flags ;
2003-05-29 16:03:53 +00:00
int i ;
2001-10-09 02:06:21 +00:00
int timeout ;
2002-03-08 23:48:42 +00:00
int getforward = 0 ;
2001-10-09 02:06:21 +00:00
char * s1 , * s2 ;
int len = 0 ;
int res ;
2003-02-07 19:23:19 +00:00
int index ;
2001-10-09 02:06:21 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Starting simple switch on '%s' \n " , chan - > name ) ;
2003-02-07 19:23:19 +00:00
index = zt_get_index ( chan , p , 1 ) ;
if ( index < 0 ) {
ast_log ( LOG_WARNING , " Huh? \n " ) ;
ast_hangup ( chan ) ;
return NULL ;
}
if ( p - > dsp )
ast_dsp_digitreset ( p - > dsp ) ;
2001-10-09 02:06:21 +00:00
switch ( p - > sig ) {
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2001-10-09 02:06:21 +00:00
case SIG_EMWINK :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATD :
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
case SIG_SFWINK :
2003-05-29 16:03:53 +00:00
if ( zt_wink ( p , index ) )
return NULL ;
2001-10-09 02:06:21 +00:00
/* Fall through */
case SIG_EM :
2003-03-17 20:04:36 +00:00
case SIG_SF :
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
if ( p - > dsp )
ast_dsp_digitreset ( p - > dsp ) ;
2002-06-24 17:59:56 +00:00
/* set digit mode appropriately */
2003-02-07 19:23:19 +00:00
if ( p - > dsp ) {
if ( ( p - > sig = = SIG_FEATDMF ) | | ( p - > sig = = SIG_FEATB ) )
ast_dsp_digitmode ( p - > dsp , DSP_DIGITMODE_MF | p - > dtmfrelax ) ;
else
ast_dsp_digitmode ( p - > dsp , DSP_DIGITMODE_DTMF | p - > dtmfrelax ) ;
}
2003-05-19 23:33:41 +00:00
dtmfbuf [ 0 ] = 0 ;
/* Wait for the first digit only if immediate=no */
if ( ( ( p - > sig = = SIG_EM ) | | ( p - > sig = = SIG_EMWINK ) ) & & ! p - > immediate )
/* Wait for the first digit (up to 5 seconds). */
res = ast_waitfordigit ( chan , 5000 ) ;
else res = 0 ;
2003-02-07 19:23:19 +00:00
if ( res > 0 ) {
/* save first char */
dtmfbuf [ 0 ] = res ;
2002-06-24 17:59:56 +00:00
switch ( p - > sig )
{
case SIG_FEATD :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATD :
2003-02-07 19:23:19 +00:00
res = my_getsigstr ( chan , dtmfbuf + 1 , ' * ' , 3000 ) ;
2002-06-24 17:59:56 +00:00
if ( res > 0 )
2003-02-07 19:23:19 +00:00
res = my_getsigstr ( chan , dtmfbuf + strlen ( dtmfbuf ) , ' * ' , 3000 ) ;
if ( res < 1 ) ast_dsp_digitreset ( p - > dsp ) ;
2002-06-24 17:59:56 +00:00
break ;
case SIG_FEATDMF :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATDMF :
2003-02-07 19:23:19 +00:00
res = my_getsigstr ( chan , dtmfbuf + 1 , ' # ' , 3000 ) ;
if ( res > 0 )
res = my_getsigstr ( chan , dtmfbuf + strlen ( dtmfbuf ) , ' # ' , 3000 ) ;
if ( res < 1 ) ast_dsp_digitreset ( p - > dsp ) ;
2002-06-24 17:59:56 +00:00
break ;
case SIG_FEATB :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATB :
2003-02-07 19:23:19 +00:00
res = my_getsigstr ( chan , dtmfbuf + 1 , ' # ' , 3000 ) ;
if ( res < 1 ) ast_dsp_digitreset ( p - > dsp ) ;
2002-06-24 17:59:56 +00:00
break ;
default :
/* If we got it, get the rest */
2003-02-07 19:23:19 +00:00
res = my_getsigstr ( chan , dtmfbuf + 1 , ' ' , 250 ) ;
2002-06-24 17:59:56 +00:00
break ;
}
2001-10-09 02:06:21 +00:00
}
if ( res = = - 1 ) {
ast_log ( LOG_WARNING , " getdtmf on channel %d: %s \n " , p - > channel , strerror ( errno ) ) ;
ast_hangup ( chan ) ;
return NULL ;
} else if ( res < 0 ) {
ast_log ( LOG_DEBUG , " Got hung up before digits finished \n " ) ;
ast_hangup ( chan ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
strncpy ( exten , dtmfbuf , sizeof ( exten ) - 1 ) ;
2001-10-09 02:06:21 +00:00
if ( ! strlen ( exten ) )
2001-12-29 18:04:21 +00:00
strncpy ( exten , " s " , sizeof ( exten ) - 1 ) ;
2001-10-09 02:06:21 +00:00
if ( p - > sig = = SIG_FEATD ) {
if ( exten [ 0 ] = = ' * ' ) {
2003-02-07 19:23:19 +00:00
char * stringp = NULL ;
2001-12-29 18:04:21 +00:00
strncpy ( exten2 , exten , sizeof ( exten2 ) - 1 ) ;
2001-10-09 02:06:21 +00:00
/* Parse out extension and callerid */
2003-02-07 19:23:19 +00:00
stringp = exten2 + 1 ;
s1 = strsep ( & stringp , " * " ) ;
s2 = strsep ( & stringp , " * " ) ;
2001-10-09 02:06:21 +00:00
if ( s2 ) {
if ( strlen ( p - > callerid ) )
chan - > callerid = strdup ( p - > callerid ) ;
else
chan - > callerid = strdup ( s1 ) ;
2001-12-29 18:04:21 +00:00
if ( chan - > callerid )
2002-03-08 23:48:42 +00:00
chan - > ani = strdup ( chan - > callerid ) ;
2001-12-29 18:04:21 +00:00
strncpy ( exten , s2 , sizeof ( exten ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else
2001-12-29 18:04:21 +00:00
strncpy ( exten , s1 , sizeof ( exten ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else
ast_log ( LOG_WARNING , " Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead \n " , p - > channel ) ;
}
2002-06-24 17:59:56 +00:00
if ( p - > sig = = SIG_FEATDMF ) {
if ( exten [ 0 ] = = ' * ' ) {
2003-02-07 19:23:19 +00:00
char * stringp = NULL ;
2002-06-24 17:59:56 +00:00
strncpy ( exten2 , exten , sizeof ( exten2 ) - 1 ) ;
/* Parse out extension and callerid */
2003-02-07 19:23:19 +00:00
stringp = exten2 + 1 ;
s1 = strsep ( & stringp , " # " ) ;
s2 = strsep ( & stringp , " # " ) ;
2002-06-24 17:59:56 +00:00
if ( s2 ) {
if ( strlen ( p - > callerid ) )
chan - > callerid = strdup ( p - > callerid ) ;
else
if ( * ( s1 + 2 ) ) chan - > callerid = strdup ( s1 + 2 ) ;
if ( chan - > callerid )
chan - > ani = strdup ( chan - > callerid ) ;
strncpy ( exten , s2 + 1 , sizeof ( exten ) - 1 ) ;
} else
strncpy ( exten , s1 + 2 , sizeof ( exten ) - 1 ) ;
} else
ast_log ( LOG_WARNING , " Got a non-Feature Group D input on channel %d. Assuming E&M Wink instead \n " , p - > channel ) ;
}
if ( p - > sig = = SIG_FEATB ) {
if ( exten [ 0 ] = = ' * ' ) {
2003-02-07 19:23:19 +00:00
char * stringp = NULL ;
2002-06-24 17:59:56 +00:00
strncpy ( exten2 , exten , sizeof ( exten2 ) - 1 ) ;
/* Parse out extension and callerid */
2003-02-07 19:23:19 +00:00
stringp = exten2 + 1 ;
s1 = strsep ( & stringp , " # " ) ;
2002-06-24 17:59:56 +00:00
strncpy ( exten , exten2 + 1 , sizeof ( exten ) - 1 ) ;
} else
ast_log ( LOG_WARNING , " Got a non-Feature Group B input on channel %d. Assuming E&M Wink instead \n " , p - > channel ) ;
}
2003-05-29 16:03:53 +00:00
if ( p - > sig = = SIG_FEATDMF ) {
zt_wink ( p , index ) ;
}
2001-10-09 02:06:21 +00:00
zt_enable_ec ( p ) ;
if ( ast_exists_extension ( chan , chan - > context , exten , 1 , chan - > callerid ) ) {
2001-12-29 18:04:21 +00:00
strncpy ( chan - > exten , exten , sizeof ( chan - > exten ) - 1 ) ;
2003-02-07 19:23:19 +00:00
ast_dsp_digitreset ( p - > dsp ) ;
2001-10-09 02:06:21 +00:00
res = ast_pbx_run ( chan ) ;
if ( res ) {
ast_log ( LOG_WARNING , " PBX exited non-zero \n " ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
}
return NULL ;
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_2 " Unknown extension '%s' in context '%s' requested \n " , exten , chan - > context ) ;
sleep ( 2 ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_INFO ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to start special tone on %d \n " , p - > channel ) ;
else
sleep ( 1 ) ;
res = ast_streamfile ( chan , " ss-noservice " , chan - > language ) ;
if ( res > = 0 )
ast_waitstream ( chan , " " ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
ast_hangup ( chan ) ;
return NULL ;
}
break ;
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
/* Read the first digit */
timeout = firstdigittimeout ;
2003-02-13 06:00:14 +00:00
/* If starting a threeway call, never timeout on the first digit so someone
can use flash - hook as a " hold " feature */
if ( p - > subs [ SUB_THREEWAY ] . owner )
timeout = 999999 ;
2001-10-09 02:06:21 +00:00
while ( len < AST_MAX_EXTENSION - 1 ) {
res = ast_waitfordigit ( chan , timeout ) ;
2003-02-07 19:23:19 +00:00
timeout = 0 ;
if ( res < 0 ) {
ast_log ( LOG_DEBUG , " waitfordigit returned < 0... \n " ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
2001-10-09 02:06:21 +00:00
ast_hangup ( chan ) ;
return NULL ;
2003-02-07 19:23:19 +00:00
} else if ( res ) {
2001-10-09 02:06:21 +00:00
exten [ len + + ] = res ;
2003-02-13 06:00:14 +00:00
exten [ len ] = ' \0 ' ;
2001-10-09 02:06:21 +00:00
}
if ( ! ast_ignore_pattern ( chan - > context , exten ) )
2003-02-07 19:23:19 +00:00
tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
else
tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALTONE ) ;
2001-10-09 02:06:21 +00:00
if ( ast_exists_extension ( chan , chan - > context , exten , 1 , p - > callerid ) ) {
2003-02-07 19:23:19 +00:00
if ( ! res | | ! ast_matchmore_extension ( chan , chan - > context , exten , 1 , p - > callerid ) ) {
if ( getforward ) {
/* Record this as the forwarding extension */
strncpy ( p - > call_forward , exten , sizeof ( p - > call_forward ) ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Setting call forward to '%s' on channel %d \n " , p - > call_forward , p - > channel ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
if ( res )
break ;
usleep ( 500000 ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
sleep ( 1 ) ;
memset ( exten , 0 , sizeof ( exten ) ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALTONE ) ;
len = 0 ;
getforward = 0 ;
} else {
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
strncpy ( chan - > exten , exten , sizeof ( chan - > exten ) - 1 ) ;
if ( strlen ( p - > callerid ) ) {
if ( ! p - > hidecallerid )
chan - > callerid = strdup ( p - > callerid ) ;
chan - > ani = strdup ( p - > callerid ) ;
}
ast_setstate ( chan , AST_STATE_RING ) ;
zt_enable_ec ( p ) ;
res = ast_pbx_run ( chan ) ;
if ( res ) {
ast_log ( LOG_WARNING , " PBX exited non-zero \n " ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
}
return NULL ;
2002-03-08 23:48:42 +00:00
}
2003-02-07 19:23:19 +00:00
} else {
/* It's a match, but they just typed a digit, and there is an ambiguous match,
so just set the timeout to matchdigittimeout and wait some more */
timeout = matchdigittimeout ;
2001-12-29 18:04:21 +00:00
}
2003-02-07 19:23:19 +00:00
} else if ( res = = 0 ) {
ast_log ( LOG_DEBUG , " not enough digits (and no ambiguous match)... \n " ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
zt_wait_event ( p - > subs [ index ] . zfd ) ;
ast_hangup ( chan ) ;
return NULL ;
2001-10-09 02:06:21 +00:00
} else if ( p - > callwaiting & & ! strcmp ( exten , " *70 " ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Disabling call waiting on %s \n " , chan - > name ) ;
/* Disable call waiting if enabled */
p - > callwaiting = 0 ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to do dial recall on channel %s: %s \n " ,
chan - > name , strerror ( errno ) ) ;
}
len = 0 ;
2003-02-07 19:23:19 +00:00
ioctl ( p - > subs [ index ] . zfd , ZT_CONFDIAG , & len ) ;
2001-10-09 02:06:21 +00:00
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
2003-04-09 04:00:43 +00:00
} else if ( ! strcmp ( exten , ast_pickup_ext ( ) ) ) {
2001-10-09 02:06:21 +00:00
/* Scan all channels and see if any there
* ringing channqels with that have call groups
* that equal this channels pickup group
*/
2003-04-09 04:00:43 +00:00
if ( index = = SUB_REAL ) {
/* Switch us from Third call to Call Wait */
if ( p - > subs [ SUB_THREEWAY ] . owner ) {
/* If you make a threeway call and the *8# a call, it should actually
look like a callwait */
alloc_sub ( p , SUB_CALLWAIT ) ;
swap_subs ( p , SUB_CALLWAIT , SUB_THREEWAY ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
}
zt_enable_ec ( p ) ;
if ( ast_pickup_call ( chan ) ) {
ast_log ( LOG_DEBUG , " No call pickup possible... \n " ) ;
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
zt_wait_event ( p - > subs [ index ] . zfd ) ;
2001-10-09 02:06:21 +00:00
}
2003-04-09 04:00:43 +00:00
ast_hangup ( chan ) ;
return NULL ;
} else {
ast_log ( LOG_WARNING , " Huh? Got *8# on call not on real \n " ) ;
ast_hangup ( chan ) ;
return NULL ;
2001-10-09 02:06:21 +00:00
}
2003-04-09 04:00:43 +00:00
2001-10-09 02:06:21 +00:00
} else if ( ! p - > hidecallerid & & ! strcmp ( exten , " *67 " ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Disabling Caller*ID on %s \n " , chan - > name ) ;
/* Disable Caller*ID if enabled */
p - > hidecallerid = 1 ;
if ( chan - > callerid )
free ( chan - > callerid ) ;
chan - > callerid = NULL ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to do dial recall on channel %s: %s \n " ,
chan - > name , strerror ( errno ) ) ;
}
len = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
2003-02-07 19:23:19 +00:00
} else if ( p - > callreturn & & ! strcmp ( exten , " *69 " ) ) {
res = 0 ;
if ( strlen ( p - > lastcallerid ) ) {
res = ast_say_digit_str ( chan , p - > lastcallerid , " " , chan - > language ) ;
}
if ( ! res )
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
break ;
2002-09-10 04:45:51 +00:00
} else if ( ! strcmp ( exten , " *78 " ) ) {
/* Do not disturb */
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Enabled DND on channel %d \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2002-09-10 04:45:51 +00:00
p - > dnd = 1 ;
getforward = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
} else if ( ! strcmp ( exten , " *79 " ) ) {
/* Do not disturb */
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Disabled DND on channel %d \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2002-09-10 04:45:51 +00:00
p - > dnd = 0 ;
getforward = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
2002-03-08 23:48:42 +00:00
} else if ( p - > cancallforward & & ! strcmp ( exten , " *72 " ) ) {
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2002-03-08 23:48:42 +00:00
getforward = 1 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
} else if ( p - > cancallforward & & ! strcmp ( exten , " *73 " ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Cancelling call forwarding on channel %d \n " , p - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2002-03-08 23:48:42 +00:00
memset ( p - > call_forward , 0 , sizeof ( p - > call_forward ) ) ;
getforward = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
2001-12-29 18:04:21 +00:00
} else if ( p - > transfer & & ! strcmp ( exten , ast_parking_ext ( ) ) & &
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_THREEWAY ] . owner & &
p - > subs [ SUB_THREEWAY ] . owner - > bridge ) {
2001-12-29 18:04:21 +00:00
/* This is a three way call, the main call being a real channel,
and we ' re parking the first call . */
2003-02-07 19:23:19 +00:00
ast_masq_park_call ( p - > subs [ SUB_THREEWAY ] . owner - > bridge , chan , 0 , NULL ) ;
2001-12-29 18:04:21 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Parking call to '%s' \n " , chan - > name ) ;
break ;
2003-03-06 06:00:17 +00:00
} else if ( strlen ( p - > lastcallerid ) & & ! strcmp ( exten , " *80 " ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Blacklisting number %s \n " , p - > lastcallerid ) ;
res = ast_db_put ( " blacklist " , p - > lastcallerid , " 1 " ) ;
if ( ! res ) {
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
memset ( exten , 0 , sizeof ( exten ) ) ;
len = 0 ;
}
2001-10-09 02:06:21 +00:00
} else if ( p - > hidecallerid & & ! strcmp ( exten , " *82 " ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Enabling Caller*ID on %s \n " , chan - > name ) ;
/* Enable Caller*ID if enabled */
p - > hidecallerid = 0 ;
if ( chan - > callerid )
free ( chan - > callerid ) ;
2001-12-29 18:04:21 +00:00
if ( strlen ( p - > callerid ) )
chan - > callerid = strdup ( p - > callerid ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_DIALRECALL ) ;
2001-10-09 02:06:21 +00:00
if ( res ) {
ast_log ( LOG_WARNING , " Unable to do dial recall on channel %s: %s \n " ,
chan - > name , strerror ( errno ) ) ;
}
len = 0 ;
memset ( exten , 0 , sizeof ( exten ) ) ;
timeout = firstdigittimeout ;
} else if ( ! strcmp ( exten , " *0 " ) ) {
struct ast_channel * nbridge =
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_THREEWAY ] . owner ;
2001-10-09 02:06:21 +00:00
struct zt_pvt * pbridge = NULL ;
/* set up the private struct of the bridged one, if any */
2003-02-07 19:23:19 +00:00
if ( nbridge & & nbridge - > bridge ) pbridge = nbridge - > bridge - > pvt - > pvt ;
if ( nbridge & &
2001-10-09 02:06:21 +00:00
( ! strcmp ( nbridge - > type , " Zap " ) ) & &
ISTRUNK ( pbridge ) ) {
int func = ZT_FLASH ;
2003-05-19 23:33:41 +00:00
/* Clear out the dial buffer */
p - > dop . dialstr [ 0 ] = ' \0 ' ;
2001-10-09 02:06:21 +00:00
/* flash hookswitch */
2003-02-07 19:23:19 +00:00
if ( ( ioctl ( pbridge - > subs [ SUB_REAL ] . zfd , ZT_HOOK , & func ) = = - 1 ) & & ( errno ! = EINPROGRESS ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to flash external trunk on channel %s: %s \n " ,
nbridge - > name , strerror ( errno ) ) ;
2003-02-07 19:23:19 +00:00
}
swap_subs ( p , SUB_REAL , SUB_THREEWAY ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
2001-10-09 02:06:21 +00:00
ast_hangup ( chan ) ;
return NULL ;
} else {
2003-02-07 19:23:19 +00:00
tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
zt_wait_event ( p - > subs [ index ] . zfd ) ;
tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
swap_subs ( p , SUB_REAL , SUB_THREEWAY ) ;
unalloc_sub ( p , SUB_THREEWAY ) ;
p - > owner = p - > subs [ SUB_REAL ] . owner ;
2001-10-09 02:06:21 +00:00
ast_hangup ( chan ) ;
return NULL ;
}
} else if ( ! ast_canmatch_extension ( chan , chan - > context , exten , 1 , chan - > callerid ) & &
( ( exten [ 0 ] ! = ' * ' ) | | ( strlen ( exten ) > 2 ) ) ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Can't match %s from '%s' in context %s \n " , exten , chan - > callerid ? chan - > callerid : " <Unknown Caller> " , chan - > context ) ;
break ;
}
2003-02-07 19:23:19 +00:00
if ( ! timeout )
timeout = gendigittimeout ;
2001-10-09 02:06:21 +00:00
if ( len & & ! ast_ignore_pattern ( chan - > context , exten ) )
2003-02-07 19:23:19 +00:00
tone_zone_play_tone ( p - > subs [ index ] . zfd , - 1 ) ;
2001-10-09 02:06:21 +00:00
}
break ;
case SIG_FXSLS :
case SIG_FXSGS :
case SIG_FXSKS :
if ( p - > use_callerid ) {
cs = callerid_new ( ) ;
if ( cs ) {
# if 1
bump_gains ( p ) ;
# endif
len = 0 ;
2003-02-07 19:23:19 +00:00
/* Take out of linear mode for Caller*ID processing */
zt_setlinear ( p - > subs [ index ] . zfd , 0 ) ;
2001-10-09 02:06:21 +00:00
for ( ; ; ) {
i = ZT_IOMUX_READ | ZT_IOMUX_SIGEVENT ;
2003-02-07 19:23:19 +00:00
if ( ( res = ioctl ( p - > subs [ index ] . zfd , ZT_IOMUX , & i ) ) ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " I/O MUX failed: %s \n " , strerror ( errno ) ) ;
callerid_free ( cs ) ;
ast_hangup ( chan ) ;
return NULL ;
}
if ( i & ZT_IOMUX_SIGEVENT ) {
2003-02-07 19:23:19 +00:00
res = zt_get_event ( p - > subs [ index ] . zfd ) ;
2001-10-09 02:06:21 +00:00
ast_log ( LOG_NOTICE , " Got event %d (%s)... \n " , res , event2str ( res ) ) ;
res = 0 ;
break ;
} else if ( i & ZT_IOMUX_READ ) {
2003-02-07 19:23:19 +00:00
res = read ( p - > subs [ index ] . zfd , buf , sizeof ( buf ) ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
if ( errno ! = ELAST ) {
ast_log ( LOG_WARNING , " read returned error: %s \n " , strerror ( errno ) ) ;
callerid_free ( cs ) ;
ast_hangup ( chan ) ;
return NULL ;
}
break ;
}
if ( p - > ringt )
p - > ringt - - ;
if ( p - > ringt = = 1 ) {
res = - 1 ;
break ;
}
2003-02-07 19:23:19 +00:00
res = callerid_feed ( cs , buf , res , AST_LAW ( p ) ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
ast_log ( LOG_WARNING , " CallerID feed failed: %s \n " , strerror ( errno ) ) ;
break ;
} else if ( res )
break ;
}
}
if ( res = = 1 ) {
callerid_get ( cs , & name , & number , & flags ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " CallerID number: %s, name: %s, flags=%d \n " , number , name , flags ) ;
}
2003-02-07 19:23:19 +00:00
/* Restore linear mode (if appropriate) for Caller*ID processing */
zt_setlinear ( p - > subs [ index ] . zfd , p - > subs [ index ] . linear ) ;
2001-10-09 02:06:21 +00:00
# if 1
restore_gains ( p ) ;
# endif
if ( res < 0 ) {
ast_log ( LOG_WARNING , " CallerID returned with error on channel '%s' \n " , chan - > name ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to get caller ID space \n " ) ;
}
if ( name & & number ) {
snprintf ( cid , sizeof ( cid ) , " \" %s \" <%s> " , name , number ) ;
} else if ( name ) {
snprintf ( cid , sizeof ( cid ) , " \" %s \" " , name ) ;
} else if ( number ) {
snprintf ( cid , sizeof ( cid ) , " %s " , number ) ;
} else {
strcpy ( cid , " " ) ;
}
2001-12-29 18:04:21 +00:00
if ( strlen ( cid ) ) {
2001-10-09 02:06:21 +00:00
chan - > callerid = strdup ( cid ) ;
2002-03-08 23:48:42 +00:00
chan - > ani = strdup ( cid ) ;
2001-12-29 18:04:21 +00:00
}
2002-09-10 04:45:51 +00:00
ast_setstate ( chan , AST_STATE_RING ) ;
2001-10-09 02:06:21 +00:00
chan - > rings = 1 ;
p - > ringt = RINGT ;
zt_enable_ec ( p ) ;
res = ast_pbx_run ( chan ) ;
if ( res ) {
ast_hangup ( chan ) ;
ast_log ( LOG_WARNING , " PBX exited non-zero \n " ) ;
}
return NULL ;
default :
ast_log ( LOG_WARNING , " Don't know how to handle simple switch with signalling %s on channel %d \n " , sig2str ( p - > sig ) , p - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play congestion tone on channel %d \n " , p - > channel ) ;
}
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( p - > subs [ index ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play congestion tone on channel %d \n " , p - > channel ) ;
ast_hangup ( chan ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
static int handle_init_r2_event ( struct zt_pvt * i , mfcr2_event_t * e )
{
struct ast_channel * chan ;
switch ( e - > e ) {
case MFCR2_EVENT_UNBLOCKED :
i - > r2blocked = 0 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " R2 Channel %d unblocked \n " , i - > channel ) ;
break ;
case MFCR2_EVENT_BLOCKED :
i - > r2blocked = 1 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " R2 Channel %d unblocked \n " , i - > channel ) ;
break ;
case MFCR2_EVENT_IDLE :
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " R2 Channel %d idle \n " , i - > channel ) ;
break ;
case MFCR2_EVENT_RINGING :
/* This is what Asterisk refers to as a "RING" event. For some reason they're reversed in
Steve ' s code */
/* Check for callerid, digits, etc */
i - > hasr2call = 1 ;
chan = zt_new ( i , AST_STATE_RING , 0 , SUB_REAL , 0 ) ;
if ( ! chan ) {
ast_log ( LOG_WARNING , " Unable to create channel for channel %d \n " , i - > channel ) ;
mfcr2_DropCall ( i - > r2 , NULL , UC_NETWORK_CONGESTION ) ;
i - > hasr2call = 0 ;
}
if ( ast_pbx_start ( chan ) ) {
ast_log ( LOG_WARNING , " Unable to start PBX on channel %s \n " , chan - > name ) ;
ast_hangup ( chan ) ;
}
break ;
default :
ast_log ( LOG_WARNING , " Don't know how to handle initial R2 event %s on channel %d \n " , mfcr2_event2str ( e - > e ) , i - > channel ) ;
return - 1 ;
}
return 0 ;
}
# endif
2001-10-09 02:06:21 +00:00
static int handle_init_event ( struct zt_pvt * i , int event )
{
int res ;
pthread_t threadid ;
pthread_attr_t attr ;
struct ast_channel * chan ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2003-02-07 19:23:19 +00:00
if ( i - > radio ) return 0 ;
2001-10-09 02:06:21 +00:00
/* Handle an event on a given channel for the monitor thread. */
switch ( event ) {
2003-02-07 19:23:19 +00:00
case ZT_EVENT_NONE :
case ZT_EVENT_BITSCHANGED :
# ifdef ZAPATA_R2
if ( i - > r2 ) {
mfcr2_event_t * e ;
e = r2_get_event_bits ( i ) ;
i - > sigchecked = 1 ;
if ( e )
handle_init_r2_event ( i , e ) ;
}
# endif
break ;
case ZT_EVENT_WINKFLASH :
2001-10-09 02:06:21 +00:00
case ZT_EVENT_RINGOFFHOOK :
if ( i - > inalarm ) break ;
/* Got a ring/answer. What kind of channel are we? */
switch ( i - > sig ) {
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FXOKS :
2003-02-07 19:23:19 +00:00
if ( i - > cidspill ) {
/* Cancel VMWI spill */
free ( i - > cidspill ) ;
i - > cidspill = NULL ;
}
2001-10-09 02:06:21 +00:00
if ( i - > immediate ) {
zt_enable_ec ( i ) ;
/* The channel is immediately up. Start right away */
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_RINGTONE ) ;
chan = zt_new ( i , AST_STATE_RING , 1 , SUB_REAL , 0 ) ;
2001-12-29 18:04:21 +00:00
if ( ! chan ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to start PBX on channel %d \n " , i - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play congestion tone on channel %d \n " , i - > channel ) ;
}
} else {
/* Check for callerid, digits, etc */
2003-02-07 19:23:19 +00:00
chan = zt_new ( i , AST_STATE_DOWN , 0 , SUB_REAL , 0 ) ;
2001-12-29 18:04:21 +00:00
if ( chan ) {
2002-03-08 23:48:42 +00:00
if ( has_voicemail ( i ) )
2003-05-19 23:33:41 +00:00
# ifdef ZT_TONE_STUTTER
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_STUTTER ) ;
# else
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_DIALRECALL ) ;
2003-05-19 23:33:41 +00:00
# endif
2002-03-08 23:48:42 +00:00
else
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_DIALTONE ) ;
2001-12-29 18:04:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play dialtone on channel %d \n " , i - > channel ) ;
if ( pthread_create ( & threadid , & attr , ss_thread , chan ) ) {
ast_log ( LOG_WARNING , " Unable to start simple switch thread on channel %d \n " , i - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_CONGESTION ) ;
2001-12-29 18:04:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play congestion tone on channel %d \n " , i - > channel ) ;
ast_hangup ( chan ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to create channel \n " ) ;
2001-10-09 02:06:21 +00:00
#if 0
printf ( " Created thread %ld detached in switch \n " , threadid ) ;
# endif
}
break ;
case SIG_FXSLS :
case SIG_FXSGS :
case SIG_FXSKS :
i - > ringt = RINGT ;
/* Fall through */
case SIG_EMWINK :
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2001-10-09 02:06:21 +00:00
case SIG_EM :
2003-03-17 20:04:36 +00:00
case SIG_SFWINK :
case SIG_SF_FEATD :
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
case SIG_SF :
2001-10-09 02:06:21 +00:00
/* Check for callerid, digits, etc */
2003-02-07 19:23:19 +00:00
chan = zt_new ( i , AST_STATE_RING , 0 , SUB_REAL , 0 ) ;
2001-10-09 02:06:21 +00:00
if ( pthread_create ( & threadid , & attr , ss_thread , chan ) ) {
ast_log ( LOG_WARNING , " Unable to start simple switch thread on channel %d \n " , i - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play congestion tone on channel %d \n " , i - > channel ) ;
ast_hangup ( chan ) ;
}
#if 0
printf ( " Created thread %ld detached in switch(2) \n " , threadid ) ;
# endif
break ;
default :
ast_log ( LOG_WARNING , " Don't know how to handle ring/answer with signalling %s on channel %d \n " , sig2str ( i - > sig ) , i - > channel ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , ZT_TONE_CONGESTION ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to play congestion tone on channel %d \n " , i - > channel ) ;
return - 1 ;
}
break ;
case ZT_EVENT_NOALARM :
i - > inalarm = 0 ;
2003-02-26 19:41:10 +00:00
ast_log ( LOG_NOTICE , " Alarm cleared on channel %d \n " , i - > channel ) ;
2001-10-09 02:06:21 +00:00
break ;
case ZT_EVENT_ALARM :
i - > inalarm = 1 ;
2003-02-28 06:00:18 +00:00
res = get_alarms ( i ) ;
ast_log ( LOG_WARNING , " Detected alarm on channel %d: %s \n " , i - > channel , alarm2str ( res ) ) ;
2001-10-09 02:06:21 +00:00
/* fall thru intentionally */
case ZT_EVENT_ONHOOK :
/* Back on hook. Hang up. */
switch ( i - > sig ) {
case SIG_FXOLS :
case SIG_FXOGS :
case SIG_FEATD :
2002-06-24 17:59:56 +00:00
case SIG_FEATDMF :
case SIG_FEATB :
2001-10-09 02:06:21 +00:00
case SIG_EM :
case SIG_EMWINK :
2003-03-17 20:04:36 +00:00
case SIG_SF_FEATD :
case SIG_SF_FEATDMF :
case SIG_SF_FEATB :
case SIG_SF :
case SIG_SFWINK :
2001-10-09 02:06:21 +00:00
case SIG_FXSLS :
case SIG_FXSGS :
case SIG_FXSKS :
zt_disable_ec ( i ) ;
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , - 1 ) ;
zt_set_hook ( i - > subs [ SUB_REAL ] . zfd , ZT_ONHOOK ) ;
2001-10-09 02:06:21 +00:00
break ;
2002-06-24 17:59:56 +00:00
case SIG_FXOKS :
zt_disable_ec ( i ) ;
/* Diddle the battery for the zhone */
# ifdef ZHONE_HACK
2003-02-07 19:23:19 +00:00
zt_set_hook ( i - > subs [ SUB_REAL ] . zfd , ZT_OFFHOOK ) ;
2002-06-24 17:59:56 +00:00
usleep ( 1 ) ;
# endif
2003-02-07 19:23:19 +00:00
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , - 1 ) ;
zt_set_hook ( i - > subs [ SUB_REAL ] . zfd , ZT_ONHOOK ) ;
2002-06-24 17:59:56 +00:00
break ;
2003-02-26 19:41:10 +00:00
case SIG_PRI :
zt_disable_ec ( i ) ;
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , - 1 ) ;
break ;
2001-10-09 02:06:21 +00:00
default :
2003-02-07 19:23:19 +00:00
ast_log ( LOG_WARNING , " Don't know how to handle on hook with signalling %s on channel %d \n " , sig2str ( i - > sig ) , i - > channel ) ;
res = tone_zone_play_tone ( i - > subs [ SUB_REAL ] . zfd , - 1 ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
break ;
}
return 0 ;
}
static void * do_monitor ( void * data )
{
fd_set efds ;
2003-02-07 19:23:19 +00:00
fd_set rfds ;
int n , res , res2 ;
2001-10-09 02:06:21 +00:00
struct zt_pvt * i ;
2003-02-07 19:23:19 +00:00
struct zt_pvt * last = NULL ;
struct timeval tv ;
time_t thispass = 0 , lastpass = 0 ;
int found ;
char buf [ 1024 ] ;
2001-10-09 02:06:21 +00:00
/* This thread monitors all the frame relay interfaces which are not yet in use
( and thus do not have a separate thread ) indefinitely */
/* From here on out, we die whenever asked */
#if 0
if ( pthread_setcanceltype ( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) ) {
ast_log ( LOG_WARNING , " Unable to set cancel type to asynchronous \n " ) ;
return NULL ;
}
ast_log ( LOG_DEBUG , " Monitor starting... \n " ) ;
# endif
for ( ; ; ) {
/* Lock the interface list */
if ( ast_pthread_mutex_lock ( & iflock ) ) {
ast_log ( LOG_ERROR , " Unable to grab interface lock \n " ) ;
return NULL ;
}
/* Build the stuff we're going to select on, that is the socket of every
zt_pvt that does not have an associated owner channel */
n = - 1 ;
FD_ZERO ( & efds ) ;
2003-02-07 19:23:19 +00:00
FD_ZERO ( & rfds ) ;
2001-10-09 02:06:21 +00:00
i = iflist ;
while ( i ) {
2003-02-07 19:23:19 +00:00
if ( ( i - > subs [ SUB_REAL ] . zfd > - 1 ) & & i - > sig & & ( ! i - > radio ) ) {
if ( FD_ISSET ( i - > subs [ SUB_REAL ] . zfd , & efds ) )
ast_log ( LOG_WARNING , " Descriptor %d appears twice? \n " , i - > subs [ SUB_REAL ] . zfd ) ;
if ( ! i - > owner & & ! i - > subs [ SUB_REAL ] . owner ) {
2002-06-24 17:59:56 +00:00
/* This needs to be watched, as it lacks an owner */
2003-02-07 19:23:19 +00:00
FD_SET ( i - > subs [ SUB_REAL ] . zfd , & efds ) ;
/* Message waiting or r2 channels also get watched for reading */
# ifdef ZAPATA_R2
if ( i - > cidspill | | i - > r2 )
# else
if ( i - > cidspill )
# endif
FD_SET ( i - > subs [ SUB_REAL ] . zfd , & rfds ) ;
if ( i - > subs [ SUB_REAL ] . zfd > n )
n = i - > subs [ SUB_REAL ] . zfd ;
2002-06-24 17:59:56 +00:00
}
2001-10-09 02:06:21 +00:00
}
i = i - > next ;
}
/* Okay, now that we know what to do, release the interface lock */
ast_pthread_mutex_unlock ( & iflock ) ;
pthread_testcancel ( ) ;
2003-02-07 19:23:19 +00:00
/* Wait at least a second for something to happen */
tv . tv_sec = 1 ;
tv . tv_usec = 0 ;
2003-05-19 23:33:41 +00:00
res = ast_select ( n + 1 , & rfds , NULL , & efds , & tv ) ;
2001-10-09 02:06:21 +00:00
pthread_testcancel ( ) ;
/* Okay, select has finished. Let's see what happened. */
if ( res < 0 ) {
if ( ( errno ! = EAGAIN ) & & ( errno ! = EINTR ) )
ast_log ( LOG_WARNING , " select return %d: %s \n " , res , strerror ( errno ) ) ;
continue ;
}
/* Alright, lock the interface list again, and let's look and see what has
happened */
if ( ast_pthread_mutex_lock ( & iflock ) ) {
ast_log ( LOG_WARNING , " Unable to lock the interface list \n " ) ;
continue ;
}
2003-02-07 19:23:19 +00:00
found = 0 ;
lastpass = thispass ;
thispass = time ( NULL ) ;
2001-10-09 02:06:21 +00:00
i = iflist ;
while ( i ) {
2003-02-07 19:23:19 +00:00
if ( thispass ! = lastpass ) {
if ( ! found & & ( ( i = = last ) | | ( ( i = = iflist ) & & ! last ) ) ) {
last = i ;
if ( last ) {
#if 0
printf ( " Checking channel %d \n " , last - > channel ) ;
# endif
if ( ! last - > cidspill & & ! last - > owner & & strlen ( last - > mailbox ) & & ( thispass - last - > onhooktime > 3 ) & &
( last - > sig & __ZT_SIG_FXO ) ) {
#if 0
printf ( " Channel %d has mailbox %s \n " , last - > channel , last - > mailbox ) ;
# endif
res = ast_app_has_voicemail ( last - > mailbox ) ;
if ( last - > msgstate ! = res ) {
int x ;
ast_log ( LOG_DEBUG , " Message status for %s changed from %d to %d on %d \n " , last - > mailbox , last - > msgstate , res , last - > channel ) ;
x = ZT_FLUSH_WRITE ;
res2 = ioctl ( last - > subs [ SUB_REAL ] . zfd , ZT_FLUSH , & x ) ;
if ( res2 )
ast_log ( LOG_WARNING , " Unable to flush input on channel %d \n " , last - > channel ) ;
last - > cidspill = malloc ( 8192 ) ;
if ( last - > cidspill ) {
last - > cidlen = vmwi_generate ( last - > cidspill , res , 1 , AST_LAW ( last ) ) ;
last - > cidpos = 0 ;
#if 0
printf ( " Made %d bytes of message waiting for %d \n " , last - > cidlen , res ) ;
# endif
last - > msgstate = res ;
last - > onhooktime = thispass ;
}
found + + ;
}
}
last = last - > next ;
}
}
}
if ( ( i - > subs [ SUB_REAL ] . zfd > - 1 ) & & i - > sig & & ( ! i - > radio ) ) {
if ( FD_ISSET ( i - > subs [ SUB_REAL ] . zfd , & rfds ) ) {
if ( i - > owner | | i - > subs [ SUB_REAL ] . owner ) {
ast_log ( LOG_WARNING , " Whoa.... I'm owned but found (%d) in read... \n " , i - > subs [ SUB_REAL ] . zfd ) ;
i = i - > next ;
continue ;
}
# ifdef ZAPATA_R2
if ( i - > r2 ) {
/* If it's R2 signalled, we always have to check for events */
mfcr2_event_t * e ;
e = mfcr2_check_event ( i - > r2 ) ;
if ( e )
handle_init_r2_event ( i , e ) ;
else {
e = mfcr2_schedule_run ( i - > r2 ) ;
if ( e )
handle_init_r2_event ( i , e ) ;
}
i = i - > next ;
continue ;
}
# endif
if ( ! i - > cidspill ) {
ast_log ( LOG_WARNING , " Whoa.... I'm reading but have no cidspill (%d)... \n " , i - > subs [ SUB_REAL ] . zfd ) ;
i = i - > next ;
continue ;
}
res = read ( i - > subs [ SUB_REAL ] . zfd , buf , sizeof ( buf ) ) ;
if ( res > 0 ) {
/* We read some number of bytes. Write an equal amount of data */
if ( res > i - > cidlen - i - > cidpos )
res = i - > cidlen - i - > cidpos ;
res2 = write ( i - > subs [ SUB_REAL ] . zfd , i - > cidspill + i - > cidpos , res ) ;
if ( res2 > 0 ) {
i - > cidpos + = res2 ;
if ( i - > cidpos > = i - > cidlen ) {
free ( i - > cidspill ) ;
i - > cidspill = 0 ;
i - > cidpos = 0 ;
i - > cidlen = 0 ;
}
} else {
ast_log ( LOG_WARNING , " Write failed: %s \n " , strerror ( errno ) ) ;
i - > msgstate = - 1 ;
}
} else {
ast_log ( LOG_WARNING , " Read failed with %d: %s \n " , res , strerror ( errno ) ) ;
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Monitor doohicky got event %s on channel %d \n " , event2str ( res ) , i - > channel ) ;
handle_init_event ( i , res ) ;
}
# ifdef ZAPATA_R2
if ( FD_ISSET ( i - > subs [ SUB_REAL ] . zfd , & efds ) | | ( i - > r2 & & ! i - > sigchecked ) )
# else
if ( FD_ISSET ( i - > subs [ SUB_REAL ] . zfd , & efds ) )
# endif
{
if ( i - > owner | | i - > subs [ SUB_REAL ] . owner ) {
ast_log ( LOG_WARNING , " Whoa.... I'm owned but found (%d)... \n " , i - > subs [ SUB_REAL ] . zfd ) ;
2002-06-24 17:59:56 +00:00
i = i - > next ;
continue ;
}
2003-02-07 19:23:19 +00:00
res = zt_get_event ( i - > subs [ SUB_REAL ] . zfd ) ;
2002-06-24 17:59:56 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Monitor doohicky got event %s on channel %d \n " , event2str ( res ) , i - > channel ) ;
handle_init_event ( i , res ) ;
2001-10-09 02:06:21 +00:00
}
}
i = i - > next ;
}
ast_pthread_mutex_unlock ( & iflock ) ;
}
/* Never reached */
return NULL ;
}
static int restart_monitor ( void )
{
pthread_attr_t attr ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
/* If we're supposed to be stopped -- stay stopped */
if ( monitor_thread = = - 2 )
return 0 ;
if ( ast_pthread_mutex_lock ( & monlock ) ) {
ast_log ( LOG_WARNING , " Unable to lock monitor \n " ) ;
return - 1 ;
}
if ( monitor_thread = = pthread_self ( ) ) {
ast_pthread_mutex_unlock ( & monlock ) ;
ast_log ( LOG_WARNING , " Cannot kill myself \n " ) ;
return - 1 ;
}
if ( monitor_thread ) {
2002-03-08 23:48:42 +00:00
/* Just signal it to be sure it wakes up */
#if 0
2001-10-09 02:06:21 +00:00
pthread_cancel ( monitor_thread ) ;
2002-03-08 23:48:42 +00:00
# endif
2001-10-09 02:06:21 +00:00
pthread_kill ( monitor_thread , SIGURG ) ;
2002-03-08 23:48:42 +00:00
#if 0
2001-10-09 02:06:21 +00:00
pthread_join ( monitor_thread , NULL ) ;
2002-03-08 23:48:42 +00:00
# endif
} else {
/* Start a new monitor */
if ( pthread_create ( & monitor_thread , & attr , do_monitor , NULL ) < 0 ) {
ast_pthread_mutex_unlock ( & monlock ) ;
ast_log ( LOG_ERROR , " Unable to start monitor thread. \n " ) ;
return - 1 ;
}
2001-10-09 02:06:21 +00:00
}
#if 0
printf ( " Created thread %ld detached in restart monitor \n " , monitor_thread ) ;
# endif
ast_pthread_mutex_unlock ( & monlock ) ;
return 0 ;
}
static int reset_channel ( struct zt_pvt * p )
{
int ioctlflag = 1 ;
int res = 0 ;
int i = 0 ;
ast_log ( LOG_DEBUG , " reset_channel() \n " ) ;
if ( p - > owner ) {
ioctlflag = 0 ;
2002-09-10 04:45:51 +00:00
p - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2001-10-09 02:06:21 +00:00
}
for ( i = 0 ; i < 3 ; i + + ) {
2003-02-07 19:23:19 +00:00
if ( p - > subs [ i ] . owner ) {
2001-10-09 02:06:21 +00:00
ioctlflag = 0 ;
2003-02-07 19:23:19 +00:00
p - > subs [ i ] . owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2001-10-09 02:06:21 +00:00
}
}
if ( ioctlflag ) {
2003-02-07 19:23:19 +00:00
res = zt_set_hook ( p - > subs [ SUB_REAL ] . zfd , ZT_ONHOOK ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
ast_log ( LOG_ERROR , " Unable to hangup chan_zap channel %d (ioctl) \n " , p - > channel ) ;
return - 1 ;
}
}
return 0 ;
}
2003-02-07 19:23:19 +00:00
static struct zt_pvt * mkintf ( int channel , int signalling , int radio )
2001-10-09 02:06:21 +00:00
{
/* Make a zt_pvt structure for this interface */
struct zt_pvt * tmp = NULL , * tmp2 , * prev = NULL ;
char fn [ 80 ] ;
# if 1
struct zt_bufferinfo bi ;
2002-06-24 17:59:56 +00:00
# endif
2001-10-09 02:06:21 +00:00
struct zt_spaninfo si ;
int res ;
2002-06-24 17:59:56 +00:00
int span = 0 ;
2001-10-09 02:06:21 +00:00
int here = 0 ;
2003-02-07 19:23:19 +00:00
int x ;
2001-10-09 02:06:21 +00:00
ZT_PARAMS p ;
2002-06-24 17:59:56 +00:00
2001-10-09 02:06:21 +00:00
tmp2 = iflist ;
prev = NULL ;
while ( tmp2 ) {
if ( tmp2 - > channel = = channel ) {
tmp = tmp2 ;
here = 1 ;
break ;
}
if ( tmp2 - > channel > channel ) {
break ;
}
prev = tmp2 ;
tmp2 = tmp2 - > next ;
}
if ( ! here ) {
tmp = ( struct zt_pvt * ) malloc ( sizeof ( struct zt_pvt ) ) ;
if ( ! tmp ) {
ast_log ( LOG_ERROR , " MALLOC FAILED \n " ) ;
return NULL ;
}
memset ( tmp , 0 , sizeof ( struct zt_pvt ) ) ;
2003-02-07 19:23:19 +00:00
for ( x = 0 ; x < 3 ; x + + )
tmp - > subs [ x ] . zfd = - 1 ;
2001-10-09 02:06:21 +00:00
tmp - > next = tmp2 ;
if ( ! prev ) {
iflist = tmp ;
} else {
prev - > next = tmp ;
}
}
if ( tmp ) {
2002-06-24 17:59:56 +00:00
if ( channel ! = CHAN_PSEUDO ) {
snprintf ( fn , sizeof ( fn ) , " %d " , channel ) ;
/* Open non-blocking */
if ( ! here )
2003-02-07 19:23:19 +00:00
tmp - > subs [ SUB_REAL ] . zfd = zt_open ( fn ) ;
2002-06-24 17:59:56 +00:00
/* Allocate a zapata structure */
2003-02-07 19:23:19 +00:00
if ( tmp - > subs [ SUB_REAL ] . zfd < 0 ) {
2002-06-24 17:59:56 +00:00
ast_log ( LOG_ERROR , " Unable to open channel %d: %s \n here = %d, tmp->channel = %d, channel = %d \n " , channel , strerror ( errno ) , here , tmp - > channel , channel ) ;
free ( tmp ) ;
return NULL ;
}
2002-09-10 04:45:51 +00:00
memset ( & p , 0 , sizeof ( p ) ) ;
2003-02-07 19:23:19 +00:00
res = ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_GET_PARAMS , & p ) ;
2002-06-24 17:59:56 +00:00
if ( res < 0 ) {
ast_log ( LOG_ERROR , " Unable to get parameters \n " ) ;
free ( tmp ) ;
return NULL ;
}
if ( p . sigtype ! = ( signalling & 0xffff ) ) {
ast_log ( LOG_ERROR , " Signalling requested is %s but line is in %s signalling \n " , sig2str ( signalling ) , sig2str ( p . sigtype ) ) ;
free ( tmp ) ;
return NULL ;
}
if ( here ) {
if ( tmp - > sig ! = signalling ) {
if ( reset_channel ( tmp ) ) {
ast_log ( LOG_ERROR , " Failed to reset chan_zap channel %d \n " , tmp - > channel ) ;
return NULL ;
}
2001-10-09 02:06:21 +00:00
}
}
2002-06-24 17:59:56 +00:00
tmp - > law = p . curlaw ;
tmp - > span = p . spanno ;
span = p . spanno - 1 ;
} else {
signalling = 0 ;
2001-10-09 02:06:21 +00:00
}
# ifdef ZAPATA_PRI
if ( signalling = = SIG_PRI ) {
int offset ;
2001-12-29 18:04:21 +00:00
int numchans ;
int dchannel ;
2003-04-23 16:04:35 +00:00
offset = 0 ;
2003-02-07 19:23:19 +00:00
if ( ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_AUDIOMODE , & offset ) ) {
2003-04-23 16:04:35 +00:00
ast_log ( LOG_ERROR , " Unable to set clear mode on clear channel %d of span %d: %s \n " , channel , p . spanno , strerror ( errno ) ) ;
2001-10-09 02:06:21 +00:00
return NULL ;
}
if ( span > = NUM_SPANS ) {
ast_log ( LOG_ERROR , " Channel %d does not lie on a span I know of (%d) \n " , channel , span ) ;
free ( tmp ) ;
return NULL ;
} else {
2001-12-29 18:04:21 +00:00
si . spanno = 0 ;
2003-02-07 19:23:19 +00:00
if ( ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_SPANSTAT , & si ) = = - 1 ) {
2001-12-29 18:04:21 +00:00
ast_log ( LOG_ERROR , " Unable to get span status: %s \n " , strerror ( errno ) ) ;
free ( tmp ) ;
return NULL ;
}
if ( si . totalchans = = 31 ) { /* if it's an E1 */
dchannel = 16 ;
numchans = 31 ;
} else {
dchannel = 24 ;
2003-02-07 19:23:19 +00:00
numchans = 23 ;
2001-12-29 18:04:21 +00:00
}
offset = p . chanpos ;
if ( offset ! = dchannel ) {
2001-10-09 02:06:21 +00:00
if ( pris [ span ] . nodetype & & ( pris [ span ] . nodetype ! = pritype ) ) {
ast_log ( LOG_ERROR , " Span %d is already a %s node \n " , span + 1 , pri_node2str ( pris [ span ] . nodetype ) ) ;
free ( tmp ) ;
return NULL ;
}
if ( pris [ span ] . switchtype & & ( pris [ span ] . switchtype ! = switchtype ) ) {
ast_log ( LOG_ERROR , " Span %d is already a %s switch \n " , span + 1 , pri_switch2str ( pris [ span ] . switchtype ) ) ;
free ( tmp ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
if ( ( pris [ span ] . dialplan ) & & ( pris [ span ] . dialplan ! = dialplan ) ) {
ast_log ( LOG_ERROR , " Span %d is already a %s dialing plan \n " , span + 1 , pri_plan2str ( pris [ span ] . dialplan ) ) ;
free ( tmp ) ;
return NULL ;
}
2002-06-24 17:59:56 +00:00
if ( strlen ( pris [ span ] . idledial ) & & strcmp ( pris [ span ] . idledial , idledial ) ) {
ast_log ( LOG_ERROR , " Span %d already has idledial '%s'. \n " , span + 1 , idledial ) ;
free ( tmp ) ;
return NULL ;
}
if ( strlen ( pris [ span ] . idleext ) & & strcmp ( pris [ span ] . idleext , idleext ) ) {
ast_log ( LOG_ERROR , " Span %d already has idleext '%s'. \n " , span + 1 , idleext ) ;
free ( tmp ) ;
return NULL ;
}
if ( pris [ span ] . minunused & & ( pris [ span ] . minunused ! = minunused ) ) {
ast_log ( LOG_ERROR , " Span %d already has minunused of %d. \n " , span + 1 , minunused ) ;
free ( tmp ) ;
return NULL ;
}
if ( pris [ span ] . minidle & & ( pris [ span ] . minidle ! = minidle ) ) {
ast_log ( LOG_ERROR , " Span %d already has minidle of %d. \n " , span + 1 , minidle ) ;
free ( tmp ) ;
return NULL ;
}
2001-10-09 02:06:21 +00:00
pris [ span ] . nodetype = pritype ;
pris [ span ] . switchtype = switchtype ;
2003-02-07 19:23:19 +00:00
pris [ span ] . dialplan = dialplan ;
2001-10-09 02:06:21 +00:00
pris [ span ] . chanmask [ offset ] | = MASK_AVAIL ;
pris [ span ] . pvt [ offset ] = tmp ;
2001-12-29 18:04:21 +00:00
pris [ span ] . channels = numchans ;
pris [ span ] . dchannel = dchannel ;
2002-06-24 17:59:56 +00:00
pris [ span ] . minunused = minunused ;
pris [ span ] . minidle = minidle ;
2003-05-19 23:33:41 +00:00
pris [ span ] . overlapdial = overlapdial ;
2002-06-24 17:59:56 +00:00
strncpy ( pris [ span ] . idledial , idledial , sizeof ( pris [ span ] . idledial ) - 1 ) ;
strncpy ( pris [ span ] . idleext , idleext , sizeof ( pris [ span ] . idleext ) - 1 ) ;
2001-12-29 18:04:21 +00:00
2001-10-09 02:06:21 +00:00
tmp - > pri = & pris [ span ] ;
2003-02-07 19:23:19 +00:00
tmp - > prioffset = offset ;
2001-10-09 02:06:21 +00:00
tmp - > call = NULL ;
} else {
2001-12-29 18:04:21 +00:00
ast_log ( LOG_ERROR , " Channel %d is reserved for D-channel. \n " , offset ) ;
2001-10-09 02:06:21 +00:00
free ( tmp ) ;
return NULL ;
}
}
2003-02-07 19:23:19 +00:00
} else {
tmp - > prioffset = 0 ;
}
# endif
# ifdef ZAPATA_R2
if ( signalling = = SIG_R2 ) {
if ( r2prot < 0 ) {
ast_log ( LOG_WARNING , " R2 Country not specified for channel %d -- Assuming China \n " , tmp - > channel ) ;
tmp - > r2prot = MFCR2_PROT_CHINA ;
} else
tmp - > r2prot = r2prot ;
tmp - > r2 = mfcr2_new ( tmp - > subs [ SUB_REAL ] . zfd , tmp - > r2prot , 1 ) ;
if ( ! tmp - > r2 ) {
ast_log ( LOG_WARNING , " Unable to create r2 call :( \n " ) ;
zt_close ( tmp - > subs [ SUB_REAL ] . zfd ) ;
free ( tmp ) ;
return NULL ;
}
} else {
if ( tmp - > r2 )
mfcr2_free ( tmp - > r2 ) ;
tmp - > r2 = NULL ;
2001-10-09 02:06:21 +00:00
}
2002-06-24 17:59:56 +00:00
# endif
2001-10-09 02:06:21 +00:00
/* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
if ( ( signalling = = SIG_FXSKS ) | | ( signalling = = SIG_FXSLS ) | |
2001-12-29 18:04:21 +00:00
( signalling = = SIG_EM ) | | ( signalling = = SIG_EMWINK ) | |
2002-06-24 17:59:56 +00:00
( signalling = = SIG_FEATD ) | | ( signalling = = SIG_FEATDMF ) | |
2003-03-17 20:04:36 +00:00
( signalling = = SIG_FEATB ) | |
( signalling = = SIG_SF ) | | ( signalling = = SIG_SFWINK ) | |
( signalling = = SIG_SF_FEATD ) | | ( signalling = = SIG_SF_FEATDMF ) | |
( signalling = = SIG_SF_FEATB ) ) {
2001-10-09 02:06:21 +00:00
p . starttime = 250 ;
2003-02-07 19:23:19 +00:00
res = ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_SET_PARAMS , & p ) ;
if ( res < 0 ) {
ast_log ( LOG_ERROR , " Unable to set parameters \n " ) ;
free ( tmp ) ;
return NULL ;
}
}
if ( radio )
{
p . channo = channel ;
p . rxwinktime = 1 ;
p . rxflashtime = 1 ;
p . starttime = 1 ;
p . debouncetime = 5 ;
res = ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_SET_PARAMS , & p ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
ast_log ( LOG_ERROR , " Unable to set parameters \n " ) ;
free ( tmp ) ;
return NULL ;
}
}
# if 1
2003-02-07 19:23:19 +00:00
if ( ! here & & ( tmp - > subs [ SUB_REAL ] . zfd > - 1 ) ) {
memset ( & bi , 0 , sizeof ( bi ) ) ;
res = ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_GET_BUFINFO , & bi ) ;
2001-10-09 02:06:21 +00:00
if ( ! res ) {
bi . txbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . rxbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . numbufs = 4 ;
2003-02-07 19:23:19 +00:00
res = ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_SET_BUFINFO , & bi ) ;
2001-10-09 02:06:21 +00:00
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to set buffer policy on channel %d \n " , channel ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to check buffer policy on channel %d \n " , channel ) ;
}
# endif
tmp - > immediate = immediate ;
tmp - > sig = signalling ;
2003-02-07 19:23:19 +00:00
tmp - > radio = radio ;
tmp - > firstradio = 0 ;
2001-10-09 02:06:21 +00:00
if ( ( signalling = = SIG_FXOKS ) | | ( signalling = = SIG_FXOLS ) | | ( signalling = = SIG_FXOGS ) )
tmp - > permcallwaiting = callwaiting ;
else
tmp - > permcallwaiting = 0 ;
/* Flag to destroy the channel must be cleared on new mkif. Part of changes for reload to work */
tmp - > destroy = 0 ;
tmp - > callwaitingcallerid = callwaitingcallerid ;
tmp - > threewaycalling = threewaycalling ;
2001-12-29 18:04:21 +00:00
tmp - > adsi = adsi ;
2001-10-09 02:06:21 +00:00
tmp - > permhidecallerid = hidecallerid ;
2003-02-07 19:23:19 +00:00
tmp - > callreturn = callreturn ;
2001-10-09 02:06:21 +00:00
tmp - > echocancel = echocancel ;
2002-09-10 04:45:51 +00:00
tmp - > echocanbridged = echocanbridged ;
2003-02-07 19:23:19 +00:00
tmp - > busydetect = busydetect ;
2003-03-06 06:00:17 +00:00
tmp - > busycount = busycount ;
2003-02-07 19:23:19 +00:00
tmp - > callprogress = callprogress ;
2002-03-08 23:48:42 +00:00
tmp - > cancallforward = cancallforward ;
2003-02-07 19:23:19 +00:00
tmp - > dtmfrelax = relaxdtmf ;
2001-10-09 02:06:21 +00:00
tmp - > callwaiting = tmp - > permcallwaiting ;
tmp - > hidecallerid = tmp - > permhidecallerid ;
tmp - > channel = channel ;
tmp - > stripmsd = stripmsd ;
tmp - > use_callerid = use_callerid ;
2001-12-29 18:04:21 +00:00
strncpy ( tmp - > accountcode , accountcode , sizeof ( tmp - > accountcode ) - 1 ) ;
tmp - > amaflags = amaflags ;
2001-10-09 02:06:21 +00:00
if ( ! here ) {
tmp - > confno = - 1 ;
2003-02-07 19:23:19 +00:00
tmp - > propconfno = - 1 ;
2001-10-09 02:06:21 +00:00
}
tmp - > transfer = transfer ;
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_init ( & tmp - > lock ) ;
2001-12-29 18:04:21 +00:00
strncpy ( tmp - > language , language , sizeof ( tmp - > language ) - 1 ) ;
2002-06-24 17:59:56 +00:00
strncpy ( tmp - > musicclass , musicclass , sizeof ( tmp - > musicclass ) - 1 ) ;
2001-12-29 18:04:21 +00:00
strncpy ( tmp - > context , context , sizeof ( tmp - > context ) - 1 ) ;
strncpy ( tmp - > callerid , callerid , sizeof ( tmp - > callerid ) - 1 ) ;
2002-03-08 23:48:42 +00:00
strncpy ( tmp - > mailbox , mailbox , sizeof ( tmp - > mailbox ) - 1 ) ;
2003-02-07 19:23:19 +00:00
tmp - > msgstate = - 1 ;
2001-10-09 02:06:21 +00:00
tmp - > group = cur_group ;
tmp - > callgroup = cur_callergroup ;
tmp - > pickupgroup = cur_pickupgroup ;
tmp - > rxgain = rxgain ;
tmp - > txgain = txgain ;
2003-02-07 19:23:19 +00:00
tmp - > onhooktime = time ( NULL ) ;
if ( tmp - > subs [ SUB_REAL ] . zfd > - 1 ) {
set_actual_gain ( tmp - > subs [ SUB_REAL ] . zfd , 0 , tmp - > rxgain , tmp - > txgain , tmp - > law ) ;
if ( tmp - > dsp )
ast_dsp_digitmode ( tmp - > dsp , DSP_DIGITMODE_DTMF | tmp - > dtmfrelax ) ;
update_conf ( tmp ) ;
2002-06-24 17:59:56 +00:00
if ( ! here ) {
2003-02-07 19:23:19 +00:00
if ( ( signalling ! = SIG_PRI ) & & ( signalling ! = SIG_R2 ) )
2002-06-24 17:59:56 +00:00
/* Hang it up to be sure it's good */
2003-02-07 19:23:19 +00:00
zt_set_hook ( tmp - > subs [ SUB_REAL ] . zfd , ZT_ONHOOK ) ;
2002-06-24 17:59:56 +00:00
}
tmp - > inalarm = 0 ;
2003-02-07 19:23:19 +00:00
memset ( & si , 0 , sizeof ( si ) ) ;
if ( ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_SPANSTAT , & si ) = = - 1 ) {
2002-06-24 17:59:56 +00:00
ast_log ( LOG_ERROR , " Unable to get span status: %s \n " , strerror ( errno ) ) ;
free ( tmp ) ;
return NULL ;
}
if ( si . alarms ) tmp - > inalarm = 1 ;
2001-10-09 02:06:21 +00:00
}
}
return tmp ;
}
static inline int available ( struct zt_pvt * p , int channelmatch , int groupmatch )
{
2001-12-29 18:04:21 +00:00
int res ;
ZT_PARAMS par ;
2001-10-09 02:06:21 +00:00
/* First, check group matching */
if ( ( p - > group & groupmatch ) ! = groupmatch )
return 0 ;
/* Check to see if we have a channel match */
if ( ( channelmatch > 0 ) & & ( p - > channel ! = channelmatch ) )
return 0 ;
2002-09-10 04:45:51 +00:00
/* If do not distrub, definitely not */
if ( p - > dnd )
return 0 ;
2001-10-09 02:06:21 +00:00
/* If no owner definitely available */
2001-12-29 18:04:21 +00:00
if ( ! p - > owner ) {
/* Trust PRI */
# ifdef ZAPATA_PRI
2002-06-24 17:59:56 +00:00
if ( p - > pri ) {
if ( p - > resetting | | p - > call )
return 0 ;
else
return 1 ;
}
2003-02-07 19:23:19 +00:00
# endif
# ifdef ZAPATA_R2
/* Trust R2 as well */
if ( p - > r2 ) {
if ( p - > hasr2call | | p - > r2blocked )
return 0 ;
else
return 1 ;
}
2001-12-29 18:04:21 +00:00
# endif
if ( ( p - > sig = = SIG_FXSKS ) | | ( p - > sig = = SIG_FXSLS ) | |
2002-06-24 17:59:56 +00:00
( p - > sig = = SIG_FXSGS ) | | ! p - > sig )
2001-12-29 18:04:21 +00:00
return 1 ;
2003-02-07 19:23:19 +00:00
if ( ! p - > radio )
{
/* Check hook state */
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GET_PARAMS , & par ) ;
if ( res ) {
ast_log ( LOG_WARNING , " Unable to check hook state on channel %d \n " , p - > channel ) ;
} else if ( par . rxisoffhook ) {
ast_log ( LOG_DEBUG , " Channel %d off hook, can't use \n " , p - > channel ) ;
/* Not available when the other end is off hook */
return 0 ;
}
2001-12-29 18:04:21 +00:00
}
2001-10-09 02:06:21 +00:00
return 1 ;
2001-12-29 18:04:21 +00:00
}
2001-10-09 02:06:21 +00:00
/* If it's not an FXO, forget about call wait */
if ( ( p - > sig ! = SIG_FXOKS ) & & ( p - > sig ! = SIG_FXOLS ) & & ( p - > sig ! = SIG_FXOGS ) )
return 0 ;
if ( ! p - > callwaiting ) {
/* If they don't have call waiting enabled, then for sure they're unavailable at this point */
return 0 ;
}
2003-02-07 19:23:19 +00:00
if ( p - > subs [ SUB_CALLWAIT ] . zfd > - 1 ) {
2001-10-09 02:06:21 +00:00
/* If there is already a call waiting call, then we can't take a second one */
return 0 ;
}
2002-09-10 04:45:51 +00:00
if ( ( p - > owner - > _state ! = AST_STATE_UP ) & &
( p - > owner - > _state ! = AST_STATE_RINGING ) ) {
2001-10-09 02:06:21 +00:00
/* If the current call is not up, then don't allow the call */
return 0 ;
}
2003-02-07 19:23:19 +00:00
if ( ( p - > subs [ SUB_THREEWAY ] . owner ) & & ( ! p - > subs [ SUB_THREEWAY ] . inthreeway ) ) {
2001-10-09 02:06:21 +00:00
/* Can't take a call wait when the three way calling hasn't been merged yet. */
return 0 ;
}
/* We're cool */
return 1 ;
}
2002-06-24 17:59:56 +00:00
static struct zt_pvt * chandup ( struct zt_pvt * src )
{
struct zt_pvt * p ;
ZT_BUFFERINFO bi ;
int res ;
p = malloc ( sizeof ( struct zt_pvt ) ) ;
if ( p ) {
memcpy ( p , src , sizeof ( struct zt_pvt ) ) ;
2003-02-07 19:23:19 +00:00
p - > subs [ SUB_REAL ] . zfd = zt_open ( " /dev/zap/pseudo " ) ;
2002-06-24 17:59:56 +00:00
/* Allocate a zapata structure */
2003-02-07 19:23:19 +00:00
if ( p - > subs [ SUB_REAL ] . zfd < 0 ) {
2002-06-24 17:59:56 +00:00
ast_log ( LOG_ERROR , " Unable to dup channel: %s \n " , strerror ( errno ) ) ;
free ( p ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_GET_BUFINFO , & bi ) ;
2002-06-24 17:59:56 +00:00
if ( ! res ) {
bi . txbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . rxbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . numbufs = 4 ;
2003-02-07 19:23:19 +00:00
res = ioctl ( p - > subs [ SUB_REAL ] . zfd , ZT_SET_BUFINFO , & bi ) ;
2002-06-24 17:59:56 +00:00
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to set buffer policy on dup channel \n " ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to check buffer policy on dup channel \n " ) ;
}
p - > destroy = 1 ;
p - > next = iflist ;
iflist = p ;
return p ;
}
2001-10-09 02:06:21 +00:00
static struct ast_channel * zt_request ( char * type , int format , void * data )
{
int oldformat ;
int groupmatch = 0 ;
int channelmatch = - 1 ;
2003-02-07 19:23:19 +00:00
int callwait = 0 ;
2001-10-09 02:06:21 +00:00
struct zt_pvt * p ;
struct ast_channel * tmp = NULL ;
char * dest = NULL ;
int x ;
char * s ;
2003-02-07 19:23:19 +00:00
char opt = 0 ;
int res = 0 , y = 0 ;
2001-10-09 02:06:21 +00:00
/* We do signed linear */
oldformat = format ;
format & = ( AST_FORMAT_SLINEAR | AST_FORMAT_ULAW ) ;
if ( ! format ) {
ast_log ( LOG_NOTICE , " Asked to get a channel of unsupported format '%d' \n " , oldformat ) ;
return NULL ;
}
if ( data ) {
dest = strdup ( ( char * ) data ) ;
} else {
ast_log ( LOG_WARNING , " Channel requested with no data \n " ) ;
return NULL ;
}
if ( dest [ 0 ] = = ' g ' ) {
/* Retrieve the group number */
2003-02-07 19:23:19 +00:00
char * stringp = NULL ;
stringp = dest + 1 ;
s = strsep ( & stringp , " / " ) ;
if ( ( res = sscanf ( s , " %d%c%d " , & x , & opt , & y ) ) < 1 ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to determine group for data %s \n " , ( char * ) data ) ;
free ( dest ) ;
return NULL ;
}
groupmatch = 1 < < x ;
} else {
2003-02-07 19:23:19 +00:00
char * stringp = NULL ;
stringp = dest ;
s = strsep ( & stringp , " / " ) ;
2002-06-24 17:59:56 +00:00
if ( ! strcasecmp ( s , " pseudo " ) ) {
/* Special case for pseudo */
x = CHAN_PSEUDO ;
} else if ( ( res = sscanf ( s , " %d%c%d " , & x , & opt , & y ) ) < 1 ) {
2001-10-09 02:06:21 +00:00
ast_log ( LOG_WARNING , " Unable to determine channel for data %s \n " , ( char * ) data ) ;
free ( dest ) ;
return NULL ;
}
channelmatch = x ;
}
/* Search for an unowned channel */
if ( ast_pthread_mutex_lock ( & iflock ) ) {
ast_log ( LOG_ERROR , " Unable to lock interface list??? \n " ) ;
return NULL ;
}
p = iflist ;
while ( p & & ! tmp ) {
if ( available ( p , channelmatch , groupmatch ) ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Using channel %d \n " , p - > channel ) ;
if ( p - > inalarm ) {
p = p - > next ;
continue ;
}
callwait = ( p - > owner ! = NULL ) ;
2002-06-24 17:59:56 +00:00
if ( p - > channel = = CHAN_PSEUDO ) {
p = chandup ( p ) ;
if ( ! p ) {
break ;
}
}
2003-02-07 19:23:19 +00:00
if ( p - > owner ) {
if ( alloc_sub ( p , SUB_CALLWAIT ) ) {
p = NULL ;
break ;
}
}
2003-04-11 03:47:19 +00:00
p - > outgoing = 1 ;
2003-02-07 19:23:19 +00:00
tmp = zt_new ( p , AST_STATE_RESERVED , 0 , p - > owner ? SUB_CALLWAIT : SUB_REAL , 0 ) ;
2002-06-24 17:59:56 +00:00
/* Make special notes */
if ( res > 1 ) {
if ( opt = = ' c ' ) {
/* Confirm answer */
p - > confirmanswer = 1 ;
} else if ( opt = = ' r ' ) {
/* Distinctive ring */
if ( res < 3 )
ast_log ( LOG_WARNING , " Distinctive ring missing identifier in '%s' \n " , ( char * ) data ) ;
else
p - > distinctivering = y ;
2003-02-07 19:23:19 +00:00
} else if ( opt = = ' d ' ) {
/* If this is an ISDN call, make it digital */
p - > digital = 1 ;
2002-06-24 17:59:56 +00:00
} else {
ast_log ( LOG_WARNING , " Unknown option '%c' in '%s' \n " , opt , ( char * ) data ) ;
}
}
2001-10-09 02:06:21 +00:00
/* Note if the call is a call waiting call */
if ( callwait )
tmp - > cdrflags | = AST_CDR_CALLWAIT ;
break ;
}
p = p - > next ;
}
ast_pthread_mutex_unlock ( & iflock ) ;
restart_monitor ( ) ;
return tmp ;
}
# ifdef ZAPATA_PRI
static int pri_find_empty_chan ( struct zt_pri * pri )
{
int x ;
2003-02-07 19:23:19 +00:00
for ( x = pri - > channels ; x > 0 ; x - - ) {
2001-10-09 02:06:21 +00:00
if ( pri - > pvt [ x ] & & ! pri - > pvt [ x ] - > owner )
return x ;
}
return 0 ;
}
static int pri_fixup ( struct zt_pri * pri , int channel , q931_call * c )
{
int x ;
2003-02-07 19:23:19 +00:00
if ( ! c ) {
if ( channel < 1 )
return 0 ;
return channel ;
}
2001-12-29 18:04:21 +00:00
for ( x = 1 ; x < = pri - > channels ; x + + ) {
2001-10-09 02:06:21 +00:00
if ( ! pri - > pvt [ x ] ) continue ;
if ( pri - > pvt [ x ] - > call = = c ) {
/* Found our call */
if ( channel ! = x ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Moving call from channel %d to channel %d \n " ,
x , channel ) ;
if ( pri - > pvt [ channel ] - > owner ) {
ast_log ( LOG_WARNING , " Can't fix up channel from %d to %d because %d is already in use \n " ,
x , channel , channel ) ;
return 0 ;
}
/* Fix it all up now */
pri - > pvt [ channel ] - > owner = pri - > pvt [ x ] - > owner ;
2003-02-07 19:23:19 +00:00
if ( pri - > pvt [ channel ] - > owner ) {
pri - > pvt [ channel ] - > owner - > pvt - > pvt = pri - > pvt [ channel ] ;
pri - > pvt [ channel ] - > owner - > fds [ 0 ] = pri - > pvt [ channel ] - > subs [ SUB_REAL ] . zfd ;
} else
ast_log ( LOG_WARNING , " Whoa, there's no owner, and we're having to fix up channel %d to channel %d \n " , x , channel ) ;
2001-10-09 02:06:21 +00:00
pri - > pvt [ channel ] - > call = pri - > pvt [ x ] - > call ;
/* Free up the old channel, now not in use */
pri - > pvt [ x ] - > owner = NULL ;
pri - > pvt [ x ] - > call = NULL ;
}
return channel ;
}
}
2003-02-07 19:23:19 +00:00
ast_log ( LOG_WARNING , " Call specified, but not found? \n " ) ;
2001-10-09 02:06:21 +00:00
return 0 ;
}
2002-06-24 17:59:56 +00:00
static void * do_idle_thread ( void * vchan )
{
struct ast_channel * chan = vchan ;
struct zt_pvt * pvt = chan - > pvt - > pvt ;
struct ast_frame * f ;
char ex [ 80 ] ;
/* Wait up to 30 seconds for an answer */
int newms , ms = 30000 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Initiating idle call on channel %s \n " , chan - > name ) ;
snprintf ( ex , sizeof ( ex ) , " %d/%s " , pvt - > channel , pvt - > pri - > idledial ) ;
if ( ast_call ( chan , ex , 0 ) ) {
ast_log ( LOG_WARNING , " Idle dial failed on '%s' to '%s' \n " , chan - > name , ex ) ;
ast_hangup ( chan ) ;
return NULL ;
}
while ( ( newms = ast_waitfor ( chan , ms ) ) > 0 ) {
f = ast_read ( chan ) ;
if ( ! f ) {
/* Got hangup */
break ;
}
if ( f - > frametype = = AST_FRAME_CONTROL ) {
switch ( f - > subclass ) {
case AST_CONTROL_ANSWER :
/* Launch the PBX */
strncpy ( chan - > exten , pvt - > pri - > idleext , sizeof ( chan - > exten ) - 1 ) ;
strncpy ( chan - > context , pvt - > pri - > idlecontext , sizeof ( chan - > context ) - 1 ) ;
chan - > priority = 1 ;
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_3 " Idle channel '%s' answered, sending to %s@%s \n " , chan - > name , chan - > exten , chan - > context ) ;
ast_pbx_run ( chan ) ;
/* It's already hungup, return immediately */
return NULL ;
case AST_CONTROL_BUSY :
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_3 " Idle channel '%s' busy, waiting... \n " , chan - > name ) ;
break ;
case AST_CONTROL_CONGESTION :
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_3 " Idle channel '%s' congested, waiting... \n " , chan - > name ) ;
break ;
} ;
}
ast_frfree ( f ) ;
ms = newms ;
}
#if 0
printf ( " Hanging up '%s' \n " , chan - > name ) ;
# endif
/* Hangup the channel since nothing happend */
ast_hangup ( chan ) ;
return NULL ;
}
2003-02-07 19:23:19 +00:00
static void zt_pri_message ( char * s )
{
ast_verbose ( s ) ;
}
static void zt_pri_error ( char * s )
{
ast_log ( LOG_WARNING , " PRI: %s " , s ) ;
}
2003-03-20 05:20:19 +00:00
static int pri_check_restart ( struct zt_pri * pri )
{
do {
pri - > resetchannel + + ;
} while ( ( pri - > resetchannel < = pri - > channels ) & &
( ! pri - > pvt [ pri - > resetchannel ] | |
pri - > pvt [ pri - > resetchannel ] - > call | |
pri - > pvt [ pri - > resetchannel ] - > resetting ) ) ;
if ( pri - > resetchannel < = pri - > channels ) {
/* Mark the channel as resetting and restart it */
pri - > pvt [ pri - > resetchannel ] - > resetting = 1 ;
pri_reset ( pri - > pri , pri - > resetchannel ) ;
} else {
pri - > resetting = 0 ;
2003-03-20 05:49:27 +00:00
time ( & pri - > lastreset ) ;
2003-03-20 05:20:19 +00:00
}
return 0 ;
}
2001-10-09 02:06:21 +00:00
static void * pri_dchannel ( void * vpri )
{
struct zt_pri * pri = vpri ;
pri_event * e ;
fd_set efds ;
fd_set rfds ;
int res ;
2003-05-19 23:33:41 +00:00
int chan = 0 ;
2001-10-09 02:06:21 +00:00
int x ;
2002-06-24 17:59:56 +00:00
int haveidles ;
int activeidles ;
int nextidle = - 1 ;
2001-10-09 02:06:21 +00:00
struct ast_channel * c ;
2001-12-29 18:04:21 +00:00
struct timeval tv , * next ;
2002-06-24 17:59:56 +00:00
struct timeval lastidle = { 0 , 0 } ;
int doidling = 0 ;
char * cc ;
char idlen [ 80 ] ;
struct ast_channel * idle ;
pthread_t p ;
time_t t ;
2003-02-07 19:23:19 +00:00
gettimeofday ( & lastidle , NULL ) ;
2002-06-24 17:59:56 +00:00
if ( strlen ( pri - > idledial ) & & strlen ( pri - > idleext ) ) {
/* Need to do idle dialing, check to be sure though */
cc = strchr ( pri - > idleext , ' @ ' ) ;
if ( cc ) {
* cc = ' \0 ' ;
cc + + ;
strncpy ( pri - > idlecontext , cc , sizeof ( pri - > idlecontext ) - 1 ) ;
#if 0
/* Extensions may not be loaded yet */
if ( ! ast_exists_extension ( NULL , pri - > idlecontext , pri - > idleext , 1 , NULL ) )
ast_log ( LOG_WARNING , " Extension '%s @ %s' does not exist \n " , pri - > idleext , pri - > idlecontext ) ;
else
# endif
doidling = 1 ;
} else
ast_log ( LOG_WARNING , " Idle dial string '%s' lacks '@context' \n " , pri - > idleext ) ;
}
2001-10-09 02:06:21 +00:00
for ( ; ; ) {
FD_ZERO ( & rfds ) ;
FD_ZERO ( & efds ) ;
FD_SET ( pri - > fd , & rfds ) ;
FD_SET ( pri - > fd , & efds ) ;
2002-06-24 17:59:56 +00:00
time ( & t ) ;
ast_pthread_mutex_lock ( & pri - > lock ) ;
2003-02-07 19:23:19 +00:00
if ( pri - > resetting & & pri - > up ) {
2003-03-20 05:20:19 +00:00
if ( ! pri - > resetchannel )
2003-03-20 05:49:27 +00:00
pri_check_restart ( pri ) ;
2002-06-24 17:59:56 +00:00
} else {
2003-03-20 05:49:27 +00:00
if ( ! pri - > resetting & & ( ( t - pri - > lastreset ) > = RESET_INTERVAL ) ) {
2002-06-24 17:59:56 +00:00
pri - > resetting = 1 ;
2003-02-07 19:23:19 +00:00
pri - > resetchannel = 0 ;
2002-06-24 17:59:56 +00:00
}
}
/* Look for any idle channels if appropriate */
2003-02-07 19:23:19 +00:00
if ( doidling & & pri - > up ) {
2002-06-24 17:59:56 +00:00
nextidle = - 1 ;
haveidles = 0 ;
activeidles = 0 ;
for ( x = pri - > channels ; x > = 0 ; x - - ) {
if ( pri - > pvt [ x ] & & ! pri - > pvt [ x ] - > owner & &
! pri - > pvt [ x ] - > call ) {
if ( haveidles < pri - > minunused ) {
haveidles + + ;
} else if ( ! pri - > pvt [ x ] - > resetting ) {
nextidle = x ;
break ;
}
} else if ( pri - > pvt [ x ] & & pri - > pvt [ x ] - > owner & & pri - > pvt [ x ] - > isidlecall )
activeidles + + ;
}
#if 0
printf ( " nextidle: %d, haveidles: %d, minunsed: %d \n " ,
nextidle , haveidles , minunused ) ;
gettimeofday ( & tv , NULL ) ;
printf ( " nextidle: %d, haveidles: %d, ms: %ld, minunsed: %d \n " ,
nextidle , haveidles , ( tv . tv_sec - lastidle . tv_sec ) * 1000 +
( tv . tv_usec - lastidle . tv_usec ) / 1000 , minunused ) ;
# endif
if ( nextidle > - 1 ) {
gettimeofday ( & tv , NULL ) ;
if ( ( ( tv . tv_sec - lastidle . tv_sec ) * 1000 +
( tv . tv_usec - lastidle . tv_usec ) / 1000 ) > 1000 ) {
/* Don't create a new idle call more than once per second */
snprintf ( idlen , sizeof ( idlen ) , " %d/%s " , pri - > pvt [ nextidle ] - > channel , pri - > idledial ) ;
idle = zt_request ( " Zap " , AST_FORMAT_ULAW , idlen ) ;
if ( idle ) {
pri - > pvt [ nextidle ] - > isidlecall = 1 ;
if ( pthread_create ( & p , NULL , do_idle_thread , idle ) ) {
ast_log ( LOG_WARNING , " Unable to start new thread for idle channel '%s' \n " , idle - > name ) ;
zt_hangup ( idle ) ;
}
} else
ast_log ( LOG_WARNING , " Unable to request channel 'Zap/%s' for idle call \n " , idlen ) ;
gettimeofday ( & lastidle , NULL ) ;
}
} else if ( ( haveidles < pri - > minunused ) & &
( activeidles > pri - > minidle ) ) {
/* Mark something for hangup if there is something
that can be hungup */
2003-02-07 19:23:19 +00:00
for ( x = pri - > channels ; x > 0 ; x - - ) {
2002-06-24 17:59:56 +00:00
/* find a candidate channel */
if ( pri - > pvt [ x ] & & pri - > pvt [ x ] - > owner & & pri - > pvt [ x ] - > isidlecall ) {
2002-09-10 04:45:51 +00:00
pri - > pvt [ x ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2002-06-24 17:59:56 +00:00
haveidles + + ;
/* Stop if we have enough idle channels or
can ' t spare any more active idle ones */
if ( ( haveidles > = pri - > minunused ) | |
( activeidles < = pri - > minidle ) )
break ;
}
}
}
}
2001-12-29 18:04:21 +00:00
if ( ( next = pri_schedule_next ( pri - > pri ) ) ) {
/* We need relative time here */
gettimeofday ( & tv , NULL ) ;
tv . tv_sec = next - > tv_sec - tv . tv_sec ;
tv . tv_usec = next - > tv_usec - tv . tv_usec ;
if ( tv . tv_usec < 0 ) {
tv . tv_usec + = 1000000 ;
tv . tv_sec - = 1 ;
}
if ( tv . tv_sec < 0 ) {
tv . tv_sec = 0 ;
tv . tv_usec = 0 ;
}
2002-06-24 17:59:56 +00:00
if ( doidling | | pri - > resetting ) {
if ( tv . tv_sec > 1 ) {
tv . tv_sec = 1 ;
tv . tv_usec = 0 ;
}
} else {
if ( tv . tv_sec > 60 ) {
tv . tv_sec = 60 ;
tv . tv_usec = 0 ;
}
}
} else if ( doidling | | pri - > resetting ) {
/* Make sure we stop at least once per second if we're
monitoring idle channels */
tv . tv_sec = 1 ;
tv . tv_usec = 0 ;
} else {
/* Don't poll for more than 60 seconds */
tv . tv_sec = 60 ;
tv . tv_usec = 0 ;
2001-12-29 18:04:21 +00:00
}
2002-06-24 17:59:56 +00:00
pthread_mutex_unlock ( & pri - > lock ) ;
2002-03-08 23:48:42 +00:00
e = NULL ;
2003-05-19 23:33:41 +00:00
res = ast_select ( pri - > fd + 1 , & rfds , NULL , & efds , & tv ) ;
2002-06-24 17:59:56 +00:00
ast_pthread_mutex_lock ( & pri - > lock ) ;
2001-10-09 02:06:21 +00:00
if ( ! res ) {
/* Just a timeout, run the scheduler */
2002-03-08 23:48:42 +00:00
e = pri_schedule_run ( pri - > pri ) ;
2001-10-09 02:06:21 +00:00
} else if ( res > - 1 ) {
e = pri_check_event ( pri - > pri ) ;
2002-03-08 23:48:42 +00:00
} else if ( errno ! = EINTR )
ast_log ( LOG_WARNING , " pri_event returned error %d (%s) \n " , errno , strerror ( errno ) ) ;
if ( e ) {
if ( pri - > debug )
pri_dump_event ( pri - > pri , e ) ;
switch ( e - > e ) {
case PRI_EVENT_DCHAN_UP :
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " D-Channel on span %d up \n " , pri - > span ) ;
pri - > up = 1 ;
2003-03-20 05:49:27 +00:00
time ( & pri - > lastreset ) ;
/* Restart in 5 seconds */
pri - > lastreset - = RESET_INTERVAL ;
pri - > lastreset + = 5 ;
pri - > resetting = 0 ;
2002-03-08 23:48:42 +00:00
break ;
case PRI_EVENT_DCHAN_DOWN :
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " D-Channel on span %d down \n " , pri - > span ) ;
pri - > up = 0 ;
2003-03-20 05:49:27 +00:00
pri - > resetting = 0 ;
2002-03-08 23:48:42 +00:00
break ;
case PRI_EVENT_RESTART :
chan = e - > restart . channel ;
if ( chan > - 1 ) {
if ( ( chan < 1 ) | | ( chan > pri - > channels ) )
ast_log ( LOG_WARNING , " Restart requested on odd channel number %d on span %d \n " , chan , pri - > span ) ;
else if ( ! pri - > pvt [ chan ] )
ast_log ( LOG_WARNING , " Restart requested on unconfigured channel %d on span %d \n " , chan , pri - > span ) ;
else {
2001-10-09 02:06:21 +00:00
if ( option_verbose > 2 )
2002-03-08 23:48:42 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " B-channel %d restarted on span %d \n " ,
chan , pri - > span ) ;
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_lock ( & pri - > pvt [ chan ] - > lock ) ;
2002-03-08 23:48:42 +00:00
/* Force soft hangup if appropriate */
if ( pri - > pvt [ chan ] - > owner )
2002-09-10 04:45:51 +00:00
pri - > pvt [ chan ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_unlock ( & pri - > pvt [ chan ] - > lock ) ;
2001-10-09 02:06:21 +00:00
}
2002-03-08 23:48:42 +00:00
} else {
if ( option_verbose > 2 )
2003-02-07 19:23:19 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Restart on requested on entire span %d \n " , pri - > span ) ;
2002-03-08 23:48:42 +00:00
for ( x = 1 ; x < = pri - > channels ; x + + )
2003-03-19 16:44:19 +00:00
if ( ( x ! = pri - > dchannel ) & & pri - > pvt [ x ] ) {
2003-03-23 18:55:52 +00:00
ast_pthread_mutex_lock ( & pri - > pvt [ x ] - > lock ) ;
2003-03-19 16:44:19 +00:00
if ( pri - > pvt [ x ] - > owner )
pri - > pvt [ x ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2003-03-23 18:55:52 +00:00
ast_pthread_mutex_unlock ( & pri - > pvt [ x ] - > lock ) ;
2003-03-19 16:44:19 +00:00
}
2002-03-08 23:48:42 +00:00
}
break ;
2003-02-12 13:59:15 +00:00
case PRI_EVENT_INFO_RECEIVED :
2002-03-08 23:48:42 +00:00
case PRI_EVENT_RING :
chan = e - > ring . channel ;
2003-03-24 22:12:11 +00:00
if ( e - > e = = PRI_EVENT_RING ) {
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Ring requested on odd channel number %d span %d \n " , chan , pri - > span ) ;
2001-10-09 02:06:21 +00:00
chan = 0 ;
2003-03-24 22:12:11 +00:00
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Ring requested on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
} else if ( pri - > pvt [ chan ] - > owner ) {
if ( pri - > pvt [ chan ] - > call = = e - > ring . call ) {
ast_log ( LOG_WARNING , " Duplicate setup requested on channel %d already in use on span %d \n " , chan , pri - > span ) ;
break ;
} else {
ast_log ( LOG_WARNING , " Ring requested on channel %d already in use on span %d. Hanging up owner. \n " , chan , pri - > span ) ;
pri - > pvt [ chan ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
chan = 0 ;
}
2001-10-09 02:06:21 +00:00
}
2003-03-24 22:12:11 +00:00
if ( ! chan & & ( e - > ring . flexible ) )
chan = pri_find_empty_chan ( pri ) ;
2002-03-08 23:48:42 +00:00
}
if ( chan ) {
2003-02-12 13:59:15 +00:00
if ( e - > e = = PRI_EVENT_RING ) {
/* Get caller ID */
if ( pri - > pvt [ chan ] - > use_callerid ) {
if ( strlen ( e - > ring . callingname ) ) {
snprintf ( pri - > pvt [ chan ] - > callerid , sizeof ( pri - > pvt [ chan ] - > callerid ) , " \" %s \" <%s> " , e - > ring . callingname , e - > ring . callingnum ) ;
} else
strncpy ( pri - > pvt [ chan ] - > callerid , e - > ring . callingnum , sizeof ( pri - > pvt [ chan ] - > callerid ) - 1 ) ;
2003-02-07 19:23:19 +00:00
} else
2003-02-12 13:59:15 +00:00
strcpy ( pri - > pvt [ chan ] - > callerid , " " ) ;
strncpy ( pri - > pvt [ chan ] - > rdnis , e - > ring . redirectingnum , sizeof ( pri - > pvt [ chan ] - > rdnis ) ) ;
}
2003-05-19 23:33:41 +00:00
/* If immediate=yes go to s|1 */
2003-06-03 16:24:12 +00:00
if ( pri - > pvt [ chan ] - > immediate ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Going to extension s|1 because of immediate=yes \n " ) ;
2003-05-19 23:33:41 +00:00
strcpy ( pri - > pvt [ chan ] - > exten , " s " ) ;
2003-06-03 16:24:12 +00:00
}
2002-03-08 23:48:42 +00:00
/* Get called number */
2003-05-19 23:33:41 +00:00
else if ( strlen ( e - > ring . callednum ) ) {
2003-06-05 21:13:12 +00:00
# ifndef PRI_COPY_DIGITS_CALLED_NUMBER
# error Please update the libpri package
# endif
if ( e - > e = = PRI_EVENT_RING )
strncpy ( pri - > pvt [ chan ] - > exten , e - > ring . callednum , sizeof ( pri - > pvt [ chan ] - > exten ) - 1 ) ;
else
strncat ( pri - > pvt [ chan ] - > exten , e - > ring . callednum , sizeof ( pri - > pvt [ chan ] - > exten ) - 1 ) ;
2003-03-24 22:12:11 +00:00
}
#if 0
else
2002-03-08 23:48:42 +00:00
strcpy ( pri - > pvt [ chan ] - > exten , " s " ) ;
2003-03-24 22:12:11 +00:00
# endif
else
strcpy ( pri - > pvt [ chan ] - > exten , " " ) ;
2003-05-19 23:33:41 +00:00
/* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
if ( pri - > overlapdial & & pri - > pvt [ chan ] - > call = = e - > ring . call & & pri - > pvt [ chan ] - > owner ) {
/* how to do that */
2003-06-05 21:13:12 +00:00
int digitlen = strlen ( e - > ring . callednum ) ;
char digit ;
int i ;
2003-05-19 23:33:41 +00:00
/* make sure that we store the right number in CDR */
if ( pri - > pvt [ chan ] - > owner - > cdr )
2003-06-05 21:13:12 +00:00
strncat ( pri - > pvt [ chan ] - > owner - > cdr - > dst , e - > ring . callednum , digitlen ) ;
for ( i = 0 ; i < digitlen ; i + + ) {
digit = e - > ring . callednum [ i ] ;
{
struct ast_frame f = { AST_FRAME_DTMF , digit , } ;
ast_queue_frame ( pri - > pvt [ chan ] - > owner , & f , 0 ) ;
}
}
2003-05-19 23:33:41 +00:00
}
2002-03-08 23:48:42 +00:00
/* Make sure extension exists */
2003-05-19 23:33:41 +00:00
/* If extensions is empty then make sure we send later on SETUP_ACKNOWLEDGE to get digits in overlap mode */
else if ( strlen ( pri - > pvt [ chan ] - > exten ) & & ast_exists_extension ( NULL , pri - > pvt [ chan ] - > context , pri - > pvt [ chan ] - > exten , 1 , pri - > pvt [ chan ] - > callerid ) ) {
2002-03-08 23:48:42 +00:00
/* Setup law */
int law ;
2003-05-19 23:33:41 +00:00
/* Set to audio mode at this poitn mode */
law = 1 ;
if ( ioctl ( pri - > pvt [ chan ] - > subs [ SUB_REAL ] . zfd , ZT_AUDIOMODE , & law ) = = - 1 )
ast_log ( LOG_WARNING , " Unable to set audio mode on channel %d to %d \n " , pri - > pvt [ chan ] - > channel , law ) ;
2002-03-08 23:48:42 +00:00
if ( e - > ring . layer1 = = PRI_LAYER_1_ALAW )
law = ZT_LAW_ALAW ;
2001-10-09 02:06:21 +00:00
else
2002-03-08 23:48:42 +00:00
law = ZT_LAW_MULAW ;
2003-02-07 19:23:19 +00:00
res = zt_setlaw ( pri - > pvt [ chan ] - > subs [ SUB_REAL ] . zfd , law ) ;
2002-03-08 23:48:42 +00:00
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to set law on channel %d \n " , pri - > pvt [ chan ] - > channel ) ;
2003-02-07 19:23:19 +00:00
res = set_actual_gain ( pri - > pvt [ chan ] - > subs [ SUB_REAL ] . zfd , 0 , pri - > pvt [ chan ] - > rxgain , pri - > pvt [ chan ] - > txgain , law ) ;
if ( res < 0 )
ast_log ( LOG_WARNING , " Unable to set gains on channel %d \n " , pri - > pvt [ chan ] - > channel ) ;
2002-03-08 23:48:42 +00:00
/* Start PBX */
pri - > pvt [ chan ] - > call = e - > ring . call ;
2003-02-07 19:23:19 +00:00
c = zt_new ( pri - > pvt [ chan ] , AST_STATE_RING , 1 , SUB_REAL , law ) ;
2002-03-08 23:48:42 +00:00
if ( c ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Accepting call from '%s' to '%s' on channel %d, span %d \n " ,
e - > ring . callingnum , pri - > pvt [ chan ] - > exten , chan , pri - > span ) ;
2003-05-19 23:33:41 +00:00
if ( ! pri - > overlapdial ) {
pri_acknowledge ( pri - > pri , e - > ring . call , chan , 1 ) ;
}
/* If we got here directly and didn't send the SETUP_ACKNOWLEDGE we need to send it otherwise we don't sent anything */
else if ( e - > e = = PRI_EVENT_RING ) {
pri_need_more_info ( pri - > pri , e - > ring . call , chan , 1 ) ;
}
2002-03-08 23:48:42 +00:00
zt_enable_ec ( pri - > pvt [ chan ] ) ;
2001-10-09 02:06:21 +00:00
} else {
2002-03-08 23:48:42 +00:00
ast_log ( LOG_WARNING , " Unable to start PBX on channel %d, span %d \n " , chan , pri - > span ) ;
pri_release ( pri - > pri , e - > ring . call , PRI_CAUSE_SWITCH_CONGESTION ) ;
pri - > pvt [ chan ] - > call = 0 ;
2001-10-09 02:06:21 +00:00
}
2002-03-08 23:48:42 +00:00
} else {
2003-03-24 22:12:11 +00:00
if ( ! strlen ( pri - > pvt [ chan ] - > exten ) | | ast_matchmore_extension ( NULL , pri - > pvt [ chan ] - > context , pri - > pvt [ chan ] - > exten , 1 , pri - > pvt [ chan ] - > callerid ) )
2003-02-12 13:59:15 +00:00
{
2003-05-19 23:33:41 +00:00
/* Send SETUP_ACKNOWLEDGE only when we receive SETUP, don't send if we got INFORMATION */
2003-02-12 13:59:15 +00:00
if ( e - > e = = PRI_EVENT_RING ) pri_need_more_info ( pri - > pri , e - > ring . call , chan , 1 ) ;
} else {
if ( option_verbose > 2 )
2003-05-19 23:33:41 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Extension '%s' in context '%s' from '%s' does not exist. Rejecting call on channel %d, span %d \n " , pri - > pvt [ chan ] - > exten , pri - > pvt [ chan ] - > context , pri - > pvt [ chan ] - > callerid , chan , pri - > span ) ;
2003-02-12 13:59:15 +00:00
pri_release ( pri - > pri , e - > ring . call , PRI_CAUSE_UNALLOCATED ) ;
}
2001-10-09 02:06:21 +00:00
}
2002-03-08 23:48:42 +00:00
} else
pri_release ( pri - > pri , e - > ring . call , PRI_CAUSE_REQUESTED_CHAN_UNAVAIL ) ;
break ;
case PRI_EVENT_RINGING :
chan = e - > ringing . channel ;
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Ringing requested on odd channel number %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Ringing requested on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
}
if ( chan ) {
chan = pri_fixup ( pri , chan , e - > ringing . call ) ;
if ( ! chan ) {
ast_log ( LOG_WARNING , " Ringing requested on channel %d not in use on span %d \n " , e - > ringing . channel , pri - > span ) ;
2001-10-09 02:06:21 +00:00
chan = 0 ;
2003-02-07 19:23:19 +00:00
} else if ( ! strlen ( pri - > pvt [ chan ] - > dop . dialstr ) ) {
2003-02-14 06:00:11 +00:00
zt_enable_ec ( pri - > pvt [ chan ] ) ;
2003-02-07 19:23:19 +00:00
pri - > pvt [ chan ] - > subs [ SUB_REAL ] . needringing = 1 ;
2003-05-19 23:33:41 +00:00
# ifdef PRI_EVENT_PROCEEDING
pri - > pvt [ chan ] - > proceeding = 1 ;
# endif
2002-03-08 23:48:42 +00:00
} else
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Deferring ringing notification because of extra digits to dial... \n " ) ;
}
2003-05-19 23:33:41 +00:00
# ifndef PRI_EVENT_PROCEEDING
2003-02-07 19:23:19 +00:00
break ;
2003-05-19 23:33:41 +00:00
# else
/* Fall through */
if ( ! chan ) break ;
# endif
# ifdef PRI_EVENT_PROCEEDING
case PRI_EVENT_PROCEEDING :
/* Get chan value if e->e is not PRI_EVNT_RINGING */
if ( e - > e = = PRI_EVENT_PROCEEDING )
chan = e - > proceeding . channel ;
if ( ( chan > = 1 ) & & ( chan < = pri - > channels ) )
if ( pri - > pvt [ chan ] & & pri - > overlapdial & & ! pri - > pvt [ chan ] - > proceeding ) {
struct ast_frame f = { AST_FRAME_CONTROL , AST_CONTROL_PROGRESS , } ;
ast_log ( LOG_DEBUG , " queling frame from PRI_EVENT_PROCEEDING on channel %d span %d \n " , chan , pri - > pvt [ chan ] - > span ) ;
ast_queue_frame ( pri - > pvt [ chan ] - > owner , & f , 0 ) ;
pri - > pvt [ chan ] - > proceeding = 1 ;
}
break ;
# endif
2003-02-07 19:23:19 +00:00
case PRI_EVENT_FACNAME :
chan = e - > facname . channel ;
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Facilty Name requested on odd channel number %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Facility Name requested on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
}
if ( chan ) {
chan = pri_fixup ( pri , chan , e - > facname . call ) ;
if ( ! chan ) {
ast_log ( LOG_WARNING , " Facility Name requested on channel %d not in use on span %d \n " , e - > ringing . channel , pri - > span ) ;
chan = 0 ;
} else {
/* Re-use *69 field for PRI */
snprintf ( pri - > pvt [ chan ] - > lastcallerid , sizeof ( pri - > pvt [ chan ] - > lastcallerid ) , " \" %s \" <%s> " , e - > facname . callingname , e - > facname . callingnum ) ;
pri - > pvt [ chan ] - > subs [ SUB_REAL ] . needcallerid = 1 ;
2003-02-18 18:15:30 +00:00
zt_enable_ec ( pri - > pvt [ chan ] ) ;
2003-02-07 19:23:19 +00:00
}
2002-03-08 23:48:42 +00:00
}
break ;
case PRI_EVENT_ANSWER :
chan = e - > answer . channel ;
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Answer on odd channel number %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Answer on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
}
if ( chan ) {
2003-02-07 19:23:19 +00:00
chan = pri_fixup ( pri , chan , e - > answer . call ) ;
2002-03-08 23:48:42 +00:00
if ( ! chan ) {
2003-02-07 19:23:19 +00:00
ast_log ( LOG_WARNING , " Answer requested on channel %d not in use on span %d \n " , chan , pri - > span ) ;
2001-10-09 02:06:21 +00:00
chan = 0 ;
2003-02-07 19:23:19 +00:00
} else {
if ( strlen ( pri - > pvt [ chan ] - > dop . dialstr ) ) {
pri - > pvt [ chan ] - > dialing = 1 ;
/* Send any "w" waited stuff */
res = ioctl ( pri - > pvt [ chan ] - > subs [ SUB_REAL ] . zfd , ZT_DIAL , & pri - > pvt [ chan ] - > dop ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to initiate dialing on trunk channel %d \n " , pri - > pvt [ chan ] - > channel ) ;
pri - > pvt [ chan ] - > dop . dialstr [ 0 ] = ' \0 ' ;
return NULL ;
} else
ast_log ( LOG_DEBUG , " Sent deferred digit string: %s \n " , pri - > pvt [ chan ] - > dop . dialstr ) ;
pri - > pvt [ chan ] - > dop . dialstr [ 0 ] = ' \0 ' ;
} else
pri - > pvt [ chan ] - > subs [ SUB_REAL ] . needanswer = 1 ;
/* Enable echo cancellation if it's not on already */
zt_enable_ec ( pri - > pvt [ chan ] ) ;
}
2002-03-08 23:48:42 +00:00
}
break ;
case PRI_EVENT_HANGUP :
chan = e - > hangup . channel ;
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Hangup requested on odd channel number %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Hangup requested on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
}
if ( chan ) {
chan = pri_fixup ( pri , chan , e - > hangup . call ) ;
2001-10-09 02:06:21 +00:00
if ( chan ) {
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_lock ( & pri - > pvt [ chan ] - > lock ) ;
2002-03-08 23:48:42 +00:00
if ( pri - > pvt [ chan ] - > owner ) {
2003-02-07 19:23:19 +00:00
pri - > pvt [ chan ] - > alreadyhungup = 1 ;
2002-09-10 04:45:51 +00:00
pri - > pvt [ chan ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
2002-06-24 17:59:56 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Channel %d, span %d got hangup \n " , chan , pri - > span ) ;
2001-10-09 02:06:21 +00:00
}
2002-06-24 17:59:56 +00:00
if ( e - > hangup . cause = = PRI_CAUSE_REQUESTED_CHAN_UNAVAIL ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Forcing restart of channel %d since channel reported in use \n " , chan ) ;
pri_reset ( pri - > pri , chan ) ;
pri - > pvt [ chan ] - > resetting = 1 ;
}
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_unlock ( & pri - > pvt [ chan ] - > lock ) ;
2002-03-08 23:48:42 +00:00
} else {
ast_log ( LOG_WARNING , " Hangup on bad channel %d \n " , e - > hangup . channel ) ;
2001-10-09 02:06:21 +00:00
}
2002-03-08 23:48:42 +00:00
}
break ;
case PRI_EVENT_HANGUP_ACK :
chan = e - > hangup . channel ;
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Hangup ACK requested on odd channel number %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Hangup ACK requested on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
}
if ( chan ) {
chan = pri_fixup ( pri , chan , e - > hangup . call ) ;
2001-10-09 02:06:21 +00:00
if ( chan ) {
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_lock ( & pri - > pvt [ chan ] - > lock ) ;
2003-02-07 19:23:19 +00:00
pri - > pvt [ chan ] - > call = NULL ;
2002-06-24 17:59:56 +00:00
pri - > pvt [ chan ] - > resetting = 0 ;
2002-03-08 23:48:42 +00:00
if ( pri - > pvt [ chan ] - > owner ) {
2002-06-24 17:59:56 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Channel %d, span %d got hangup ACK \n " , chan , pri - > span ) ;
2001-10-09 02:06:21 +00:00
}
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_unlock ( & pri - > pvt [ chan ] - > lock ) ;
2001-10-09 02:06:21 +00:00
}
}
2002-03-08 23:48:42 +00:00
break ;
case PRI_EVENT_CONFIG_ERR :
ast_log ( LOG_WARNING , " PRI Error: %s \n " , e - > err . err ) ;
break ;
2002-06-24 17:59:56 +00:00
case PRI_EVENT_RESTART_ACK :
chan = e - > restartack . channel ;
2003-02-07 19:23:19 +00:00
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
/* Sometime switches (e.g. I421 / British Telecom) don't give us the
channel number , so we have to figure it out . . . This must be why
everybody resets exactly a channel at a time . */
for ( x = 1 ; x < = pri - > channels ; x + + ) {
if ( pri - > pvt [ x ] & & pri - > pvt [ x ] - > resetting ) {
chan = x ;
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_lock ( & pri - > pvt [ chan ] - > lock ) ;
2003-02-07 19:23:19 +00:00
ast_log ( LOG_DEBUG , " Assuming restart ack is really for channel %d span %d \n " , chan , pri - > span ) ;
if ( pri - > pvt [ chan ] - > owner ) {
2003-03-19 16:44:19 +00:00
ast_log ( LOG_WARNING , " Got restart ack on channel %d with owner \n " , chan ) ;
2003-02-07 19:23:19 +00:00
pri - > pvt [ chan ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
}
pri - > pvt [ chan ] - > resetting = 0 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " B-channel %d successfully restarted on span %d \n " , chan , pri - > span ) ;
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_unlock ( & pri - > pvt [ chan ] - > lock ) ;
2003-03-20 05:20:19 +00:00
if ( pri - > resetting )
pri_check_restart ( pri ) ;
2003-02-07 19:23:19 +00:00
break ;
}
}
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Restart ACK requested on strange channel %d span %d \n " , chan , pri - > span ) ;
}
chan = 0 ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Restart ACK requested on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
chan = 0 ;
}
2003-03-19 16:44:19 +00:00
if ( ( chan > = 1 ) & & ( chan < = pri - > channels ) ) {
2003-02-07 19:23:19 +00:00
if ( pri - > pvt [ chan ] ) {
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_lock ( & pri - > pvt [ chan ] - > lock ) ;
2003-02-07 19:23:19 +00:00
if ( pri - > pvt [ chan ] - > owner ) {
2003-03-19 16:44:19 +00:00
ast_log ( LOG_WARNING , " Got restart ack on channel %d with owner \n " , chan ) ;
2003-02-07 19:23:19 +00:00
pri - > pvt [ chan ] - > owner - > _softhangup | = AST_SOFTHANGUP_DEV ;
}
pri - > pvt [ chan ] - > resetting = 0 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " B-channel %d successfully restarted on span %d \n " , chan , pri - > span ) ;
2003-03-19 16:44:19 +00:00
ast_pthread_mutex_unlock ( & pri - > pvt [ chan ] - > lock ) ;
2003-03-20 05:49:27 +00:00
if ( pri - > resetting )
pri_check_restart ( pri ) ;
2002-06-24 17:59:56 +00:00
}
}
break ;
2003-05-19 23:33:41 +00:00
# ifdef PRI_EVENT_SETUP_ACK
case PRI_EVENT_SETUP_ACK :
chan = e - > setup_ack . channel ;
if ( ( chan < 1 ) | | ( chan > pri - > channels ) ) {
ast_log ( LOG_WARNING , " Received SETUP_ACKNOWLEDGE on strange channel %d span %d \n " , chan , pri - > span ) ;
} else if ( ! pri - > pvt [ chan ] ) {
ast_log ( LOG_WARNING , " Received SETUP_ACKNOWLEDGE on unconfigured channel %d span %d \n " , chan , pri - > span ) ;
} else {
pri - > pvt [ chan ] - > setup_ack = 1 ;
}
2003-05-15 22:16:26 +00:00
break ;
2003-05-19 23:33:41 +00:00
# endif
2002-03-08 23:48:42 +00:00
default :
ast_log ( LOG_DEBUG , " Event: %d \n " , e - > e ) ;
2001-10-09 02:06:21 +00:00
}
} else {
2002-03-08 23:48:42 +00:00
/* Check for an event */
x = 0 ;
res = ioctl ( pri - > fd , ZT_GETEVENT , & x ) ;
if ( x )
printf ( " PRI got event: %d \n " , x ) ;
if ( option_debug )
ast_log ( LOG_DEBUG , " Got event %s (%d) on D-channel for span %d \n " , event2str ( x ) , x , pri - > span ) ;
2001-10-09 02:06:21 +00:00
}
pthread_mutex_unlock ( & pri - > lock ) ;
}
/* Never reached */
return NULL ;
}
static int start_pri ( struct zt_pri * pri )
{
2002-03-08 23:48:42 +00:00
int res , x ;
2001-10-09 02:06:21 +00:00
ZT_PARAMS p ;
ZT_BUFFERINFO bi ;
2002-03-08 23:48:42 +00:00
pri - > fd = open ( " /dev/zap/channel " , O_RDWR , 0600 ) ;
x = pri - > offset + pri - > dchannel ;
if ( ( pri - > fd < 0 ) | | ( ioctl ( pri - > fd , ZT_SPECIFY , & x ) = = - 1 ) ) {
ast_log ( LOG_ERROR , " Unable to open D-channel %d (%s) \n " , x , strerror ( errno ) ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
2002-03-08 23:48:42 +00:00
2001-10-09 02:06:21 +00:00
res = ioctl ( pri - > fd , ZT_GET_PARAMS , & p ) ;
if ( res ) {
close ( pri - > fd ) ;
pri - > fd = - 1 ;
2003-02-07 19:23:19 +00:00
ast_log ( LOG_ERROR , " Unable to get parameters for D-channel %d (%s) \n " , x , strerror ( errno ) ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
if ( p . sigtype ! = ZT_SIG_HDLCFCS ) {
close ( pri - > fd ) ;
pri - > fd = - 1 ;
2003-02-07 19:23:19 +00:00
ast_log ( LOG_ERROR , " D-channel %x is not in HDLC/FCS mode. See /etc/tormenta.conf \n " , x ) ;
2001-10-09 02:06:21 +00:00
return - 1 ;
}
bi . txbufpolicy = ZT_POLICY_IMMEDIATE ;
bi . rxbufpolicy = ZT_POLICY_IMMEDIATE ;
2001-12-29 18:04:21 +00:00
bi . numbufs = 8 ;
2001-10-09 02:06:21 +00:00
bi . bufsize = 1024 ;
if ( ioctl ( pri - > fd , ZT_SET_BUFINFO , & bi ) ) {
2003-02-07 19:23:19 +00:00
ast_log ( LOG_ERROR , " Unable to set appropriate buffering on channel %d \n " , x ) ;
2001-10-09 02:06:21 +00:00
close ( pri - > fd ) ;
pri - > fd = - 1 ;
return - 1 ;
}
pri - > pri = pri_new ( pri - > fd , pri - > nodetype , pri - > switchtype ) ;
if ( ! pri - > pri ) {
close ( pri - > fd ) ;
pri - > fd = - 1 ;
ast_log ( LOG_ERROR , " Unable to create PRI structure \n " ) ;
return - 1 ;
}
2003-05-19 23:33:41 +00:00
# ifdef PRI_SET_OVERLAPDIAL
pri_set_overlapdial ( pri - > pri , pri - > overlapdial ) ;
# endif
2001-10-09 02:06:21 +00:00
pri_set_debug ( pri - > pri , DEFAULT_PRI_DEBUG ) ;
if ( pthread_create ( & pri - > master , NULL , pri_dchannel , pri ) ) {
close ( pri - > fd ) ;
pri - > fd = - 1 ;
ast_log ( LOG_ERROR , " Unable to spawn D-channel: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
return 0 ;
}
static char * complete_span ( char * line , char * word , int pos , int state )
{
int span = 1 ;
char tmp [ 50 ] ;
while ( span < = NUM_SPANS ) {
if ( span > state )
break ;
span + + ;
}
if ( span < = NUM_SPANS ) {
snprintf ( tmp , sizeof ( tmp ) , " %d " , span ) ;
return strdup ( tmp ) ;
} else
return NULL ;
}
static int handle_pri_debug ( int fd , int argc , char * argv [ ] )
{
int span ;
2002-03-08 23:48:42 +00:00
if ( argc < 4 ) {
return RESULT_SHOWUSAGE ;
}
2001-10-09 02:06:21 +00:00
span = atoi ( argv [ 3 ] ) ;
if ( ( span < 1 ) | | ( span > NUM_SPANS ) ) {
ast_cli ( fd , " Invalid span %s. Should be a number %d to %d \n " , argv [ 3 ] , 1 , NUM_SPANS ) ;
return RESULT_SUCCESS ;
}
if ( ! pris [ span - 1 ] . pri ) {
ast_cli ( fd , " No PRI running on span %d \n " , span ) ;
return RESULT_SUCCESS ;
}
pri_set_debug ( pris [ span - 1 ] . pri , PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE ) ;
ast_cli ( fd , " Enabled debugging on span %d \n " , span ) ;
return RESULT_SUCCESS ;
}
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
static int handle_r2_no_debug ( int fd , int argc , char * argv [ ] )
{
int chan ;
struct zt_pvt * tmp = NULL ; ;
if ( argc < 5 )
return RESULT_SHOWUSAGE ;
chan = atoi ( argv [ 4 ] ) ;
if ( ( chan < 1 ) | | ( chan > NUM_SPANS ) ) {
ast_cli ( fd , " Invalid channel %s. Should be a number greater than 0 \n " ) ;
return RESULT_SUCCESS ;
}
tmp = iflist ;
while ( tmp ) {
if ( tmp - > channel = = chan ) {
if ( tmp - > r2 ) {
mfcr2_set_debug ( tmp - > r2 , 0 ) ;
ast_cli ( fd , " Disabled R2 debugging on channel %d \n " , chan ) ;
return RESULT_SUCCESS ;
}
break ;
}
tmp = tmp - > next ;
}
if ( tmp )
ast_cli ( fd , " No R2 running on channel %d \n " , chan ) ;
else
ast_cli ( fd , " No such zap channel %d \n " , chan ) ;
return RESULT_SUCCESS ;
}
static int handle_r2_debug ( int fd , int argc , char * argv [ ] )
{
int chan ;
struct zt_pvt * tmp = NULL ; ;
if ( argc < 4 ) {
return RESULT_SHOWUSAGE ;
}
chan = atoi ( argv [ 3 ] ) ;
if ( ( chan < 1 ) | | ( chan > NUM_SPANS ) ) {
ast_cli ( fd , " Invalid channel %s. Should be a number greater than 0 \n " ) ;
return RESULT_SUCCESS ;
}
tmp = iflist ;
while ( tmp ) {
if ( tmp - > channel = = chan ) {
if ( tmp - > r2 ) {
mfcr2_set_debug ( tmp - > r2 , 0xFFFFFFFF ) ;
ast_cli ( fd , " Enabled R2 debugging on channel %d \n " , chan ) ;
return RESULT_SUCCESS ;
}
break ;
}
tmp = tmp - > next ;
}
if ( tmp )
ast_cli ( fd , " No R2 running on channel %d \n " , chan ) ;
else
ast_cli ( fd , " No such zap channel %d \n " , chan ) ;
return RESULT_SUCCESS ;
}
static char r2_debug_help [ ] =
" Usage: r2 debug channel <channel> \n "
" Enables R2 protocol level debugging on a given channel \n " ;
static char r2_no_debug_help [ ] =
" Usage: r2 no debug channel <channel> \n "
" Enables R2 protocol level debugging on a given channel \n " ;
static struct ast_cli_entry r2_debug = {
{ " r2 " , " debug " , " channel " , NULL } , handle_r2_debug , " Enables R2 debugging on a channel " , r2_debug_help } ;
static struct ast_cli_entry r2_no_debug = {
{ " r2 " , " no " , " debug " , " channel " , NULL } , handle_r2_no_debug , " Disables R2 debugging on a channel " , r2_no_debug_help } ;
# endif
2001-10-09 02:06:21 +00:00
static int handle_pri_no_debug ( int fd , int argc , char * argv [ ] )
{
int span ;
2002-03-08 23:48:42 +00:00
if ( argc < 5 )
return RESULT_SHOWUSAGE ;
2001-10-09 02:06:21 +00:00
span = atoi ( argv [ 4 ] ) ;
if ( ( span < 1 ) | | ( span > NUM_SPANS ) ) {
ast_cli ( fd , " Invalid span %s. Should be a number %d to %d \n " , argv [ 4 ] , 1 , NUM_SPANS ) ;
return RESULT_SUCCESS ;
}
if ( ! pris [ span - 1 ] . pri ) {
ast_cli ( fd , " No PRI running on span %d \n " , span ) ;
return RESULT_SUCCESS ;
}
pri_set_debug ( pris [ span - 1 ] . pri , 0 ) ;
ast_cli ( fd , " Disabled debugging on span %d \n " , span ) ;
return RESULT_SUCCESS ;
}
2001-12-29 18:04:21 +00:00
static int handle_pri_really_debug ( int fd , int argc , char * argv [ ] )
{
int span ;
2003-02-07 19:23:19 +00:00
if ( argc < 5 )
return RESULT_SHOWUSAGE ;
2001-12-29 18:04:21 +00:00
span = atoi ( argv [ 4 ] ) ;
if ( ( span < 1 ) | | ( span > NUM_SPANS ) ) {
ast_cli ( fd , " Invalid span %s. Should be a number %d to %d \n " , argv [ 4 ] , 1 , NUM_SPANS ) ;
return RESULT_SUCCESS ;
}
if ( ! pris [ span - 1 ] . pri ) {
ast_cli ( fd , " No PRI running on span %d \n " , span ) ;
return RESULT_SUCCESS ;
}
pri_set_debug ( pris [ span - 1 ] . pri , ( PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE ) ) ;
ast_cli ( fd , " Enabled EXTENSIVE debugging on span %d \n " , span ) ;
return RESULT_SUCCESS ;
}
2001-10-09 02:06:21 +00:00
static char pri_debug_help [ ] =
" Usage: pri debug span <span> \n "
" Enables debugging on a given PRI span \n " ;
static char pri_no_debug_help [ ] =
" Usage: pri no debug span <span> \n "
" Disables debugging on a given PRI span \n " ;
2001-12-29 18:04:21 +00:00
static char pri_really_debug_help [ ] =
" Usage: pri intensive debug span <span> \n "
" Enables debugging down to the Q.921 level \n " ;
2001-10-09 02:06:21 +00:00
static struct ast_cli_entry pri_debug = {
{ " pri " , " debug " , " span " , NULL } , handle_pri_debug , " Enables PRI debugging on a span " , pri_debug_help , complete_span
} ;
static struct ast_cli_entry pri_no_debug = {
2002-06-24 17:59:56 +00:00
{ " pri " , " no " , " debug " , " span " , NULL } , handle_pri_no_debug , " Disables PRI debugging on a span " , pri_no_debug_help , complete_span } ;
2001-10-09 02:06:21 +00:00
2001-12-29 18:04:21 +00:00
static struct ast_cli_entry pri_really_debug = {
{ " pri " , " intense " , " debug " , " span " , NULL } , handle_pri_really_debug , " Enables REALLY INTENSE PRI debugging " , pri_really_debug_help , complete_span } ;
2001-10-09 02:06:21 +00:00
# endif /* ZAPATA_PRI */
static int zap_destroy_channel ( int fd , int argc , char * * argv )
{
int channel = 0 ;
struct zt_pvt * tmp = NULL ;
struct zt_pvt * prev = NULL ;
if ( argc ! = 4 ) {
return RESULT_SHOWUSAGE ;
}
channel = atoi ( argv [ 3 ] ) ;
tmp = iflist ;
while ( tmp ) {
if ( tmp - > channel = = channel ) {
destroy_channel ( prev , tmp , 1 ) ;
return RESULT_SUCCESS ;
}
prev = tmp ;
tmp = tmp - > next ;
}
return RESULT_FAILURE ;
}
static int zap_show_channels ( int fd , int argc , char * * argv )
{
2002-06-24 17:59:56 +00:00
# define FORMAT "%3d %-10.10s %-10.10s %-10.10s %-8.8s\n"
# define FORMAT2 "%3s %-10.10s %-10.10s %-10.10s %-8.8s\n"
2001-10-09 02:06:21 +00:00
struct zt_pvt * tmp = NULL ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
ast_pthread_mutex_lock ( & iflock ) ;
2002-06-24 17:59:56 +00:00
ast_cli ( fd , FORMAT2 , " Chan. Num. " , " Extension " , " Context " , " Language " , " MusicOnHold " ) ;
2001-10-09 02:06:21 +00:00
tmp = iflist ;
while ( tmp ) {
2002-06-24 17:59:56 +00:00
ast_cli ( fd , FORMAT , tmp - > channel , tmp - > exten , tmp - > context , tmp - > language , tmp - > musicclass ) ;
2001-10-09 02:06:21 +00:00
tmp = tmp - > next ;
}
ast_pthread_mutex_unlock ( & iflock ) ;
return RESULT_SUCCESS ;
# undef FORMAT
# undef FORMAT2
}
static int zap_show_channel ( int fd , int argc , char * * argv )
{
int channel ;
struct zt_pvt * tmp = NULL ;
2003-02-07 19:23:19 +00:00
ZT_CONFINFO ci ;
int x ;
2001-10-09 02:06:21 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
channel = atoi ( argv [ 3 ] ) ;
ast_pthread_mutex_lock ( & iflock ) ;
tmp = iflist ;
while ( tmp ) {
if ( tmp - > channel = = channel ) {
ast_cli ( fd , " Channel: %d \n " , tmp - > channel ) ;
2003-02-07 19:23:19 +00:00
ast_cli ( fd , " File Descriptor: %d \n " , tmp - > subs [ SUB_REAL ] . zfd ) ;
2001-10-09 02:06:21 +00:00
ast_cli ( fd , " Span: %d \n " , tmp - > span ) ;
ast_cli ( fd , " Extension: %s \n " , tmp - > exten ) ;
ast_cli ( fd , " Context: %s \n " , tmp - > context ) ;
ast_cli ( fd , " Caller ID string: %s \n " , tmp - > callerid ) ;
ast_cli ( fd , " Destroy: %d \n " , tmp - > destroy ) ;
ast_cli ( fd , " Signalling Type: %s \n " , sig2str ( tmp - > sig ) ) ;
2003-02-07 19:23:19 +00:00
ast_cli ( fd , " Owner: %s \n " , tmp - > owner ? tmp - > owner - > name : " <None> " ) ;
ast_cli ( fd , " Real: %s%s%s \n " , tmp - > subs [ SUB_REAL ] . owner ? tmp - > subs [ SUB_REAL ] . owner - > name : " <None> " , tmp - > subs [ SUB_REAL ] . inthreeway ? " (Confed) " : " " , tmp - > subs [ SUB_REAL ] . linear ? " (Linear) " : " " ) ;
ast_cli ( fd , " Callwait: %s%s%s \n " , tmp - > subs [ SUB_CALLWAIT ] . owner ? tmp - > subs [ SUB_CALLWAIT ] . owner - > name : " <None> " , tmp - > subs [ SUB_CALLWAIT ] . inthreeway ? " (Confed) " : " " , tmp - > subs [ SUB_CALLWAIT ] . linear ? " (Linear) " : " " ) ;
ast_cli ( fd , " Threeway: %s%s%s \n " , tmp - > subs [ SUB_THREEWAY ] . owner ? tmp - > subs [ SUB_THREEWAY ] . owner - > name : " <None> " , tmp - > subs [ SUB_THREEWAY ] . inthreeway ? " (Confed) " : " " , tmp - > subs [ SUB_THREEWAY ] . linear ? " (Linear) " : " " ) ;
ast_cli ( fd , " Confno: %d \n " , tmp - > confno ) ;
ast_cli ( fd , " Propagated Conference: %d \n " , tmp - > propconfno ) ;
ast_cli ( fd , " Real in conference: %d \n " , tmp - > inconference ) ;
ast_cli ( fd , " DSP: %s \n " , tmp - > dsp ? " yes " : " no " ) ;
ast_cli ( fd , " Relax DTMF: %s \n " , tmp - > dtmfrelax ? " yes " : " no " ) ;
ast_cli ( fd , " Dialing/CallwaitCAS: %d/%d \n " , tmp - > dialing , tmp - > callwaitcas ) ;
ast_cli ( fd , " Default law: %s \n " , tmp - > law = = ZT_LAW_MULAW ? " ulaw " : tmp - > law = = ZT_LAW_ALAW ? " alaw " : " unknown " ) ;
ast_cli ( fd , " Fax Handled: %s \n " , tmp - > faxhandled ? " yes " : " no " ) ;
ast_cli ( fd , " Pulse phone: %s \n " , tmp - > pulsedial ? " yes " : " no " ) ;
2003-03-10 20:39:12 +00:00
ast_cli ( fd , " Echo Cancellation: %d taps%s, currently %s \n " , tmp - > echocancel , tmp - > echocanbridged ? " " : " unless TDM bridged " , tmp - > echocanon ? " ON " : " OFF " ) ;
2003-02-07 19:23:19 +00:00
if ( tmp - > master )
ast_cli ( fd , " Master Channel: %d \n " , tmp - > master - > channel ) ;
for ( x = 0 ; x < MAX_SLAVES ; x + + ) {
if ( tmp - > slaves [ x ] )
ast_cli ( fd , " Slave Channel: %d \n " , tmp - > slaves [ x ] - > channel ) ;
}
# ifdef ZAPATA_PRI
if ( tmp - > pri ) {
ast_cli ( fd , " PRI Flags: " ) ;
if ( tmp - > resetting )
ast_cli ( fd , " Resetting " ) ;
if ( tmp - > call )
ast_cli ( fd , " Call " ) ;
ast_cli ( fd , " \n " ) ;
}
# endif
# ifdef ZAPATA_R2
if ( tmp - > r2 ) {
ast_cli ( fd , " R2 Flags: " ) ;
if ( tmp - > r2blocked )
ast_cli ( fd , " Blocked " ) ;
if ( tmp - > hasr2call )
ast_cli ( fd , " Call " ) ;
ast_cli ( fd , " \n " ) ;
}
# endif
memset ( & ci , 0 , sizeof ( ci ) ) ;
if ( ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_GETCONF , & ci ) ) {
ast_log ( LOG_WARNING , " Failed to get conference info on channel %d \n " , tmp - > channel ) ;
} else {
ast_cli ( fd , " Actual Confinfo: Num/%d, Mode/0x%04x \n " , ci . confno , ci . confmode ) ;
}
2003-05-19 23:33:41 +00:00
# ifdef ZT_GETCONFMUTE
if ( ioctl ( tmp - > subs [ SUB_REAL ] . zfd , ZT_GETCONFMUTE , & x ) ) {
ast_log ( LOG_WARNING , " Failed to get confmute info on channel %d \n " , tmp - > channel ) ;
} else {
ast_cli ( fd , " Actual Confmute: %s \n " , x ? " Yes " : " No " ) ;
}
# endif
2001-10-09 02:06:21 +00:00
ast_pthread_mutex_unlock ( & iflock ) ;
return RESULT_SUCCESS ;
}
tmp = tmp - > next ;
}
ast_cli ( fd , " Unable to find given channel %d \n " , channel ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
return RESULT_FAILURE ;
}
static char show_channels_usage [ ] =
" Usage: zap show channels \n "
" Shows a list of available channels \n " ;
static char show_channel_usage [ ] =
" Usage: zap show channel <chan num> \n "
" Detailed information about a given channel \n " ;
static char destroy_channel_usage [ ] =
" Usage: zap destroy channel <chan num> \n "
" DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING. Immediately removes a given channel, whether it is in use or not \n " ;
static struct ast_cli_entry cli_show_channels = {
{ " zap " , " show " , " channels " , NULL } , zap_show_channels , " Show active zapata channels " , show_channels_usage , NULL } ;
static struct ast_cli_entry cli_show_channel = {
{ " zap " , " show " , " channel " , NULL } , zap_show_channel , " Show information on a channel " , show_channel_usage , NULL } ;
static struct ast_cli_entry cli_destroy_channel = {
{ " zap " , " destroy " , " channel " , NULL } , zap_destroy_channel , " Destroy a channel " , destroy_channel_usage , NULL } ;
int load_module ( )
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct zt_pvt * tmp ;
char * chan ;
2003-02-07 19:23:19 +00:00
char * c ;
2001-10-09 02:06:21 +00:00
int start , finish , x ;
int y ;
2003-02-07 19:23:19 +00:00
int cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
2001-12-29 18:04:21 +00:00
int offset ;
2001-10-09 02:06:21 +00:00
memset ( pris , 0 , sizeof ( pris ) ) ;
2001-12-29 18:04:21 +00:00
for ( y = 0 ; y < NUM_SPANS ; y + + ) {
pris [ y ] . offset = - 1 ;
2001-10-09 02:06:21 +00:00
pris [ y ] . fd = - 1 ;
2001-12-29 18:04:21 +00:00
}
2003-02-07 19:23:19 +00:00
pri_set_error ( zt_pri_error ) ;
pri_set_message ( zt_pri_message ) ;
2001-10-09 02:06:21 +00:00
# endif
cfg = ast_load ( config ) ;
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_ERROR , " Unable to load config %s \n " , config ) ;
return - 1 ;
}
if ( ast_pthread_mutex_lock ( & iflock ) ) {
/* It's a little silly to lock it, but we mind as well just to be sure */
ast_log ( LOG_ERROR , " Unable to lock interface list??? \n " ) ;
return - 1 ;
}
v = ast_variable_browse ( cfg , " channels " ) ;
while ( v ) {
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " channel " ) ) {
if ( cur_signalling < 0 ) {
ast_log ( LOG_ERROR , " Signalling must be specified before any channels are. \n " ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
unload_module ( ) ;
return - 1 ;
}
2003-02-07 19:23:19 +00:00
c = v - > value ;
chan = strsep ( & c , " , " ) ;
2001-10-09 02:06:21 +00:00
while ( chan ) {
if ( sscanf ( chan , " %d-%d " , & start , & finish ) = = 2 ) {
/* Range */
} else if ( sscanf ( chan , " %d " , & start ) ) {
/* Just one */
finish = start ;
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( chan , " pseudo " ) ) {
finish = start = CHAN_PSEUDO ;
2001-10-09 02:06:21 +00:00
} else {
ast_log ( LOG_ERROR , " Syntax error parsing '%s' at '%s' \n " , v - > value , chan ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
unload_module ( ) ;
return - 1 ;
}
if ( finish < start ) {
ast_log ( LOG_WARNING , " Sillyness: %d < %d \n " , start , finish ) ;
x = finish ;
finish = start ;
start = x ;
}
for ( x = start ; x < = finish ; x + + ) {
2003-02-07 19:23:19 +00:00
tmp = mkintf ( x , cur_signalling , cur_radio ) ;
2001-10-09 02:06:21 +00:00
if ( tmp ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Registered channel %d, %s signalling \n " , x , sig2str ( tmp - > sig ) ) ;
} else {
ast_log ( LOG_ERROR , " Unable to register channel '%s' \n " , v - > value ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
unload_module ( ) ;
return - 1 ;
}
}
2003-02-07 19:23:19 +00:00
chan = strsep ( & c , " , " ) ;
2001-10-09 02:06:21 +00:00
}
} else if ( ! strcasecmp ( v - > name , " usecallerid " ) ) {
use_callerid = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " threewaycalling " ) ) {
threewaycalling = ast_true ( v - > value ) ;
2002-03-08 23:48:42 +00:00
} else if ( ! strcasecmp ( v - > name , " cancallforward " ) ) {
cancallforward = ast_true ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " relaxdtmf " ) ) {
if ( ast_true ( v - > value ) )
relaxdtmf = DSP_DIGITMODE_RELAXDTMF ;
else
relaxdtmf = 0 ;
2002-03-08 23:48:42 +00:00
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
strncpy ( mailbox , v - > value , sizeof ( mailbox ) - 1 ) ;
2001-12-29 18:04:21 +00:00
} else if ( ! strcasecmp ( v - > name , " adsi " ) ) {
adsi = ast_true ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " transfer " ) ) {
transfer = ast_true ( v - > value ) ;
2002-09-10 04:45:51 +00:00
} else if ( ! strcasecmp ( v - > name , " echocancelwhenbridged " ) ) {
echocanbridged = ast_true ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " busydetect " ) ) {
busydetect = ast_true ( v - > value ) ;
2003-03-06 06:00:17 +00:00
} else if ( ! strcasecmp ( v - > name , " busycount " ) ) {
busycount = atoi ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " callprogress " ) ) {
callprogress = ast_true ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " echocancel " ) ) {
2003-03-24 20:33:33 +00:00
if ( v - > value & & strlen ( v - > value ) ) {
2002-03-08 23:48:42 +00:00
y = atoi ( v - > value ) ;
2003-03-24 20:33:33 +00:00
} else
2002-03-08 23:48:42 +00:00
y = 0 ;
if ( ( y = = 32 ) | | ( y = = 64 ) | | ( y = = 128 ) | | ( y = = 256 ) )
echocancel = y ;
2003-03-24 20:33:33 +00:00
else {
2002-03-08 23:48:42 +00:00
echocancel = ast_true ( v - > value ) ;
2003-03-24 20:33:33 +00:00
if ( echocancel )
echocancel = 128 ;
}
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " hidecallerid " ) ) {
hidecallerid = ast_true ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " callreturn " ) ) {
callreturn = ast_true ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " callwaiting " ) ) {
callwaiting = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " callwaitingcallerid " ) ) {
callwaitingcallerid = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
2001-12-29 18:04:21 +00:00
strncpy ( context , v - > value , sizeof ( context ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
2001-12-29 18:04:21 +00:00
strncpy ( language , v - > value , sizeof ( language ) - 1 ) ;
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > name , " musiconhold " ) ) {
strncpy ( musicclass , v - > value , sizeof ( musicclass ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " stripmsd " ) ) {
stripmsd = atoi ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " group " ) ) {
2003-04-09 04:00:43 +00:00
cur_group = ast_get_group ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
2003-04-09 04:00:43 +00:00
cur_callergroup = ast_get_group ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
2003-04-09 04:00:43 +00:00
cur_pickupgroup = ast_get_group ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " immediate " ) ) {
immediate = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " rxgain " ) ) {
if ( sscanf ( v - > value , " %f " , & rxgain ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid rxgain: %s \n " , v - > value ) ;
}
} else if ( ! strcasecmp ( v - > name , " txgain " ) ) {
if ( sscanf ( v - > value , " %f " , & txgain ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid txgain: %s \n " , v - > value ) ;
}
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
if ( ! strcasecmp ( v - > value , " asreceived " ) )
strcpy ( callerid , " " ) ;
else
2001-12-29 18:04:21 +00:00
strncpy ( callerid , v - > value , sizeof ( callerid ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " accountcode " ) ) {
strncpy ( accountcode , v - > value , sizeof ( accountcode ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " amaflags " ) ) {
y = ast_cdr_amaflags2int ( v - > value ) ;
if ( y < 0 )
ast_log ( LOG_WARNING , " Invalid AMA flags: %s at line %d \n " , v - > value , v - > lineno ) ;
else
amaflags = y ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " signalling " ) ) {
if ( ! strcasecmp ( v - > value , " em " ) ) {
cur_signalling = SIG_EM ;
} else if ( ! strcasecmp ( v - > value , " em_w " ) ) {
cur_signalling = SIG_EMWINK ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " fxs_ls " ) ) {
cur_signalling = SIG_FXSLS ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " fxs_gs " ) ) {
cur_signalling = SIG_FXSGS ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " fxs_ks " ) ) {
cur_signalling = SIG_FXSKS ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " fxo_ls " ) ) {
cur_signalling = SIG_FXOLS ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " fxo_gs " ) ) {
cur_signalling = SIG_FXOGS ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " fxo_ks " ) ) {
cur_signalling = SIG_FXOKS ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
} else if ( ! strcasecmp ( v - > value , " fxs_rx " ) ) {
cur_signalling = SIG_FXSKS ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " fxo_rx " ) ) {
cur_signalling = SIG_FXOLS ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " fxs_tx " ) ) {
cur_signalling = SIG_FXSLS ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " fxo_tx " ) ) {
cur_signalling = SIG_FXOGS ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " em_rx " ) ) {
cur_signalling = SIG_EM ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " em_tx " ) ) {
cur_signalling = SIG_EM ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " em_rxtx " ) ) {
cur_signalling = SIG_EM ;
cur_radio = 2 ;
} else if ( ! strcasecmp ( v - > value , " em_txrx " ) ) {
cur_signalling = SIG_EM ;
cur_radio = 2 ;
2003-03-17 18:11:33 +00:00
} else if ( ! strcasecmp ( v - > value , " sf " ) ) {
cur_signalling = SIG_SF ;
cur_radio = 0 ;
2003-03-17 20:04:36 +00:00
} else if ( ! strcasecmp ( v - > value , " sf_w " ) ) {
cur_signalling = SIG_SFWINK ;
cur_radio = 0 ;
} else if ( ! strcasecmp ( v - > value , " sf_featd " ) ) {
cur_signalling = SIG_FEATD ;
cur_radio = 0 ;
} else if ( ! strcasecmp ( v - > value , " sf_featdmf " ) ) {
cur_signalling = SIG_FEATDMF ;
cur_radio = 0 ;
} else if ( ! strcasecmp ( v - > value , " sf_featb " ) ) {
cur_signalling = SIG_SF_FEATB ;
cur_radio = 0 ;
} else if ( ! strcasecmp ( v - > value , " sf " ) ) {
cur_signalling = SIG_SF ;
cur_radio = 0 ;
2003-03-17 18:11:33 +00:00
} else if ( ! strcasecmp ( v - > value , " sf_rx " ) ) {
cur_signalling = SIG_SF ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " sf_tx " ) ) {
cur_signalling = SIG_SF ;
cur_radio = 1 ;
} else if ( ! strcasecmp ( v - > value , " sf_rxtx " ) ) {
cur_signalling = SIG_SF ;
cur_radio = 2 ;
} else if ( ! strcasecmp ( v - > value , " sf_txrx " ) ) {
cur_signalling = SIG_SF ;
cur_radio = 2 ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > value , " featd " ) ) {
cur_signalling = SIG_FEATD ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > value , " featdmf " ) ) {
cur_signalling = SIG_FEATDMF ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > value , " featb " ) ) {
cur_signalling = SIG_FEATB ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
} else if ( ! strcasecmp ( v - > value , " pri_net " ) ) {
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
cur_signalling = SIG_PRI ;
pritype = PRI_NETWORK ;
} else if ( ! strcasecmp ( v - > value , " pri_cpe " ) ) {
cur_signalling = SIG_PRI ;
2003-02-07 19:23:19 +00:00
cur_radio = 0 ;
2001-10-09 02:06:21 +00:00
pritype = PRI_CPE ;
# endif
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
} else if ( ! strcasecmp ( v - > value , " r2 " ) ) {
cur_signalling = SIG_R2 ;
cur_radio = 0 ;
# endif
2001-10-09 02:06:21 +00:00
} else {
ast_log ( LOG_ERROR , " Unknown signalling method '%s' \n " , v - > value ) ;
}
2003-02-07 19:23:19 +00:00
# ifdef ZAPATA_R2
} else if ( ! strcasecmp ( v - > name , " r2country " ) ) {
r2prot = str2r2prot ( v - > value ) ;
if ( r2prot < 0 ) {
ast_log ( LOG_WARNING , " Unknown R2 Country '%s' at line %d. \n " , v - > value , v - > lineno ) ;
}
# endif
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " pridialplan " ) ) {
if ( ! strcasecmp ( v - > value , " national " ) ) {
dialplan = PRI_NATIONAL_ISDN + 1 ;
} else if ( ! strcasecmp ( v - > value , " unknown " ) ) {
dialplan = PRI_UNKNOWN + 1 ;
} else if ( ! strcasecmp ( v - > value , " private " ) ) {
dialplan = PRI_PRIVATE + 1 ;
} else if ( ! strcasecmp ( v - > value , " international " ) ) {
dialplan = PRI_INTERNATIONAL_ISDN + 1 ;
} else if ( ! strcasecmp ( v - > value , " local " ) ) {
dialplan = PRI_LOCAL_ISDN + 1 ;
} else {
ast_log ( LOG_WARNING , " Unknown PRI dialplan '%s' at line %d. \n " , v - > value , v - > lineno ) ;
}
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " switchtype " ) ) {
if ( ! strcasecmp ( v - > value , " national " ) )
switchtype = PRI_SWITCH_NI2 ;
2003-05-28 22:40:26 +00:00
# ifdef PRI_SWITCH_NI1
else if ( ! strcasecmp ( v - > value , " ni1 " ) )
switchtype = PRI_SWITCH_NI1 ;
# endif
2001-10-09 02:06:21 +00:00
else if ( ! strcasecmp ( v - > value , " dms100 " ) )
switchtype = PRI_SWITCH_DMS100 ;
else if ( ! strcasecmp ( v - > value , " 4ess " ) )
switchtype = PRI_SWITCH_ATT4ESS ;
else if ( ! strcasecmp ( v - > value , " 5ess " ) )
switchtype = PRI_SWITCH_LUCENT5E ;
2001-12-29 18:04:21 +00:00
else if ( ! strcasecmp ( v - > value , " euroisdn " ) )
switchtype = PRI_SWITCH_EUROISDN_E1 ;
2001-10-09 02:06:21 +00:00
else {
ast_log ( LOG_ERROR , " Unknown switchtype '%s' \n " , v - > value ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
unload_module ( ) ;
return - 1 ;
}
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > name , " minunused " ) ) {
minunused = atoi ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " idleext " ) ) {
strncpy ( idleext , v - > value , sizeof ( idleext ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " idledial " ) ) {
strncpy ( idledial , v - > value , sizeof ( idledial ) - 1 ) ;
2003-05-19 23:33:41 +00:00
} else if ( ! strcasecmp ( v - > name , " overlapdial " ) ) {
overlapdial = ast_true ( v - > value ) ;
2001-10-09 02:06:21 +00:00
# endif
} else
2003-03-12 06:00:18 +00:00
ast_log ( LOG_WARNING , " Ignoring %s \n " , v - > name ) ;
2001-10-09 02:06:21 +00:00
v = v - > next ;
}
ast_pthread_mutex_unlock ( & iflock ) ;
/* Make sure we can register our Zap channel type */
if ( ast_channel_register ( type , tdesc , AST_FORMAT_SLINEAR | AST_FORMAT_ULAW , zt_request ) ) {
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , type ) ;
ast_destroy ( cfg ) ;
unload_module ( ) ;
return - 1 ;
}
if ( ast_channel_register ( typecompat , tdesc , AST_FORMAT_SLINEAR | AST_FORMAT_ULAW , zt_request ) ) {
ast_log ( LOG_ERROR , " Unable to register channel class %s \n " , typecompat ) ;
ast_destroy ( cfg ) ;
unload_module ( ) ;
return - 1 ;
}
ast_destroy ( cfg ) ;
# ifdef ZAPATA_PRI
for ( x = 0 ; x < NUM_SPANS ; x + + ) {
2001-12-29 18:04:21 +00:00
for ( y = 1 ; y < pris [ x ] . channels ; y + + ) {
2001-10-09 02:06:21 +00:00
if ( pris [ x ] . chanmask [ y ] ) {
2001-12-29 18:04:21 +00:00
offset = pris [ x ] . pvt [ y ] - > channel - y ;
if ( ( pris [ x ] . offset > - 1 ) & & ( pris [ x ] . offset ! = offset ) ) {
ast_log ( LOG_WARNING , " Huh?? Offset mismatch... \n " ) ;
}
pris [ x ] . offset = offset ;
2001-10-09 02:06:21 +00:00
pris [ x ] . span = x + 1 ;
if ( start_pri ( pris + x ) ) {
ast_log ( LOG_ERROR , " Unable to start D-channel on span %d \n " , x + 1 ) ;
return - 1 ;
} else if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Starting D-Channel on span %d \n " , x + 1 ) ;
break ;
}
}
}
ast_cli_register ( & pri_debug ) ;
ast_cli_register ( & pri_no_debug ) ;
2001-12-29 18:04:21 +00:00
ast_cli_register ( & pri_really_debug ) ;
2003-02-07 19:23:19 +00:00
# endif
# ifdef ZAPATA_R2
ast_cli_register ( & r2_debug ) ;
ast_cli_register ( & r2_no_debug ) ;
2001-10-09 02:06:21 +00:00
# endif
ast_cli_register ( & cli_show_channels ) ;
ast_cli_register ( & cli_show_channel ) ;
ast_cli_register ( & cli_destroy_channel ) ;
/* And start the monitor for the first time */
restart_monitor ( ) ;
return 0 ;
}
int unload_module ( )
{
struct zt_pvt * p , * pl ;
/* First, take us out of the channel loop */
ast_channel_unregister ( type ) ;
ast_channel_unregister ( typecompat ) ;
ast_cli_unregister ( & cli_show_channels ) ;
ast_cli_unregister ( & cli_show_channel ) ;
ast_cli_unregister ( & cli_destroy_channel ) ;
if ( ! ast_pthread_mutex_lock ( & iflock ) ) {
/* Hangup all interfaces if they have an owner */
p = iflist ;
while ( p ) {
if ( p - > owner )
2002-09-10 04:45:51 +00:00
ast_softhangup ( p - > owner , AST_SOFTHANGUP_APPUNLOAD ) ;
2001-10-09 02:06:21 +00:00
p = p - > next ;
}
iflist = NULL ;
ast_pthread_mutex_unlock ( & iflock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
if ( ! ast_pthread_mutex_lock ( & monlock ) ) {
if ( monitor_thread ) {
pthread_cancel ( monitor_thread ) ;
pthread_kill ( monitor_thread , SIGURG ) ;
pthread_join ( monitor_thread , NULL ) ;
}
monitor_thread = - 2 ;
ast_pthread_mutex_unlock ( & monlock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
if ( ! ast_pthread_mutex_lock ( & iflock ) ) {
/* Destroy all the interfaces and free their memory */
p = iflist ;
while ( p ) {
/* Free any callerid */
if ( p - > cidspill )
free ( p - > cidspill ) ;
/* Close the zapata thingy */
2003-02-07 19:23:19 +00:00
if ( p - > subs [ SUB_REAL ] . zfd > - 1 )
zt_close ( p - > subs [ SUB_REAL ] . zfd ) ;
2001-10-09 02:06:21 +00:00
pl = p ;
p = p - > next ;
/* Free associated memory */
free ( pl ) ;
}
iflist = NULL ;
ast_pthread_mutex_unlock ( & iflock ) ;
} else {
ast_log ( LOG_WARNING , " Unable to lock the monitor \n " ) ;
return - 1 ;
}
return 0 ;
}
2003-02-07 19:23:19 +00:00
#if 0
2001-10-09 02:06:21 +00:00
static int reload_zt ( void )
{
struct ast_config * cfg ;
struct ast_variable * v ;
struct zt_pvt * tmp ;
struct zt_pvt * prev = NULL ;
char * chan ;
int start , finish , x ;
2003-02-07 19:23:19 +00:00
char * stringp = NULL ;
2001-10-09 02:06:21 +00:00
/* Some crap that needs to be reinitialized on the reload */
strcpy ( context , " default " ) ;
language [ 0 ] = ' \0 ' ;
2002-06-24 17:59:56 +00:00
musicclass [ 0 ] = ' \0 ' ;
2001-10-09 02:06:21 +00:00
use_callerid = 1 ;
cur_signalling = - 1 ;
cur_group = 0 ;
cur_callergroup = 0 ;
cur_pickupgroup = 0 ;
immediate = 0 ;
stripmsd = 0 ;
callwaiting = 0 ;
2003-02-07 19:23:19 +00:00
busydetect = 0 ;
2003-03-06 06:00:17 +00:00
busycount = 3 ;
2003-02-07 19:23:19 +00:00
callprogress = 0 ;
2001-10-09 02:06:21 +00:00
callwaitingcallerid = 0 ;
hidecallerid = 0 ;
2003-02-07 19:23:19 +00:00
callreturn = 0 ;
2001-10-09 02:06:21 +00:00
threewaycalling = 0 ;
transfer = 0 ;
rxgain = 0.0 ;
txgain = 0.0 ;
firstdigittimeout = 16000 ;
gendigittimeout = 8000 ;
2001-12-29 18:04:21 +00:00
amaflags = 0 ;
adsi = 0 ;
strncpy ( accountcode , " " , sizeof ( accountcode ) - 1 ) ;
2002-06-24 17:59:56 +00:00
# ifdef ZAPATA_PRI
strncpy ( idleext , " " , sizeof ( idleext ) - 1 ) ;
strncpy ( idledial , " " , sizeof ( idledial ) - 1 ) ;
minunused = 2 ;
minidle = 0 ;
# endif
2001-10-09 02:06:21 +00:00
// usecnt = 0;
#if 0
# ifdef ZAPATA_PRI
int y ;
# endif
# endif
#if 0
# ifdef ZAPATA_PRI
memset ( pris , 0 , sizeof ( pris ) ) ;
for ( y = 0 ; y < NUM_SPANS ; y + + )
pris [ y ] . fd = - 1 ;
# endif
# endif /* 0 */
cfg = ast_load ( config ) ;
/* We *must* have a config file otherwise stop immediately */
if ( ! cfg ) {
ast_log ( LOG_ERROR , " Unable to load config %s \n " , config ) ;
return - 1 ;
}
if ( ast_pthread_mutex_lock ( & iflock ) ) {
/* It's a little silly to lock it, but we mind as well just to be sure */
ast_log ( LOG_ERROR , " Unable to lock interface list??? \n " ) ;
return - 1 ;
}
/* Part of the primary changes for the reload... */
tmp = iflist ;
while ( tmp ) {
tmp - > destroy = 1 ;
tmp = tmp - > next ;
}
v = ast_variable_browse ( cfg , " channels " ) ;
while ( v ) {
/* Create the interface list */
if ( ! strcasecmp ( v - > name , " channel " ) ) {
if ( cur_signalling < 0 ) {
ast_log ( LOG_ERROR , " Signalling must be specified before any channels are. \n " ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
return - 1 ;
}
2003-02-07 19:23:19 +00:00
stringp = v - > value ;
chan = strsep ( & stringp , " , " ) ;
2001-10-09 02:06:21 +00:00
while ( chan ) {
if ( sscanf ( chan , " %d-%d " , & start , & finish ) = = 2 ) {
/* Range */
} else if ( sscanf ( chan , " %d " , & start ) ) {
/* Just one */
finish = start ;
} else {
ast_log ( LOG_ERROR , " Syntax error parsing '%s' at '%s' \n " , v - > value , chan ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
return - 1 ;
}
if ( finish < start ) {
ast_log ( LOG_WARNING , " Sillyness: %d < %d \n " , start , finish ) ;
x = finish ;
finish = start ;
start = x ;
}
for ( x = start ; x < = finish ; x + + ) {
tmp = mkintf ( x , cur_signalling ) ;
if ( tmp ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Registered channel %d, %s signalling \n " , x , sig2str ( tmp - > sig ) ) ;
} else {
ast_log ( LOG_ERROR , " Unable to register channel '%s' \n " , v - > value ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
return - 1 ;
}
}
2003-02-07 19:23:19 +00:00
chan = strsep ( & stringp , " , " ) ;
2001-10-09 02:06:21 +00:00
}
} else if ( ! strcasecmp ( v - > name , " usecallerid " ) ) {
use_callerid = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " threewaycalling " ) ) {
threewaycalling = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " transfer " ) ) {
transfer = ast_true ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " busydetect " ) ) {
busydetect = ast_true ( v - > value ) ;
2003-03-06 06:00:17 +00:00
} else if ( ! strcasecmp ( v - > name , " busycount " ) ) {
busycount = atoi ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " callprogress " ) ) {
callprogress = ast_true ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " hidecallerid " ) ) {
hidecallerid = ast_true ( v - > value ) ;
2003-02-07 19:23:19 +00:00
} else if ( ! strcasecmp ( v - > name , " callreturn " ) ) {
callreturn = ast_true ( v - > value ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " callwaiting " ) ) {
callwaiting = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " callwaitingcallerid " ) ) {
callwaitingcallerid = ast_true ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " context " ) ) {
2001-12-29 18:04:21 +00:00
strncpy ( context , v - > value , sizeof ( context ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " language " ) ) {
2001-12-29 18:04:21 +00:00
strncpy ( language , v - > value , sizeof ( language ) - 1 ) ;
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > name , " musiconhold " ) ) {
strncpy ( musicclass , v - > value , sizeof ( musicclass ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " stripmsd " ) ) {
stripmsd = atoi ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " group " ) ) {
cur_group = get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " callgroup " ) ) {
cur_callergroup = get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " pickupgroup " ) ) {
cur_pickupgroup = get_group ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " immediate " ) ) {
immediate = ast_true ( v - > value ) ;
2002-03-08 23:48:42 +00:00
} else if ( ! strcasecmp ( v - > name , " mailbox " ) ) {
strncpy ( mailbox , v - > value , sizeof ( mailbox ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " rxgain " ) ) {
if ( sscanf ( v - > value , " %f " , & rxgain ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid rxgain: %s \n " , v - > value ) ;
}
} else if ( ! strcasecmp ( v - > name , " txgain " ) ) {
if ( sscanf ( v - > value , " %f " , & txgain ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid txgain: %s \n " , v - > value ) ;
}
} else if ( ! strcasecmp ( v - > name , " callerid " ) ) {
if ( ! strcasecmp ( v - > value , " asreceived " ) )
strcpy ( callerid , " " ) ;
else
2001-12-29 18:04:21 +00:00
strncpy ( callerid , v - > value , sizeof ( callerid ) - 1 ) ;
2001-10-09 02:06:21 +00:00
} else if ( ! strcasecmp ( v - > name , " signalling " ) ) {
if ( ! strcasecmp ( v - > value , " em " ) ) {
cur_signalling = SIG_EM ;
} else if ( ! strcasecmp ( v - > value , " em_w " ) ) {
cur_signalling = SIG_EMWINK ;
} else if ( ! strcasecmp ( v - > value , " fxs_ls " ) ) {
cur_signalling = SIG_FXSLS ;
} else if ( ! strcasecmp ( v - > value , " fxs_gs " ) ) {
cur_signalling = SIG_FXSGS ;
} else if ( ! strcasecmp ( v - > value , " fxs_ks " ) ) {
cur_signalling = SIG_FXSKS ;
} else if ( ! strcasecmp ( v - > value , " fxo_ls " ) ) {
cur_signalling = SIG_FXOLS ;
} else if ( ! strcasecmp ( v - > value , " fxo_gs " ) ) {
cur_signalling = SIG_FXOGS ;
} else if ( ! strcasecmp ( v - > value , " fxo_ks " ) ) {
cur_signalling = SIG_FXOKS ;
} else if ( ! strcasecmp ( v - > value , " featd " ) ) {
cur_signalling = SIG_FEATD ;
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > value , " featdmf " ) ) {
cur_signalling = SIG_FEATDMF ;
} else if ( ! strcasecmp ( v - > value , " featb " ) ) {
cur_signalling = SIG_FEATB ;
2001-10-09 02:06:21 +00:00
# ifdef ZAPATA_PRI
} else if ( ! strcasecmp ( v - > value , " pri_net " ) ) {
cur_signalling = SIG_PRI ;
pritype = PRI_NETWORK ;
} else if ( ! strcasecmp ( v - > value , " pri_cpe " ) ) {
cur_signalling = SIG_PRI ;
pritype = PRI_CPE ;
# endif
} else {
ast_log ( LOG_ERROR , " Unknown signalling method '%s' \n " , v - > value ) ;
}
# ifdef ZAPATA_PRI
} else if ( ! strcasecmp ( v - > name , " switchtype " ) ) {
if ( ! strcasecmp ( v - > value , " national " ) )
switchtype = PRI_SWITCH_NI2 ;
else if ( ! strcasecmp ( v - > value , " dms100 " ) )
switchtype = PRI_SWITCH_DMS100 ;
else if ( ! strcasecmp ( v - > value , " 4ess " ) )
switchtype = PRI_SWITCH_ATT4ESS ;
else if ( ! strcasecmp ( v - > value , " 5ess " ) )
switchtype = PRI_SWITCH_LUCENT5E ;
else {
ast_log ( LOG_ERROR , " Unknown switchtype '%s' \n " , v - > value ) ;
ast_destroy ( cfg ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
return - 1 ;
}
2002-06-24 17:59:56 +00:00
} else if ( ! strcasecmp ( v - > name , " minunused " ) ) {
minunused = atoi ( v - > value ) ;
} else if ( ! strcasecmp ( v - > name , " idleext " ) ) {
strncpy ( idleext , v - > value , sizeof ( idleext ) - 1 ) ;
} else if ( ! strcasecmp ( v - > name , " idledial " ) ) {
strncpy ( idledial , v - > value , sizeof ( idledial ) - 1 ) ;
# endif
2001-10-09 02:06:21 +00:00
} else
2003-03-12 06:00:18 +00:00
ast_log ( LOG_WARNING , " Ignoring %s \n " , v - > name ) ;
2001-10-09 02:06:21 +00:00
v = v - > next ;
}
tmp = iflist ;
prev = NULL ;
while ( tmp ) {
if ( tmp - > destroy ) {
if ( destroy_channel ( prev , tmp , 0 ) ) {
ast_log ( LOG_ERROR , " Unable to destroy chan_zap channel %d \n " , tmp - > channel ) ;
ast_pthread_mutex_unlock ( & iflock ) ;
return - 1 ;
}
tmp = tmp - > next ;
} else {
prev = tmp ;
tmp = tmp - > next ;
}
}
ast_pthread_mutex_unlock ( & iflock ) ;
ast_destroy ( cfg ) ;
#if 0
# ifdef ZAPATA_PRI
for ( x = 0 ; x < NUM_SPANS ; x + + ) {
for ( y = 1 ; y < 23 ; y + + ) {
if ( pris [ x ] . chanmask [ y ] ) {
pris [ x ] . offset = x * 24 ;
pris [ x ] . span = x + 1 ;
if ( start_pri ( pris + x ) ) {
ast_log ( LOG_ERROR , " Unable to start D-channel on span %d \n " , x + 1 ) ;
return - 1 ;
} else if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Starting D-Channel on span %d \n " , x + 1 ) ;
break ;
}
}
}
# endif
# endif
/* And start the monitor for the first time */
restart_monitor ( ) ;
return 0 ;
}
2003-02-07 19:23:19 +00:00
# endif
2001-10-09 02:06:21 +00:00
2001-12-29 18:04:21 +00:00
static int zt_sendtext ( struct ast_channel * c , char * text )
{
# define END_SILENCE_LEN 400
2002-06-24 17:59:56 +00:00
# define HEADER_MS 50
# define TRAILER_MS 5
# define HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
# define ASCII_BYTES_PER_CHAR 80
2001-12-29 18:04:21 +00:00
unsigned char * buf , * mybuf ;
struct zt_pvt * p = c - > pvt - > pvt ;
fd_set wfds , efds ;
2002-06-24 17:59:56 +00:00
int size , res , fd , len , x ;
int bytes = 0 ;
/* Initial carrier (imaginary) */
float cr = 1.0 ;
float ci = 0.0 ;
float scont = 0.0 ;
2003-02-07 19:23:19 +00:00
int index ;
2002-06-24 17:59:56 +00:00
2003-02-07 19:23:19 +00:00
index = zt_get_index ( c , p , 0 ) ;
if ( index < 0 ) {
ast_log ( LOG_WARNING , " Huh? I don't exist? \n " ) ;
return - 1 ;
}
2002-09-10 04:45:51 +00:00
if ( ! text [ 0 ] ) return ( 0 ) ; /* if nothing to send, dont */
2002-06-24 17:59:56 +00:00
if ( ( ! p - > tdd ) & & ( ! p - > mate ) ) return ( 0 ) ; /* if not in TDD mode, just return */
if ( p - > mate )
buf = malloc ( ( ( strlen ( text ) + 1 ) * ASCII_BYTES_PER_CHAR ) + END_SILENCE_LEN + HEADER_LEN ) ;
2002-09-10 04:45:51 +00:00
else
buf = malloc ( ( ( strlen ( text ) + 1 ) * TDD_BYTES_PER_CHAR ) + END_SILENCE_LEN ) ;
2001-12-29 18:04:21 +00:00
if ( ! buf ) {
ast_log ( LOG_ERROR , " MALLOC FAILED \n " ) ;
return - 1 ;
}
mybuf = buf ;
2002-06-24 17:59:56 +00:00
if ( p - > mate ) {
2003-02-07 19:23:19 +00:00
int codec = AST_LAW ( p ) ;
2002-06-24 17:59:56 +00:00
for ( x = 0 ; x < HEADER_MS ; x + + ) { /* 50 ms of Mark */
PUT_CLID_MARKMS ;
}
/* Put actual message */
for ( x = 0 ; text [ x ] ; x + + ) {
PUT_CLID ( text [ x ] ) ;
}
for ( x = 0 ; x < TRAILER_MS ; x + + ) { /* 5 ms of Mark */
PUT_CLID_MARKMS ;
}
len = bytes ;
buf = mybuf ;
}
else {
len = tdd_generate ( p - > tdd , buf , text ) ;
if ( len < 1 ) {
ast_log ( LOG_ERROR , " TDD generate (len %d) failed!! \n " , strlen ( text ) ) ;
free ( mybuf ) ;
return - 1 ;
}
2001-12-29 18:04:21 +00:00
}
memset ( buf + len , 0x7f , END_SILENCE_LEN ) ;
len + = END_SILENCE_LEN ;
2003-02-07 19:23:19 +00:00
fd = p - > subs [ index ] . zfd ;
2001-12-29 18:04:21 +00:00
while ( len ) {
if ( ast_check_hangup ( c ) ) {
free ( mybuf ) ;
return - 1 ;
}
size = len ;
if ( size > READ_SIZE )
size = READ_SIZE ;
FD_ZERO ( & wfds ) ;
FD_ZERO ( & efds ) ;
FD_SET ( fd , & wfds ) ;
FD_SET ( fd , & efds ) ;
2003-05-19 23:33:41 +00:00
res = ast_select ( fd + 1 , NULL , & wfds , & efds , NULL ) ;
2001-12-29 18:04:21 +00:00
if ( ! res ) {
ast_log ( LOG_DEBUG , " select (for write) ret. 0 on channel %d \n " , p - > channel ) ;
continue ;
}
/* if got exception */
if ( FD_ISSET ( fd , & efds ) ) return - 1 ;
if ( ! FD_ISSET ( fd , & wfds ) ) {
ast_log ( LOG_DEBUG , " write fd not ready on channel %d \n " , p - > channel ) ;
continue ;
}
res = write ( fd , buf , size ) ;
if ( res ! = size ) {
if ( res = = - 1 ) {
free ( mybuf ) ;
return - 1 ;
}
if ( option_debug )
ast_log ( LOG_DEBUG , " Write returned %d (%s) on channel %d \n " , res , strerror ( errno ) , p - > channel ) ;
break ;
}
len - = size ;
buf + = size ;
}
free ( mybuf ) ;
return ( 0 ) ;
}
2001-10-09 02:06:21 +00:00
#if 0
/* XXX Very broken on PRI XXX */
int reload ( void )
{
if ( reload_zt ( ) ) {
ast_log ( LOG_WARNING , " Reload of chan_zap is unsuccessful \n " ) ;
return - 1 ;
}
return 0 ;
}
# endif
int usecount ( )
{
int res ;
ast_pthread_mutex_lock ( & usecnt_lock ) ;
res = usecnt ;
ast_pthread_mutex_unlock ( & usecnt_lock ) ;
return res ;
}
char * description ( )
{
return desc ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}