aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2001-12-29 18:04:21 +0000
committermarkster <markster@f38db490-d61c-443f-a65b-d21fe96a405b>2001-12-29 18:04:21 +0000
commit9985c93908f8b118b1024e7cd324457c1ca79183 (patch)
tree3ce56114805fc61a368b075d3ca8f69272813992
parentfc3d66ee67a7574780a6df782856432ffa8c13b1 (diff)
Version 0.1.10 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@399 f38db490-d61c-443f-a65b-d21fe96a405b
-rwxr-xr-xchannels/chan_zap.c668
1 files changed, 516 insertions, 152 deletions
diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index 36c559dee..3e6786adb 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -24,7 +24,11 @@
#include <asterisk/file.h>
#include <asterisk/ulaw.h>
#include <asterisk/callerid.h>
+#include <asterisk/adsi.h>
#include <asterisk/cli.h>
+#include <asterisk/cdr.h>
+#include <asterisk/parking.h>
+#include <asterisk/tdd.h>
#include <sys/signal.h>
#include <sys/select.h>
#include <errno.h>
@@ -69,7 +73,7 @@ static char *config = "zapata.conf";
#define SIG_FXOKS ZT_SIG_FXOKS
#define SIG_PRI ZT_SIG_CLEAR
-#define NUM_SPANS 2
+#define NUM_SPANS 32
static char context[AST_MAX_EXTENSION] = "default";
static char callerid[256] = "";
@@ -104,6 +108,12 @@ static float txgain = 0.0;
static int echocancel;
+static char accountcode[20] = "";
+
+static int amaflags = 0;
+
+static int adsi = 0;
+
/* Wait up to 16 seconds for first digit (FXO logic) */
static int firstdigittimeout = 16000;
@@ -128,6 +138,8 @@ 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);
+static int zt_sendtext(struct ast_channel *c, char *text);
+
static inline int zt_get_event(int fd)
{
/* Avoid the silly zt_getevent which ignores a bunch of events */
@@ -164,15 +176,17 @@ struct zt_pri {
pthread_mutex_t lock; /* Mutex */
int nodetype; /* Node type */
int switchtype; /* Type of switch to emulate */
+ int dchannel; /* What channel the dchannel is on */
+ int channels; /* Num of chans in span (31 or 24) */
struct pri *pri;
int debug;
int fd;
int up;
int offset;
int span;
- int chanmask[24]; /* Channel status */
- struct zt_pvt *pvt[24]; /* Member channel pvt structs */
- struct zt_channel *chan[24]; /* Channels on each line */
+ int chanmask[31]; /* Channel status */
+ struct zt_pvt *pvt[30]; /* Member channel pvt structs */
+ struct zt_channel *chan[30]; /* Channels on each line */
};
@@ -181,12 +195,9 @@ static struct zt_pri pris[NUM_SPANS];
static int pritype = PRI_CPE;
#if 0
-#define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE)
+#define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
#else
#define DEFAULT_PRI_DEBUG 0
-/*
-#define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW)
-*/
#endif
static inline int pri_grab(struct zt_pri *pri)
@@ -235,12 +246,14 @@ static struct zt_pvt {
struct ast_frame f[3]; /* One frame for each channel. How did this ever work before? */
short buffer[3][AST_FRIENDLY_OFFSET/2 + READ_SIZE];
int group;
+ int law;
int callgroup;
int pickupgroup;
int immediate; /* Answer before getting digits? */
int channel; /* Channel Number */
int span; /* Span number */
int dialing;
+ int dialednone;
int use_callerid; /* Whether or not to use caller id on this channel */
int hidecallerid;
int permhidecallerid; /* Whether to hide our outgoing caller ID or not */
@@ -270,6 +283,12 @@ static struct zt_pvt {
int destroy;
int ignoredtmf;
int inalarm;
+ 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 linear;
+ int adsi;
#ifdef ZAPATA_PRI
struct zt_pri *pri;
q931_call *call;
@@ -523,7 +542,7 @@ static void zt_enable_ec(struct zt_pvt *p)
{
int x;
int res;
- if (p->echocancel) {
+ if (p && p->echocancel) {
x = 1;
res = ioctl(zap_fd(p->z), ZT_ECHOCANCEL, &x);
if (res)
@@ -576,14 +595,15 @@ static int set_actual_gain(int fd, int chan, float rxgain, float txgain)
/* caluculate linear value of rx gain */
lrxgain = pow(10.0,rxgain / 20.0);
for (j=0;j<256;j++) {
- k = (int)(((float)ast_mulaw[j]) * lrxgain);
+ /* XXX Fix for A-law XXX */
+ k = (int)(((float)AST_MULAW(j)) * lrxgain);
if (k > 32767) k = 32767;
if (k < -32767) k = -32767;
- g.rxgain[j] = ast_lin2mu[k + 32768];
- k = (int)(((float)ast_mulaw[j]) * ltxgain);
+ g.rxgain[j] = AST_LIN2MU(k);
+ k = (int)(((float)AST_MULAW(j)) * ltxgain);
if (k > 32767) k = 32767;
if (k < -32767) k = -32767;
- g.txgain[j] = ast_lin2mu[k + 32768];
+ g.txgain[j] = AST_LIN2MU(k);
}
/* set 'em */
@@ -723,11 +743,11 @@ static int send_callerid(struct zt_pvt *p)
p->cidspill = 0;
if (p->callwaitcas) {
zap_clrdtmfn(p->z);
- /* Check for a the ack on the CAS */
- res = zap_getdtmf(p->z, 1, NULL, 0, 250, 250, ZAP_HOOKEXIT | ZAP_TIMEOUTOK);
+ /* Check for a the ack on the CAS (up to 500 ms) */
+ res = zap_getdtmf(p->z, 1, NULL, 0, 500, 500, ZAP_HOOKEXIT | ZAP_TIMEOUTOK);
if (res > 0) {
char tmp[2];
- strncpy(tmp, zap_dtmfbuf(p->z), sizeof(tmp));
+ strncpy(tmp, zap_dtmfbuf(p->z), sizeof(tmp)-1);
zap_clrdtmfn(p->z);
if ((tmp[0] == 'A') || (tmp[0] == 'D')) {
send_cwcidspill(p);
@@ -756,11 +776,11 @@ static int zt_callwait(struct ast_channel *ast)
/* Silence */
memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
if (!p->callwaitrings && p->callwaitingcallerid) {
- ast_callerid_gen_cas(p->cidspill, 2400 + 680);
+ ast_gen_cas(p->cidspill, 1, 2400 + 680);
p->callwaitcas = 1;
p->cidlen = 2400 + 680 + READ_SIZE * 4;
} else {
- ast_callerid_gen_cas(p->cidspill, 2400);
+ ast_gen_cas(p->cidspill, 1, 2400);
p->callwaitcas = 0;
p->cidlen = 2400 + READ_SIZE * 4;
}
@@ -783,6 +803,7 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
ast_log(LOG_WARNING, "zt_call called on %s, neither down nor reserved\n", ast->name);
return -1;
}
+ p->dialednone = 0;
switch(p->sig) {
case SIG_FXOLS:
case SIG_FXOGS:
@@ -814,7 +835,7 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
/* Call waiting call */
p->callwaitrings = 0;
if (ast->callerid)
- strncpy(p->callwaitcid, ast->callerid, sizeof(p->callwaitcid));
+ strncpy(p->callwaitcid, ast->callerid, sizeof(p->callwaitcid)-1);
else
strcpy(p->callwaitcid, "");
/* Call waiting tone instead */
@@ -856,7 +877,7 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
p->dop.op = ZT_DIAL_OP_REPLACE;
if (p->sig == SIG_FEATD) {
if (ast->callerid) {
- strncpy(callerid, ast->callerid, sizeof(callerid));
+ strncpy(callerid, ast->callerid, sizeof(callerid)-1);
ast_callerid_parse(callerid, &n, &l);
if (l) {
ast_shrink_phone_number(l);
@@ -881,6 +902,7 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
} else
ast_log(LOG_DEBUG, "Deferring dialing...\n");
p->dialing = 1;
+ if (strlen(c + p->stripmsd) < 1) p->dialednone = 1;
ast->state = AST_STATE_DIALING;
break;
#ifdef ZAPATA_PRI
@@ -891,7 +913,7 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
else
c = dest;
if (ast->callerid) {
- strncpy(callerid, ast->callerid, sizeof(callerid));
+ strncpy(callerid, ast->callerid, sizeof(callerid)-1);
ast_callerid_parse(callerid, &n, &l);
if (l) {
ast_shrink_phone_number(l);
@@ -905,9 +927,10 @@ static int zt_call(struct ast_channel *ast, char *dest, int timeout)
return -1;
}
if (pri_call(p->pri->pri, p->call, PRI_TRANS_CAP_SPEECH,
- ((p->channel - 1) % 24) + 1, p->pri->nodetype == PRI_NETWORK ? 0 : 1, 1, l, PRI_NATIONAL_ISDN,
+ ((p->channel - 1) % p->pri->channels) + 1, p->pri->nodetype == PRI_NETWORK ? 0 : 1, 1, l, PRI_NATIONAL_ISDN,
l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE,
- c + p->stripmsd, PRI_NATIONAL_ISDN)) {
+ c + p->stripmsd, PRI_NATIONAL_ISDN,
+ ((p->law == ZT_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW))) {
ast_log(LOG_WARNING, "Unable to setup call to %s\n", c + p->stripmsd);
return -1;
}
@@ -971,7 +994,7 @@ static int destroy_channel(struct zt_pvt *prev, struct zt_pvt *cur, int now)
static int zt_hangup(struct ast_channel *ast)
{
int res;
- int index,x;
+ int index,x, law;
static int restore_gains(struct zt_pvt *p);
struct zt_pvt *p = ast->pvt->pvt;
struct zt_pvt *tmp = NULL;
@@ -1034,6 +1057,12 @@ static int zt_hangup(struct ast_channel *ast)
if (!p->owners[0] && !p->owners[1] && !p->owners[2]) {
p->owner = NULL;
p->ringt = 0;
+ law = ZT_LAW_DEFAULT;
+ res = ioctl(zap_fd(p->z), ZT_SETLAW, &law);
+ p->linear = 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);
/* Perform low level hangup if no owner left */
#ifdef ZAPATA_PRI
if (p->sig == SIG_PRI) {
@@ -1085,6 +1114,8 @@ static int zt_hangup(struct ast_channel *ast)
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);
+ p->didtdd = 0;
p->cidspill = NULL;
p->callwaitcas = 0;
p->callwaiting = p->permcallwaiting;
@@ -1169,9 +1200,11 @@ static int zt_answer(struct ast_channel *ast)
static inline int bridge_cleanup(struct zt_pvt *p0, struct zt_pvt *p1)
{
- int res;
- res = conf_clear(p0);
- res |= conf_clear(p1);
+ int res = 0;
+ if (p0)
+ res = conf_clear(p0);
+ if (p1)
+ res |= conf_clear(p1);
return res;
}
@@ -1181,7 +1214,9 @@ char *cp;
struct zt_pvt *p = chan->pvt->pvt;
- if (option != AST_OPTION_TONE_VERIFY)
+
+ if ((option != AST_OPTION_TONE_VERIFY) &&
+ (option != AST_OPTION_TDD))
{
errno = ENOSYS;
return -1;
@@ -1192,18 +1227,78 @@ char *cp;
errno = EINVAL;
return -1;
}
- switch(*cp) {
- case 1:
- ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
- zap_digitmode(p->z,ZAP_MUTECONF); /* set mute mode if desired */
- break;
- case 2:
- ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
- zap_digitmode(p->z,ZAP_MUTECONF | ZAP_MUTEMAX); /* set mute mode if desired */
+ switch(option) {
+ case AST_OPTION_TONE_VERIFY:
+ switch(*cp) {
+ case 1:
+ ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
+ zap_digitmode(p->z,ZAP_MUTECONF); /* set mute mode if desired */
+ break;
+ case 2:
+ ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
+ zap_digitmode(p->z,ZAP_MUTECONF | ZAP_MUTEMAX); /* set mute mode if desired */
+ break;
+ default:
+ ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
+ zap_digitmode(p->z,0); /* set mute mode if desired */
+ break;
+ }
break;
- default:
- ast_log(LOG_DEBUG, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
- zap_digitmode(p->z,0); /* set mute mode if desired */
+ case AST_OPTION_TDD: /* turn on or off TDD */
+ if (!*cp) { /* turn it off */
+ ast_log(LOG_DEBUG, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
+ if (p->tdd) tdd_free(p->tdd);
+ p->tdd = 0;
+ break;
+ }
+ ast_log(LOG_DEBUG, "Set option TDD MODE, value: ON(1) on %s\n",chan->name);
+ /* otherwise, turn it on */
+ if (!p->didtdd) { /* if havent done it yet */
+ unsigned char mybuf[41000],*buf;
+ int size,res,fd,len;
+ fd_set wfds,efds;
+ buf = mybuf;
+ memset(buf,0x7f,sizeof(mybuf)); /* set to silence */
+ ast_tdd_gen_ecdisa(buf + 16000,16000); /* put in tone */
+ len = 40000;
+ if (chan != p->owner) /* if in three-way */
+ fd = zap_fd(p->pseudo);
+ else
+ fd = zap_fd(p->z);
+ while(len) {
+ if (ast_check_hangup(chan)) return -1;
+ size = len;
+ if (size > READ_SIZE)
+ size = READ_SIZE;
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ FD_SET(fd,&wfds);
+ FD_SET(fd,&efds);
+ res = select(fd + 1,NULL,&wfds,&efds,NULL);
+ if (!res) {
+ ast_log(LOG_DEBUG, "select (for write) ret. 0 on channel %d\n", p->channel);
+ continue;
+ }
+ /* if got exception */
+ if (FD_ISSET(fd,&efds)) return -1;
+ if (!FD_ISSET(fd,&wfds)) {
+ ast_log(LOG_DEBUG, "write fd not ready on channel %d\n", p->channel);
+ continue;
+ }
+ res = write(fd, buf, size);
+ if (res != size) {
+ if (res == -1) return -1;
+ ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
+ break;
+ }
+ len -= size;
+ buf += size;
+ }
+ p->didtdd = 1; /* set to have done it now */
+ }
+ if (!p->tdd) { /* if we dont have one yet */
+ p->tdd = tdd_new(); /* allocate one */
+ }
break;
}
errno = 0;
@@ -1251,7 +1346,7 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
p1 = c1->pvt->pvt;
/* Stop if we're a zombie or need a soft hangup */
- if (c0->zombie || c0->softhangup || c1->zombie || c1->softhangup) {
+ if (c0->zombie || ast_check_hangup(c0) || c1->zombie || ast_check_hangup(c1)) {
*fo = NULL;
if (who) *rc = who;
bridge_cleanup(p0, p1);
@@ -1509,18 +1604,17 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
ast_log(LOG_DEBUG, "ZT_DIALING ioctl failed on %s\n",ast->name);
return NULL;
}
- if (!x) /* if not still dialing in driver */
- {
+ if (!x) { /* if not still dialing in driver */
zt_enable_ec(p);
p->dialing = 0;
if (ast->state == AST_STATE_DIALING) {
-#if 0
- ast->state = AST_STATE_RINGING;
-#else
+ if (!p->dialednone && ((p->sig == SIG_EM) || (p->sig == SIG_EMWINK) || (p->sig == SIG_FEATD))) {
+ 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;
-#endif
+ }
}
}
break;
@@ -1791,6 +1885,7 @@ struct ast_frame *zt_handle_event(struct ast_channel *ast)
case SIG_FXSKS:
case SIG_EM:
case SIG_EMWINK:
+ case SIG_FEATD:
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);
@@ -1890,11 +1985,10 @@ struct ast_frame *zt_exception(struct ast_channel *ast)
struct ast_frame *zt_read(struct ast_channel *ast)
{
struct zt_pvt *p = ast->pvt->pvt;
- int res,x;
+ int res;
int index;
- unsigned char ireadbuf[READ_SIZE];
- unsigned char *readbuf;
ZAP *z = NULL;
+ void *readbuf;
pthread_mutex_lock(&p->lock);
@@ -1928,6 +2022,7 @@ struct ast_frame *zt_read(struct ast_channel *ast)
p->needringing[index] = 0;
p->f[index].frametype = AST_FRAME_CONTROL;
p->f[index].subclass = AST_CONTROL_RINGING;
+ ast->state = AST_STATE_RINGING;
pthread_mutex_unlock(&p->lock);
return &p->f[index];
}
@@ -1937,6 +2032,7 @@ struct ast_frame *zt_read(struct ast_channel *ast)
p->needanswer[index] = 0;
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];
}
@@ -1974,16 +2070,26 @@ struct ast_frame *zt_read(struct ast_channel *ast)
}
if (ast->pvt->rawreadformat == AST_FORMAT_SLINEAR) {
- /* Read into temporary buffer */
- readbuf = ireadbuf;
- } else if (ast->pvt->rawreadformat == AST_FORMAT_ULAW) {
- /* Read ulaw directly into frame */
- readbuf = ((unsigned char *)p->buffer[index]) + AST_FRIENDLY_OFFSET;
+ if (!p->linear) {
+ p->linear = 1;
+ res = zap_setlinear(p->z, p->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 (res)
+ ast_log(LOG_WARNING, "Unable to set channel %d to linear mode.\n", p->channel);
+ }
} else {
ast_log(LOG_WARNING, "Don't know how to read frames in format %d\n", ast->pvt->rawreadformat);
pthread_mutex_unlock(&p->lock);
return NULL;
}
+ readbuf = ((unsigned char *)p->buffer[index]) + AST_FRIENDLY_OFFSET;
CHECK_BLOCKING(ast);
if ((z != p->z) && (z != p->pseudo)) {
pthread_mutex_unlock(&p->lock);
@@ -2019,7 +2125,7 @@ struct ast_frame *zt_read(struct ast_channel *ast)
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));
+ strncpy(p->dtmfq + strlen(p->dtmfq), zap_dtmfbuf(z), sizeof(p->dtmfq) - strlen(p->dtmfq)-1);
zap_clrdtmfn(z);
}
} else {
@@ -2034,6 +2140,26 @@ struct ast_frame *zt_read(struct ast_channel *ast)
pthread_mutex_unlock(&p->lock);
return &p->f[index];
}
+ if (p->tdd) { /* if in TDD mode, see if we receive that */
+ int c;
+
+ c = tdd_feed(p->tdd,readbuf,READ_SIZE);
+ if (c < 0) {
+ ast_log(LOG_DEBUG,"tdd_feed failed\n");
+ return NULL;
+ }
+ if (c) { /* if a char to return */
+ p->f[index].subclass = 0;
+ p->f[index].frametype = AST_FRAME_TEXT;
+ p->f[index].mallocd = 0;
+ p->f[index].offset = AST_FRIENDLY_OFFSET;
+ p->f[index].data = p->buffer[index] + AST_FRIENDLY_OFFSET;
+ p->f[index].datalen = 1;
+ *((char *) p->f[index].data) = c;
+ pthread_mutex_unlock(&p->lock);
+ return &p->f[index];
+ }
+ }
if (p->callwaitingrepeat)
p->callwaitingrepeat--;
/* Repeat callwaiting */
@@ -2042,9 +2168,6 @@ struct ast_frame *zt_read(struct ast_channel *ast)
zt_callwait(ast);
}
if (ast->pvt->rawreadformat == AST_FORMAT_SLINEAR) {
- for (x=0;x<READ_SIZE;x++) {
- p->buffer[index][x + AST_FRIENDLY_OFFSET/2] = ast_mulaw[readbuf[x]];
- }
p->f[index].datalen = READ_SIZE * 2;
} else
p->f[index].datalen = READ_SIZE;
@@ -2092,7 +2215,8 @@ static int my_zt_write(struct zt_pvt *p, unsigned char *buf, int len, int threew
size = READ_SIZE;
res = write(fd, buf, size);
if (res != size) {
- ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
return sent;
}
len -= size;
@@ -2104,10 +2228,8 @@ static int my_zt_write(struct zt_pvt *p, unsigned char *buf, int len, int threew
static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
{
struct zt_pvt *p = ast->pvt->pvt;
- int x;
int res;
unsigned char outbuf[4096];
- short *inbuf;
if (ast != p->owner) {
/* If it's not us. If this isn't a three way call, return immediately */
@@ -2125,21 +2247,19 @@ static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
return -1;
}
- if ((frame->subclass != AST_FORMAT_SLINEAR) && (frame->subclass != AST_FORMAT_ULAW)) {
+ if ((frame->subclass != AST_FORMAT_SLINEAR) &&
+ (frame->subclass != AST_FORMAT_ULAW) &&
+ (frame->subclass != AST_FORMAT_ALAW)) {
ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
return -1;
}
if (p->dialing) {
-#if 0
if (option_debug)
-#endif
ast_log(LOG_DEBUG, "Dropping frame since I'm still dialing on %s...\n",ast->name);
return 0;
}
if (p->cidspill) {
-#if 0
if (option_debug)
-#endif
ast_log(LOG_DEBUG, "Dropping frame since I've still got a callerid spill\n");
return 0;
}
@@ -2151,21 +2271,27 @@ static int zt_write(struct ast_channel *ast, struct ast_frame *frame)
return 0;
}
if (frame->subclass == AST_FORMAT_SLINEAR) {
- inbuf = frame->data;
- for (x=0;x<frame->datalen/2;x++)
- outbuf[x] = ast_lin2mu[inbuf[x]+32768];
- res = my_zt_write(p, outbuf, frame->datalen/2, (ast != p->owner));
+ 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);
+ }
+ res = my_zt_write(p, (unsigned char *)frame->data, frame->datalen, (ast != p->owner));
} else {
- /* uLaw already */
+ /* 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);
+ }
res = my_zt_write(p, (unsigned char *)frame->data, frame->datalen, (ast != p->owner));
}
if (res < 0) {
ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
return -1;
- } else if (res != frame->datalen/2) {
- /* Some sort of an event */
- return 0;
- }
+ }
return 0;
}
@@ -2200,6 +2326,9 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
{
struct ast_channel *tmp;
int x;
+ int deflaw;
+ int res;
+ ZT_PARAMS ps;
for (x=0;x<3;x++)
if (!i->owners[x])
break;
@@ -2209,21 +2338,34 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
}
tmp = ast_channel_alloc();
if (tmp) {
+ ps.channo = i->channel;
+ res = ioctl(zap_fd(i->z), ZT_GET_PARAMS, &ps);
+ if (res) {
+ ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW\n");
+ ps.curlaw = ZT_LAW_MULAW;
+ }
+ if (ps.curlaw == ZT_LAW_ALAW)
+ deflaw = AST_FORMAT_ALAW;
+ else
+ deflaw = AST_FORMAT_ULAW;
snprintf(tmp->name, sizeof(tmp->name), "Zap/%d-%d", i->channel, x + 1);
tmp->type = type;
tmp->fds[0] = zap_fd(i->z);
- tmp->nativeformats = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW;
+
+ tmp->nativeformats = AST_FORMAT_SLINEAR | deflaw;
+
/* Start out assuming ulaw since it's smaller :) */
- tmp->pvt->rawreadformat = AST_FORMAT_ULAW;
- tmp->readformat = AST_FORMAT_ULAW;
- tmp->pvt->rawwriteformat = AST_FORMAT_ULAW;
- tmp->writeformat = AST_FORMAT_ULAW;
+ tmp->pvt->rawreadformat = deflaw;
+ tmp->readformat = deflaw;
+ tmp->pvt->rawwriteformat = deflaw;
+ tmp->writeformat = deflaw;
tmp->state = state;
if (state == AST_STATE_RING)
tmp->rings = 1;
tmp->pvt->pvt = i;
tmp->pvt->send_digit = zt_digit;
+ tmp->pvt->send_text = zt_sendtext;
tmp->pvt->call = zt_call;
tmp->pvt->hangup = zt_hangup;
tmp->pvt->answer = zt_answer;
@@ -2235,11 +2377,15 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
tmp->pvt->fixup = zt_fixup;
tmp->pvt->setoption = zt_setoption;
if (strlen(i->language))
- strncpy(tmp->language, i->language, sizeof(tmp->language));
+ strncpy(tmp->language, i->language, sizeof(tmp->language)-1);
/* Keep track of who owns it */
i->owners[x] = tmp;
if (!i->owner)
i->owner = tmp;
+ if (strlen(i->accountcode))
+ strncpy(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode)-1);
+ if (i->amaflags)
+ tmp->amaflags = i->amaflags;
if (callwaiting) {
if (i->callwaitindex > -1)
ast_log(LOG_WARNING, "channel %d already has a call wait call\n", i->channel);
@@ -2257,12 +2403,21 @@ static struct ast_channel *zt_new(struct zt_pvt *i, int state, int startpbx, int
usecnt++;
ast_pthread_mutex_unlock(&usecnt_lock);
ast_update_use_count();
- strncpy(tmp->context, i->context, sizeof(tmp->context));
+ strncpy(tmp->context, i->context, sizeof(tmp->context)-1);
+ /* If we've been told "no ADSI" then enforce it */
+ if (!i->adsi)
+ tmp->adsicpe = AST_ADSI_UNAVAILABLE;
if (strlen(i->exten))
- strncpy(tmp->exten, i->exten, sizeof(tmp->exten));
+ strncpy(tmp->exten, i->exten, sizeof(tmp->exten)-1);
if (startpbx) {
- if (strlen(i->callerid))
+ if (strlen(i->callerid)) {
tmp->callerid = strdup(i->callerid);
+ tmp->hidden_callerid = 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);
@@ -2342,12 +2497,12 @@ static void *ss_thread(void *data)
ast_hangup(chan);
return NULL;
}
- strncpy(exten, zap_dtmfbuf(p->z), sizeof(exten));
+ strncpy(exten, zap_dtmfbuf(p->z), sizeof(exten)-1);
if (!strlen(exten))
- strncpy(exten, "s", sizeof(exten));
+ strncpy(exten, "s", sizeof(exten)-1);
if (p->sig == SIG_FEATD) {
if (exten[0] == '*') {
- strncpy(exten2, exten, sizeof(exten2));
+ strncpy(exten2, exten, sizeof(exten2)-1);
/* Parse out extension and callerid */
s1 = strtok(exten2 + 1, "*");
s2 = strtok(NULL, "*");
@@ -2356,15 +2511,17 @@ static void *ss_thread(void *data)
chan->callerid = strdup(p->callerid);
else
chan->callerid = strdup(s1);
- strncpy(exten, s2, sizeof(exten));
+ if (chan->callerid)
+ chan->hidden_callerid = strdup(chan->callerid);
+ strncpy(exten, s2, sizeof(exten)-1);
} else
- strncpy(exten, s1, sizeof(exten));
+ strncpy(exten, s1, 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);
}
zt_enable_ec(p);
if (ast_exists_extension(chan, chan->context, exten, 1, chan->callerid)) {
- strncpy(chan->exten, exten, sizeof(chan->exten));
+ strncpy(chan->exten, exten, sizeof(chan->exten)-1);
zap_clrdtmf(p->z);
res = ast_pbx_run(chan);
if (res) {
@@ -2415,9 +2572,12 @@ static void *ss_thread(void *data)
tone_zone_play_tone(zap_fd(p->z), -1);
if (ast_exists_extension(chan, chan->context, exten, 1, p->callerid)) {
res = tone_zone_play_tone(zap_fd(p->z), -1);
- strncpy(chan->exten, exten, sizeof(chan->exten));
- if (strlen(p->callerid) && !p->hidecallerid)
- chan->callerid = strdup(p->callerid);
+ strncpy(chan->exten, exten, sizeof(chan->exten)-1);
+ if (strlen(p->callerid)) {
+ if (!p->hidecallerid)
+ chan->callerid = strdup(p->callerid);
+ chan->hidden_callerid = strdup(p->callerid);
+ }
chan->state = AST_STATE_RING;
zt_enable_ec(p);
res = ast_pbx_run(chan);
@@ -2486,7 +2646,15 @@ static void *ss_thread(void *data)
len = 0;
memset(exten, 0, sizeof(exten));
timeout = firstdigittimeout;
-
+ } else if (p->transfer && !strcmp(exten, ast_parking_ext()) &&
+ (zt_get_index(chan, p, 1) == p->thirdcallindex) &&
+ p->owners[p->normalindex]->bridge) {
+ /* This is a three way call, the main call being a real channel,
+ and we're parking the first call. */
+ ast_masq_park_call(p->owners[p->normalindex]->bridge, chan);
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
+ break;
} else if (p->hidecallerid && !strcmp(exten, "*82")) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Enabling Caller*ID on %s\n", chan->name);
@@ -2494,7 +2662,8 @@ static void *ss_thread(void *data)
p->hidecallerid = 0;
if (chan->callerid)
free(chan->callerid);
- chan->callerid = NULL;
+ if (strlen(p->callerid))
+ chan->callerid = strdup(p->callerid);
res = tone_zone_play_tone(zap_fd(p->z), ZT_TONE_DIALRECALL);
if (res) {
ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n",
@@ -2614,8 +2783,10 @@ static void *ss_thread(void *data)
} else {
strcpy(cid, "");
}
- if (strlen(cid))
+ if (strlen(cid)) {
chan->callerid = strdup(cid);
+ chan->hidden_callerid = strdup(cid);
+ }
chan->state = AST_STATE_RING;
chan->rings = 1;
p->ringt = RINGT;
@@ -2661,25 +2832,35 @@ static int handle_init_event(struct zt_pvt *i, int event)
/* The channel is immediately up. Start right away */
res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_RINGTONE);
chan = zt_new(i, AST_STATE_RING, 1, 0, 0);
- if (!chan) {
+ if (!chan) {
ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_CONGESTION);
if (res < 0)
ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
}
} else {
- res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_DIALTONE);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play dialtone on channel %d\n", i->channel);
/* Check for callerid, digits, etc */
chan = zt_new(i, AST_STATE_DOWN, 0, 0, 0);
- if (pthread_create(&threadid, &attr, ss_thread, chan)) {
- ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
- res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_CONGESTION);
- if (res < 0)
- ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
- ast_hangup(chan);
- }
+ 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);
+ }
+ res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_DIALTONE);
+ if (res < 0)
+ ast_log(LOG_WARNING, "Unable to play dialtone on channel %d\n", i->channel);
+ if (pthread_create(&threadid, &attr, ss_thread, chan)) {
+ ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
+ res = tone_zone_play_tone(zap_fd(i->z), ZT_TONE_CONGESTION);
+ if (res < 0)
+ ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
+ ast_hangup(chan);
+ }
+ } else
+ ast_log(LOG_WARNING, "Unable to create channel\n");
#if 0
printf("Created thread %ld detached in switch\n", threadid);
#endif
@@ -2935,7 +3116,7 @@ static struct zt_pvt *mkintf(int channel, int signalling)
}
if (tmp) {
- snprintf(fn, sizeof(fn), "/dev/zap/%d", channel);
+ snprintf(fn, sizeof(fn), "%d", channel);
/* Open non-blocking */
if (!here)
tmp->z = zap_open(fn, 1);
@@ -2964,15 +3145,17 @@ static struct zt_pvt *mkintf(int channel, int signalling)
}
}
}
-
- span = (channel - 1)/24;
- tmp->span = span + 1;
+ tmp->law = p.curlaw;
+ tmp->span = p.spanno;
+ span = p.spanno - 1;
#ifdef ZAPATA_PRI
if (signalling == SIG_PRI) {
int offset;
+ int numchans;
+ int dchannel;
offset = 1;
if (ioctl(zap_fd(tmp->z), ZT_AUDIOMODE, &offset)) {
- ast_log(LOG_ERROR, "Unable to set audio mode on clear channel %d of span %d: %s\n", channel, span, strerror(errno));
+ ast_log(LOG_ERROR, "Unable to set audio mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
return NULL;
}
if (span >= NUM_SPANS) {
@@ -2980,8 +3163,21 @@ static struct zt_pvt *mkintf(int channel, int signalling)
free(tmp);
return NULL;
} else {
- offset = (channel -1) % 24 + 1;
- if (offset < 24) {
+ 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.totalchans == 31) { /* if it's an E1 */
+ dchannel = 16;
+ numchans = 31;
+ } else {
+ dchannel = 24;
+ numchans = 24;
+ }
+ offset = p.chanpos;
+ if (offset != dchannel) {
if (pris[span].nodetype && (pris[span].nodetype != pritype)) {
ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
free(tmp);
@@ -2996,10 +3192,13 @@ static struct zt_pvt *mkintf(int channel, int signalling)
pris[span].switchtype = switchtype;
pris[span].chanmask[offset] |= MASK_AVAIL;
pris[span].pvt[offset] = tmp;
+ pris[span].channels = numchans;
+ pris[span].dchannel = dchannel;
+
tmp->pri = &pris[span];
tmp->call = NULL;
} else {
- ast_log(LOG_ERROR, "Channel 24 is reserved for D-channel.\n");
+ ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
free(tmp);
return NULL;
}
@@ -3008,7 +3207,8 @@ static struct zt_pvt *mkintf(int channel, int signalling)
#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_EM) || (signalling == SIG_EMWINK) ||
+ (signalling == SIG_FEATD)) {
p.starttime = 250;
res = ioctl(zap_fd(tmp->z), ZT_SET_PARAMS, &p);
if (res < 0) {
@@ -3051,6 +3251,7 @@ static struct zt_pvt *mkintf(int channel, int signalling)
tmp->destroy = 0;
tmp->callwaitingcallerid = callwaitingcallerid;
tmp->threewaycalling = threewaycalling;
+ tmp->adsi = adsi;
tmp->permhidecallerid = hidecallerid;
tmp->echocancel = echocancel;
tmp->callwaiting = tmp->permcallwaiting;
@@ -3058,6 +3259,8 @@ static struct zt_pvt *mkintf(int channel, int signalling)
tmp->channel = channel;
tmp->stripmsd = stripmsd;
tmp->use_callerid = use_callerid;
+ strncpy(tmp->accountcode, accountcode, sizeof(tmp->accountcode)-1);
+ tmp->amaflags = amaflags;
if (!here) {
tmp->callwaitindex = -1;
tmp->normalindex = -1;
@@ -3069,9 +3272,9 @@ static struct zt_pvt *mkintf(int channel, int signalling)
}
tmp->transfer = transfer;
pthread_mutex_init(&tmp->lock, NULL);
- strncpy(tmp->language, language, sizeof(tmp->language));
- strncpy(tmp->context, context, sizeof(tmp->context));
- strncpy(tmp->callerid, callerid, sizeof(tmp->callerid));
+ strncpy(tmp->language, language, sizeof(tmp->language)-1);
+ strncpy(tmp->context, context, sizeof(tmp->context)-1);
+ strncpy(tmp->callerid, callerid, sizeof(tmp->callerid)-1);
tmp->group = cur_group;
tmp->callgroup=cur_callergroup;
tmp->pickupgroup=cur_pickupgroup;
@@ -3099,6 +3302,8 @@ static struct zt_pvt *mkintf(int channel, int signalling)
static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch)
{
+ int res;
+ ZT_PARAMS par;
/* First, check group matching */
if ((p->group & groupmatch) != groupmatch)
return 0;
@@ -3107,8 +3312,26 @@ static inline int available(struct zt_pvt *p, int channelmatch, int groupmatch)
return 0;
/* If no owner definitely available */
- if (!p->owner)
+ if (!p->owner) {
+ /* Trust PRI */
+#ifdef ZAPATA_PRI
+ if (p->pri)
+ return 1;
+#endif
+ if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSLS) ||
+ (p->sig == SIG_FXSGS))
+ return 1;
+ /* Check hook state */
+ res = ioctl(zap_fd(p->z), ZT_GET_PARAMS, &par);
+ if (res) {
+ ast_log(LOG_WARNING, "Unable to check hook state on channel %d\n", p->channel);
+ } else if (par.rxisoffhook) {
+ ast_log(LOG_DEBUG, "Channel %d off hook, can't use\n", p->channel);
+ /* Not available when the other end is off hook */
+ return 0;
+ }
return 1;
+ }
/* If it's not an FXO, forget about call wait */
if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS))
@@ -3255,7 +3478,7 @@ static int get_group(char *s)
static int pri_find_empty_chan(struct zt_pri *pri)
{
int x;
- for (x=23;x>0;x--) {
+ for (x=pri->channels-1;x>0;x--) {
if (pri->pvt[x] && !pri->pvt[x]->owner)
return x;
}
@@ -3265,7 +3488,7 @@ static int pri_find_empty_chan(struct zt_pri *pri)
static int pri_fixup(struct zt_pri *pri, int channel, q931_call *c)
{
int x;
- for (x=1;x<24;x++) {
+ for (x=1;x<=pri->channels;x++) {
if (!pri->pvt[x]) continue;
if (pri->pvt[x]->call == c) {
/* Found our call */
@@ -3304,12 +3527,27 @@ static void *pri_dchannel(void *vpri)
int chan;
int x;
struct ast_channel *c;
+ struct timeval tv, *next;
for(;;) {
FD_ZERO(&rfds);
FD_ZERO(&efds);
FD_SET(pri->fd, &rfds);
FD_SET(pri->fd, &efds);
- res = select(pri->fd + 1, &rfds, NULL, &efds, pri_schedule_next(pri->pri));
+ if ((next = pri_schedule_next(pri->pri))) {
+ /* We need relative time here */
+ gettimeofday(&tv, NULL);
+ tv.tv_sec = next->tv_sec - tv.tv_sec;
+ tv.tv_usec = next->tv_usec - tv.tv_usec;
+ if (tv.tv_usec < 0) {
+ tv.tv_usec += 1000000;
+ tv.tv_sec -= 1;
+ }
+ if (tv.tv_sec < 0) {
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ }
+ res = select(pri->fd + 1, &rfds, NULL, &efds, next ? &tv : NULL);
pthread_mutex_lock(&pri->lock);
if (!res) {
/* Just a timeout, run the scheduler */
@@ -3333,7 +3571,7 @@ static void *pri_dchannel(void *vpri)
case PRI_EVENT_RESTART:
chan = e->restart.channel;
if (chan > -1) {
- if ((chan < 1) || (chan > 23) )
+ if ((chan < 1) || (chan > pri->channels) )
ast_log(LOG_WARNING, "Restart requested on odd channel number %d on span %d\n", chan, pri->span);
else if (!pri->pvt[chan])
ast_log(LOG_WARNING, "Restart requested on unconfigured channel %d on span %d\n", chan, pri->span);
@@ -3348,14 +3586,14 @@ static void *pri_dchannel(void *vpri)
} else {
if (option_verbose > 2)
ast_verbose("Restart on requested on entire span %d\n", pri->span);
- for (x=1;x<24;x++)
- if (pri->pvt[chan]->owner)
- pri->pvt[chan]->owner->softhangup = 1;
+ for (x=1;x <= pri->channels;x++)
+ if ((x != pri->dchannel) && (pri->pvt[x]->owner))
+ pri->pvt[x]->owner->softhangup = 1;
}
break;
case PRI_EVENT_RING:
chan = e->ring.channel;
- if ((chan < 1) || (chan > 23)) {
+ if ((chan < 1) || (chan > pri->channels)) {
ast_log(LOG_WARNING, "Ring requested on odd channel number %d span %d\n", chan, pri->span);
chan = 0;
} else if (!pri->pvt[chan]) {
@@ -3366,7 +3604,8 @@ static void *pri_dchannel(void *vpri)
ast_log(LOG_WARNING, "Duplicate setup requested on channel %d already in use on span %d\n", chan, pri->span);
break;
} else {
- ast_log(LOG_WARNING, "Ring requested on channel %d already in use on span %d\n", chan, pri->span);
+ ast_log(LOG_WARNING, "Ring requested on channel %d already in use on span %d. Hanging up owner.\n", chan, pri->span);
+ pri->pvt[chan]->owner->softhangup = 1;
chan = 0;
}
}
@@ -3375,16 +3614,25 @@ static void *pri_dchannel(void *vpri)
if (chan) {
/* Get caller ID */
if (pri->pvt[chan]->use_callerid)
- strncpy(pri->pvt[chan]->callerid, e->ring.callingnum, sizeof(pri->pvt[chan]->callerid));
+ strncpy(pri->pvt[chan]->callerid, e->ring.callingnum, sizeof(pri->pvt[chan]->callerid)-1);
else
strcpy(pri->pvt[chan]->callerid, "");
/* Get called number */
if (strlen(e->ring.callednum)) {
- strncpy(pri->pvt[chan]->exten, e->ring.callednum, sizeof(pri->pvt[chan]->exten));
+ strncpy(pri->pvt[chan]->exten, e->ring.callednum, sizeof(pri->pvt[chan]->exten)-1);
} else
strcpy(pri->pvt[chan]->exten, "s");
/* Make sure extension exists */
if (ast_exists_extension(NULL, pri->pvt[chan]->context, pri->pvt[chan]->exten, 1, pri->pvt[chan]->callerid)) {
+ /* Setup law */
+ int law;
+ if (e->ring.layer1 == PRI_LAYER_1_ALAW)
+ law = ZT_LAW_ALAW;
+ else
+ law = ZT_LAW_MULAW;
+ res = ioctl(zap_fd(pri->pvt[chan]->z), ZT_SETLAW, &law);
+ if (res < 0)
+ ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvt[chan]->channel);
/* Start PBX */
pri->pvt[chan]->call = e->ring.call;
c = zt_new(pri->pvt[chan], AST_STATE_RING, 1, 0, 0);
@@ -3401,8 +3649,8 @@ static void *pri_dchannel(void *vpri)
}
} else {
if (option_verbose > 2)
- ast_verbose(VERBOSE_PREFIX_3 "Extension '%s' in context '%s' does not exist. Rejecting call on channel %d, span %d\n",
- pri->pvt[chan]->exten, pri->pvt[chan]->context, chan, pri->span);
+ ast_verbose(VERBOSE_PREFIX_3 "Extension '%s' in context '%s' from '%s' does not exist. Rejecting call on channel %d, span %d\n",
+ pri->pvt[chan]->exten, pri->pvt[chan]->context, pri->pvt[chan]->callerid, chan, pri->span);
pri_release(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
}
} else
@@ -3410,7 +3658,7 @@ static void *pri_dchannel(void *vpri)
break;
case PRI_EVENT_RINGING:
chan = e->ringing.channel;
- if ((chan < 1) || (chan > 23)) {
+ if ((chan < 1) || (chan > pri->channels)) {
ast_log(LOG_WARNING, "Ringing requested on odd channel number %d span %d\n", chan, pri->span);
chan = 0;
} else if (!pri->pvt[chan]) {
@@ -3429,7 +3677,7 @@ static void *pri_dchannel(void *vpri)
break;
case PRI_EVENT_ANSWER:
chan = e->answer.channel;
- if ((chan < 1) || (chan > 23)) {
+ if ((chan < 1) || (chan > pri->channels)) {
ast_log(LOG_WARNING, "Answer on odd channel number %d span %d\n", chan, pri->span);
chan = 0;
} else if (!pri->pvt[chan]) {
@@ -3447,11 +3695,11 @@ static void *pri_dchannel(void *vpri)
break;
case PRI_EVENT_HANGUP:
chan = e->hangup.channel;
- if ((chan < 1) || (chan > 23)) {
+ if ((chan < 1) || (chan > pri->channels)) {
ast_log(LOG_WARNING, "Hangup requested on odd channel number %d span %d\n", chan, pri->span);
chan = 0;
} else if (!pri->pvt[chan]) {
- ast_log(LOG_WARNING, "Hanngup requested on unconfigured channel %d span %d\n", chan, pri->span);
+ ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d span %d\n", chan, pri->span);
chan = 0;
}
if (chan) {
@@ -3462,12 +3710,14 @@ static void *pri_dchannel(void *vpri)
ast_verbose(VERBOSE_PREFIX_3, "Channel %d, span %d got hangup\n", chan, pri->span);
pri->pvt[chan]->owner->softhangup = 1;
}
+ } else {
+ ast_log(LOG_WARNING, "Hangup on bad channel %d\n", e->hangup.channel);
}
- }
+ }
break;
case PRI_EVENT_HANGUP_ACK:
chan = e->hangup.channel;
- if ((chan < 1) || (chan > 23)) {
+ if ((chan < 1) || (chan > pri->channels)) {
ast_log(LOG_WARNING, "Hangup ACK requested on odd channel number %d span %d\n", chan, pri->span);
chan = 0;
} else if (!pri->pvt[chan]) {
@@ -3516,7 +3766,7 @@ static int start_pri(struct zt_pri *pri)
int res;
ZT_PARAMS p;
ZT_BUFFERINFO bi;
- snprintf(filename, sizeof(filename), "/dev/zap/%d", pri->offset + 24);
+ snprintf(filename, sizeof(filename), "/dev/zap/%d", pri->offset + pri->dchannel);
pri->fd = open(filename, O_RDWR, 0600);
if (pri->fd < 0) {
ast_log(LOG_ERROR, "Unable to open D-channel %s (%s)\n", filename, strerror(errno));
@@ -3537,7 +3787,7 @@ static int start_pri(struct zt_pri *pri)
}
bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
- bi.numbufs = 4;
+ bi.numbufs = 8;
bi.bufsize = 1024;
if (ioctl(pri->fd, ZT_SET_BUFINFO, &bi)) {
ast_log(LOG_ERROR, "Unable to set appropriate buffering on %s\n", filename);
@@ -3612,6 +3862,23 @@ static int handle_pri_no_debug(int fd, int argc, char *argv[])
return RESULT_SUCCESS;
}
+static int handle_pri_really_debug(int fd, int argc, char *argv[])
+{
+ int span;
+ span = atoi(argv[4]);
+ if ((span < 1) || (span > NUM_SPANS)) {
+ ast_cli(fd, "Invalid span %s. Should be a number %d to %d\n", argv[4], 1, NUM_SPANS);
+ return RESULT_SUCCESS;
+ }
+ if (!pris[span-1].pri) {
+ ast_cli(fd, "No PRI running on span %d\n", span);
+ return RESULT_SUCCESS;
+ }
+ pri_set_debug(pris[span-1].pri, (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE));
+ ast_cli(fd, "Enabled EXTENSIVE debugging on span %d\n", span);
+ return RESULT_SUCCESS;
+}
+
static char pri_debug_help[] =
"Usage: pri debug span <span>\n"
" Enables debugging on a given PRI span\n";
@@ -3620,6 +3887,10 @@ static char pri_no_debug_help[] =
"Usage: pri no debug span <span>\n"
" Disables debugging on a given PRI span\n";
+static char pri_really_debug_help[] =
+ "Usage: pri intensive debug span <span>\n"
+ " Enables debugging down to the Q.921 level\n";
+
#if 0
static struct ast_cli_entry cli_show_channel = {
{"zap", "show", "channel", NULL}, zap_show_channel, "Show the detailed status of a single zapata channel", show_channel_usage
@@ -3633,6 +3904,9 @@ 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 };
+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 };
+
#endif /* ZAPATA_PRI */
@@ -3742,14 +4016,16 @@ int load_module()
struct zt_pvt *tmp;
char *chan;
int start, finish,x;
-#ifdef ZAPATA_PRI
int y;
-#endif
#ifdef ZAPATA_PRI
+ int offset;
+
memset(pris, 0, sizeof(pris));
- for (y=0;y<NUM_SPANS;y++)
+ for (y=0;y<NUM_SPANS;y++) {
+ pris[y].offset = -1;
pris[y].fd = -1;
+ }
#endif
cfg = ast_load(config);
@@ -3816,6 +4092,8 @@ int load_module()
use_callerid = ast_true(v->value);
} else if (!strcasecmp(v->name, "threewaycalling")) {
threewaycalling = ast_true(v->value);
+ } else if (!strcasecmp(v->name, "adsi")) {
+ adsi = ast_true(v->value);
} else if (!strcasecmp(v->name, "transfer")) {
transfer = ast_true(v->value);
} else if (!strcasecmp(v->name, "echocancel")) {
@@ -3827,9 +4105,9 @@ int load_module()
} else if (!strcasecmp(v->name, "callwaitingcallerid")) {
callwaitingcallerid = ast_true(v->value);
} else if (!strcasecmp(v->name, "context")) {
- strncpy(context, v->value, sizeof(context));
+ strncpy(context, v->value, sizeof(context)-1);
} else if (!strcasecmp(v->name, "language")) {
- strncpy(language, v->value, sizeof(language));
+ strncpy(language, v->value, sizeof(language)-1);
} else if (!strcasecmp(v->name, "stripmsd")) {
stripmsd = atoi(v->value);
} else if (!strcasecmp(v->name, "group")) {
@@ -3852,7 +4130,15 @@ int load_module()
if (!strcasecmp(v->value, "asreceived"))
strcpy(callerid,"");
else
- strncpy(callerid, v->value, sizeof(callerid));
+ strncpy(callerid, v->value, sizeof(callerid)-1);
+ } else if (!strcasecmp(v->name, "accountcode")) {
+ strncpy(accountcode, v->value, sizeof(accountcode)-1);
+ } else if (!strcasecmp(v->name, "amaflags")) {
+ y = ast_cdr_amaflags2int(v->value);
+ if (y < 0)
+ ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d\n", v->value, v->lineno);
+ else
+ amaflags = y;
} else if (!strcasecmp(v->name, "signalling")) {
if (!strcasecmp(v->value, "em")) {
cur_signalling = SIG_EM;
@@ -3893,6 +4179,8 @@ int load_module()
switchtype = PRI_SWITCH_ATT4ESS;
else if (!strcasecmp(v->value, "5ess"))
switchtype = PRI_SWITCH_LUCENT5E;
+ else if (!strcasecmp(v->value, "euroisdn"))
+ switchtype = PRI_SWITCH_EUROISDN_E1;
else {
ast_log(LOG_ERROR, "Unknown switchtype '%s'\n", v->value);
ast_destroy(cfg);
@@ -3922,9 +4210,13 @@ int load_module()
ast_destroy(cfg);
#ifdef ZAPATA_PRI
for (x=0;x<NUM_SPANS;x++) {
- for (y=1;y<23;y++) {
+ for (y=1;y<pris[x].channels;y++) {
if (pris[x].chanmask[y]) {
- pris[x].offset = x * 24;
+ offset = pris[x].pvt[y]->channel - y;
+ if ((pris[x].offset > -1) && (pris[x].offset != offset)) {
+ ast_log(LOG_WARNING, "Huh?? Offset mismatch...\n");
+ }
+ pris[x].offset = offset;
pris[x].span = x + 1;
if (start_pri(pris + x)) {
ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
@@ -3937,6 +4229,7 @@ int load_module()
}
ast_cli_register(&pri_debug);
ast_cli_register(&pri_no_debug);
+ ast_cli_register(&pri_really_debug);
#endif
ast_cli_register(&cli_show_channels);
ast_cli_register(&cli_show_channel);
@@ -4035,6 +4328,9 @@ static int reload_zt(void)
txgain = 0.0;
firstdigittimeout = 16000;
gendigittimeout = 8000;
+ amaflags = 0;
+ adsi = 0;
+ strncpy(accountcode, "", sizeof(accountcode)-1);
// usecnt = 0;
#if 0
@@ -4134,9 +4430,9 @@ static int reload_zt(void)
} else if (!strcasecmp(v->name, "callwaitingcallerid")) {
callwaitingcallerid = ast_true(v->value);
} else if (!strcasecmp(v->name, "context")) {
- strncpy(context, v->value, sizeof(context));
+ strncpy(context, v->value, sizeof(context)-1);
} else if (!strcasecmp(v->name, "language")) {
- strncpy(language, v->value, sizeof(language));
+ strncpy(language, v->value, sizeof(language)-1);
} else if (!strcasecmp(v->name, "stripmsd")) {
stripmsd = atoi(v->value);
} else if (!strcasecmp(v->name, "group")) {
@@ -4159,7 +4455,7 @@ static int reload_zt(void)
if (!strcasecmp(v->value, "asreceived"))
strcpy(callerid,"");
else
- strncpy(callerid, v->value, sizeof(callerid));
+ strncpy(callerid, v->value, sizeof(callerid)-1);
} else if (!strcasecmp(v->name, "signalling")) {
if (!strcasecmp(v->value, "em")) {
cur_signalling = SIG_EM;
@@ -4256,6 +4552,74 @@ static int reload_zt(void)
return 0;
}
+static int zt_sendtext(struct ast_channel *c, char *text)
+{
+#define END_SILENCE_LEN 400
+
+ unsigned char *buf,*mybuf;
+ struct zt_pvt *p = c->pvt->pvt;
+ fd_set wfds,efds;
+ int size,res,fd,len;
+
+ 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 (!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;
+ }
+ memset(buf + len,0x7f,END_SILENCE_LEN);
+ len += END_SILENCE_LEN;
+ if (c != p->owner) /* if in three-way */
+ fd = zap_fd(p->pseudo);
+ else
+ fd = zap_fd(p->z);
+ while(len) {
+ if (ast_check_hangup(c)) {
+ free(mybuf);
+ return -1;
+ }
+ size = len;
+ if (size > READ_SIZE)
+ size = READ_SIZE;
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ FD_SET(fd,&wfds);
+ FD_SET(fd,&efds);
+ res = select(fd + 1,NULL,&wfds,&efds,NULL);
+ if (!res) {
+ ast_log(LOG_DEBUG, "select (for write) ret. 0 on channel %d\n", p->channel);
+ continue;
+ }
+ /* if got exception */
+ if (FD_ISSET(fd,&efds)) return -1;
+ if (!FD_ISSET(fd,&wfds)) {
+ ast_log(LOG_DEBUG, "write fd not ready on channel %d\n", p->channel);
+ continue;
+ }
+ res = write(fd, buf, size);
+ if (res != size) {
+ if (res == -1) {
+ free(mybuf);
+ return -1;
+ }
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
+ break;
+ }
+ len -= size;
+ buf += size;
+ }
+ free(mybuf);
+ return(0);
+}
+
#if 0
/* XXX Very broken on PRI XXX */
int reload(void)