- ccbsnr struct is now allocated, no static array any more.
- added command to set the local party to 'busy' or 'free' status.V1_1
parent
fd795e17da
commit
60f76b3c70
33
README
33
README
|
@ -208,6 +208,32 @@ Peer link creation:
|
|||
Example:
|
||||
exten => s,1,capicommand(peerlink)
|
||||
|
||||
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
|
||||
call you back for CCBS/CCNR, chan-capi normaly doesn't know
|
||||
about the status of the extension who started the callback.
|
||||
By default chan-capi assumes 'free', but you can change that
|
||||
with:
|
||||
exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|yes)
|
||||
or
|
||||
exten => s,1,capicommand(ccpartybusy|${CCLINKAGEID}|no)
|
||||
|
||||
Call completion on subscriber busy (CCBS):
|
||||
To receive a callback when the dialed and busy party becomes free, aka
|
||||
call completion on subscriber busy, you can do the following:
|
||||
Example:
|
||||
exten => s,1,capicommand(peerlink) ;to let chan-capi know who is the calling channel.
|
||||
exten => s,2,Dial(CAPI/contr1/123456,60,g) ;'g' to go-on with the dialplan on busy.
|
||||
exten => s,3,NoOp(${CCLINKAGEID}) ;if this variable now contains a number, CCBS is possible.
|
||||
;here you can ask the caller if CCBS shall be activated...
|
||||
exten => s,4,capicommand(ccbs|${CCLINKAGEID}|<context>|<exten>|<priority>)
|
||||
exten => s,5,NoOp(${CCBSSTATUS}) ;if CCBS was successfully enabled, it is set to "ACTIVATED".
|
||||
If the remote party becomes 'non-busy', the network initiates the callback which will be
|
||||
sent to the provided context/exten/priority. Of course, this only happens if your local
|
||||
phone is set to 'free' with capicommand(ccpartybusy), which is the default.
|
||||
|
||||
|
||||
Using CLIR
|
||||
==========
|
||||
Use the SetCallerPres() application before you dial:
|
||||
|
@ -368,8 +394,15 @@ CALLINGSUBADDRESS
|
|||
CALLEDSUBADDRESS
|
||||
If set on dial(), the called subaddress will be set to the content.
|
||||
|
||||
CCBSSTATUS
|
||||
When using capicommand(ccbs|....), this variable is set to either "ERROR" or
|
||||
"ACTIVATED".
|
||||
|
||||
CCLINKAGEID
|
||||
If a Call-Linkage-Id is received for CCBS/CCNR, this variable contains this Id.
|
||||
But you need to use capicommand(peerlink) before dialing a CAPI channel, because
|
||||
of a design problem in Asterisk, chan-capi is not able to set channel variables
|
||||
of the calling channel.
|
||||
|
||||
CONNECTEDNUMBER
|
||||
Can be set before answering and if set, the content is used for
|
||||
|
|
28
chan_capi.c
28
chan_capi.c
|
@ -2819,7 +2819,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
/*
|
||||
* CAPI FACILITY_IND line interconnect
|
||||
*/
|
||||
static void handle_facility_indication_line_interconnect(
|
||||
static int handle_facility_indication_line_interconnect(
|
||||
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||
{
|
||||
if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x01) &&
|
||||
|
@ -2832,12 +2832,13 @@ static void handle_facility_indication_line_interconnect(
|
|||
(FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] > 8)) {
|
||||
show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[8]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* CAPI FACILITY_IND dtmf received
|
||||
*/
|
||||
static void handle_facility_indication_dtmf(
|
||||
static int handle_facility_indication_dtmf(
|
||||
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||
{
|
||||
struct ast_frame fr = { AST_FRAME_NULL, };
|
||||
|
@ -2867,7 +2868,8 @@ static void handle_facility_indication_dtmf(
|
|||
}
|
||||
dtmflen--;
|
||||
dtmfpos++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2876,28 +2878,31 @@ static void handle_facility_indication_dtmf(
|
|||
static void capidev_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||
{
|
||||
_cmsg CMSG2;
|
||||
int resp_done = 0;
|
||||
|
||||
FACILITY_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), PLCI);
|
||||
FACILITY_RESP_FACILITYSELECTOR(&CMSG2) = FACILITY_IND_FACILITYSELECTOR(CMSG);
|
||||
FACILITY_RESP_FACILITYRESPONSEPARAMETERS(&CMSG2) = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG);
|
||||
_capi_put_cmsg(&CMSG2);
|
||||
|
||||
switch (FACILITY_IND_FACILITYSELECTOR(CMSG)) {
|
||||
case FACILITYSELECTOR_LINE_INTERCONNECT:
|
||||
return_on_no_interface("FACILITY_IND LI");
|
||||
handle_facility_indication_line_interconnect(CMSG, PLCI, NCCI, i);
|
||||
resp_done = handle_facility_indication_line_interconnect(CMSG, PLCI, NCCI, i);
|
||||
break;
|
||||
case FACILITYSELECTOR_DTMF:
|
||||
return_on_no_interface("FACILITY_IND DTMF");
|
||||
handle_facility_indication_dtmf(CMSG, PLCI, NCCI, i);
|
||||
resp_done = handle_facility_indication_dtmf(CMSG, PLCI, NCCI, i);
|
||||
break;
|
||||
case FACILITYSELECTOR_SUPPLEMENTARY:
|
||||
handle_facility_indication_supplementary(CMSG, PLCI, NCCI, i);
|
||||
resp_done = handle_facility_indication_supplementary(CMSG, PLCI, NCCI, i);
|
||||
break;
|
||||
default:
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND selector %d\n",
|
||||
(i) ? i->vname:"???", FACILITY_IND_FACILITYSELECTOR(CMSG));
|
||||
}
|
||||
|
||||
if (!resp_done) {
|
||||
FACILITY_RESP_HEADER(&CMSG2, capi_ApplID, HEADER_MSGNUM(CMSG), PLCI);
|
||||
FACILITY_RESP_FACILITYSELECTOR(&CMSG2) = FACILITY_IND_FACILITYSELECTOR(CMSG);
|
||||
FACILITY_RESP_FACILITYRESPONSEPARAMETERS(&CMSG2) = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG);
|
||||
_capi_put_cmsg(&CMSG2);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4385,6 +4390,7 @@ static struct capicommands_s {
|
|||
{ "ect", pbx_capi_ect, 1 },
|
||||
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
||||
{ "ccbs", pbx_capi_ccbs, 0 },
|
||||
{ "ccpartybusy", pbx_capi_ccpartybusy, 0 },
|
||||
{ "qsig_ssct", pbx_capi_qsig_ssct, 1 },
|
||||
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
||||
{ "qsig_callmark",pbx_capi_qsig_callmark, 1 },
|
||||
|
|
|
@ -20,8 +20,7 @@
|
|||
#include "chan_capi_supplementary.h"
|
||||
#include "chan_capi_utils.h"
|
||||
|
||||
#define CCBSNR_MAX_LIST_ENTRIES 32
|
||||
static struct ccbsnr_s ccbsnr_list[CCBSNR_MAX_LIST_ENTRIES];
|
||||
static struct ccbsnr_s *ccbsnr_list = NULL;
|
||||
AST_MUTEX_DEFINE_STATIC(ccbsnr_lock);
|
||||
|
||||
/*
|
||||
|
@ -30,32 +29,83 @@ AST_MUTEX_DEFINE_STATIC(ccbsnr_lock);
|
|||
static void new_ccbsnr_id(ccbsnrtype_t type, unsigned int plci,
|
||||
_cword id, struct capi_pvt *i)
|
||||
{
|
||||
int a;
|
||||
char buffer[CAPI_MAX_STRING];
|
||||
struct ccbsnr_s *ccbsnr;
|
||||
|
||||
ccbsnr = malloc(sizeof(struct ccbsnr_s));
|
||||
if (ccbsnr == NULL) {
|
||||
cc_log(LOG_ERROR, "Unable to allocate CCBS/CCNR struct.\n");
|
||||
return;
|
||||
}
|
||||
memset(ccbsnr, 0, sizeof(struct ccbsnr_s));
|
||||
|
||||
ccbsnr->type = type;
|
||||
ccbsnr->id = id;
|
||||
ccbsnr->plci = plci;
|
||||
ccbsnr->state = CCBSNR_AVAILABLE;
|
||||
ccbsnr->handle = (id | ((plci & 0xff) << 16));
|
||||
|
||||
if (i->peer) {
|
||||
snprintf(buffer, CAPI_MAX_STRING-1, "%u", ccbsnr->handle);
|
||||
pbx_builtin_setvar_helper(i->peer, "CCLINKAGEID", buffer);
|
||||
} else {
|
||||
cc_log(LOG_NOTICE, "No peerlink found to set CCBS/CCNR linkage ID.\n");
|
||||
}
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
||||
if (ccbsnr_list[a].type == CCBSNR_TYPE_NULL) {
|
||||
ccbsnr_list[a].type = type;
|
||||
ccbsnr_list[a].id = id;
|
||||
ccbsnr_list[a].plci = plci;
|
||||
ccbsnr_list[a].state = CCBSNR_AVAILABLE;
|
||||
ccbsnr_list[a].handle = (id | ((plci & 0xff) << 16));
|
||||
ccbsnr->next = ccbsnr_list;
|
||||
ccbsnr_list = ccbsnr;
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
|
||||
if (i->peer) {
|
||||
snprintf(buffer, CAPI_MAX_STRING-1, "%u", ccbsnr_list[a].handle);
|
||||
pbx_builtin_setvar_helper(i->peer, "CCLINKAGEID", buffer);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3
|
||||
"%s: PLCI=%#x CCBS/CCNR new id=0x%04x handle=%d\n",
|
||||
i->vname, plci, id, ccbsnr->handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* return the pointer to ccbsnr structure by handle
|
||||
*/
|
||||
static struct ccbsnr_s *get_ccbsnr_link(unsigned int handle, unsigned int *state)
|
||||
{
|
||||
struct ccbsnr_s *ret;
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
ret = ccbsnr_list;
|
||||
while (ret) {
|
||||
if (ret->handle == handle) {
|
||||
if (state) {
|
||||
*state = ret->state;
|
||||
}
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "%s: PLCI=%#x CCBS/CCNR new id=0x%04x handle=%d\n",
|
||||
i->vname, plci, id, ccbsnr_list[a].handle);
|
||||
break;
|
||||
}
|
||||
ret = ret->next;
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the pointer to ccbsnr structure by ref
|
||||
*/
|
||||
static struct ccbsnr_s *get_ccbsnr_linkref(_cword ref, char *busy)
|
||||
{
|
||||
struct ccbsnr_s *ret;
|
||||
|
||||
if (a == CCBSNR_MAX_LIST_ENTRIES) {
|
||||
cc_log(LOG_ERROR, "No free entry for new CCBS/CCNR ID\n");
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
ret = ccbsnr_list;
|
||||
while (ret) {
|
||||
if (ret->rbref == ref) {
|
||||
if (busy) {
|
||||
*busy = ret->partybusy;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ret = ret->next;
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -64,35 +114,12 @@ static void new_ccbsnr_id(ccbsnrtype_t type, unsigned int plci,
|
|||
static int ccbsnr_tell_activated(void *data)
|
||||
{
|
||||
unsigned int handle = (unsigned int)data;
|
||||
int a;
|
||||
int ret = 0;
|
||||
unsigned int state;
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
||||
if (ccbsnr_list[a].handle == handle) {
|
||||
if (ccbsnr_list[a].state == CCBSNR_REQUESTED) {
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* return the pointer to ccbsnr structure
|
||||
*/
|
||||
static struct ccbsnr_s *get_ccbsnr_link(unsigned int handle)
|
||||
{
|
||||
struct ccbsnr_s *ret = NULL;
|
||||
int a;
|
||||
|
||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
||||
if (ccbsnr_list[a].handle == handle) {
|
||||
ret = &ccbsnr_list[a];
|
||||
break;
|
||||
if (get_ccbsnr_link(handle, &state) != NULL) {
|
||||
if (state == CCBSNR_REQUESTED) {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,29 +129,32 @@ static struct ccbsnr_s *get_ccbsnr_link(unsigned int handle)
|
|||
/*
|
||||
* select CCBS/CCNR id
|
||||
*/
|
||||
static int select_ccbsnr_id(unsigned int id, ccbsnrtype_t type,
|
||||
static unsigned int select_ccbsnr_id(unsigned int id, ccbsnrtype_t type,
|
||||
char *context, char *exten, int priority)
|
||||
{
|
||||
struct ccbsnr_s *ccbsnr;
|
||||
int ret = 0;
|
||||
int a;
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
||||
if (((ccbsnr_list[a].plci & 0xff) == ((id >> 16) & 0xff)) &&
|
||||
(ccbsnr_list[a].id == (id & 0xffff)) &&
|
||||
(ccbsnr_list[a].type == type) &&
|
||||
(ccbsnr_list[a].state == CCBSNR_AVAILABLE)) {
|
||||
strncpy(ccbsnr_list[a].context, context, sizeof(ccbsnr_list[a].context) - 1);
|
||||
strncpy(ccbsnr_list[a].exten, exten, sizeof(ccbsnr_list[a].exten) - 1);
|
||||
ccbsnr_list[a].priority = priority;
|
||||
ccbsnr_list[a].state = CCBSNR_REQUESTED;
|
||||
ret = ccbsnr_list[a].handle;
|
||||
ccbsnr = ccbsnr_list;
|
||||
while (ccbsnr) {
|
||||
if (((ccbsnr->plci & 0xff) == ((id >> 16) & 0xff)) &&
|
||||
(ccbsnr->id == (id & 0xffff)) &&
|
||||
(ccbsnr->type == type) &&
|
||||
(ccbsnr->state == CCBSNR_AVAILABLE)) {
|
||||
strncpy(ccbsnr->context, context, sizeof(ccbsnr->context) - 1);
|
||||
strncpy(ccbsnr->exten, exten, sizeof(ccbsnr->exten) - 1);
|
||||
ccbsnr->priority = priority;
|
||||
ccbsnr->state = CCBSNR_REQUESTED;
|
||||
ret = ccbsnr->handle;
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: request CCBS/NR id=0x%x handle=%d (%s,%s,%d)\n",
|
||||
id, ret, context, exten, priority);
|
||||
break;
|
||||
}
|
||||
ccbsnr = ccbsnr->next;
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -133,22 +163,26 @@ static int select_ccbsnr_id(unsigned int id, ccbsnrtype_t type,
|
|||
*/
|
||||
static void del_ccbsnr_ref(unsigned int plci, _cword ref)
|
||||
{
|
||||
int a;
|
||||
struct ccbsnr_s *ccbsnr;
|
||||
struct ccbsnr_s *tmp = NULL;
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
||||
if (((ccbsnr_list[a].plci & 0xff) == (plci & 0xff)) &&
|
||||
(ccbsnr_list[a].rbref == ref)) {
|
||||
ccbsnr_list[a].id = 0;
|
||||
ccbsnr_list[a].state = 0;
|
||||
ccbsnr_list[a].handle = 0;
|
||||
ccbsnr_list[a].rbref = 0;
|
||||
ccbsnr_list[a].plci = 0;
|
||||
ccbsnr_list[a].type = CCBSNR_TYPE_NULL;
|
||||
ccbsnr = ccbsnr_list;
|
||||
while (ccbsnr) {
|
||||
if (((ccbsnr->plci & 0xff) == (plci & 0xff)) &&
|
||||
(ccbsnr->rbref == ref)) {
|
||||
if (!tmp) {
|
||||
ccbsnr_list = ccbsnr->next;
|
||||
} else {
|
||||
tmp->next = ccbsnr->next;
|
||||
}
|
||||
free(ccbsnr);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR deactivated "
|
||||
"ref=0x%04x\n", plci, ref);
|
||||
break;
|
||||
}
|
||||
tmp = ccbsnr;
|
||||
ccbsnr = ccbsnr->next;
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
}
|
||||
|
@ -158,26 +192,33 @@ static void del_ccbsnr_ref(unsigned int plci, _cword ref)
|
|||
*/
|
||||
static void del_ccbsnr_id(unsigned int plci, _cword id)
|
||||
{
|
||||
int a;
|
||||
struct ccbsnr_s *ccbsnr;
|
||||
struct ccbsnr_s *tmp = NULL;
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
||||
if (((ccbsnr_list[a].plci & 0xff) == (plci & 0xff)) &&
|
||||
(ccbsnr_list[a].id == id)) {
|
||||
ccbsnr_list[a].id = 0;
|
||||
if ((ccbsnr_list[a].state == CCBSNR_AVAILABLE) ||
|
||||
(ccbsnr_list[a].rbref == 0)) {
|
||||
ccbsnr_list[a].state = 0;
|
||||
ccbsnr_list[a].handle = 0;
|
||||
ccbsnr_list[a].rbref = 0;
|
||||
ccbsnr_list[a].plci = 0;
|
||||
ccbsnr_list[a].type = CCBSNR_TYPE_NULL;
|
||||
}
|
||||
ccbsnr = ccbsnr_list;
|
||||
while (ccbsnr) {
|
||||
if (((ccbsnr->plci & 0xff) == (plci & 0xff)) &&
|
||||
(ccbsnr->id == id)) {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR deleted id=0x%04x "
|
||||
"handle=%d status=%d\n", plci, id,
|
||||
ccbsnr_list[a].handle, ccbsnr_list[a].state);
|
||||
ccbsnr->handle, ccbsnr->state);
|
||||
if ((ccbsnr->state == CCBSNR_AVAILABLE) ||
|
||||
(ccbsnr->rbref == 0)) {
|
||||
if (!tmp) {
|
||||
ccbsnr_list = ccbsnr->next;
|
||||
} else {
|
||||
tmp->next = ccbsnr->next;
|
||||
}
|
||||
free(ccbsnr);
|
||||
} else {
|
||||
/* just deactivate the linkage id */
|
||||
ccbsnr->id = 0xdead;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tmp = ccbsnr;
|
||||
ccbsnr = ccbsnr->next;
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
}
|
||||
|
@ -216,7 +257,7 @@ void ListenOnSupplementary(unsigned controller)
|
|||
/*
|
||||
* CAPI FACILITY_IND supplementary services
|
||||
*/
|
||||
void handle_facility_indication_supplementary(
|
||||
int handle_facility_indication_supplementary(
|
||||
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||
{
|
||||
_cword function;
|
||||
|
@ -226,6 +267,8 @@ void handle_facility_indication_supplementary(
|
|||
_cword mode;
|
||||
_cword rbref;
|
||||
struct ccbsnr_s *ccbsnrlink;
|
||||
char partybusy = 0;
|
||||
int ret = 0;
|
||||
|
||||
function = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]);
|
||||
length = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3];
|
||||
|
@ -243,7 +286,7 @@ void handle_facility_indication_supplementary(
|
|||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS request reason=0x%04x "
|
||||
"handle=%d mode=0x%x rbref=0x%x\n",
|
||||
PLCI & 0xff, PLCI, infoword, handle, mode, rbref);
|
||||
if ((ccbsnrlink = get_ccbsnr_link(handle)) == NULL) {
|
||||
if ((ccbsnrlink = get_ccbsnr_link(handle, NULL)) == NULL) {
|
||||
cc_log(LOG_WARNING, "capi ccbs request indication without request!\n");
|
||||
break;
|
||||
}
|
||||
|
@ -258,17 +301,26 @@ void handle_facility_indication_supplementary(
|
|||
}
|
||||
show_capi_info(NULL, infoword);
|
||||
break;
|
||||
case 0x800e: /* CCBS status */
|
||||
rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS status ref=0x%04x mode=0x%x\n",
|
||||
PLCI & 0xff, PLCI, rbref, infoword);
|
||||
/* XXX report we are free */
|
||||
break;
|
||||
case 0x800d: /* CCBS erase call linkage ID */
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS/CCNR erase id=0x%04x\n",
|
||||
PLCI & 0xff, PLCI, infoword);
|
||||
del_ccbsnr_id(PLCI, infoword);
|
||||
break;
|
||||
case 0x800e: /* CCBS status */
|
||||
rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS status ref=0x%04x mode=0x%x\n",
|
||||
PLCI & 0xff, PLCI, rbref, infoword);
|
||||
if (get_ccbsnr_linkref(rbref, &partybusy) == NULL) {
|
||||
cc_log(LOG_WARNING, "capi CCBS status reference not found!\n");
|
||||
}
|
||||
capi_sendf(NULL, 0, CAPI_FACILITY_RESP, PLCI, HEADER_MSGNUM(CMSG),
|
||||
"w(w(w))",
|
||||
FACILITYSELECTOR_SUPPLEMENTARY,
|
||||
0x800e, /* CCBS status */
|
||||
(partybusy) ? 0x0000 : 0x0001
|
||||
);
|
||||
ret = 1;
|
||||
break;
|
||||
case 0x800f: /* CCBS remote user free */
|
||||
rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS status ref=0x%04x mode=0x%x\n",
|
||||
|
@ -292,7 +344,11 @@ void handle_facility_indication_supplementary(
|
|||
break;
|
||||
}
|
||||
|
||||
return_on_no_interface("FACILITY_IND SUPPLEMENTARY");
|
||||
if (!i) {
|
||||
cc_verbose(4, 1, "CAPI: FACILITY_IND SUPPLEMENTARY "
|
||||
"no interface for PLCI=%#x\n", PLCI);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* now functions bound to interface */
|
||||
switch (function) {
|
||||
|
@ -362,6 +418,7 @@ void handle_facility_indication_supplementary(
|
|||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND supplementary function %04x\n",
|
||||
i->vname, function);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -401,6 +458,44 @@ void handle_facility_confirmation_supplementary(
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* capicommand 'ccpartybusy'
|
||||
*/
|
||||
int pbx_capi_ccpartybusy(struct ast_channel *c, char *data)
|
||||
{
|
||||
char *slinkageid, *yesno;
|
||||
unsigned int linkid = 0;
|
||||
struct ccbsnr_s *ccbsnr;
|
||||
char partybusy = 0;
|
||||
|
||||
slinkageid = strsep(&data, "|");
|
||||
yesno = data;
|
||||
|
||||
if (slinkageid) {
|
||||
linkid = (unsigned int)strtoul(slinkageid, NULL, 0);
|
||||
}
|
||||
|
||||
if ((yesno) && ast_true(yesno)) {
|
||||
partybusy = 1;
|
||||
}
|
||||
|
||||
cc_mutex_lock(&ccbsnr_lock);
|
||||
ccbsnr = ccbsnr_list;
|
||||
while (ccbsnr) {
|
||||
if (((ccbsnr->plci & 0xff) == ((linkid >> 16) & 0xff)) &&
|
||||
(ccbsnr->id == (linkid & 0xffff))) {
|
||||
ccbsnr->partybusy = partybusy;
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: CCBS/NR id=0x%x busy set to %d\n",
|
||||
linkid, partybusy);
|
||||
break;
|
||||
}
|
||||
ccbsnr = ccbsnr->next;
|
||||
}
|
||||
cc_mutex_unlock(&ccbsnr_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* capicommand 'ccbs'
|
||||
*/
|
||||
|
@ -408,11 +503,11 @@ int pbx_capi_ccbs(struct ast_channel *c, char *data)
|
|||
{
|
||||
char *slinkageid, *context, *exten, *priority;
|
||||
unsigned int linkid = 0;
|
||||
int handle, a;
|
||||
unsigned int handle, a;
|
||||
char *result = "ERROR";
|
||||
char *goodresult = "ACTIVATED";
|
||||
MESSAGE_EXCHANGE_ERROR error;
|
||||
struct ccbsnr_s *ccbsnrlink;
|
||||
unsigned int ccbsnrstate;
|
||||
|
||||
slinkageid = strsep(&data, "|");
|
||||
context = strsep(&data, "|");
|
||||
|
@ -454,8 +549,8 @@ int pbx_capi_ccbs(struct ast_channel *c, char *data)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if ((ccbsnrlink = get_ccbsnr_link(handle)) != NULL) {
|
||||
if (ccbsnrlink->state == CCBSNR_ACTIVATED) {
|
||||
if (get_ccbsnr_link(handle, &ccbsnrstate) != NULL) {
|
||||
if (ccbsnrstate == CCBSNR_ACTIVATED) {
|
||||
result = goodresult;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,19 +32,22 @@ struct ccbsnr_s {
|
|||
unsigned int handle;
|
||||
_cword mode;
|
||||
_cword rbref;
|
||||
char partybusy;
|
||||
char context[AST_MAX_CONTEXT];
|
||||
char exten[AST_MAX_EXTENSION];
|
||||
int priority;
|
||||
struct ccbsnr_s *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* prototypes
|
||||
*/
|
||||
extern void ListenOnSupplementary(unsigned controller);
|
||||
extern void handle_facility_indication_supplementary(
|
||||
extern int handle_facility_indication_supplementary(
|
||||
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i);
|
||||
extern void handle_facility_confirmation_supplementary(
|
||||
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i);
|
||||
extern int pbx_capi_ccbs(struct ast_channel *c, char *data);
|
||||
extern int pbx_capi_ccpartybusy(struct ast_channel *c, char *data);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue