diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 4e6c59132..f78c882ce 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -12,8 +12,8 @@ */ #include -#include #include +#include #include #include #include @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -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); + 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; } - 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; } 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;xtdd,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; } +