- implemented support for decoding Call Transfer event - have clean up the code early
   Makes atm only debugging output of feature.
 - moved some code out of chan_capi.c
This commit is contained in:
MelwareDE 2007-06-07 19:24:32 +00:00
parent cae2b60cd4
commit bb3bbe31d3
7 changed files with 192 additions and 29 deletions

View File

@ -81,16 +81,19 @@ The QSIG support includes:
to see the name and number of his connected peer.
This should be configurable in the next release.
- decoding of incoming Call Transfer feature
Does nothing useful yet, only some debug output. It's now a small step to implement inbound Path Replacement.
Future Targets:
===============
- check code for buffer overflows
- Call Transfer inbound
- complete Call Transfer inbound
- Path Replacement inbound
- Allow/Disallow Path Replacement within capi.conf
- Call Rerouting feature [ECMA-174]
- CCBS
- AOC
- Sent out LEG_INFO2 - maybe this would allow an sendtext (display instructions on the connected set)
- Sent out LEG_INFO3 - maybe this would allow an sendtext (display instructions on the connected set)
- ...
How to use:
@ -111,3 +114,4 @@ ToDo List:
==========
- Support for inbound routing
- Enhance ASN1-97 Addressing Data Elements support - will save much code

View File

@ -3448,9 +3448,8 @@ static void capidev_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, un
pbx_builtin_setvar_helper(i->owner, "SECONDCALLERID", buffer);
*/
if (i->qsigfeat != QSIG_DISABLED) {
cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i);
}
/* Handle QSIG informations, if any */
cc_qsig_handle_capiind(CONNECT_IND_FACILITYDATAARRAY(CMSG), i);
if ((i->isdnmode == CAPI_ISDNMODE_MSN) && (i->immediate)) {
/* if we don't want to wait for SETUP/SENDING-COMPLETE in MSN mode */
@ -4859,11 +4858,9 @@ int mkif(struct cc_capi_conf *conf)
tmp->doDTMF = conf->softdtmf;
tmp->capability = conf->capability;
tmp->qsigfeat = conf->qsigfeat;
if (conf->qsigfeat) {
cc_qsig_interface_init(conf, tmp);
}
/* Initialize QSIG code */
cc_qsig_interface_init(conf, tmp);
tmp->next = capi_iflist; /* prepend */
capi_iflist = tmp;
cc_verbose(2, 0, VERBOSE_PREFIX_3 "capi %c %s (%s:%s) contr=%d devs=%d EC=%d,opt=%d,tail=%d\n",
@ -5734,8 +5731,7 @@ int unload_module(void)
if (i->smoother)
ast_smoother_free(i->smoother);
if (i->qsigfeat)
pbx_capi_qsig_unload_module(i);
pbx_capi_qsig_unload_module(i);
cc_mutex_destroy(&i->lock);
ast_cond_destroy(&i->event_trigger);

View File

@ -95,6 +95,7 @@
/* QSIG Operations += 1000 */
#define CCQSIG__ECMA__NAMEPRES 1000 /* Setting an own constant for ECMA Operation/Namepresentation, others will follow */
#define CCQSIG__ECMA__PRPROPOSE 1004 /* Path Replacement Propose */
#define CCQSIG__ECMA__CTCOMPLETE 1012 /* Call Transfer Complete */
#define CCQSIG__ECMA__LEGINFO2 1021 /* LEG INFORMATION2 */
@ -195,5 +196,6 @@ extern void cc_qsig_encode_ecma_prpropose(unsigned char * buf, unsigned int *idx
extern void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param);
extern void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param, int info);
extern char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
#endif

View File

@ -25,6 +25,7 @@
#include <asterisk/options.h>
#include "chan_capi20.h"
#include "chan_capi.h"
#include "chan_capi_utils.h"
#include "chan_capi_qsig.h"
#include "chan_capi_qsig_asn197ade.h"
@ -48,12 +49,17 @@ unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx,
numtype = (data[myidx++] & 0x0F); /* defines type of Number: numDigits, publicPartyNum, nsapEncNum, dataNumDigits */
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */
switch (numtype){
case 0:
if (data[myidx++] > 0) /* length of this context data */
if (data[myidx++] == ASN1_TC_CONTEXTSPEC)
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1;
if (data[myidx] > 0) { /* length of this context data */
if (data[myidx+1] == ASN1_TC_CONTEXTSPEC) {
myidx += 2;
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
} else {
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
}
}
break;
case 1: /* publicPartyNumber (E.164) not supported yet */
return 0;
@ -62,9 +68,14 @@ unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx,
return 0;
break;
case 3:
if (data[myidx++] > 0) /* length of this context data */
if (data[myidx++] == ASN1_TC_CONTEXTSPEC)
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data) + 1;
if (data[myidx++] > 0) { /* length of this context data */
if (data[myidx+1] == ASN1_TC_CONTEXTSPEC) {
myidx += 2;
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
} else {
myidx += cc_qsig_asn197ade_get_numdigits(buf, buflen, &myidx, data);
}
}
break;
};
return myidx - *idx;
@ -84,7 +95,7 @@ unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, un
memcpy(buf, &data[myidx], strsize);
buf[strsize] = 0;
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i\n", strsize); */
// cc_verbose(1, 1, VERBOSE_PREFIX_4 " * string length %i\n", strsize);
return strsize;
}

View File

@ -22,6 +22,11 @@
#define ASN197ADE_NUMDIGITS_STRSIZE 20
struct asn197ade_numberscreened {
unsigned char *partyNumber;
enum screeningInd { userProvidedNotScreened, userProvidedVerifiedAndPassed, userProvidedVerifiedAndFailed, networkProvided };
};
extern unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, unsigned char *data);
extern unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, unsigned char *data);

View File

@ -483,6 +483,8 @@ static int ident_qsig_invoke(int invoketype)
return CCQSIG__ECMA__NAMEPRES;
case 4:
return CCQSIG__ECMA__PRPROPOSE;
case 12:
return CCQSIG__ECMA__CTCOMPLETE;
case 21:
return CCQSIG__ECMA__LEGINFO2;
default:
@ -572,9 +574,19 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
}
static void pbx_capi_qsig_handle_ctc(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
char *destination = cc_qsig_decode_ecma_calltransfer(invoke, i);
if (destination) {
free(destination);
}
return ;
}
/*
*
* Handle inbound INVOKEs
*/
unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
@ -585,6 +597,9 @@ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invo
case CCQSIG__ECMA__PRPROPOSE:
cc_qsig_op_ecma_isdn_prpropose(invoke, i);
break;
case CCQSIG__ECMA__CTCOMPLETE:
pbx_capi_qsig_handle_ctc(invoke, i);
break;
case CCQSIG__ECMA__LEGINFO2:
cc_qsig_op_ecma_isdn_leginfo2(invoke, i);
break;
@ -647,6 +662,9 @@ unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i)
int faclen = 0;
int facidx = 2;
if (!i->qsigfeat)
return 0;
if (!data) {
return 0;
}
@ -965,14 +983,14 @@ int pbx_capi_qsig_ct(struct ast_channel *c, char *param)
cc_qsig_do_facility(fac, c, param, 12, 0);
capi_sendf(NULL, 0, CAPI_INFO_REQ, ii->PLCI, get_capi_MessageNumber(),
"()(()()()s)",
"()(()()()s())",
fac
);
cc_qsig_do_facility(fac, c, param, 12, 1);
capi_sendf(NULL, 0, CAPI_INFO_REQ, i->PLCI, get_capi_MessageNumber(),
"()(()()()s)",
"()(()()()s())",
fac
);
@ -980,7 +998,7 @@ int pbx_capi_qsig_ct(struct ast_channel *c, char *param)
}
/*
* Initiate a QSIG Call Transfer
* mark an call
*/
int pbx_capi_qsig_callmark(struct ast_channel *c, char *param)
{
@ -1025,6 +1043,10 @@ static void send_feature_calltransfer(struct capi_pvt *i)
*/
void cc_qsig_interface_init(struct cc_capi_conf *conf, struct capi_pvt *tmp)
{
tmp->qsigfeat = conf->qsigfeat;
if (!conf->qsigfeat)
return;
tmp->qsig_data.calltransfer_active = 0;
tmp->qsig_data.calltransfer = 0;
tmp->qsig_data.calltransfer_onring = 0;
@ -1088,6 +1110,8 @@ void interface_cleanup_qsig(struct capi_pvt *i)
*/
void pbx_capi_qsig_unload_module(struct capi_pvt *i)
{
if (!i->qsigfeat)
return;
ast_cond_destroy(&i->qsig_data.event_trigger);
}

View File

@ -144,12 +144,8 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru
invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */
invoke->type = 0; /* Invoke Operation Number, if OID it's the last byte*/
/* HACK: */
if (nametype)
invoke->type = 2;
if (namelen>0) {
data[dataidx++] = 0x80; /* We send only simple Name, Namepresentation allowed */
data[dataidx++] = 0x80 | (nametype % 4); /* We send only simple Name, Namepresentation allowed */
data[dataidx++] = namelen;
memcpy(&data[dataidx], namebuf, namelen);
dataidx += namelen;
@ -416,6 +412,131 @@ void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, st
}
/*
* Decode Operation: 1.3.12.9.12 ECMA/ISDN/CALLTRANSFER
*
* This function decodes the call transfer facility
*
* We create an invoke struct with the complete encoded invoke.
*
* parameters
* buf is pointer to facility array, not used now
* idx current idx in facility array, not used now
* invoke struct, which contains encoded data from facility
* i is pointer to capi channel
* returns
* transfer to destination number
*/
char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
{
unsigned int datalength;
unsigned int seqlength = 0;
unsigned char *data = invoke->data;
int myidx = 0;
/* TODO: write more code */
char *ct_status_txt[] = { "ANSWERED", "ALERTING" };
int ct_status = 0;
char ct_target[ASN197ADE_NUMDIGITS_STRSIZE+1] = { 0 };
char ct_name[ASN197NO_NAME_STRSIZE+1] = { "EMPTY" };
int ct_enddesignation = 0;
int ct_numberpresentation = 0;
unsigned int namelength = 0;
int temp = 0;
#define ct_err(x...) { cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - "x); return NULL; }
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG CALL TRANSFER (id# %#x)\n", invoke->id);
if (data[myidx++] != (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */
/* We do not handle this, because it should start with an sequence tag */
ct_err("not a sequence\n");
}
/* This facility is encoded as SEQUENCE */
seqlength = data[myidx++];
datalength = invoke->datalen;
if (datalength < (seqlength+1)) {
ct_err("buffer error\n");
}
if (data[myidx++] == ASN1_ENUMERATED) {
ct_enddesignation = cc_qsig_asn1_get_integer(data, &myidx);
} else {
ct_err("no endDesignation information.\n");
}
if (data[myidx] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { /* Parameter 0: partyNumber - transferee number */
myidx ++;
temp = cc_qsig_asn197ade_get_partynumber(ct_target, ASN197ADE_NUMDIGITS_STRSIZE+1, &myidx, data);
if (temp)
myidx += temp + 1;
/* HACK: this has to be moved to _get_presentednumberscreened */
if (data[myidx++] == ASN1_ENUMERATED) {
ct_numberpresentation = cc_qsig_asn1_get_integer(data, &myidx);
} else {
ct_err("screeningIndicator is missing.\n");
return NULL;
}
} else {
myidx += 2; /* HACK: I've seen an IMPLICIT ade "numberNotAvailableDueToInterworking NULL" */
}
/* TODO: remove this code snippet, when it's 100% working */
/*
if (data[myidx++] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { */ /* Parameter 0: partyNumber - transferee number */
/* if (!data[myidx++]) /* length = 0 */
/* ct_err("No destination received.\n");
if (data[myidx++] != ASN1_TC_CONTEXTSPEC)
ct_err("No destination received.\n");
temp = cc_qsig_asn1_get_string((unsigned char*)&ct_target, sizeof(ct_target), &data[myidx]);
if (temp) {
myidx += temp + 1;
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - partyNumber expected (%i)\n", myidx);
return NULL;
}
if (data[myidx++] == ASN1_ENUMERATED) {
ct_numberpresentation = cc_qsig_asn1_get_integer(data, &myidx);
} else {
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - wrong encoded #2.\n");
return NULL;
}
}*/
if (myidx < datalength) {
if (data[myidx] == ASN1_TC_APPLICATION) {
/* ignore special Application Parameters - have no info about content */
myidx++;
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - ignoring application data (%i bytes).\n", (int)data[myidx]);
myidx += data[myidx] + 1;
}
}
if (myidx < datalength) {
if (data[myidx] != ASN1_ENUMERATED) { /* Maybe we get an name (OPTIONAL) */
myidx += cc_qsig_asn197no_get_name(ct_name, ASN197NO_NAME_STRSIZE+1, &namelength, &myidx, data );
}
}
if (myidx < datalength) {
if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */
ct_status = cc_qsig_asn1_get_integer(data, &myidx);
}
}
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got QSIG CALL TRANSFER endDesignation: %i partyNumber: %s (ScreeningInd: %i), partyName: \"%s\", Call state: %s\n", ct_enddesignation, ct_target, ct_numberpresentation, ct_name, ct_status_txt[ct_status]);
return strdup(ct_target);
#undef ct_err
}
/*
* Encode Operation: 1.3.12.9.99 ECMA/ISDN/SINGLESTEPCALLTRANSFER