From afd122b8959ed28b01eaf7fa41a734e7bd68c05b Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Mon, 24 Jun 2002 17:59:56 +0000
Subject: [PATCH] Version 0.1.12 from FTP

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@467 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_zap.c | 1034 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 845 insertions(+), 189 deletions(-)

diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 4e6c591323..f78c882ce6 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -12,8 +12,8 @@
  */
 
 #include <stdio.h>
-#include <pthread.h>
 #include <string.h>
+#include <asterisk/lock.h>
 #include <asterisk/channel.h>
 #include <asterisk/channel_pvt.h>
 #include <asterisk/config.h>
@@ -28,6 +28,7 @@
 #include <asterisk/cli.h>
 #include <asterisk/cdr.h>
 #include <asterisk/parking.h>
+#include <asterisk/musiconhold.h>
 #include <asterisk/tdd.h>
 #include <sys/signal.h>
 #include <sys/select.h>
@@ -54,6 +55,20 @@
 
 #define RINGT 274
 
+/*
+ * 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.
+ */
+
+#define ZHONE_HACK
+
+#define CHANNEL_PSEUDO -12
+
 #ifdef ZAPATA_PRI
 static char *desc = "Zapata Telephony (PRI) Driver";
 static char *tdesc = "Zapata Telephony + PRI Interface Driver";
@@ -68,6 +83,8 @@ 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)
+#define	SIG_FEATDMF	(0x40000 | ZT_SIG_EM)
+#define	SIG_FEATB	(0x80000 | ZT_SIG_EM)
 #define SIG_FXSLS	ZT_SIG_FXSLS
 #define SIG_FXSGS	ZT_SIG_FXSGS
 #define SIG_FXSKS	ZT_SIG_FXSKS
@@ -77,11 +94,15 @@ static char *config = "zapata.conf";
 #define SIG_PRI		ZT_SIG_CLEAR
 
 #define NUM_SPANS 	32
+#define RESET_INTERVAL	3600	/* How often (in seconds) to reset unused channels */
+
+#define CHAN_PSEUDO	-2
 
 static char context[AST_MAX_EXTENSION] = "default";
 static char callerid[256] = "";
 
 static char language[MAX_LANGUAGE] = "";
+static char musicclass[MAX_LANGUAGE] = "";
 
 static int use_callerid = 1;
 
@@ -121,6 +142,13 @@ static int amaflags = 0;
 
 static int adsi = 0;
 
+#ifdef ZAPATA_PRI
+static int minunused = 2;
+static int minidle = 0;
+static char idleext[AST_MAX_EXTENSION];
+static char idledial[AST_MAX_EXTENSION];
+#endif
+
 /* Wait up to 16 seconds for first digit (FXO logic) */
 static int firstdigittimeout = 16000;
 
@@ -128,14 +156,14 @@ static int firstdigittimeout = 16000;
 static int gendigittimeout = 8000;
 
 static int usecnt =0;
-static pthread_mutex_t usecnt_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
 
 /* Protect the interface list (of zt_pvt's) */
-static pthread_mutex_t iflock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t iflock = AST_MUTEX_INITIALIZER;
 
 /* Protect the monitoring thread, so only one process can kill or start it, and not
    when it's doing something critical. */
-static pthread_mutex_t monlock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t monlock = AST_MUTEX_INITIALIZER;
 
 /* This is the thread for the monitor which checks for input on the channels
    which are not currently in use.  */
@@ -181,6 +209,11 @@ struct zt_pvt;
 struct zt_pri {
 	pthread_t master;			/* Thread of master */
 	pthread_mutex_t lock;		/* Mutex */
+	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 */
 	int nodetype;				/* Node type */
 	int switchtype;				/* Type of switch to emulate */
 	int dchannel;			/* What channel the dchannel is on */
@@ -192,8 +225,11 @@ struct zt_pri {
 	int offset;
 	int span;
 	int chanmask[31];			/* Channel status */
-	struct zt_pvt *pvt[30];	/* Member channel pvt structs */
-	struct zt_channel *chan[30];	/* Channels on each line */
+	int resetting;
+	int resetchannel;
+	time_t lastreset;
+	struct zt_pvt *pvt[31];	/* Member channel pvt structs */
+	struct zt_channel *chan[31];	/* Channels on each line */
 };
 
 
@@ -246,6 +282,7 @@ static struct zt_pvt {
 	char context[AST_MAX_EXTENSION];
 	char exten[AST_MAX_EXTENSION];
 	char language[MAX_LANGUAGE];
+	char musicclass[MAX_LANGUAGE];
 	char callerid[AST_MAX_EXTENSION];
 	char callwaitcid[AST_MAX_EXTENSION];
 	char dtmfq[AST_MAX_EXTENSION];
@@ -294,17 +331,42 @@ static struct zt_pvt {
 	int amaflags;				/* AMA Flags */
 	char didtdd;			/* flag to say its done it once */
 	struct tdd_state *tdd;		/* TDD flag */
-	int linear;
+	int reallinear;
+	int pseudolinear;
 	int adsi;
 	int cancallforward;
 	char call_forward[AST_MAX_EXTENSION];
 	char mailbox[AST_MAX_EXTENSION];
+	
+	int confirmanswer;		/* Wait for '#' to confirm answer */
+	int distinctivering;	/* Which distinctivering to use */
+	int cidrings;			/* Which ring to deliver CID on */
+	
+	char mate;			/* flag to say its in MATE mode */
 #ifdef ZAPATA_PRI
 	struct zt_pri *pri;
 	q931_call *call;
+	int isidlecall;
+	int resetting;
 #endif	
 } *iflist = NULL;
 
+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]))
+
 #define INTHREEWAY(p) ((p->normalindex > -1) && (p->thirdcallindex > -1) && \
 		(p->owner == p->owners[p->normalindex]))
 
@@ -381,6 +443,7 @@ static int unalloc_pseudo(struct zt_pvt *p)
 		zap_close(p->pseudo);
 	if (option_debug)
 		ast_log(LOG_DEBUG, "Released pseudo channel %d\n", p->pseudochan);
+	p->pseudolinear = 0;
 	p->pseudo = NULL;
 	p->pseudochan = 0;
 	return 0;
@@ -438,7 +501,11 @@ static char *sig2str(int sig)
 	case SIG_EMWINK:
 		return "E & M Wink";
 	case SIG_FEATD:
-		return "Feature Group D";
+		return "Feature Group D (DTMF)";
+	case SIG_FEATDMF:
+		return "Feature Group D (MF)";
+	case SIG_FEATB:
+		return "Feature Group B (MF)";
 	case SIG_FXSLS:
 		return "FXS Loopstart";
 	case SIG_FXSGS:
@@ -453,8 +520,10 @@ static char *sig2str(int sig)
 		return "FXO Kewlstart";
 	case SIG_PRI:
 		return "PRI Signalling";
+	case 0:
+		return "Pseudo Signalling";
 	default:
-		snprintf(buf, sizeof(buf), "Unknown signalling %d\n", sig);
+		snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
 		return buf;
 	}
 }
@@ -480,7 +549,7 @@ static int conf_set(struct zt_pvt *p, int req, int force)
 		return -1;
 	}
 	if (!force && ci.confmode && (ci.confno != p->confno)) {
-		ast_log(LOG_WARNING, "Channel %d is already in a conference (%d, %x) we didn't create (req = %d)\n", p->channel, ci.confno, ci.confmode, req);
+		ast_log(LOG_WARNING, "Channel %d is already in a conference (%d, %x) we didn't create (though we did make %d) (req = %d)\n", p->channel, ci.confno, ci.confmode, p->confno, req);
 		return -1;
 	}
 	ci.chan = 0;
@@ -511,12 +580,12 @@ static int conf_set(struct zt_pvt *p, int req, int force)
 			ast_log(LOG_DEBUG, "There's a pseudo something on %d (channel %d), but we're not conferencing it in at the moment?\n",
 				zap_fd(p->pseudo), p->pseudochan);
 			cip.chan = 0;
-			cip.confno = ci.confno;
+			cip.confno = 0;
 			cip.confmode = ZT_CONF_NORMAL;
 			res = ioctl(zap_fd(p->pseudo), ZT_SETCONF, &cip);
 			if (res < 0) {
-				ast_log(LOG_WARNING, "Failed to set conference info on pseudo channel %d: %s\n",
-					p->pseudochan, strerror(errno));
+				ast_log(LOG_WARNING, "Failed to set conference info on pseudo channel %d (mode %08x, conf %d): %s\n",
+					p->pseudochan, cip.confno, cip.confmode, strerror(errno));
 				return -1;
 			}
 		}
@@ -681,7 +750,7 @@ static int save_conference(struct zt_pvt *p)
 		p->conf2.confmode = 0;
 		break;
 	default:
-		ast_log(LOG_WARNING, "Don't know how to save conference state for conf mode %d\n", p->conf.confmode);
+		ast_log(LOG_WARNING, "Don't know how to save conference state for conf mode %08x\n", p->conf.confmode);
 		return -1;
 	}
 	if (option_debug)
@@ -746,7 +815,7 @@ static int has_voicemail(struct zt_pvt *p)
 	if (!dir)
 		return 0;
 	while ((de = readdir(dir))) {
-		if (strncasecmp(de->d_name, "msg", 3))
+		if (!strncasecmp(de->d_name, "msg", 3))
 			break;
 	}
 	closedir(dir);
@@ -859,6 +928,16 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
 				} else
 					ast_log(LOG_WARNING, "Unable to generate CallerID spill\n");
 			}
+			/* Select proper cadence */
+			if ((p->distinctivering > 0) && (p->distinctivering <= NUM_CADENCE)) {
+				if (ioctl(zap_fd(p->z), ZT_SETCADENCE, &cadences[p->distinctivering-1]))
+					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 {
+				if (ioctl(zap_fd(p->z), ZT_SETCADENCE, NULL))
+					ast_log(LOG_WARNING, "Unable to reset default ring on '%s'\n", ast->name);
+				p->cidrings = 1;
+			}
 			x = ZT_RING;
 			if (ioctl(zap_fd(p->z), ZT_HOOK, &x) && (errno != EINPROGRESS)) {
 				ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
@@ -889,6 +968,8 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
 	case SIG_EMWINK:
 	case SIG_EM:
 	case SIG_FEATD:
+	case SIG_FEATDMF:
+	case SIG_FEATB:
 		c = strchr(dest, '/');
 		if (c)
 			c++;
@@ -924,6 +1005,25 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
 				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);
+		} 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);
 		} else 
 			snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%s", c + p->stripmsd);
 		if (!res) {
@@ -969,7 +1069,11 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
 			return -1;
 		}
 		break;
-#endif				
+#endif		
+	case 0:
+		/* Special pseudo -- automatically up*/
+		ast->state = AST_STATE_UP;
+		break;		
 	default:
 		ast_log(LOG_DEBUG, "not yet implemented\n");
 		return -1;
@@ -1045,6 +1149,7 @@ static int zt_hangup(struct ast_channel *ast)
 
 	restore_gains(p);
 	zap_digitmode(p->z,0);
+
 	ast->state = AST_STATE_DOWN;
 	ast_log(LOG_DEBUG, "Hangup: index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
 		index, p->normalindex, p->callwaitindex, p->thirdcallindex);
@@ -1087,12 +1192,16 @@ static int zt_hangup(struct ast_channel *ast)
 		}
 	}
 
+
 	if (!p->owners[0] && !p->owners[1] && !p->owners[2]) {
 		p->owner = NULL;
 		p->ringt = 0;
+		p->distinctivering = 0;
+		p->confirmanswer = 0;
+		p->cidrings = 1;
 		law = ZT_LAW_DEFAULT;
 		res = ioctl(zap_fd(p->z), ZT_SETLAW, &law);
-		p->linear = 0;
+		p->reallinear = 0;
 		zap_setlinear(p->z, 0);
 		if (res < 0) 
 			ast_log(LOG_WARNING, "Unable to set law on channel %d to default\n", p->channel);
@@ -1113,8 +1222,9 @@ static int zt_hangup(struct ast_channel *ast)
 			} else
 				res = 0;
 
-		} else
+		} else 
 #endif
+		if (p->sig)
 			res = zt_set_hook(zap_fd(p->z), ZT_ONHOOK);
 		if (res < 0) {
 			ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
@@ -1145,7 +1255,8 @@ static int zt_hangup(struct ast_channel *ast)
 		}
 		if (p->cidspill)
 			free(p->cidspill);
-		zt_disable_ec(p);
+		if (p->sig)
+			zt_disable_ec(p);
 		x = 0;
 		ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
 		ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
@@ -1159,6 +1270,8 @@ static int zt_hangup(struct ast_channel *ast)
 		unalloc_pseudo(p);
 		restart_monitor();
 	}
+
+
 	p->callwaitingrepeat = 0;
 	ast->pvt->pvt = NULL;
 	ast->state = AST_STATE_DOWN;
@@ -1171,11 +1284,12 @@ static int zt_hangup(struct ast_channel *ast)
 	if (option_verbose > 2) 
 		ast_verbose( VERBOSE_PREFIX_3 "Hungup '%s'\n", ast->name);
 
+	ast_pthread_mutex_lock(&iflock);
 	tmp = iflist;
 	prev = NULL;
 	if (p->destroy) {
 		while (tmp) {
-			if (tmp->channel == p->channel) {
+			if (tmp == p) {
 				destroy_channel(prev, tmp, 0);
 				break;
 			} else {
@@ -1184,7 +1298,7 @@ static int zt_hangup(struct ast_channel *ast)
 			}
 		}
 	}
-
+	ast_pthread_mutex_unlock(&iflock);
 	return 0;
 }
 
@@ -1202,6 +1316,8 @@ static int zt_answer(struct ast_channel *ast)
 	case SIG_EM:
 	case SIG_EMWINK:
 	case SIG_FEATD:
+	case SIG_FEATDMF:
+	case SIG_FEATB:
 	case SIG_FXOLS:
 	case SIG_FXOGS:
 	case SIG_FXOKS:
@@ -1283,9 +1399,14 @@ char	*cp;
 			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;
+			p->mate = 0;
 			break;
 		}
-		ast_log(LOG_DEBUG, "Set option TDD MODE, value: ON(1) on %s\n",chan->name);
+		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);
 		/* otherwise, turn it on */
 		if (!p->didtdd) { /* if havent done it yet */
 			unsigned char mybuf[41000],*buf;
@@ -1330,6 +1451,12 @@ char	*cp;
 			}
 			p->didtdd = 1; /* set to have done it now */		
 		}
+		if (*cp == 2) { /* Mate mode */
+			if (p->tdd) tdd_free(p->tdd);
+			p->tdd = 0;
+			p->mate = 1;
+			break;
+			}		
 		if (!p->tdd) { /* if we dont have one yet */
 			p->tdd = tdd_new(); /* allocate one */
 		}		
@@ -1354,8 +1481,8 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
 	if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
 		return -2;
 	  /* if cant run clear DTMF, cant native bridge */
-	pthread_mutex_lock(&c0->lock);
-	pthread_mutex_lock(&c1->lock);
+	ast_pthread_mutex_lock(&c0->lock);
+	ast_pthread_mutex_lock(&c1->lock);
 	if (!CLEARDTMF(c0) || !CLEARDTMF(c1)) {
 		pthread_mutex_unlock(&c1->lock);
 		pthread_mutex_unlock(&c0->lock);
@@ -1374,8 +1501,8 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
 	cs[0] = c0;
 	cs[1] = c1;
 	for (;;) {
-		pthread_mutex_lock(&c0->lock);
-		pthread_mutex_lock(&c1->lock);
+		ast_pthread_mutex_lock(&c0->lock);
+		ast_pthread_mutex_lock(&c1->lock);
 		p0 = c0->pvt->pvt;
 		p1 = c1->pvt->pvt;
 
@@ -1642,12 +1769,12 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 				zt_enable_ec(p);
 				p->dialing = 0;
 				if (ast->state == AST_STATE_DIALING) {
-					if (!p->dialednone && ((p->sig == SIG_EM) || (p->sig == SIG_EMWINK) || (p->sig == SIG_FEATD))) {
+					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)))) {
 						ast->state = AST_STATE_RINGING;
 					} else {
-					ast->state = AST_STATE_UP;
-					p->f[index].frametype = AST_FRAME_CONTROL;
-					p->f[index].subclass = AST_CONTROL_ANSWER;
+						ast->state = AST_STATE_UP;
+						p->f[index].frametype = AST_FRAME_CONTROL;
+						p->f[index].subclass = AST_CONTROL_ANSWER;
 					}
 				}
 			}
@@ -1669,7 +1796,7 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 						/* There's a call waiting call, so ring the phone */
 						p->owner = p->owners[p->callwaitindex];
 						if (option_verbose > 2) 
-							ast_verbose(VERBOSE_PREFIX_3 "Channel %s still has (callwait) call, ringing phone\n", p->owner);
+							ast_verbose(VERBOSE_PREFIX_3 "Channel %s still has (callwait) call, ringing phone\n", p->owner->name);
 						p->needanswer[index] = 0;
 						p->needringing[index] = 0;
 						p->callwaitingrepeat = 0;
@@ -1688,8 +1815,8 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 						    p->owners[p->callwaitindex]->pvt->pvt);
 						/* There's a call waiting call, so ring the phone */
 						p->owner = p->owners[p->normalindex];
-						if (option_verbose > 2) 
-							ast_verbose(VERBOSE_PREFIX_3 "Channel %s still has (normal) call, ringing phone\n", p->owner);
+						if (option_verbose > 2)
+							ast_verbose(VERBOSE_PREFIX_3 "Channel %s still has (normal) call, ringing phone\n", p->owner->name);
 						p->needanswer[index] = 0;
 						p->needringing[index] = 0;
 						p->callwaitingrepeat = 0;
@@ -1735,7 +1862,6 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 				switch(ast->state) {
 				case AST_STATE_RINGING:
 					zt_enable_ec(p);
-					ast->state = AST_STATE_UP;
 					p->f[index].frametype = AST_FRAME_CONTROL;
 					p->f[index].subclass = AST_CONTROL_ANSWER;
 					/* Make sure it stops ringing */
@@ -1747,6 +1873,12 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 						p->cidspill = NULL;
 					}
 					p->dialing = 0;
+					if (p->confirmanswer) {
+						/* Ignore answer if "confirm answer" is selected */
+						p->f[index].frametype = AST_FRAME_NULL;
+						p->f[index].subclass = 0;
+					} else 
+						ast->state = AST_STATE_UP;
 					return &p->f[index];
 				case AST_STATE_DOWN:
 					ast->state = AST_STATE_RING;
@@ -1759,6 +1891,8 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 					/* Make sure it stops ringing */
 					zt_set_hook(zap_fd(p->z), ZT_OFFHOOK);
 					/* Okay -- probably call waiting*/
+					if (p->owner->bridge)
+							ast_moh_stop(p->owner->bridge);
 					break;
 				default:
 					ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->state);
@@ -1774,6 +1908,8 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 			case SIG_EM:
 			case SIG_EMWINK:
 			case SIG_FEATD:
+			case SIG_FEATDMF:
+			case SIG_FEATB:
 				if (ast->state == AST_STATE_DOWN) {
 					if (option_debug)
 						ast_log(LOG_DEBUG, "Ring detected\n");
@@ -1782,9 +1918,14 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 				} else if (ast->state == AST_STATE_RINGING) {
 					if (option_debug)
 						ast_log(LOG_DEBUG, "Line answered\n");
-					p->f[index].frametype = AST_FRAME_CONTROL;
-					p->f[index].subclass = AST_CONTROL_ANSWER;
-					ast->state = AST_STATE_UP;
+					if (p->confirmanswer) {
+						p->f[index].frametype = AST_FRAME_NULL;
+						p->f[index].subclass = 0;
+					} else {
+						p->f[index].frametype = AST_FRAME_CONTROL;
+						p->f[index].subclass = AST_CONTROL_ANSWER;
+						ast->state = AST_STATE_UP;
+					}
 				} 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);
 				break;
@@ -1795,7 +1936,7 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 		case ZT_EVENT_RINGEROFF:
 			if (p->inalarm) break;
 			ast->rings++;
-			if ((ast->rings > 1) && (p->cidspill)) {
+			if ((ast->rings > p->cidrings) && (p->cidspill)) {
 				ast_log(LOG_WARNING, "Didn't finish Caller-ID spill.  Cancelling.\n");
 				free(p->cidspill);
 				p->cidspill = NULL;
@@ -1827,6 +1968,11 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 						}
 						p->callwaitingrepeat = 0;
 						conf_clear(p);
+						/* Start music on hold if appropriate */
+						if (p->owners[p->normalindex]->bridge)
+								ast_moh_start(p->owners[p->normalindex]->bridge, NULL);
+						if (p->owners[p->callwaitindex]->bridge)
+								ast_moh_stop(p->owners[p->callwaitindex]->bridge);
 					} else if (p->thirdcallindex == -1) {
 						if (p->threewaycalling) {
 							if ((ast->state == AST_STATE_RINGING) ||
@@ -1850,6 +1996,9 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 										if (option_verbose > 2)	
 											ast_verbose(VERBOSE_PREFIX_3 "Started three way call on channel %d (index %d)\n", p->channel, p->thirdcallindex);
 										conf_clear(p);
+										/* Start music on hold if appropriate */
+										if (p->owners[p->normalindex]->bridge)
+												ast_moh_start(p->owners[p->normalindex]->bridge, NULL);
 									}		
 								} else
 									ast_log(LOG_WARNING, "Unable to allocate pseudo channel\n");
@@ -1871,10 +2020,18 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 						p->owner = p->owners[p->normalindex];
 						p->callwaitingrepeat = 0;
 						conf_clear(p);
+						/* Start music on hold if appropriate */
+						if (p->owners[p->callwaitindex]->bridge)
+								ast_moh_start(p->owners[p->callwaitindex]->bridge, NULL);
+						if (p->owners[p->normalindex]->bridge)
+								ast_moh_stop(p->owners[p->normalindex]->bridge);
 					} else
 						ast_log(LOG_WARNING, "Wink/Flash on call wait, with no normal channel to flash to on channel %d?\n", p->channel);
 				} else if (index == p->thirdcallindex) {
 					if (p->normalindex > -1) {
+						/* One way or another, cancel music on hold */
+						if (p->owners[p->normalindex]->bridge)
+								ast_moh_stop(p->owners[p->normalindex]->bridge);
 						if ((ast->state != AST_STATE_RINGING) && (ast->state != AST_STATE_UP) && (ast->state != AST_STATE_RING)) {
 							tone_zone_play_tone(zap_fd(p->z), -1);
 							p->owner = p->owners[p->normalindex];
@@ -1913,6 +2070,18 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 				else
 					ast_log(LOG_DEBUG, "Got wink in weird state %d on channel %d\n", ast->state, p->channel);
 				break;
+			case SIG_FEATDMF:
+			case SIG_FEATB:
+				/* FGD MF *Must* wait for wink */
+				res = ioctl(zap_fd(p->z), 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;
+				} else 
+					ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr);
+				p->dop.dialstr[0] = '\0';
+				break;
 			default:
 				ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
 			}
@@ -1935,6 +2104,10 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
 					ast_log(LOG_DEBUG, "Sent deferred digit string: %s\n", p->dop.dialstr);
 				p->dop.dialstr[0] = '\0';
 				break;
+			case SIG_FEATDMF:
+			case SIG_FEATB:
+				ast_log(LOG_DEBUG, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
+				break;
 			default:
 				break;
 			}
@@ -2007,6 +2180,8 @@ struct ast_frame *zt_exception(struct ast_channel *ast)
 					p->owner->state = AST_STATE_UP;
 				}
 				p->callwaitingrepeat = 0;
+				if (p->owner->bridge)
+						ast_moh_stop(p->owner->bridge);
 			} else
 				ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
 			break;
@@ -2027,10 +2202,11 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
 	struct zt_pvt *p = ast->pvt->pvt;
 	int res;
 	int index;
+	int *linear;
 	ZAP *z = NULL;
 	void *readbuf;
 	
-	pthread_mutex_lock(&p->lock);
+	ast_pthread_mutex_lock(&p->lock);
 	
 	index = zt_get_index(ast, p, 0);
 	
@@ -2090,9 +2266,12 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
 		}
 		if (!p->pseudo) 
 			ast_log(LOG_ERROR, "No pseudo channel\n");
-		z = p->pseudo;		
-	} else
+		z = p->pseudo;	
+		linear = &p->pseudolinear;
+	} else {
 		z = p->z;
+		linear = &p->reallinear;
+	}
 
 	if (!z) {
 		ast_log(LOG_WARNING, "No zap structure?!?\n");
@@ -2105,22 +2284,30 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
 		p->f[index].subclass = p->dtmfq[0];
 		memmove(p->dtmfq, p->dtmfq + 1, sizeof(p->dtmfq) - 1);
 		p->f[index].frametype = AST_FRAME_DTMF;
+		if (p->confirmanswer) {
+			printf("Confirm answer!\n");
+			/* Upon receiving a DTMF digit, consider this an answer confirmation instead
+			   of a DTMF digit */
+			p->f[index].frametype = AST_FRAME_CONTROL;
+			p->f[index].subclass = AST_CONTROL_ANSWER;
+			ast->state = AST_STATE_UP;
+		}
 		pthread_mutex_unlock(&p->lock);
 		return &p->f[index];
 	}
 	
 	if (ast->pvt->rawreadformat == AST_FORMAT_SLINEAR) {
-		if (!p->linear) {
-			p->linear = 1;
-			res = zap_setlinear(p->z, p->linear);
+		if (!*linear) {
+			*linear = 1;
+			res = zap_setlinear(p->z, *linear);
 			if (res) 
 				ast_log(LOG_WARNING, "Unable to set channel %d to linear mode.\n", p->channel);
 		}
 	} else if ((ast->pvt->rawreadformat == AST_FORMAT_ULAW) ||
 		   (ast->pvt->rawreadformat == AST_FORMAT_ALAW)) {
-		if (p->linear) {
-			p->linear = 0;
-			res = zap_setlinear(p->z, p->linear);
+		if (*linear) {
+			*linear = 0;
+			res = zap_setlinear(p->z, *linear);
 			if (res) 
 				ast_log(LOG_WARNING, "Unable to set channel %d to linear mode.\n", p->channel);
 		}
@@ -2152,21 +2339,30 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
 			zap_getdtmf(z, 1, NULL, 0, 1, 1, 0);
 		}
 		if (strlen(zap_dtmfbuf(z))) {
-			ast_log(LOG_DEBUG, "Got some dtmf ('%s')... on channel %s\n", zap_dtmfbuf(z), ast->name);
-			/* DTMF tone detected.  Queue and erturn */
-			if (p->callwaitcas) {
-				if (!strcmp(zap_dtmfbuf(z), "A") || !strcmp(zap_dtmfbuf(z), "D")) {
-					ast_log(LOG_DEBUG, "Got some DTMF, but it's for the CAS\n");
-					if (p->cidspill)
-						free(p->cidspill);
-					send_cwcidspill(p);
-				}
-				/* Return NULL */
-				pthread_mutex_unlock(&p->lock);
-				return &p->f[index];
+			if (p->confirmanswer) {
+				printf("Confirm answer!\n");
+				/* Upon receiving a DTMF digit, consider this an answer confirmation instead
+				   of a DTMF digit */
+				p->f[index].frametype = AST_FRAME_CONTROL;
+				p->f[index].subclass = AST_CONTROL_ANSWER;
+				ast->state = AST_STATE_UP;
 			} else {
-				strncpy(p->dtmfq + strlen(p->dtmfq), zap_dtmfbuf(z), sizeof(p->dtmfq) - strlen(p->dtmfq)-1);
-				zap_clrdtmfn(z);
+				ast_log(LOG_DEBUG, "Got some dtmf ('%s')... on channel %s\n", zap_dtmfbuf(z), ast->name);
+				/* DTMF tone detected.  Queue and erturn */
+				if (p->callwaitcas) {
+					if (!strcmp(zap_dtmfbuf(z), "A") || !strcmp(zap_dtmfbuf(z), "D")) {
+						ast_log(LOG_DEBUG, "Got some DTMF, but it's for the CAS\n");
+						if (p->cidspill)
+							free(p->cidspill);
+						send_cwcidspill(p);
+					}
+					/* Return NULL */
+					pthread_mutex_unlock(&p->lock);
+					return &p->f[index];
+				} else {
+					strncpy(p->dtmfq + strlen(p->dtmfq), zap_dtmfbuf(z), sizeof(p->dtmfq) - strlen(p->dtmfq)-1);
+					zap_clrdtmfn(z);
+				}
 			}
 		} else {
 			pthread_mutex_unlock(&p->lock);
@@ -2213,8 +2409,9 @@ struct ast_frame  *zt_read(struct ast_channel *ast)
 		p->f[index].datalen = READ_SIZE;
 
 	/* Handle CallerID Transmission */
-	if (p->cidspill &&((ast->state == AST_STATE_UP) || (ast->rings == 1)))
+	if (p->cidspill &&((ast->state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
 		send_callerid(p);
+	}
 
 	p->f[index].frametype = AST_FRAME_VOICE;
 	p->f[index].subclass = ast->pvt->rawreadformat;
@@ -2284,8 +2481,9 @@ static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
 	
 	/* Write a frame of (presumably voice) data */
 	if (frame->frametype != AST_FRAME_VOICE) {
-		ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
-		return -1;
+		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;
 	}
 	if ((frame->subclass != AST_FORMAT_SLINEAR) && 
 	    (frame->subclass != AST_FORMAT_ULAW) &&
@@ -2311,20 +2509,38 @@ static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
 		return 0;
 	}
 	if (frame->subclass == AST_FORMAT_SLINEAR) {
-		if (!p->linear) {
-			p->linear = 1;
-			res = zap_setlinear(p->z, p->linear);
-			if (res)
-				ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
+		if (ast == p->owner) {
+			if (!p->reallinear) {
+				p->reallinear = 1;
+				res = zap_setlinear(p->z, p->reallinear);
+				if (res)
+					ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
+			}
+		} else {
+			if (!p->pseudolinear) {
+				p->pseudolinear = 1;
+				res = zap_setlinear(p->pseudo, p->pseudolinear);
+				if (res)
+					ast_log(LOG_WARNING, "Unable to set linear mode on channel %d (pseudo)\n", p->channel);
+			}
 		}
 		res = my_zt_write(p, (unsigned char *)frame->data, frame->datalen, (ast != p->owner));
 	} else {
 		/* x-law already */
-		if (p->linear) {
-			p->linear = 0;
-			res = zap_setlinear(p->z, p->linear);
-			if (res)
-				ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
+		if (ast == p->owner) {
+			if (p->reallinear) {
+				p->reallinear = 0;
+				res = zap_setlinear(p->z, p->reallinear);
+				if (res)
+					ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
+			}
+		} else {
+			if (p->pseudolinear) {
+				p->pseudolinear = 0;
+				res = zap_setlinear(p->pseudo, p->pseudolinear);
+				if (res)
+					ast_log(LOG_WARNING, "Unable to set linear mode on channel %d (pseudo)\n", p->channel);
+			}
 		}
 		res = my_zt_write(p, (unsigned char *)frame->data, frame->datalen, (ast != p->owner));
 	}
@@ -2356,6 +2572,9 @@ static int zt_indicate(struct ast_channel *chan, int condition)
 	case AST_CONTROL_CONGESTION:
 		res = tone_zone_play_tone(zap_fd(p->z), ZT_TONE_CONGESTION);
 		break;
+	case -1:
+		res = tone_zone_play_tone(zap_fd(p->z), -1);
+		break;
 	default:
 		ast_log(LOG_WARNING, "Don't know how to set condition %d on channel %s\n", condition, chan->name);
 	}
@@ -2376,7 +2595,7 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
 		ast_log(LOG_WARNING, "No available owner slots\n");
 		return NULL;
 	}
-	tmp = ast_channel_alloc();
+	tmp = ast_channel_alloc(0);
 	if (tmp) {
 		ps.channo = i->channel;
 		res = ioctl(zap_fd(i->z), ZT_GET_PARAMS, &ps);
@@ -2418,6 +2637,8 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
 		tmp->pvt->setoption = zt_setoption;
 		if (strlen(i->language))
 			strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
+		if (strlen(i->musicclass))
+			strncpy(tmp->musicclass, i->musicclass, sizeof(tmp->musicclass)-1);
 		/* Keep track of who owns it */
 		i->owners[x] = tmp;
 		if (!i->owner)
@@ -2451,15 +2672,15 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
 			tmp->adsicpe = AST_ADSI_UNAVAILABLE;
 		if (strlen(i->exten))
 			strncpy(tmp->exten, i->exten, sizeof(tmp->exten)-1);
+		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
 		if (startpbx) {
-			if (strlen(i->callerid)) {
-				tmp->callerid = strdup(i->callerid);
-				tmp->ani = strdup(i->callerid);
-			}
-			if (i->adsi) {
-				/* Initialize ADSI here */
-				adsi_channel_init(tmp);
-			}
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
 				ast_hangup(tmp);
@@ -2518,18 +2739,45 @@ static void *ss_thread(void *data)
 	zap_clrdtmf(p->z);
 	switch(p->sig) {
 	case SIG_FEATD:
+	case SIG_FEATDMF:
+	case SIG_FEATB:
 	case SIG_EMWINK:
 		zap_wink(p->z);
 		/* Fall through */
 	case SIG_EM:
 		res = tone_zone_play_tone(zap_fd(p->z), -1);
 		zap_clrdtmf(p->z);
-		/* Wait for the first digit (up to 1 second). */
-		res = zap_getdtmf(p->z, 1, NULL, 0, 1000, 1000, ZAP_TIMEOUTOK | ZAP_HOOKEXIT);
+		/* set digit mode appropriately */
+		if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATB)) zap_digitmode(p->z,ZAP_MF); 
+		else zap_digitmode(p->z,ZAP_DTMF);
+		/* Wait for the first digit (up to 5 seconds). */
+		res = zap_getdtmf(p->z, 1, NULL, 0, 5000, 5000, ZAP_TIMEOUTOK | ZAP_HOOKEXIT);
 
 		if (res == 1) {
-			/* If we got it, get the rest */
-			res = zap_getdtmf(p->z, 50, NULL, 0, 250, 15000, ZAP_TIMEOUTOK | ZAP_HOOKEXIT);
+			switch(p->sig)
+			{
+			    case SIG_FEATD:
+				res = zap_getdtmf(p->z, 50, "*", 0, 3000, 15000, ZAP_HOOKEXIT);
+				if (res > 0)
+					res = zap_getdtmf(p->z, 50, "*", 0, 3000, 15000, ZAP_HOOKEXIT);
+				if (res < 1) zap_clrdtmf(p->z);
+				break;
+			    case SIG_FEATDMF:
+				res = zap_getdtmf(p->z, 50, "#", 0, 3000, 15000, ZAP_HOOKEXIT);
+				if (res > 0) {
+					res = zap_getdtmf(p->z, 50, "#", 0, 3000, 15000, ZAP_HOOKEXIT);
+				}
+				if (res < 1) zap_clrdtmf(p->z);
+				break;
+			    case SIG_FEATB:
+				res = zap_getdtmf(p->z, 50, "#", 0, 3000, 15000, ZAP_HOOKEXIT);
+				if (res < 1) zap_clrdtmf(p->z);
+				break;
+			    default:
+				/* If we got it, get the rest */
+				res = zap_getdtmf(p->z, 50, NULL, 0, 250, 15000, ZAP_TIMEOUTOK | ZAP_HOOKEXIT);
+				break;
+			}
 		}
 		if (res == -1) {
 			ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
@@ -2562,6 +2810,34 @@ static void *ss_thread(void *data)
 			} 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_FEATDMF) {
+			if (exten[0] == '*') {
+				strncpy(exten2, exten, sizeof(exten2)-1);
+				/* Parse out extension and callerid */
+				s1 = strtok(exten2 + 1, "#");
+				s2 = strtok(NULL, "#");
+				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] == '*') {
+				strncpy(exten2, exten, sizeof(exten2)-1);
+				/* Parse out extension and callerid */
+				s1 = strtok(exten2 + 1, "#");
+				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);
+		}
 		zt_enable_ec(p);
 		if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
 			strncpy(chan->exten, exten, sizeof(chan->exten)-1);
@@ -2915,13 +3191,6 @@ static int handle_init_event(struct zt_pvt *i, int event)
 				/* Check for callerid, digits, etc */
 				chan = zt_new(i, AST_STATE_DOWN, 0, 0, 0);
 				if (chan) {
-					if (i->adsi) {
-						/* Wait 700 ms */
-						usleep(700 * 1000);
-						/* Clear anything waiting */
-						while(read(zap_fd(i->z), &res, sizeof(res)) > 0);
-						adsi_channel_init(chan);
-					}
 					if (has_voicemail(i))
 						res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_DIALRECALL);
 					else
@@ -2949,6 +3218,8 @@ static int handle_init_event(struct zt_pvt *i, int event)
 				/* Fall through */
 		case SIG_EMWINK:
 		case SIG_FEATD:
+		case SIG_FEATDMF:
+		case SIG_FEATB:
 		case SIG_EM:
 				/* Check for callerid, digits, etc */
 				chan = zt_new(i, AST_STATE_RING, 0, 0, 0);
@@ -2983,8 +3254,9 @@ static int handle_init_event(struct zt_pvt *i, int event)
 		switch(i->sig) {
 		case SIG_FXOLS:
 		case SIG_FXOGS:
-		case SIG_FXOKS:
 		case SIG_FEATD:
+		case SIG_FEATDMF:
+		case SIG_FEATB:
 		case SIG_EM:
 		case SIG_EMWINK:
 		case SIG_FXSLS:
@@ -2994,6 +3266,16 @@ static int handle_init_event(struct zt_pvt *i, int event)
 			res = tone_zone_play_tone(zap_fd(i->z), -1);
 			zt_set_hook(zap_fd(i->z), ZT_ONHOOK);
 			break;
+		case SIG_FXOKS:
+			zt_disable_ec(i);
+			/* Diddle the battery for the zhone */
+#ifdef ZHONE_HACK
+			zt_set_hook(zap_fd(i->z), ZT_OFFHOOK);
+			usleep(1);
+#endif			
+			res = tone_zone_play_tone(zap_fd(i->z), -1);
+			zt_set_hook(zap_fd(i->z), ZT_ONHOOK);
+			break;
 		default:
 			ast_log(LOG_WARNING, "Don't know hwo to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
 			res = tone_zone_play_tone(zap_fd(i->z), -1);
@@ -3031,13 +3313,15 @@ static void *do_monitor(void *data)
 		FD_ZERO(&efds);
 		i = iflist;
 		while(i) {
-			if (FD_ISSET(zap_fd(i->z), &efds)) 
-				ast_log(LOG_WARNING, "Descriptor %d appears twice?\n", zap_fd(i->z));
-			if (!i->owner) {
-				/* This needs to be watched, as it lacks an owner */
-				FD_SET(zap_fd(i->z), &efds);
-				if (zap_fd(i->z) > n)
-					n = zap_fd(i->z);
+			if (i->z && i->sig) {
+				if (FD_ISSET(zap_fd(i->z), &efds)) 
+					ast_log(LOG_WARNING, "Descriptor %d appears twice?\n", zap_fd(i->z));
+				if (!i->owner) {
+					/* This needs to be watched, as it lacks an owner */
+					FD_SET(zap_fd(i->z), &efds);
+					if (zap_fd(i->z) > n)
+						n = zap_fd(i->z);
+				}
 			}
 			i = i->next;
 		}
@@ -3062,16 +3346,18 @@ static void *do_monitor(void *data)
 		}
 		i = iflist;
 		while(i) {
-			if (FD_ISSET(zap_fd(i->z), &efds)) {
-				if (i->owner) {
-					ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d)...\n", zap_fd(i->z));
-					i = i->next;
-					continue;
+			if (i->z && i->sig) {
+				if (FD_ISSET(zap_fd(i->z), &efds)) {
+					if (i->owner) {
+						ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d)...\n", zap_fd(i->z));
+						i = i->next;
+						continue;
+					}
+					res = zt_get_event(zap_fd(i->z));
+					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);
 				}
-				res = zt_get_event(zap_fd(i->z));
-				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);
 			}
 			i=i->next;
 		}
@@ -3159,13 +3445,13 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 	char fn[80];
 #if 1
 	struct zt_bufferinfo bi;
-#endif	
+#endif
 	struct zt_spaninfo si;
 	int res;
-	int span;
+	int span=0;
 	int here = 0;
 	ZT_PARAMS p;
-	
+
 	tmp2 = iflist;
 	prev = NULL;
 
@@ -3198,38 +3484,42 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 	}
 
 	if (tmp) {
-		snprintf(fn, sizeof(fn), "%d", channel);
-		/* Open non-blocking */
-		if (!here)
-			tmp->z = zap_open(fn, 1);
-		/* Allocate a zapata structure */
-		if (!tmp->z) {
-			ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel);
-			free(tmp);
-			return NULL;
-		}
-		res = ioctl(zap_fd(tmp->z), ZT_GET_PARAMS, &p);
-		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;
+		if (channel != CHAN_PSEUDO) {
+			snprintf(fn, sizeof(fn), "%d", channel);
+			/* Open non-blocking */
+			if (!here)
+				tmp->z = zap_open(fn, 1);
+			/* Allocate a zapata structure */
+			if (!tmp->z) {
+				ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel);
+				free(tmp);
+				return NULL;
+			}
+			res = ioctl(zap_fd(tmp->z), ZT_GET_PARAMS, &p);
+			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;
+					}
 				}
 			}
+			tmp->law = p.curlaw;
+			tmp->span = p.spanno;
+			span = p.spanno - 1;
+		} else {
+			signalling = 0;
 		}
-		tmp->law = p.curlaw;
-		tmp->span = p.spanno;
-		span = p.spanno - 1;
 #ifdef ZAPATA_PRI
 		if (signalling == SIG_PRI) {
 			int offset;
@@ -3270,12 +3560,36 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 						free(tmp);
 						return NULL;
 					}
+					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;
+					}
 					pris[span].nodetype = pritype;
 					pris[span].switchtype = switchtype;
 					pris[span].chanmask[offset] |= MASK_AVAIL;
 					pris[span].pvt[offset] = tmp;
 					pris[span].channels = numchans;
 					pris[span].dchannel = dchannel;
+					pris[span].minunused = minunused;
+					pris[span].minidle = minidle;
+					strncpy(pris[span].idledial, idledial, sizeof(pris[span].idledial) - 1);
+					strncpy(pris[span].idleext, idleext, sizeof(pris[span].idleext) - 1);
 					
 					tmp->pri = &pris[span];
 					tmp->call = NULL;
@@ -3286,11 +3600,12 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 				}
 			}
 		}
-#endif		
+#endif
 		/* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
 		if ((signalling == SIG_FXSKS) || (signalling == SIG_FXSLS) ||
 		    (signalling == SIG_EM) || (signalling == SIG_EMWINK) ||
-			(signalling == SIG_FEATD)) {
+			(signalling == SIG_FEATD) || (signalling == SIG_FEATDMF) ||
+			  (signalling == SIG_FEATB)) {
 			p.starttime = 250;
 			res = ioctl(zap_fd(tmp->z), ZT_SET_PARAMS, &p);
 			if (res < 0) {
@@ -3307,9 +3622,9 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 				ast_log(LOG_WARNING, "Unable to set non-blocking mode on channel %d\n", channel);
 		} else
 			ast_log(LOG_WARNING, "Unable to read flags on channel %d\n", channel);
-#endif			
+#endif
 #if 1
-		if (!here) {
+		if (!here && tmp->z) {
 			res = ioctl(zap_fd(tmp->z), ZT_GET_BUFINFO, &bi);
 			if (!res) {
 				bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
@@ -3354,8 +3669,9 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 			tmp->pseudochan = 0;
 		}
 		tmp->transfer = transfer;
-		pthread_mutex_init(&tmp->lock, NULL);
+		ast_pthread_mutex_init(&tmp->lock);
 		strncpy(tmp->language, language, sizeof(tmp->language)-1);
+		strncpy(tmp->musicclass, musicclass, sizeof(tmp->musicclass)-1);
 		strncpy(tmp->context, context, sizeof(tmp->context)-1);
 		strncpy(tmp->callerid, callerid, sizeof(tmp->callerid)-1);
 		strncpy(tmp->mailbox, mailbox, sizeof(tmp->mailbox)-1);
@@ -3364,22 +3680,24 @@ static struct zt_pvt *mkintf(int channel, int signalling)
 		tmp->pickupgroup=cur_pickupgroup;
 		tmp->rxgain = rxgain;
 		tmp->txgain = txgain;
-		set_actual_gain(zap_fd(tmp->z), 0, tmp->rxgain, tmp->txgain);
-		zap_digitmode(tmp->z, ZAP_DTMF /* | ZAP_MUTECONF */);
-		conf_clear(tmp);
-		if (!here) {
-			if (signalling != SIG_PRI) 
-				/* Hang it up to be sure it's good */
-				zt_set_hook(zap_fd(tmp->z), ZT_ONHOOK);
-		}
-		tmp->inalarm = 0;
-		si.spanno = 0;
-		if (ioctl(zap_fd(tmp->z),ZT_SPANSTAT,&si) == -1) {
-			ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
-			free(tmp);
-			return NULL;
+		if (tmp->z) {
+			set_actual_gain(zap_fd(tmp->z), 0, tmp->rxgain, tmp->txgain);
+			zap_digitmode(tmp->z, ZAP_DTMF /* | ZAP_MUTECONF */);
+			conf_clear(tmp);
+			if (!here) {
+				if (signalling != SIG_PRI)
+					/* Hang it up to be sure it's good */
+					zt_set_hook(zap_fd(tmp->z), ZT_ONHOOK);
+			}
+			tmp->inalarm = 0;
+			si.spanno = 0;
+			if (ioctl(zap_fd(tmp->z),ZT_SPANSTAT,&si) == -1) {
+				ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
+				free(tmp);
+				return NULL;
+			}
+			if (si.alarms) tmp->inalarm = 1;
 		}
-		if (si.alarms) tmp->inalarm = 1;
 	}
 	return tmp;
 }
@@ -3399,11 +3717,15 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch)
 	if (!p->owner) {
 		/* Trust PRI */
 #ifdef ZAPATA_PRI
-		if (p->pri)
-			return 1;
+		if (p->pri) {
+			if (p->resetting || p->call)
+				return 0;
+			else
+				return 1;
+		}
 #endif
 		if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSLS) ||
-			(p->sig == SIG_FXSGS))
+			(p->sig == SIG_FXSGS) || !p->sig)
 			return 1;
 		/* Check hook state */
 		res = ioctl(zap_fd(p->z), ZT_GET_PARAMS, &par);
@@ -3444,6 +3766,40 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch)
 	return 1;
 }
 
+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));
+		p->z = zap_open("/dev/zap/pseudo", 1);
+		/* Allocate a zapata structure */
+		if (!p->z) {
+			ast_log(LOG_ERROR, "Unable to dup channel: %s\n",  strerror(errno));
+			free(p);
+			return NULL;
+		}
+		res = ioctl(zap_fd(p->z), ZT_GET_BUFINFO, &bi);
+		if (!res) {
+			bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
+			bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
+			bi.numbufs = 4;
+			res = ioctl(zap_fd(p->z), ZT_SET_BUFINFO, &bi);
+			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;
+}
+	
+
 static struct ast_channel *zt_request(char *type, int format, void *data)
 {
 	int oldformat;
@@ -3454,6 +3810,8 @@ static struct ast_channel *zt_request(char *type, int format, void *data)
 	char *dest=NULL;
 	int x;
 	char *s;
+	char opt;
+	int res=0, y;
 	int callwait;
 	
 	/* We do signed linear */
@@ -3480,7 +3838,10 @@ static struct ast_channel *zt_request(char *type, int format, void *data)
 		groupmatch = 1 << x;
 	} else {
 		s = strtok(dest, "/");
-		if (sscanf(s, "%d", &x) != 1) {
+		if (!strcasecmp(s, "pseudo")) {
+			/* Special case for pseudo */
+			x = CHAN_PSEUDO;
+		} else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
 			ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
 			free(dest);
 			return NULL;
@@ -3502,14 +3863,35 @@ static struct ast_channel *zt_request(char *type, int format, void *data)
 					continue;
 				}
 #ifdef ZAPATA_PRI
-       	if (p->pri) 
+			if (p->pri) 
 				if (!(p->call = pri_new_call(p->pri->pri))) {
 					ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
 					break;
 				}
 #endif
 			callwait = (p->owner != NULL);
+			if (p->channel == CHAN_PSEUDO) {
+				p = chandup(p);
+				if (!p) {
+					break;
+				}
+			}
 			tmp = zt_new(p, AST_STATE_RESERVED, 0, p->owner ? 1 : 0, 0);
+			/* 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;
+				} else {
+					ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
+				}
+			}
 			/* Note if the call is a call waiting call */
 			if (callwait)
 				tmp->cdrflags |= AST_CDR_CALLWAIT;
@@ -3601,6 +3983,61 @@ static int pri_fixup(struct zt_pri *pri, int channel, q931_call *c)
 	return 0;
 }
 
+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;
+}
+
 static void *pri_dchannel(void *vpri)
 {
 	struct zt_pri *pri = vpri;
@@ -3610,13 +4047,126 @@ static void *pri_dchannel(void *vpri)
 	int res;
 	int chan;
 	int x;
+	int haveidles;
+	int activeidles;
+	int nextidle = -1;
 	struct ast_channel *c;
 	struct timeval tv, *next;
+	struct timeval lastidle = { 0, 0 };
+	int doidling=0;
+	char *cc;
+	char idlen[80];
+	struct ast_channel *idle;
+	pthread_t p;
+	time_t t;
+	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);
+	}
 	for(;;) {
 		FD_ZERO(&rfds);
 		FD_ZERO(&efds);
 		FD_SET(pri->fd, &rfds);
 		FD_SET(pri->fd, &efds);
+		time(&t);
+		ast_pthread_mutex_lock(&pri->lock);
+		if (pri->resetting) {
+			/* Look for a resetable channel and go */
+			if ((t - pri->lastreset) > 0) {
+				pri->lastreset = t;
+				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;
+				}
+			}
+		} else {
+			if ((t - pri->lastreset) >= RESET_INTERVAL) {
+				pri->resetting = 1;
+				pri->resetchannel = -1;
+			}
+		}
+		/* Look for any idle channels if appropriate */
+		if (doidling) {
+			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 */
+				for (x=pri->channels;x>=0;x--) {
+					/* find a candidate channel */
+					if (pri->pvt[x] && pri->pvt[x]->owner && pri->pvt[x]->isidlecall) {
+						pri->pvt[x]->owner->softhangup = 1;
+						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;
+					} 
+				}
+			}
+		}
 		if ((next = pri_schedule_next(pri->pri))) {
 			/* We need relative time here */
 			gettimeofday(&tv, NULL);
@@ -3630,10 +4180,33 @@ static void *pri_dchannel(void *vpri)
 				tv.tv_sec = 0;
 				tv.tv_usec = 0;
 			}
+			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;
 		}
+		pthread_mutex_unlock(&pri->lock);
+
 		e = NULL;
-		res = select(pri->fd + 1, &rfds, NULL, &efds, next ? &tv : NULL);
-		pthread_mutex_lock(&pri->lock);
+		res = select(pri->fd + 1, &rfds, NULL, &efds, &tv);
+
+		ast_pthread_mutex_lock(&pri->lock);
 		if (!res) {
 			/* Just a timeout, run the scheduler */
 			e = pri_schedule_run(pri->pri);
@@ -3728,7 +4301,7 @@ static void *pri_dchannel(void *vpri)
 							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);
-							pri_acknowledge(pri->pri, e->ring.call, chan, 0);
+							pri_acknowledge(pri->pri, e->ring.call, chan, 1);
 							zt_enable_ec(pri->pvt[chan]);
 						} else {
 							ast_log(LOG_WARNING, "Unable to start PBX on channel %d, span %d\n", chan, pri->span);
@@ -3794,10 +4367,16 @@ static void *pri_dchannel(void *vpri)
 					chan = pri_fixup(pri, chan, e->hangup.call);
 					if (chan) {
 						if (pri->pvt[chan]->owner) {
-							if (option_verbose > 3) 
-								ast_verbose(VERBOSE_PREFIX_3, "Channel %d, span %d got hangup\n", chan, pri->span);
+							if (option_verbose > 2) 
+								ast_verbose(VERBOSE_PREFIX_3 "Channel %d, span %d got hangup\n", chan, pri->span);
 							pri->pvt[chan]->owner->softhangup = 1;
 						}
+						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;
+						}
 					} else {
 						ast_log(LOG_WARNING, "Hangup on bad channel %d\n", e->hangup.channel);
 					}
@@ -3815,9 +4394,10 @@ static void *pri_dchannel(void *vpri)
 				if (chan) {
 					chan = pri_fixup(pri, chan, e->hangup.call);
 					if (chan) {
+						pri->pvt[chan]->resetting = 0;
 						if (pri->pvt[chan]->owner) {
-							if (option_verbose > 3) 
-								ast_verbose(VERBOSE_PREFIX_3, "Channel %d, span %d got hangup ACK\n", chan, pri->span);
+							if (option_verbose > 2) 
+								ast_verbose(VERBOSE_PREFIX_3 "Channel %d, span %d got hangup ACK\n", chan, pri->span);
 							pri->pvt[chan]->call = NULL;
 						}
 					}
@@ -3826,6 +4406,18 @@ static void *pri_dchannel(void *vpri)
 			case PRI_EVENT_CONFIG_ERR:
 				ast_log(LOG_WARNING, "PRI Error: %s\n", e->err.err);
 				break;
+			case PRI_EVENT_RESTART_ACK:
+				chan = e->restartack.channel;
+				if (option_verbose > 2)
+					ast_verbose(VERBOSE_PREFIX_3 "B-channel %d successfully restarted on span %d\n", chan, pri->span);
+				if (pri->pvt[chan]) {
+					if (pri->pvt[chan]->owner) {
+						ast_log(LOG_WARNING, "Got restart ack on channel with owner\n");
+						pri->pvt[chan]->owner->softhangup = 1;
+					}
+					pri->pvt[chan]->resetting = 0;
+				}
+				break;
 			default:
 				ast_log(LOG_DEBUG, "Event: %d\n", e->e);
 			}
@@ -3993,7 +4585,7 @@ static struct ast_cli_entry pri_debug = {
 };
 
 static struct ast_cli_entry pri_no_debug = {
-	{ "pri", "no", "debug", "span", NULL }, handle_pri_no_debug, "Enables PRI debugging on a span", pri_no_debug_help, complete_span };
+	{ "pri", "no", "debug", "span", NULL }, handle_pri_no_debug, "Disables PRI debugging on a span", pri_no_debug_help, complete_span };
 
 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 };
@@ -4026,19 +4618,19 @@ static int zap_destroy_channel(int fd, int argc, char **argv)
 
 static int zap_show_channels(int fd, int argc, char **argv)
 {
-#define FORMAT "%3d %-10.10s %-10.10s %-10.10s\n"
-#define FORMAT2 "%3s %-10.10s %-10.10s %-10.10s\n"
+#define FORMAT "%3d %-10.10s %-10.10s %-10.10s %-8.8s\n"
+#define FORMAT2 "%3s %-10.10s %-10.10s %-10.10s %-8.8s\n"
 	struct zt_pvt *tmp = NULL;
 
 	if (argc != 3)
 		return RESULT_SHOWUSAGE;
 
 	ast_pthread_mutex_lock(&iflock);
-	ast_cli(fd, FORMAT2, "Chan. Num.", "Extension", "Context", "Language");
+	ast_cli(fd, FORMAT2, "Chan. Num.", "Extension", "Context", "Language", "MusicOnHold");
 	
 	tmp = iflist;
 	while (tmp) {
-		ast_cli(fd, FORMAT, tmp->channel, tmp->exten, tmp->context, tmp->language);
+		ast_cli(fd, FORMAT, tmp->channel, tmp->exten, tmp->context, tmp->language, tmp->musicclass);
 		tmp = tmp->next;
 	}
 	ast_pthread_mutex_unlock(&iflock);
@@ -4151,6 +4743,8 @@ int load_module()
 				} else if (sscanf(chan, "%d", &start)) {
 					/* Just one */
 					finish = start;
+				} else if (!strcasecmp(chan, "pseudo")) {
+					finish = start = CHAN_PSEUDO;
 				} else {
 					ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", v->value, chan);
 					ast_destroy(cfg);
@@ -4210,6 +4804,8 @@ int load_module()
 			strncpy(context, v->value, sizeof(context)-1);
 		} else if (!strcasecmp(v->name, "language")) {
 			strncpy(language, v->value, sizeof(language)-1);
+		} else if (!strcasecmp(v->name, "musiconhold")) {
+			strncpy(musicclass, v->value, sizeof(musicclass)-1);
 		} else if (!strcasecmp(v->name, "stripmsd")) {
 			stripmsd = atoi(v->value);
 		} else if (!strcasecmp(v->name, "group")) {
@@ -4260,6 +4856,10 @@ int load_module()
 				cur_signalling = SIG_FXOKS;
 			} else if (!strcasecmp(v->value, "featd")) {
 				cur_signalling = SIG_FEATD;
+			} else if (!strcasecmp(v->value, "featdmf")) {
+				cur_signalling = SIG_FEATDMF;
+			} else if (!strcasecmp(v->value, "featb")) {
+				cur_signalling = SIG_FEATB;
 #ifdef ZAPATA_PRI
 			} else if (!strcasecmp(v->value, "pri_net")) {
 				cur_signalling = SIG_PRI;
@@ -4290,6 +4890,12 @@ int load_module()
 				unload_module();
 				return -1;
 			}
+		} 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		
 		} else
 			ast_log(LOG_DEBUG, "Ignoring %s\n", v->name);
@@ -4414,6 +5020,7 @@ static int reload_zt(void)
 	/* Some crap that needs to be reinitialized on the reload */
 	strcpy(context, "default");
 	language[0] = '\0'; 
+	musicclass[0] = '\0';
 	use_callerid = 1;
 	cur_signalling = -1;
 	cur_group = 0;
@@ -4433,6 +5040,12 @@ static int reload_zt(void)
 	amaflags = 0;
 	adsi = 0;
 	strncpy(accountcode, "", sizeof(accountcode)-1);
+#ifdef ZAPATA_PRI
+	strncpy(idleext, "", sizeof(idleext) - 1);
+	strncpy(idledial, "", sizeof(idledial) - 1);
+	minunused = 2;
+	minidle = 0;
+#endif
 //	usecnt = 0;
 
 #if 0
@@ -4476,6 +5089,7 @@ static int reload_zt(void)
 	v = ast_variable_browse(cfg, "channels");
 	
 	while(v) {
+		printf("%s is %s\n", v->name, v->value);
 		/* Create the interface list */
 		if (!strcasecmp(v->name, "channel")) {
 			if (cur_signalling < 0) {
@@ -4535,6 +5149,8 @@ static int reload_zt(void)
 			strncpy(context, v->value, sizeof(context)-1);
 		} else if (!strcasecmp(v->name, "language")) {
 			strncpy(language, v->value, sizeof(language)-1);
+		} else if (!strcasecmp(v->name, "musiconhold")) {
+			strncpy(musicclass, v->value, sizeof(musicclass)-1);
 		} else if (!strcasecmp(v->name, "stripmsd")) {
 			stripmsd = atoi(v->value);
 		} else if (!strcasecmp(v->name, "group")) {
@@ -4580,6 +5196,10 @@ static int reload_zt(void)
 				cur_signalling = SIG_FXOKS;
 			} else if (!strcasecmp(v->value, "featd")) {
 				cur_signalling = SIG_FEATD;
+			} else if (!strcasecmp(v->value, "featdmf")) {
+				cur_signalling = SIG_FEATDMF;
+			} else if (!strcasecmp(v->value, "featb")) {
+				cur_signalling = SIG_FEATB;
 #ifdef ZAPATA_PRI
 			} else if (!strcasecmp(v->value, "pri_net")) {
 				cur_signalling = SIG_PRI;
@@ -4607,7 +5227,13 @@ static int reload_zt(void)
 				ast_pthread_mutex_unlock(&iflock);
 				return -1;
 			}
-#endif		
+		} 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
 		} else
 			ast_log(LOG_DEBUG, "Ignoring %s\n", v->name);
 		v = v->next;
@@ -4660,24 +5286,53 @@ static int reload_zt(void)
 static int zt_sendtext(struct ast_channel *c, char *text)
 {
 #define	END_SILENCE_LEN 400
+#define	HEADER_MS 50
+#define	TRAILER_MS 5
+#define	HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
+#define	ASCII_BYTES_PER_CHAR 80
 
 	unsigned char *buf,*mybuf;
 	struct zt_pvt *p = c->pvt->pvt;
 	fd_set wfds,efds;
-	int size,res,fd,len;
+	int size,res,fd,len,x;
+	int bytes=0;
+	/* Initial carrier (imaginary) */
+	float cr = 1.0;
+	float ci = 0.0;
+	float scont = 0.0;
+
 
-	if (!p->tdd) return(0);  /* if not in TDD mode, just return */
-	buf = malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
+	if ((!p->tdd) && (!p->mate)) return(0);  /* if not in TDD mode, just return */
+	if (p->mate) 
+		buf = malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
+	else
+		buf = malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN);
 	if (!buf) {
 		ast_log(LOG_ERROR, "MALLOC FAILED\n");
 		return -1;
 	}
 	mybuf = buf;
-	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;
+	if (p->mate) {
+		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;
+		}
 	}
 	memset(buf + len,0x7f,END_SILENCE_LEN);
 	len += END_SILENCE_LEN;
@@ -4755,3 +5410,4 @@ char *key()
 {
 	return ASTERISK_GPL_KEY;
 }
+
-- 
GitLab