From bb3bbe31d3d44f2247ce8d18e5ede50110800bbe Mon Sep 17 00:00:00 2001 From: MelwareDE Date: Thu, 7 Jun 2007 19:24:32 +0000 Subject: [PATCH] QSIG: - 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 --- README.qsig | 8 ++- chan_capi.c | 16 ++--- chan_capi_qsig.h | 2 + chan_capi_qsig_asn197ade.c | 27 +++++--- chan_capi_qsig_asn197ade.h | 5 ++ chan_capi_qsig_core.c | 32 +++++++-- chan_capi_qsig_ecma.c | 131 +++++++++++++++++++++++++++++++++++-- 7 files changed, 192 insertions(+), 29 deletions(-) diff --git a/README.qsig b/README.qsig index 20a0f87..d06dd52 100644 --- a/README.qsig +++ b/README.qsig @@ -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 diff --git a/chan_capi.c b/chan_capi.c index fc46d26..510568b 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -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); diff --git a/chan_capi_qsig.h b/chan_capi_qsig.h index 4c17353..0e21689 100644 --- a/chan_capi_qsig.h +++ b/chan_capi_qsig.h @@ -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 diff --git a/chan_capi_qsig_asn197ade.c b/chan_capi_qsig_asn197ade.c index 58ea285..a9e882a 100644 --- a/chan_capi_qsig_asn197ade.c +++ b/chan_capi_qsig_asn197ade.c @@ -25,6 +25,7 @@ #include #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; } diff --git a/chan_capi_qsig_asn197ade.h b/chan_capi_qsig_asn197ade.h index 15646b2..8bf9605 100644 --- a/chan_capi_qsig_asn197ade.h +++ b/chan_capi_qsig_asn197ade.h @@ -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); diff --git a/chan_capi_qsig_core.c b/chan_capi_qsig_core.c index 3751682..cf8f532 100644 --- a/chan_capi_qsig_core.c +++ b/chan_capi_qsig_core.c @@ -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); } diff --git a/chan_capi_qsig_ecma.c b/chan_capi_qsig_ecma.c index 229b24b..658c87c 100644 --- a/chan_capi_qsig_ecma.c +++ b/chan_capi_qsig_ecma.c @@ -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