diff --git a/README.qsig b/README.qsig index cbd57fb..1108dea 100644 --- a/README.qsig +++ b/README.qsig @@ -84,6 +84,13 @@ The QSIG support includes: - decoding of incoming Call Transfer feature Enables inbound Path Replacement. If received, an automatic Path Replacement with asterisk internal bridging will be fired. +- Support for sending CalledName + If in dialplan a variable CALLEDNAME was set, it will be sent out to the switch, while the asterisk extension is ringing. + +- Support for sending ConnectedName + If in dialplan a variable CONNECTEDNAME was set, it will be sent out to the switch AFTER connection is answered by asterisk + + Future Targets: =============== - check code for buffer overflows @@ -91,7 +98,7 @@ Future Targets: - Call Rerouting feature [ECMA-174] - CCBS - AOC -- Sent out LEG_INFO3 - maybe this would allow an sendtext (display instructions on the connected set) +- sendtext implementation (e.g. display instructions on the connected set) - ... How to use: diff --git a/chan_capi.c b/chan_capi.c index efcc232..0b79caf 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -779,6 +779,7 @@ static int pbx_capi_send_digit(struct ast_channel *c, char digit) static int pbx_capi_alert(struct ast_channel *c) { struct capi_pvt *i = CC_CHANNEL_PVT(c); + unsigned char *facilityarray = NULL; if ((i->state != CAPI_STATE_INCALL) && (i->state != CAPI_STATE_DID)) { @@ -787,8 +788,11 @@ static int pbx_capi_alert(struct ast_channel *c) return -1; } + facilityarray = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + cc_qsig_add_call_alert_data(facilityarray, i, c); + if (capi_sendf(NULL, 0, CAPI_ALERT_REQ, i->PLCI, get_capi_MessageNumber(), - "()") != 0) { + "(()()()s())", facilityarray) != 0) { return -1; } @@ -1311,6 +1315,7 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf) char buf[CAPI_MAX_STRING]; const char *dnid; const char *connectednumber; + unsigned char *facilityarray = NULL; if ((i->isdnmode == CAPI_ISDNMODE_DID) && ((strlen(i->incomingmsn) < strlen(i->dnid)) && @@ -1338,8 +1343,11 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf) cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Answering for %s\n", i->vname, dnid); + facilityarray = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + cc_qsig_add_call_answer_data(facilityarray, i, c); + if (capi_sendf(NULL, 0, CAPI_CONNECT_RESP, i->PLCI, i->MessageNumber, - "w(wwwssss)s()()()", + "w(wwwssss)s()()(()()()s())", 0, /* accept call */ /* B protocol */ b_protocol_table[i->bproto].b1protocol, @@ -1349,10 +1357,11 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf) b_protocol_table[i->bproto].b2configuration, b3conf, capi_set_global_configuration(i), - buf /* connected number */ + buf, /* connected number */ /* connected subaddress */ /* LLC */ /* Additional info */ + facilityarray ) != 0) { return -1; } @@ -5189,7 +5198,7 @@ const struct ast_channel_tech capi_tech = { #else .send_digit = pbx_capi_send_digit, #endif - .send_text = NULL, + .send_text = pbx_capi_qsig_sendtext, .call = pbx_capi_call, .hangup = pbx_capi_hangup, .answer = pbx_capi_answer, diff --git a/chan_capi_qsig.h b/chan_capi_qsig.h index 5ea7466..57c7f79 100644 --- a/chan_capi_qsig.h +++ b/chan_capi_qsig.h @@ -97,6 +97,7 @@ #define CCQSIG__ECMA__PRPROPOSE 1004 /* Path Replacement Propose */ #define CCQSIG__ECMA__CTCOMPLETE 1012 /* Call Transfer Complete */ #define CCQSIG__ECMA__LEGINFO2 1021 /* LEG INFORMATION2 */ +#define CCQSIG__ECMA__LEGINFO3 1022 /* LEG INFORMATION3 */ #define CCQSIG_TIMER_WAIT_PRPROPOSE 1 /* Wait x seconds */ @@ -167,6 +168,8 @@ extern signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struc extern unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i); extern unsigned int cc_qsig_handle_capi_facilityind(unsigned char *data, struct capi_pvt *i); extern unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c); +extern unsigned int cc_qsig_add_call_answer_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c); +extern unsigned int cc_qsig_add_call_alert_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c); extern unsigned int cc_qsig_add_call_facility_data(unsigned char *data, struct capi_pvt *i, int facility); extern signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protocol); @@ -179,6 +182,7 @@ extern int pbx_capi_qsig_ssct(struct ast_channel *c, char *param); extern int pbx_capi_qsig_ct(struct ast_channel *c, char *param); extern int pbx_capi_qsig_callmark(struct ast_channel *c, char *param); extern int pbx_capi_qsig_bridge(struct capi_pvt *i0, struct capi_pvt *i1); +extern int pbx_capi_qsig_sendtext(struct ast_channel *c, const char *text); extern void cc_qsig_interface_init(struct cc_capi_conf *conf, struct capi_pvt *tmp); diff --git a/chan_capi_qsig_core.c b/chan_capi_qsig_core.c index 1c61e3f..100a7f4 100644 --- a/chan_capi_qsig_core.c +++ b/chan_capi_qsig_core.c @@ -936,7 +936,7 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i } cc_qsig_build_facility_struct(data, &dataidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); - cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 0); + cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 0, i->owner->cid.cid_name); cc_qsig_add_invoke(data, &dataidx, &invoke, i); if (add_externalinfo) { @@ -950,6 +950,81 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i return 0; } +/* + * Handles outgoing Facilies on Call Answer + */ +unsigned int cc_qsig_add_call_answer_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c) +{ + struct cc_qsig_invokedata invoke; + struct cc_qsig_nfe nfe; + unsigned int dataidx = 0; + int protocolvar = 0; + const char *connectedname; + + if (!i->qsigfeat) + return 0; + + connectedname = pbx_builtin_getvar_helper(c, "CONNECTEDNAME"); + if (!strlen(connectedname)) + return 0; + + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + cc_qsig_build_facility_struct(data, &dataidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); + cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 2, (char *)connectedname); + cc_qsig_add_invoke(data, &dataidx, &invoke, i); + + return 1; +} + +/* + * Handles outgoing Facilies on Call Answer + */ +unsigned int cc_qsig_add_call_alert_data(unsigned char *data, struct capi_pvt *i, struct ast_channel *c) +{ + struct cc_qsig_invokedata invoke; + struct cc_qsig_nfe nfe; + unsigned int dataidx = 0; + int protocolvar = 0; + const char *connectedname; + + if (!i->qsigfeat) + return 0; + + connectedname = pbx_builtin_getvar_helper(c, "CALLEDNAME"); + if (!strlen(connectedname)) + return 0; + + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + cc_qsig_build_facility_struct(data, &dataidx, protocolvar, APDUINTERPRETATION_IGNORE, &nfe); + cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 1, (char *)connectedname); + cc_qsig_add_invoke(data, &dataidx, &invoke, i); + + return 1; +} /* * Handles outgoing Facilies on capicommand @@ -1301,6 +1376,44 @@ int pbx_capi_qsig_bridge(struct capi_pvt *i0,struct capi_pvt *i1) } +int pbx_capi_qsig_sendtext(struct ast_channel *c, const char *text) +{ + struct capi_pvt *i = CC_CHANNEL_PVT(c); + +#if 0 + /* suppress compiler warnings */ + unsigned char *data = alloca(CAPI_MAX_FACILITYDATAARRAY_SIZE); + unsigned int dataidx = 0; + struct cc_qsig_invokedata invoke; + struct cc_qsig_nfe nfe; +#endif + + int protocolvar = 0; + + if (!i->qsigfeat) + return 0; + + + if (!strlen(text)) + return 0; + + switch (i->qsigfeat) { + case QSIG_TYPE_ALCATEL_ECMA: + protocolvar = Q932_PROTOCOL_ROSE; + break; + case QSIG_TYPE_HICOM_ECMAV2: + protocolvar = Q932_PROTOCOL_EXTENSIONS; + break; + default: + cc_log(LOG_WARNING, " Unknown QSIG variant configured.\n"); + return 0; + break; + } + + /* TODO: implement something - QSIG_LEG_INFO3 doesn't work here */ + + return 0; +} /* * CAPI INFO_IND (QSIG part) diff --git a/chan_capi_qsig_ecma.c b/chan_capi_qsig_ecma.c index 422dd6b..da53ec7 100644 --- a/chan_capi_qsig_ecma.c +++ b/chan_capi_qsig_ecma.c @@ -116,15 +116,15 @@ void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct cap * returns * always 0 */ -int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype) +int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype, char * name) { unsigned char namebuf[51]; unsigned char data[255]; int dataidx = 0; int namelen = 0; - if (i->owner->cid.cid_name) - namelen = strlen(i->owner->cid.cid_name); + if (name) + namelen = strlen(name); if (namelen < 1) { /* There's no name available, try to take Interface-Name */ if (i->name) { @@ -138,15 +138,15 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru } else { if (namelen > 50) namelen = 50; - memcpy(namebuf, i->owner->cid.cid_name, namelen); + memcpy(namebuf, name, namelen); } invoke->id = 1; 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*/ + invoke->type = (nametype % 4); /* Invoke Operation Number, if OID it's the last byte*/ if (namelen>0) { - data[dataidx++] = 0x80 | (nametype % 4); /* We send only simple Name, Namepresentation allowed */ + data[dataidx++] = 0x80; /* We send only simple Name, Namepresentation allowed */ data[dataidx++] = namelen; memcpy(&data[dataidx], namebuf, namelen); dataidx += namelen; @@ -163,6 +163,76 @@ int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, stru return 0; } +/* + * Encode Operation: 1.3.12.9.22 ECMA/ISDN/LEG_INFO3 + * + * This function encodes the namepresentation facility + * The name will be copied from the cid.cid_name field of the asterisk channel struct. + * 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 for facility + * i is pointer to capi channel + * returns + * always 0 + */ +int cc_qsig_encode_ecma_isdn_leginfo3_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *name) +{ + unsigned char namebuf[51]; + unsigned char data[255]; + + int dataidx = 0; + int namelen = 0; + + if (name) + namelen = strlen(name); + + if (namelen < 1) { /* There's no name available, try to take Interface-Name */ + if (i->name) { + if (strlen(i->name) >= 1) { + if (namelen > 50) + namelen = 50; + namelen = strlen(i->name); + memcpy(namebuf, i->name, namelen); + } + } + } else { + if (namelen > 50) + namelen = 50; + memcpy(namebuf, name, namelen); + } + + invoke->id = 1; + invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */ + invoke->type = 22; /* Invoke Operation Number, if OID it's the last byte*/ + + data[dataidx++] = ASN1_TF_CONSTRUCTED | ASN1_SEQUENCE; + data[dataidx++] = 5 + namelen; + + data[dataidx++] = ASN1_BOOLEAN; /* PresentationAllowedIndicator */ + data[dataidx++] = 1; + data[dataidx++] = 1; + + if (namelen>0) { + data[dataidx++] = 0x80; /* We send only simple Name, Namepresentation allowed */ + data[dataidx++] = namelen; + memcpy(&data[dataidx], namebuf, namelen); + dataidx += namelen; + } else { + data[dataidx++] = 0x84; /* Name not available */ + data[dataidx++] = 0; + } + + invoke->datalen = dataidx; + memcpy(invoke->data, data, dataidx); + + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_LEG_INFO3 \"%s\": (%i byte(s))\n", namebuf, namelen); + + return 0; +} + /* * Handle Operation: 1.3.12.9.21 ECMA/ISDN/LEG_INFORMATION2 diff --git a/chan_capi_qsig_ecma.h b/chan_capi_qsig_ecma.h index ac76d62..bc246d0 100644 --- a/chan_capi_qsig_ecma.h +++ b/chan_capi_qsig_ecma.h @@ -41,7 +41,9 @@ struct cc_qsig_ctcomplete { */ extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); -extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype); +extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype, char *name); + +extern int cc_qsig_encode_ecma_isdn_leginfo3_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *name); extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);