- ccbsnr struct is now allocated, no static array any more.
- added command to set the local party to 'busy' or 'free' status.
This commit is contained in:
parent
fd795e17da
commit
60f76b3c70
33
README
33
README
|
@ -208,6 +208,32 @@ Peer link creation:
|
||||||
Example:
|
Example:
|
||||||
exten => s,1,capicommand(peerlink)
|
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
|
Using CLIR
|
||||||
==========
|
==========
|
||||||
Use the SetCallerPres() application before you dial:
|
Use the SetCallerPres() application before you dial:
|
||||||
|
@ -368,8 +394,15 @@ CALLINGSUBADDRESS
|
||||||
CALLEDSUBADDRESS
|
CALLEDSUBADDRESS
|
||||||
If set on dial(), the called subaddress will be set to the content.
|
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
|
CCLINKAGEID
|
||||||
If a Call-Linkage-Id is received for CCBS/CCNR, this variable contains this Id.
|
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
|
CONNECTEDNUMBER
|
||||||
Can be set before answering and if set, the content is used for
|
Can be set before answering and if set, the content is used for
|
||||||
|
|
26
chan_capi.c
26
chan_capi.c
|
@ -2819,7 +2819,7 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
||||||
/*
|
/*
|
||||||
* CAPI FACILITY_IND line interconnect
|
* 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)
|
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||||
{
|
{
|
||||||
if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x01) &&
|
if ((FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1] == 0x01) &&
|
||||||
|
@ -2832,12 +2832,13 @@ static void handle_facility_indication_line_interconnect(
|
||||||
(FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] > 8)) {
|
(FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[0] > 8)) {
|
||||||
show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[8]));
|
show_capi_info(i, read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[8]));
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CAPI FACILITY_IND dtmf received
|
* 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)
|
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||||
{
|
{
|
||||||
struct ast_frame fr = { AST_FRAME_NULL, };
|
struct ast_frame fr = { AST_FRAME_NULL, };
|
||||||
|
@ -2868,6 +2869,7 @@ static void handle_facility_indication_dtmf(
|
||||||
dtmflen--;
|
dtmflen--;
|
||||||
dtmfpos++;
|
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)
|
static void capidev_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||||
{
|
{
|
||||||
_cmsg CMSG2;
|
_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)) {
|
switch (FACILITY_IND_FACILITYSELECTOR(CMSG)) {
|
||||||
case FACILITYSELECTOR_LINE_INTERCONNECT:
|
case FACILITYSELECTOR_LINE_INTERCONNECT:
|
||||||
return_on_no_interface("FACILITY_IND LI");
|
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;
|
break;
|
||||||
case FACILITYSELECTOR_DTMF:
|
case FACILITYSELECTOR_DTMF:
|
||||||
return_on_no_interface("FACILITY_IND 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;
|
break;
|
||||||
case FACILITYSELECTOR_SUPPLEMENTARY:
|
case FACILITYSELECTOR_SUPPLEMENTARY:
|
||||||
handle_facility_indication_supplementary(CMSG, PLCI, NCCI, i);
|
resp_done = handle_facility_indication_supplementary(CMSG, PLCI, NCCI, i);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND selector %d\n",
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND selector %d\n",
|
||||||
(i) ? i->vname:"???", FACILITY_IND_FACILITYSELECTOR(CMSG));
|
(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 },
|
{ "ect", pbx_capi_ect, 1 },
|
||||||
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
||||||
{ "ccbs", pbx_capi_ccbs, 0 },
|
{ "ccbs", pbx_capi_ccbs, 0 },
|
||||||
|
{ "ccpartybusy", pbx_capi_ccpartybusy, 0 },
|
||||||
{ "qsig_ssct", pbx_capi_qsig_ssct, 1 },
|
{ "qsig_ssct", pbx_capi_qsig_ssct, 1 },
|
||||||
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
||||||
{ "qsig_callmark",pbx_capi_qsig_callmark, 1 },
|
{ "qsig_callmark",pbx_capi_qsig_callmark, 1 },
|
||||||
|
|
|
@ -20,8 +20,7 @@
|
||||||
#include "chan_capi_supplementary.h"
|
#include "chan_capi_supplementary.h"
|
||||||
#include "chan_capi_utils.h"
|
#include "chan_capi_utils.h"
|
||||||
|
|
||||||
#define CCBSNR_MAX_LIST_ENTRIES 32
|
static struct ccbsnr_s *ccbsnr_list = NULL;
|
||||||
static struct ccbsnr_s ccbsnr_list[CCBSNR_MAX_LIST_ENTRIES];
|
|
||||||
AST_MUTEX_DEFINE_STATIC(ccbsnr_lock);
|
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,
|
static void new_ccbsnr_id(ccbsnrtype_t type, unsigned int plci,
|
||||||
_cword id, struct capi_pvt *i)
|
_cword id, struct capi_pvt *i)
|
||||||
{
|
{
|
||||||
int a;
|
|
||||||
char buffer[CAPI_MAX_STRING];
|
char buffer[CAPI_MAX_STRING];
|
||||||
|
struct ccbsnr_s *ccbsnr;
|
||||||
|
|
||||||
cc_mutex_lock(&ccbsnr_lock);
|
ccbsnr = malloc(sizeof(struct ccbsnr_s));
|
||||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
if (ccbsnr == NULL) {
|
||||||
if (ccbsnr_list[a].type == CCBSNR_TYPE_NULL) {
|
cc_log(LOG_ERROR, "Unable to allocate CCBS/CCNR struct.\n");
|
||||||
ccbsnr_list[a].type = type;
|
return;
|
||||||
ccbsnr_list[a].id = id;
|
}
|
||||||
ccbsnr_list[a].plci = plci;
|
memset(ccbsnr, 0, sizeof(struct ccbsnr_s));
|
||||||
ccbsnr_list[a].state = CCBSNR_AVAILABLE;
|
|
||||||
ccbsnr_list[a].handle = (id | ((plci & 0xff) << 16));
|
ccbsnr->type = type;
|
||||||
|
ccbsnr->id = id;
|
||||||
|
ccbsnr->plci = plci;
|
||||||
|
ccbsnr->state = CCBSNR_AVAILABLE;
|
||||||
|
ccbsnr->handle = (id | ((plci & 0xff) << 16));
|
||||||
|
|
||||||
if (i->peer) {
|
if (i->peer) {
|
||||||
snprintf(buffer, CAPI_MAX_STRING-1, "%u", ccbsnr_list[a].handle);
|
snprintf(buffer, CAPI_MAX_STRING-1, "%u", ccbsnr->handle);
|
||||||
pbx_builtin_setvar_helper(i->peer, "CCLINKAGEID", buffer);
|
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);
|
||||||
|
ccbsnr->next = ccbsnr_list;
|
||||||
|
ccbsnr_list = ccbsnr;
|
||||||
|
cc_mutex_unlock(&ccbsnr_lock);
|
||||||
|
|
||||||
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
ret = ret->next;
|
||||||
}
|
}
|
||||||
cc_mutex_unlock(&ccbsnr_lock);
|
cc_mutex_unlock(&ccbsnr_lock);
|
||||||
|
|
||||||
if (a == CCBSNR_MAX_LIST_ENTRIES) {
|
return ret;
|
||||||
cc_log(LOG_ERROR, "No free entry for new CCBS/CCNR ID\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return the pointer to ccbsnr structure by ref
|
||||||
|
*/
|
||||||
|
static struct ccbsnr_s *get_ccbsnr_linkref(_cword ref, char *busy)
|
||||||
|
{
|
||||||
|
struct ccbsnr_s *ret;
|
||||||
|
|
||||||
|
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,36 +114,13 @@ static void new_ccbsnr_id(ccbsnrtype_t type, unsigned int plci,
|
||||||
static int ccbsnr_tell_activated(void *data)
|
static int ccbsnr_tell_activated(void *data)
|
||||||
{
|
{
|
||||||
unsigned int handle = (unsigned int)data;
|
unsigned int handle = (unsigned int)data;
|
||||||
int a;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
unsigned int state;
|
||||||
|
|
||||||
cc_mutex_lock(&ccbsnr_lock);
|
if (get_ccbsnr_link(handle, &state) != NULL) {
|
||||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
if (state == CCBSNR_REQUESTED) {
|
||||||
if (ccbsnr_list[a].handle == handle) {
|
|
||||||
if (ccbsnr_list[a].state == CCBSNR_REQUESTED) {
|
|
||||||
ret = 1;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -102,29 +129,32 @@ static struct ccbsnr_s *get_ccbsnr_link(unsigned int handle)
|
||||||
/*
|
/*
|
||||||
* select CCBS/CCNR id
|
* 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)
|
char *context, char *exten, int priority)
|
||||||
{
|
{
|
||||||
|
struct ccbsnr_s *ccbsnr;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int a;
|
|
||||||
|
|
||||||
cc_mutex_lock(&ccbsnr_lock);
|
cc_mutex_lock(&ccbsnr_lock);
|
||||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
ccbsnr = ccbsnr_list;
|
||||||
if (((ccbsnr_list[a].plci & 0xff) == ((id >> 16) & 0xff)) &&
|
while (ccbsnr) {
|
||||||
(ccbsnr_list[a].id == (id & 0xffff)) &&
|
if (((ccbsnr->plci & 0xff) == ((id >> 16) & 0xff)) &&
|
||||||
(ccbsnr_list[a].type == type) &&
|
(ccbsnr->id == (id & 0xffff)) &&
|
||||||
(ccbsnr_list[a].state == CCBSNR_AVAILABLE)) {
|
(ccbsnr->type == type) &&
|
||||||
strncpy(ccbsnr_list[a].context, context, sizeof(ccbsnr_list[a].context) - 1);
|
(ccbsnr->state == CCBSNR_AVAILABLE)) {
|
||||||
strncpy(ccbsnr_list[a].exten, exten, sizeof(ccbsnr_list[a].exten) - 1);
|
strncpy(ccbsnr->context, context, sizeof(ccbsnr->context) - 1);
|
||||||
ccbsnr_list[a].priority = priority;
|
strncpy(ccbsnr->exten, exten, sizeof(ccbsnr->exten) - 1);
|
||||||
ccbsnr_list[a].state = CCBSNR_REQUESTED;
|
ccbsnr->priority = priority;
|
||||||
ret = ccbsnr_list[a].handle;
|
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",
|
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);
|
id, ret, context, exten, priority);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
ccbsnr = ccbsnr->next;
|
||||||
}
|
}
|
||||||
cc_mutex_unlock(&ccbsnr_lock);
|
cc_mutex_unlock(&ccbsnr_lock);
|
||||||
|
|
||||||
return ret;
|
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)
|
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);
|
cc_mutex_lock(&ccbsnr_lock);
|
||||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
ccbsnr = ccbsnr_list;
|
||||||
if (((ccbsnr_list[a].plci & 0xff) == (plci & 0xff)) &&
|
while (ccbsnr) {
|
||||||
(ccbsnr_list[a].rbref == ref)) {
|
if (((ccbsnr->plci & 0xff) == (plci & 0xff)) &&
|
||||||
ccbsnr_list[a].id = 0;
|
(ccbsnr->rbref == ref)) {
|
||||||
ccbsnr_list[a].state = 0;
|
if (!tmp) {
|
||||||
ccbsnr_list[a].handle = 0;
|
ccbsnr_list = ccbsnr->next;
|
||||||
ccbsnr_list[a].rbref = 0;
|
} else {
|
||||||
ccbsnr_list[a].plci = 0;
|
tmp->next = ccbsnr->next;
|
||||||
ccbsnr_list[a].type = CCBSNR_TYPE_NULL;
|
}
|
||||||
|
free(ccbsnr);
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR deactivated "
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR deactivated "
|
||||||
"ref=0x%04x\n", plci, ref);
|
"ref=0x%04x\n", plci, ref);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
tmp = ccbsnr;
|
||||||
|
ccbsnr = ccbsnr->next;
|
||||||
}
|
}
|
||||||
cc_mutex_unlock(&ccbsnr_lock);
|
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)
|
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);
|
cc_mutex_lock(&ccbsnr_lock);
|
||||||
for (a = 0; a < CCBSNR_MAX_LIST_ENTRIES; a++) {
|
ccbsnr = ccbsnr_list;
|
||||||
if (((ccbsnr_list[a].plci & 0xff) == (plci & 0xff)) &&
|
while (ccbsnr) {
|
||||||
(ccbsnr_list[a].id == id)) {
|
if (((ccbsnr->plci & 0xff) == (plci & 0xff)) &&
|
||||||
ccbsnr_list[a].id = 0;
|
(ccbsnr->id == id)) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR deleted id=0x%04x "
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "CAPI: PLCI=%#x CCBS/CCNR deleted id=0x%04x "
|
||||||
"handle=%d status=%d\n", plci, id,
|
"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;
|
break;
|
||||||
}
|
}
|
||||||
|
tmp = ccbsnr;
|
||||||
|
ccbsnr = ccbsnr->next;
|
||||||
}
|
}
|
||||||
cc_mutex_unlock(&ccbsnr_lock);
|
cc_mutex_unlock(&ccbsnr_lock);
|
||||||
}
|
}
|
||||||
|
@ -216,7 +257,7 @@ void ListenOnSupplementary(unsigned controller)
|
||||||
/*
|
/*
|
||||||
* CAPI FACILITY_IND supplementary services
|
* 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)
|
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i)
|
||||||
{
|
{
|
||||||
_cword function;
|
_cword function;
|
||||||
|
@ -226,6 +267,8 @@ void handle_facility_indication_supplementary(
|
||||||
_cword mode;
|
_cword mode;
|
||||||
_cword rbref;
|
_cword rbref;
|
||||||
struct ccbsnr_s *ccbsnrlink;
|
struct ccbsnr_s *ccbsnrlink;
|
||||||
|
char partybusy = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
function = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]);
|
function = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[1]);
|
||||||
length = FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[3];
|
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 "
|
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",
|
"handle=%d mode=0x%x rbref=0x%x\n",
|
||||||
PLCI & 0xff, PLCI, infoword, handle, mode, rbref);
|
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");
|
cc_log(LOG_WARNING, "capi ccbs request indication without request!\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -258,17 +301,26 @@ void handle_facility_indication_supplementary(
|
||||||
}
|
}
|
||||||
show_capi_info(NULL, infoword);
|
show_capi_info(NULL, infoword);
|
||||||
break;
|
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 */
|
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",
|
cc_verbose(1, 1, VERBOSE_PREFIX_3 "contr%d: PLCI=%#x CCBS/CCNR erase id=0x%04x\n",
|
||||||
PLCI & 0xff, PLCI, infoword);
|
PLCI & 0xff, PLCI, infoword);
|
||||||
del_ccbsnr_id(PLCI, infoword);
|
del_ccbsnr_id(PLCI, infoword);
|
||||||
break;
|
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 */
|
case 0x800f: /* CCBS remote user free */
|
||||||
rbref = read_capi_word(&FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG)[6]);
|
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",
|
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;
|
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 */
|
/* now functions bound to interface */
|
||||||
switch (function) {
|
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",
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: unhandled FACILITY_IND supplementary function %04x\n",
|
||||||
i->vname, function);
|
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'
|
* capicommand 'ccbs'
|
||||||
*/
|
*/
|
||||||
|
@ -408,11 +503,11 @@ int pbx_capi_ccbs(struct ast_channel *c, char *data)
|
||||||
{
|
{
|
||||||
char *slinkageid, *context, *exten, *priority;
|
char *slinkageid, *context, *exten, *priority;
|
||||||
unsigned int linkid = 0;
|
unsigned int linkid = 0;
|
||||||
int handle, a;
|
unsigned int handle, a;
|
||||||
char *result = "ERROR";
|
char *result = "ERROR";
|
||||||
char *goodresult = "ACTIVATED";
|
char *goodresult = "ACTIVATED";
|
||||||
MESSAGE_EXCHANGE_ERROR error;
|
MESSAGE_EXCHANGE_ERROR error;
|
||||||
struct ccbsnr_s *ccbsnrlink;
|
unsigned int ccbsnrstate;
|
||||||
|
|
||||||
slinkageid = strsep(&data, "|");
|
slinkageid = strsep(&data, "|");
|
||||||
context = strsep(&data, "|");
|
context = strsep(&data, "|");
|
||||||
|
@ -454,8 +549,8 @@ int pbx_capi_ccbs(struct ast_channel *c, char *data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ccbsnrlink = get_ccbsnr_link(handle)) != NULL) {
|
if (get_ccbsnr_link(handle, &ccbsnrstate) != NULL) {
|
||||||
if (ccbsnrlink->state == CCBSNR_ACTIVATED) {
|
if (ccbsnrstate == CCBSNR_ACTIVATED) {
|
||||||
result = goodresult;
|
result = goodresult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,19 +32,22 @@ struct ccbsnr_s {
|
||||||
unsigned int handle;
|
unsigned int handle;
|
||||||
_cword mode;
|
_cword mode;
|
||||||
_cword rbref;
|
_cword rbref;
|
||||||
|
char partybusy;
|
||||||
char context[AST_MAX_CONTEXT];
|
char context[AST_MAX_CONTEXT];
|
||||||
char exten[AST_MAX_EXTENSION];
|
char exten[AST_MAX_EXTENSION];
|
||||||
int priority;
|
int priority;
|
||||||
|
struct ccbsnr_s *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* prototypes
|
* prototypes
|
||||||
*/
|
*/
|
||||||
extern void ListenOnSupplementary(unsigned controller);
|
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);
|
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i);
|
||||||
extern void handle_facility_confirmation_supplementary(
|
extern void handle_facility_confirmation_supplementary(
|
||||||
_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i);
|
_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_ccbs(struct ast_channel *c, char *data);
|
||||||
|
extern int pbx_capi_ccpartybusy(struct ast_channel *c, char *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue