Skip to content
Snippets Groups Projects
chan_zap.c 288 KiB
Newer Older
  • Learn to ignore specific revisions
  • Mark Spencer's avatar
    Mark Spencer committed
    /*
     * Asterisk -- A telephony toolkit for Linux.
     *
    
     * Zaptel Pseudo TDM interface 
    
    Mark Spencer's avatar
    Mark Spencer committed
     * 
    
     * Copyright (C) 2003 Digium
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
    
     * Mark Spencer <markster@digium.com>
    
    Mark Spencer's avatar
    Mark Spencer committed
     *
     * This program is free software, distributed under the terms of
     * the GNU General Public License
     */
    
    #include <stdio.h>
    #include <string.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/lock.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #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>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/alaw.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/callerid.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/adsi.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/cli.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/cdr.h>
    #include <asterisk/parking.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/musiconhold.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/say.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/tdd.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <asterisk/app.h>
    #include <asterisk/dsp.h>
    
    #include <asterisk/astdb.h>
    
    #include <asterisk/manager.h>
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    #include <asterisk/causes.h>
    
    #include <asterisk/term.h>
    
    #include <asterisk/utils.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <sys/signal.h>
    #include <errno.h>
    #include <stdlib.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <stdint.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <unistd.h>
    #include <sys/ioctl.h>
    
    #ifdef __linux__
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <linux/zaptel.h>
    
    #else
    #include <zaptel.h>
    #endif /* __linux__ */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <math.h>
    #include <tonezone.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include <ctype.h>
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_PRI
    #include <libpri.h>
    
    #ifndef PRI_NSF_NONE
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_R2
    #include <libmfcr2.h>
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    #include "../asterisk.h"
    
    
    #ifndef ZT_SIG_EM_E1
    #error "Your zaptel is too old.  please cvs update"
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    /*
     * 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.
     */
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* #define ZHONE_HACK */
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Typically, how many rings before we should send Caller*ID */
    #define DEFAULT_CIDRINGS 1
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define CHANNEL_PSEUDO -12
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define AST_LAW(p) (((p)->law == ZT_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
    
    static char *desc = "Zapata Telephony"
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_PRI
    
    Mark Spencer's avatar
    Mark Spencer committed
                   " 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"
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char *type = "Zap";
    static char *typecompat = "Tor";	/* Retain compatibility with chan_tor */
    static char *config = "zapata.conf";
    
    #define SIG_EM		ZT_SIG_EM
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define SIG_EMWINK 	(0x100000 | ZT_SIG_EM)
    #define SIG_FEATD	(0x200000 | ZT_SIG_EM)
    #define	SIG_FEATDMF	(0x400000 | ZT_SIG_EM)
    #define	SIG_FEATB	(0x800000 | ZT_SIG_EM)
    #define	SIG_E911	(0x1000000 | ZT_SIG_EM)
    
    Mark Spencer's avatar
    Mark Spencer committed
    #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
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define SIG_R2		ZT_SIG_CAS
    
    #define	SIG_SF		ZT_SIG_SF
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define SIG_SFWINK 	(0x100000 | ZT_SIG_SF)
    #define SIG_SF_FEATD	(0x200000 | ZT_SIG_SF)
    #define	SIG_SF_FEATDMF	(0x400000 | ZT_SIG_SF)
    #define	SIG_SF_FEATB	(0x800000 | ZT_SIG_SF)
    #define SIG_EM_E1	ZT_SIG_EM_E1
    
    #define SIG_GR303FXOKS   (0x100000 | ZT_SIG_FXOKS)
    
    #define SIG_GR303FXSKS   (0x200000 | ZT_SIG_FXSKS)
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define NUM_SPANS 	32
    
    #define NUM_DCHANS	4		/* No more than 4 d-channels */
    
    #define MAX_CHANNELS	672	/* No more than a DS3 per trunk group */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define RESET_INTERVAL	3600	/* How often (in seconds) to reset unused channels */
    
    #define CHAN_PSEUDO	-2
    
    #define DCHAN_PROVISIONED (1 << 0)
    #define DCHAN_NOTINALARM  (1 << 1)
    #define DCHAN_UP          (1 << 2)
    
    #define DCHAN_AVAILABLE	(DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char context[AST_MAX_EXTENSION] = "default";
    static char callerid[256] = "";
    
    static char language[MAX_LANGUAGE] = "";
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char musicclass[MAX_LANGUAGE] = "";
    
    static char progzone[10]= "";
    
    static int usedistinctiveringdetection = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int use_callerid = 1;
    
    static int zaptrcallerid = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int cur_signalling = -1;
    
    
    static unsigned int cur_group = 0;
    static unsigned int cur_callergroup = 0;
    static unsigned int cur_pickupgroup = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int relaxdtmf = 0;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    static int immediate = 0;
    
    static int stripmsd = 0;
    
    static int callwaiting = 0;
    
    static int callwaitingcallerid = 0;
    
    static int hidecallerid = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int callreturn = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int threewaycalling = 0;
    
    static int transfer = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int cancallforward = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static float rxgain = 0.0;
    
    static float txgain = 0.0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int echocancel;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int echocanbridged = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int busydetect = 0;
    
    
    static int busycount = 3;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int callprogress = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char accountcode[20] = "";
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char mailbox[AST_MAX_EXTENSION];
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int amaflags = 0;
    
    static int adsi = 0;
    
    
    static int numbufs = 4;
    
    
    static int cur_prewink = -1;
    static int cur_preflash = -1;
    static int cur_wink = -1;
    static int cur_flash = -1;
    static int cur_start = -1;
    static int cur_rxwink = -1;
    static int cur_rxflash = -1;
    static int cur_debounce = -1;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_PRI
    static int minunused = 2;
    static int minidle = 0;
    static char idleext[AST_MAX_EXTENSION];
    static char idledial[AST_MAX_EXTENSION];
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int overlapdial = 0;
    
    static struct ast_channel inuse = { "GR-303InUse" };
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* 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;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* How long to wait for an extra digit, if there is an ambiguous match */
    static int matchdigittimeout = 3000;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int usecnt =0;
    
    AST_MUTEX_DEFINE_STATIC(usecnt_lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    /* Protect the interface list (of zt_pvt's) */
    
    AST_MUTEX_DEFINE_STATIC(iflock);
    
    static int ifcount = 0;
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Protect the monitoring thread, so only one process can kill or start it, and not
       when it's doing something critical. */
    
    AST_MUTEX_DEFINE_STATIC(monlock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    /* 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 = AST_PTHREADT_NULL;
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    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);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int zt_sendtext(struct ast_channel *c, char *text);
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    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;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    /* Chunk size to read -- we use 20ms chunks to make things happy.  */   
    #define READ_SIZE 160
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    #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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define CIDCW_EXPIRE_SAMPLES		( (500 * 8) / READ_SIZE) /* 500 ms */
    
    #define MIN_MS_SINCE_FLASH			( (2000) )	/* 2000 ms */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define RINGT 						( (8000 * 8) / READ_SIZE)
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    struct zt_pvt;
    
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_R2
    static int r2prot = -1;
    #endif
    
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_PRI
    
    #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8))
    
    #define PRI_CHANNEL(p) ((p) & 0xff)
    #define PRI_SPAN(p) (((p) >> 8) & 0xff)
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    struct zt_pri {
    	pthread_t master;			/* Thread of master */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int nodetype;				/* Node type */
    	int switchtype;				/* Type of switch to emulate */
    
    	int nsf;			/* Network-Specific Facilities */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int dialplan;			/* Dialing plan */
    
    	int dchannels[NUM_DCHANS];	/* What channel are the dchannels on */
    
    	int trunkgroup;			/* What our trunkgroup is */
    	int mastertrunkgroup;	/* What trunk group is our master */
    
    	int prilogicalspan;		/* Logical span number within trunk group */
    
    	int numchans;			/* Num of channels we represent */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int overlapdial;		/* In overlap dialing mode */
    
    	struct pri *dchans[NUM_DCHANS];	/* Actual d-channels */
    	int dchanavail[NUM_DCHANS];		/* Whether each channel is available */
    	struct pri *pri;				/* Currently active D-channel */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int debug;
    
    	int fds[NUM_DCHANS];	/* FD's for d-channels */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int offset;
    	int span;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int resetting;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	time_t lastreset;
    
    	struct zt_pvt *pvts[MAX_CHANNELS];	/* Member channel pvt structs */
    
    	struct zt_pvt *crvs;				/* Member CRV structs */
    	struct zt_pvt *crvend;				/* Pointer to end of CRV structs */
    
    Mark Spencer's avatar
    Mark Spencer committed
    };
    
    
    static struct zt_pri pris[NUM_SPANS];
    
    static int pritype = PRI_CPE;
    
    #if 0
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
    
    Mark Spencer's avatar
    Mark Spencer committed
    #else
    #define DEFAULT_PRI_DEBUG 0
    #endif
    
    static inline void pri_rel(struct zt_pri *pri)
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    static int switchtype = PRI_SWITCH_NI2;
    
    static int nsf = PRI_NSF_NONE;
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int dialplan = PRI_NATIONAL_ISDN + 1;
    
    #else
    /* Shut up the compiler */
    struct zt_pri;
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define SUB_REAL		0			/* Active call */
    #define SUB_CALLWAIT	1			/* Call-Waiting call on hold */
    #define SUB_THREEWAY	2			/* Three-way call */
    
    
    
    static struct zt_distRings drings;
    
    struct distRingData {
    	int ring[3];
    };
    struct ringContextData {
    	char contextData[AST_MAX_EXTENSION];
    };
    struct zt_distRings {
    	struct distRingData ringnum[3];
    	struct ringContextData ringContext[3];
    };
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int needcallerid;
    	int needanswer;
    	int linear;
    	int inthreeway;
    
    	ZT_CONFINFO curconf;
    
    Mark Spencer's avatar
    Mark Spencer committed
    };
    
    #define CONF_USER_REAL		(1 << 0)
    #define CONF_USER_THIRDCALL	(1 << 1)
    
    #define MAX_SLAVES	4
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static struct zt_pvt {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_channel *owner;	/* Our current active owner (if applicable) */
    
    Mark Spencer's avatar
    Mark Spencer committed
    		/* Up to three channels can be associated with this call */
    		
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	int sig;					/* Signalling style */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int radio;				/* radio type */
    	int firstradio;				/* first radio flag */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	float rxgain;
    	float txgain;
    
    	int tonezone;				/* tone zone for this chan, or -1 for default */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct zt_pvt *next;			/* Next channel in list */
    
    	struct zt_pvt *prev;			/* Prev channel in list */
    
    
    	struct zt_distRings drings;
    
    	int usedistinctiveringdetection;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char context[AST_MAX_EXTENSION];
    
    	char defcontext[AST_MAX_EXTENSION];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char exten[AST_MAX_EXTENSION];
    	char language[MAX_LANGUAGE];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char musicclass[MAX_LANGUAGE];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char callerid[AST_MAX_EXTENSION];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char lastcallerid[AST_MAX_EXTENSION];
    
    	char *origcallerid;			/* malloced original callerid */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char callwaitcid[AST_MAX_EXTENSION];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char rdnis[AST_MAX_EXTENSION];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char dnid[AST_MAX_EXTENSION];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int law;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int confno;					/* Our conference */
    	int confusers;				/* Who is using our conference */
    	int propconfno;				/* Propagated conference number */
    
    	unsigned int callgroup;
    	unsigned int pickupgroup;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int immediate;				/* Answer before getting digits? */
    
    	int channel;				/* Channel Number or CRV */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int span;					/* Span number */
    	int dialing;
    
    	time_t guardtime;			/* Must wait this much time before using for new call */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int dialednone;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int use_callerid;			/* Whether or not to use caller id on this channel */
    	int hidecallerid;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int callreturn;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int permhidecallerid;		/* Whether to hide our outgoing caller ID or not */
    
    	int restrictcid;		/* Whether restrict the callerid -> only send ANI */
    	int use_callingpres;		/* Whether to use the callingpres the calling switch sends */
    	int callingpres;		/* The value of callling presentation that we're going to use when placing a PRI call */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int callwaitingrepeat;		/* How many samples to wait before repeating call waiting */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int cidcwexpire;			/* When to expire our muting for CID/CW */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	unsigned char *cidspill;
    	int cidpos;
    	int cidlen;
    	int ringt;
    	int stripmsd;
    	int callwaiting;
    	int callwaitcas;
    	int callwaitrings;
    	int echocancel;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int echocanbridged;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int echocanon;
    
    	char echorest[20];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int permcallwaiting;
    	int callwaitingcallerid;
    	int threewaycalling;
    	int transfer;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int digital;
    	int outgoing;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int dnd;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int busydetect;
    
    	int busycount;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int callprogress;
    
    	struct timeval flashtime;	/* Last flash-hook time */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	struct ast_dsp *dsp;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int cref;					/* Call reference number */
    	ZT_DIAL_OPERATION dop;
    	int destroy;
    	int ignoredtmf;				
    	int inalarm;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int cancallforward;
    	char call_forward[AST_MAX_EXTENSION];
    	char mailbox[AST_MAX_EXTENSION];
    
    	char dialdest[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int onhooktime;
    	int msgstate;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	
    	int confirmanswer;		/* Wait for '#' to confirm answer */
    	int distinctivering;	/* Which distinctivering to use */
    	int cidrings;			/* Which ring to deliver CID on */
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int faxhandled;			/* Has a fax tone already been handled? */
    	
    
    Mark Spencer's avatar
    Mark Spencer committed
    	char mate;			/* flag to say its in MATE mode */
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int pulsedial;		/* whether a pulse dial phone is detected */
    	int dtmfrelax;		/* whether to run in relaxed DTMF mode */
    
    	int zaptrcallerid;	/* should we use the callerid from incoming call on zap transfer or not */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #ifdef ZAPATA_PRI
    	struct zt_pri *pri;
    
    	struct zt_pvt *bearer;
    	struct zt_pvt *realcall;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	q931_call *call;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int isidlecall;
    	int resetting;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int prioffset;
    
    	int logicalspan;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int alreadyhungup;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int setup_ack;		/* wheter we received SETUP_ACKNOWLEDGE or not */
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif	
    #ifdef ZAPATA_R2
    	int r2prot;
    	mfcr2_t *r2;
    	int hasr2call;
    	int r2blocked;
    	int sigchecked;
    
    Mark Spencer's avatar
    Mark Spencer committed
    #endif	
    
    #ifdef ZAPATA_PRI
    static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri)
    {
    	int res;
    	/* Grab the lock first */
    	do {
    
    	    res = ast_mutex_trylock(&pri->lock);
    
    		if (res) {
    
    			/* Release the lock and try again */
    			usleep(1);
    
    		}
    	} while(res);
    
    	/* Then break the poll */
    
    	pthread_kill(pri->master, SIGURG);
    	return 0;
    }
    #endif
    
    
    #define NUM_CADENCE_MAX 25
    static int num_cadence = 4;
    static int user_has_defined_cadences = 0;
    
    static struct zt_ring_cadence cadences[NUM_CADENCE_MAX] = {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	{ { 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 */
    };
    
    
    int receivedRingT; /* Used to find out what ringtone we are on */
    
    
    /* cidrings says in which pause to transmit the cid information, where the first pause
     * is 1, the second pause is 2 and so on.
     */
    
    static int cidrings[NUM_CADENCE_MAX] = {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	2,										/* Right after first long ring */
    	4,										/* Right after long part */
    	3,										/* After third chirp */
    	2,										/* Second spell */
    };
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
    
    Mark Spencer's avatar
    Mark Spencer committed
    			(p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
    
    Mark Spencer's avatar
    Mark Spencer committed
    #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
    #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __ZT_SIG_FXO) */)
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    /* translate between PRI causes and asterisk's */
    
    Martin Pycko's avatar
    Martin Pycko committed
    static int hangup_pri2cause(int cause)
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    {
    	switch(cause) {
    		case PRI_CAUSE_USER_BUSY:
    			return AST_CAUSE_BUSY;
    		case PRI_CAUSE_NORMAL_CLEARING:
    			return AST_CAUSE_NORMAL;
    
    		case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
    		case PRI_CAUSE_REQUESTED_CHAN_UNAVAIL:
    			return AST_CAUSE_CONGESTION;
    		case PRI_CAUSE_UNALLOCATED:
    		case PRI_CAUSE_NUMBER_CHANGED:
    			return AST_CAUSE_UNALLOCATED;
    
    		case PRI_CAUSE_NO_USER_RESPONSE:
    		case PRI_CAUSE_NO_ANSWER:
    
    Martin Pycko's avatar
     
    Martin Pycko committed
    		default:
    			return AST_CAUSE_FAILURE;
    	}
    	/* never reached */
    	return 0;
    }
    
    
    /* translate between ast cause and PRI */
    static int hangup_cause2pri(int cause)
    {
    	switch(cause) {
    		case AST_CAUSE_BUSY:
    			return PRI_CAUSE_USER_BUSY;
    
    		case AST_CAUSE_UNALLOCATED:
    			return PRI_CAUSE_UNALLOCATED;
    
    		case AST_CAUSE_CONGESTION:
    			return PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION;
    
    		case AST_CAUSE_NORMAL:
    		default:
    			return PRI_CAUSE_NORMAL_CLEARING;
    	}
    	/* never reached */
    	return 0;
    }
    #endif
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static int zt_get_index(struct ast_channel *ast, struct zt_pvt *p, int nullok)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    	int res;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 wakeup_sub(struct zt_pvt *p, int a)
    {
    	struct ast_frame null = { AST_FRAME_NULL, };
    	for (;;) {
    		if (p->subs[a].owner) {
    			if (ast_mutex_trylock(&p->subs[a].owner->lock)) {
    				ast_mutex_unlock(&p->lock);
    				usleep(1);
    				ast_mutex_lock(&p->lock);
    			} else {
    				ast_queue_frame(p->subs[a].owner, &null);
    				ast_mutex_unlock(&p->subs[a].owner->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    				break;
    
    static void zap_queue_frame(struct zt_pvt *p, struct ast_frame *f)
    {
    	for (;;) {
    		if (p->owner) {
    			if (ast_mutex_trylock(&p->owner->lock)) {
    				ast_mutex_unlock(&p->lock);
    				usleep(1);
    				ast_mutex_lock(&p->lock);
    			} else {
    				ast_queue_frame(p->owner, f);
    				ast_mutex_unlock(&p->owner->lock);
    				break;
    			}
    		} else
    			break;
    	}
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static void swap_subs(struct zt_pvt *p, int a, int b)
    {
    	int tchan;
    	int tinthreeway;
    	struct ast_channel *towner;
    
    	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;
    
    
    	if (p->subs[a].owner) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		p->subs[a].owner->fds[0] = p->subs[a].zfd;
    
    	if (p->subs[b].owner) 
    
    Mark Spencer's avatar
    Mark Spencer committed
    		p->subs[b].owner->fds[0] = p->subs[b].zfd;
    
    	wakeup_sub(p, a);
    	wakeup_sub(p, b);
    
    Mark Spencer's avatar
    Mark Spencer committed
    }
    
    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";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	fd = open(fn, O_RDWR | O_NONBLOCK);
    	if (fd < 0) {
    		ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return -1;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    	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));
    
    Mark Spencer's avatar
    Mark Spencer committed
    			return -1;
    		}
    	}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    
    int zt_setlaw(int zfd, int law)
    
    Mark Spencer's avatar
    Mark Spencer committed
    {
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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 = numbufs;
    
    Mark Spencer's avatar
    Mark Spencer committed
    				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;
    
    	memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
    
    Mark Spencer's avatar
    Mark Spencer committed
    	return 0;
    }
    
    static int zt_digit(struct ast_channel *ast, char digit)
    {
    	ZT_DIAL_OPERATION zo;
    	struct zt_pvt *p;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	int res = 0;
    	int index;
    
    Mark Spencer's avatar
    Mark Spencer committed
    	p = ast->pvt->pvt;
    
    	ast_mutex_lock(&p->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	index = zt_get_index(ast, p, 0);
    	if (index == SUB_REAL) {
    
    #ifdef ZAPATA_PRI
    
    		if (p->sig == SIG_PRI && ast->_state == AST_STATE_DIALING && (p->proceeding < 2)) {
    			if (p->setup_ack) {
    				if (!pri_grab(p, p->pri)) {
    					pri_information(p->pri->pri,p->call,digit);
    					pri_rel(p->pri);
    				} else
    					ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
    			} else if (strlen(p->dialdest) < sizeof(p->dialdest) - 1) {
    				ast_log(LOG_DEBUG, "Queueing digit '%c' since setup_ack not yet received\n", digit);
    				res = strlen(p->dialdest);
    				p->dialdest[res++] = digit;
    				p->dialdest[res] = '\0';
    			}
    
    			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;
    		}
    
    Mark Spencer's avatar
    Mark Spencer committed
    	}
    
    	ast_mutex_unlock(&p->lock);
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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",
    
    Mark Spencer's avatar
    Mark Spencer committed
    		"Hook Transition Complete",
    		"Bits Changed",
    		"Pulse Start"
    
    Mark Spencer's avatar
    Mark Spencer committed
    };
    
    
    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";
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    static char *event2str(int event)
    {
            static char buf[256];
    
    Mark Spencer's avatar
    Mark Spencer committed
            if ((event < 15) && (event > -1))
    
    Mark Spencer's avatar
    Mark Spencer committed
                    return events[event];
    
            sprintf(buf, "Event %d", event); /* safe */
    
    Mark Spencer's avatar
    Mark Spencer committed
            return buf;
    }
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    #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
    
    
    Mark Spencer's avatar
    Mark Spencer committed
    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";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case SIG_EM_E1:
    		return "E & M E1";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case SIG_FEATD:
    
    Mark Spencer's avatar
    Mark Spencer committed
    		return "Feature Group D (DTMF)";
    	case SIG_FEATDMF:
    		return "Feature Group D (MF)";
    	case SIG_FEATB:
    		return "Feature Group B (MF)";
    
    	case SIG_E911:
    		return "E911 (MF)";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	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";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case SIG_R2:
    		return "R2 Signalling";
    
    	case SIG_SF:
    
    		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) Signalling with Feature Group D (MF)";
    
    	case SIG_SF_FEATB:
    		return "SF (Tone) Signalling with Feature Group B (MF)";
    
    	case SIG_GR303FXOKS:
    		return "GR-303 Signalling with FXOKS";
    
    	case SIG_GR303FXSKS:
    		return "GR-303 Signalling with FXSKS";
    
    Mark Spencer's avatar
    Mark Spencer committed
    	case 0: