- 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:
MelwareDE 2007-04-21 07:19:44 +00:00
parent fd795e17da
commit 60f76b3c70
4 changed files with 242 additions and 105 deletions

33
README
View File

@ -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

View File

@ -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 },

View File

@ -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;
} }
} }

View File

@ -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