Introduce new Dial option 's' for stay-online mode to postpone the
DISCONNECT_REQ. capicommand(hangup) or a timeout will then really disconnect the line. This is needed for CCBS activation.V1_1
parent
767dd90bed
commit
e5b84d2052
10
README
10
README
|
@ -93,6 +93,10 @@ The Dial string
|
|||
(Useful if additional digits shall be send afterwards or together
|
||||
with 'b' to get dialtone and then send the number, e.g. if otherwise
|
||||
no progress tones are available)
|
||||
's' : activate 'stay-online': don't disconnect CAPI connection on Hangup.
|
||||
This is needed to give additional commands like CCBS after Hangup.
|
||||
To really hangup the CAPI connection, use either capicommand(hangup)
|
||||
or wait for chan-capi/network timeout (about 20 seconds).
|
||||
|
||||
If the <interface-name> is used in dialstring, be sure the name (specified
|
||||
in capi.conf) does not start with 'contr' or 'g'.
|
||||
|
@ -212,6 +216,12 @@ Peer link creation:
|
|||
Example:
|
||||
exten => s,1,capicommand(peerlink)
|
||||
|
||||
Hangup in mode 'stay-online':
|
||||
After hangup in 'stay-online' mode, the line isn't really disconnected
|
||||
until timeout or command:
|
||||
exten => s,1,capicommand(hangup)
|
||||
This works after capicommand(peerlink) only.
|
||||
|
||||
Set local party to 'busy' or 'free':
|
||||
Set the local phone to status to 'busy' or 'free' when
|
||||
awaiting a callback for CCBS/CCNR. If the network wants to
|
||||
|
|
154
chan_capi.c
154
chan_capi.c
|
@ -804,6 +804,8 @@ static void interface_cleanup(struct capi_pvt *i)
|
|||
i->isdnstate = 0;
|
||||
i->cause = 0;
|
||||
|
||||
i->whentohangup = 0;
|
||||
|
||||
i->FaxState &= ~CAPI_FAX_STATE_MASK;
|
||||
|
||||
i->PLCI = 0;
|
||||
|
@ -826,6 +828,7 @@ static void interface_cleanup(struct capi_pvt *i)
|
|||
|
||||
i->peer = NULL;
|
||||
i->owner = NULL;
|
||||
i->used = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -920,6 +923,23 @@ static void send_progress(struct capi_pvt *i)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* send disconnect_req
|
||||
*/
|
||||
static void capi_send_disconnect(unsigned int PLCI, struct capi_pvt *i)
|
||||
{
|
||||
_cmsg CMSG;
|
||||
|
||||
DISCONNECT_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
DISCONNECT_REQ_PLCI(&CMSG) = PLCI;
|
||||
|
||||
if (i) {
|
||||
_capi_put_cmsg_wait_conf(i, &CMSG);
|
||||
} else {
|
||||
_capi_put_cmsg(&CMSG);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* hangup a line (CAPI messages)
|
||||
* (this must be called with i->lock held)
|
||||
|
@ -952,6 +972,15 @@ static void capi_activehangup(struct ast_channel *c, int state)
|
|||
_capi_put_cmsg(&CMSG);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) {
|
||||
/* user has requested to leave channel online for further actions
|
||||
like CCBS */
|
||||
cc_verbose(2, 1, VERBOSE_PREFIX_4 "%s: disconnect deferred, stay-online mode PLCI=%#x\n",
|
||||
i->vname, i->PLCI);
|
||||
i->whentohangup = time(NULL) + 18; /* timeout 18 seconds */
|
||||
return;
|
||||
}
|
||||
|
||||
/* active disconnect */
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
|
||||
|
@ -965,9 +994,7 @@ static void capi_activehangup(struct ast_channel *c, int state)
|
|||
/* CONNECT_CONF not received yet? */
|
||||
capi_wait_conf(i, CAPI_CONNECT_CONF);
|
||||
}
|
||||
DISCONNECT_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
DISCONNECT_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
_capi_put_cmsg_wait_conf(i, &CMSG);
|
||||
capi_send_disconnect(i->PLCI, i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -1018,9 +1045,12 @@ static int pbx_capi_hangup(struct ast_channel *c)
|
|||
/* not disconnected yet, we must actively do it */
|
||||
capi_activehangup(c, state);
|
||||
}
|
||||
|
||||
i->owner = NULL;
|
||||
CC_CHANNEL_PVT(c) = NULL;
|
||||
|
||||
cc_mutex_unlock(&i->lock);
|
||||
|
||||
CC_CHANNEL_PVT(c) = NULL;
|
||||
ast_setstate(c, AST_STATE_DOWN);
|
||||
|
||||
#ifdef CC_AST_HAS_VERSION_1_4
|
||||
|
@ -1091,6 +1121,11 @@ static int pbx_capi_call(struct ast_channel *c, char *idest, int timeout)
|
|||
cc_log(LOG_WARNING, "Default CID already set in '%s'\n", idest);
|
||||
use_defaultcid = 1;
|
||||
break;
|
||||
case 's': /* stay online */
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_STAYONLINE))
|
||||
cc_log(LOG_WARNING, "'stay-online' already set in '%s'\n", idest);
|
||||
i->isdnstate |= CAPI_ISDN_STATE_STAYONLINE;
|
||||
break;
|
||||
case 'q': /* disable QSIG */
|
||||
cc_verbose(4, 0, VERBOSE_PREFIX_4 "%s: QSIG extensions for this call disabled\n",
|
||||
i->vname);
|
||||
|
@ -1856,6 +1891,7 @@ static struct ast_channel *capi_new(struct capi_pvt *i, int state)
|
|||
#endif
|
||||
|
||||
i->owner = tmp;
|
||||
i->used = tmp;
|
||||
|
||||
#ifdef CC_AST_HAS_VERSION_1_4
|
||||
ast_atomic_fetchadd_int(&usecnt, 1);
|
||||
|
@ -1886,7 +1922,6 @@ pbx_capi_request(const char *type, int format, void *data, int *cause)
|
|||
char buffer[CAPI_MAX_STRING];
|
||||
ast_group_t capigroup = 0;
|
||||
unsigned int controller = 0;
|
||||
int notfound = 1;
|
||||
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "data = %s format=%d\n", (char *)data, format);
|
||||
|
||||
|
@ -1914,8 +1949,8 @@ pbx_capi_request(const char *type, int format, void *data, int *cause)
|
|||
|
||||
cc_mutex_lock(&iflock);
|
||||
|
||||
for (i = iflist; (i && notfound); i = i->next) {
|
||||
if ((i->owner) || (i->channeltype != CAPI_CHANNELTYPE_B)) {
|
||||
for (i = iflist; i; i = i->next) {
|
||||
if ((i->used) || (i->channeltype != CAPI_CHANNELTYPE_B)) {
|
||||
/* if already in use or no real channel */
|
||||
continue;
|
||||
}
|
||||
|
@ -2362,11 +2397,11 @@ static void start_pbx_on_match(struct capi_pvt *i, unsigned int PLCI, _cword Mes
|
|||
return;
|
||||
}
|
||||
|
||||
switch(search_did(i->owner)) {
|
||||
switch(search_did(c)) {
|
||||
case 0: /* match */
|
||||
i->isdnstate |= CAPI_ISDN_STATE_PBX;
|
||||
ast_setstate(c, AST_STATE_RING);
|
||||
if (ast_pbx_start(i->owner)) {
|
||||
if (ast_pbx_start(c)) {
|
||||
cc_log(LOG_ERROR, "%s: Unable to start pbx on channel!\n",
|
||||
i->vname);
|
||||
capi_channel_task(c, CAPI_CHANNEL_TASK_HANGUP);
|
||||
|
@ -2468,8 +2503,6 @@ static void queue_cause_control(struct capi_pvt *i, int control)
|
|||
*/
|
||||
static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||
{
|
||||
_cmsg CMSG2;
|
||||
|
||||
i->isdnstate |= CAPI_ISDN_STATE_DISCONNECT;
|
||||
|
||||
if ((PLCI == i->onholdPLCI) || (i->isdnstate & CAPI_ISDN_STATE_ECT)) {
|
||||
|
@ -2477,9 +2510,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
i->vname);
|
||||
/* the caller onhold hung up (or ECTed away) */
|
||||
/* send a disconnect_req , we cannot hangup the channel here!!! */
|
||||
DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
DISCONNECT_REQ_PLCI(&CMSG2) = PLCI;
|
||||
_capi_put_cmsg(&CMSG2);
|
||||
capi_send_disconnect(PLCI, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2513,9 +2544,7 @@ static void capidev_handle_info_disconnect(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
i->vname);
|
||||
if (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
|
||||
/* in fax mode, we just hangup */
|
||||
DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
DISCONNECT_REQ_PLCI(&CMSG2) = i->PLCI;
|
||||
_capi_put_cmsg(&CMSG2);
|
||||
capi_send_disconnect(i->PLCI, NULL);
|
||||
return;
|
||||
}
|
||||
queue_cause_control(i, 0);
|
||||
|
@ -3262,13 +3291,14 @@ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PL
|
|||
}
|
||||
}
|
||||
|
||||
if ((i->state == CAPI_STATE_DISCONNECTING) ||
|
||||
((!(i->isdnstate & CAPI_ISDN_STATE_B3_SELECT)) &&
|
||||
(i->FaxState & CAPI_FAX_STATE_SENDMODE))) {
|
||||
/* active disconnect */
|
||||
DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0);
|
||||
DISCONNECT_REQ_PLCI(&CMSG2) = PLCI;
|
||||
_capi_put_cmsg(&CMSG2);
|
||||
if ((i->state == CAPI_STATE_DISCONNECTING)) {
|
||||
if (!(i->isdnstate & CAPI_ISDN_STATE_STAYONLINE)) {
|
||||
/* active disconnect */
|
||||
capi_send_disconnect(PLCI, NULL);
|
||||
}
|
||||
} else if ((!(i->isdnstate & CAPI_ISDN_STATE_B3_SELECT)) &&
|
||||
(i->FaxState & CAPI_FAX_STATE_SENDMODE)) {
|
||||
capi_send_disconnect(PLCI, NULL);
|
||||
}
|
||||
|
||||
capi_controllers[i->controller]->nfreebchannels++;
|
||||
|
@ -3421,8 +3451,8 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
|
|||
/* well...somebody is calling us. let's set up a channel */
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
if (i->owner) {
|
||||
/* has already owner */
|
||||
if (i->used) {
|
||||
/* is already used */
|
||||
continue;
|
||||
}
|
||||
if (i->controller != controller) {
|
||||
|
@ -4258,6 +4288,46 @@ static int pbx_capi_holdtype(struct ast_channel *c, char *param)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* send the disconnect commands to capi
|
||||
*/
|
||||
static void capi_disconnect(struct capi_pvt *i)
|
||||
{
|
||||
cc_mutex_lock(&i->lock);
|
||||
|
||||
i->isdnstate &= ~CAPI_ISDN_STATE_STAYONLINE;
|
||||
if ((i->isdnstate & CAPI_ISDN_STATE_B3_UP)) {
|
||||
cc_disconnect_b3(i, 0);
|
||||
} else {
|
||||
capi_send_disconnect(i->PLCI, NULL);
|
||||
}
|
||||
|
||||
cc_mutex_unlock(&i->lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* really hangup a channel if the stay-online mode was activated
|
||||
*/
|
||||
static int pbx_capi_realhangup(struct ast_channel *c, char *param)
|
||||
{
|
||||
struct capi_pvt *i;
|
||||
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
if (i->peer == c)
|
||||
break;
|
||||
}
|
||||
cc_mutex_unlock(&iflock);
|
||||
|
||||
if ((i) && (i->state == CAPI_STATE_DISCONNECTING)) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: capi command hangup PLCI=0x%#x.\n",
|
||||
i->vname, i->PLCI);
|
||||
capi_disconnect(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set early-B3 (progress) for incoming connections
|
||||
* (only for NT mode)
|
||||
|
@ -4392,6 +4462,7 @@ static struct capicommands_s {
|
|||
{ "ccbs", pbx_capi_ccbs, 0 },
|
||||
{ "ccbsstop", pbx_capi_ccbsstop, 0 },
|
||||
{ "ccpartybusy", pbx_capi_ccpartybusy, 0 },
|
||||
{ "hangup", pbx_capi_realhangup, 0 },
|
||||
{ "qsig_ssct", pbx_capi_qsig_ssct, 1 },
|
||||
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
||||
{ "qsig_callmark",pbx_capi_qsig_callmark, 1 },
|
||||
|
@ -4641,6 +4712,26 @@ static void capi_do_channel_task(void)
|
|||
channel_task = CAPI_CHANNEL_TASK_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* check for tasks every second
|
||||
*/
|
||||
static void capidev_run_secondly(time_t now)
|
||||
{
|
||||
struct capi_pvt *i;
|
||||
|
||||
/* check for channels to hangup (timeout) */
|
||||
cc_mutex_lock(&iflock);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
if ((i->used) && (i->whentohangup) && (i->whentohangup < now)) {
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: stay-online timeout, hanging up.\n",
|
||||
i->vname);
|
||||
i->whentohangup = 0;
|
||||
capi_disconnect(i);
|
||||
}
|
||||
}
|
||||
cc_mutex_unlock(&iflock);
|
||||
}
|
||||
|
||||
/*
|
||||
* module stuff, monitor...
|
||||
*/
|
||||
|
@ -4648,6 +4739,8 @@ static void *capidev_loop(void *data)
|
|||
{
|
||||
unsigned int Info;
|
||||
_cmsg monCMSG;
|
||||
time_t lastcall = 0;
|
||||
time_t newtime;
|
||||
|
||||
for (/* for ever */;;) {
|
||||
switch(Info = capidev_check_wait_get_cmsg(&monCMSG)) {
|
||||
|
@ -4669,6 +4762,11 @@ static void *capidev_loop(void *data)
|
|||
/* something is wrong! */
|
||||
break;
|
||||
} /* switch */
|
||||
newtime = time(NULL);
|
||||
if (lastcall != newtime) {
|
||||
lastcall = newtime;
|
||||
capidev_run_secondly(newtime);
|
||||
}
|
||||
} /* for */
|
||||
|
||||
/* never reached */
|
||||
|
@ -5679,8 +5777,8 @@ int unload_module(void)
|
|||
|
||||
i = iflist;
|
||||
while (i) {
|
||||
if (i->owner)
|
||||
cc_log(LOG_WARNING, "On unload, interface still has owner.\n");
|
||||
if ((i->owner) || (i->used))
|
||||
cc_log(LOG_WARNING, "On unload, interface still has owner or is used.\n");
|
||||
if (i->smoother)
|
||||
ast_smoother_free(i->smoother);
|
||||
cc_mutex_destroy(&i->lock);
|
||||
|
|
|
@ -243,7 +243,8 @@ struct cc_capi_gains {
|
|||
#define CAPI_ISDN_STATE_EC 0x00002000
|
||||
#define CAPI_ISDN_STATE_DTMF 0x00004000
|
||||
#define CAPI_ISDN_STATE_B3_SELECT 0x00008000
|
||||
#define CAPI_ISDN_STATE_3PTY 0x10000000
|
||||
#define CAPI_ISDN_STATE_STAYONLINE 0x00010000
|
||||
#define CAPI_ISDN_STATE_3PTY 0x10000000
|
||||
#define CAPI_ISDN_STATE_PBX_DONT 0x40000000
|
||||
#define CAPI_ISDN_STATE_PBX 0x80000000
|
||||
|
||||
|
@ -288,9 +289,10 @@ struct capi_pvt {
|
|||
char vname[CAPI_MAX_STRING];
|
||||
unsigned char tmpbuf[CAPI_MAX_STRING];
|
||||
|
||||
/*! Channel who used us, possibly NULL */
|
||||
struct ast_channel *used;
|
||||
/*! Channel we belong to, possibly NULL */
|
||||
struct ast_channel *owner;
|
||||
|
||||
/*! Channel who called us, possibly NULL */
|
||||
struct ast_channel *peer;
|
||||
|
||||
|
@ -413,6 +415,8 @@ struct capi_pvt {
|
|||
unsigned int reason;
|
||||
unsigned int reasonb3;
|
||||
|
||||
time_t whentohangup;
|
||||
|
||||
/* RTP */
|
||||
struct ast_rtp *rtp;
|
||||
int capability;
|
||||
|
|
|
@ -223,30 +223,27 @@ MESSAGE_EXCHANGE_ERROR capidev_check_wait_get_cmsg(_cmsg *CMSG)
|
|||
MESSAGE_EXCHANGE_ERROR Info;
|
||||
struct timeval tv;
|
||||
|
||||
repeat:
|
||||
Info = capi_get_cmsg(CMSG, capi_ApplID);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 500000;
|
||||
|
||||
#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2)
|
||||
/*
|
||||
* For BSD allow controller 0:
|
||||
*/
|
||||
if ((HEADER_CID(CMSG) & 0xFF) == 0) {
|
||||
HEADER_CID(CMSG) += capi_num_controllers;
|
||||
}
|
||||
#endif
|
||||
Info = capi20_waitformessage(capi_ApplID, &tv);
|
||||
|
||||
/* if queue is empty */
|
||||
if (Info == 0x1104) {
|
||||
/* try waiting a maximum of 0.100 seconds for a message */
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 10000;
|
||||
if (Info == 0x0000) {
|
||||
|
||||
Info = capi20_waitformessage(capi_ApplID, &tv);
|
||||
Info = capi_get_cmsg(CMSG, capi_ApplID);
|
||||
|
||||
if (Info == 0x0000)
|
||||
goto repeat;
|
||||
if (Info == 0x0000) {
|
||||
#if (CAPI_OS_HINT == 1) || (CAPI_OS_HINT == 2)
|
||||
/*
|
||||
* For BSD allow controller 0:
|
||||
*/
|
||||
if ((HEADER_CID(CMSG) & 0xFF) == 0) {
|
||||
HEADER_CID(CMSG) += capi_num_controllers;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ((Info != 0x0000) && (Info != 0x1104)) {
|
||||
if (capidebug) {
|
||||
cc_log(LOG_DEBUG, "Error waiting for cmsg... INFO = %#x\n", Info);
|
||||
|
|
Loading…
Reference in New Issue