parent
6bba2bbfc6
commit
f50bb3fd2d
|
@ -54,6 +54,11 @@ The QSIG support includes:
|
||||||
In dialplan use: Set(__QSIG_SETUP=X) command.
|
In dialplan use: Set(__QSIG_SETUP=X) command.
|
||||||
The leading "__" tells asterisk, to export this variable to the outgoing channel and
|
The leading "__" tells asterisk, to export this variable to the outgoing channel and
|
||||||
its subchannels
|
its subchannels
|
||||||
|
- Simple Call Transfer
|
||||||
|
With capicommand(qsig_ct|src-id|dst-id) you can transfer an inbound call back to the qsig switch.
|
||||||
|
The B-Channel of this call will be relased, so that the line is free for a next call.
|
||||||
|
Unfortunately the call will be completely released by the switch, if the target is busy.
|
||||||
|
I have to read the ECMA-300 standard, if there's a chance, to refuse the transfer in such a case.
|
||||||
|
|
||||||
Future Targets:
|
Future Targets:
|
||||||
===============
|
===============
|
||||||
|
|
29
chan_capi.c
29
chan_capi.c
|
@ -145,6 +145,7 @@ static char *commandtdesc = "CAPI command interface.\n"
|
||||||
"\"3pty_begin|${MYHOLDVAR})\" Three-Party-Conference (3PTY) with active and held call\n"
|
"\"3pty_begin|${MYHOLDVAR})\" Three-Party-Conference (3PTY) with active and held call\n"
|
||||||
"\"receivefax|filename|stationID|headline\" receive a CAPIfax\n"
|
"\"receivefax|filename|stationID|headline\" receive a CAPIfax\n"
|
||||||
"\"sendfax|filename.sff|stationID|headline\" send a CAPIfax\n"
|
"\"sendfax|filename.sff|stationID|headline\" send a CAPIfax\n"
|
||||||
|
"\"qsig_ct|cidsrc|ciddst\" QSIG call transfer\n"
|
||||||
"Variables set after fax receive:\n"
|
"Variables set after fax receive:\n"
|
||||||
"FAXSTATUS :0=OK, 1=Error\n"
|
"FAXSTATUS :0=OK, 1=Error\n"
|
||||||
"FAXREASON :B3 disconnect reason\n"
|
"FAXREASON :B3 disconnect reason\n"
|
||||||
|
@ -4793,6 +4794,33 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initiate a QSIG Call Transfer
|
||||||
|
*/
|
||||||
|
static int pbx_capi_qsig_ct(struct ast_channel *c, char *param)
|
||||||
|
{
|
||||||
|
unsigned char fac[CAPI_MAX_FACILITYDATAARRAY_SIZE];
|
||||||
|
_cmsg CMSG;
|
||||||
|
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||||
|
|
||||||
|
if (!param) { /* no data implies no Calling Number and Destination Number */
|
||||||
|
cc_log(LOG_WARNING, "capi qsig_ct requires source number and destination number\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_qsig_do_facility(fac, c, param, 99);
|
||||||
|
|
||||||
|
INFO_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0);
|
||||||
|
INFO_REQ_PLCI(&CMSG) = i->PLCI;
|
||||||
|
// / *INFO_REQ_FACILITYSELECTOR(&CMSG) = 0;* /
|
||||||
|
INFO_REQ_FACILITYDATAARRAY(&CMSG) = fac;
|
||||||
|
|
||||||
|
_capi_put_cmsg(&CMSG);
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct of capi commands
|
* struct of capi commands
|
||||||
*/
|
*/
|
||||||
|
@ -4813,6 +4841,7 @@ static struct capicommands_s {
|
||||||
{ "retrieve", pbx_capi_retrieve, 0 },
|
{ "retrieve", pbx_capi_retrieve, 0 },
|
||||||
{ "ect", pbx_capi_ect, 1 },
|
{ "ect", pbx_capi_ect, 1 },
|
||||||
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
||||||
|
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
||||||
{ NULL, NULL, 0 }
|
{ NULL, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -136,9 +136,13 @@ struct cc_qsig_nfe {
|
||||||
|
|
||||||
extern int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe);
|
extern int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe);
|
||||||
extern int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke);
|
extern int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke);
|
||||||
|
|
||||||
extern unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned char *data);
|
extern unsigned int cc_qsig_asn1_get_string(unsigned char *buf, int buflen, unsigned char *data);
|
||||||
extern unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx);
|
extern unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx);
|
||||||
extern unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx);
|
extern unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx);
|
||||||
|
extern unsigned int cc_qsig_asn1_add_string(unsigned char *buf, int *idx, char *data, int datalen);
|
||||||
|
extern unsigned int cc_qsig_asn1_add_integer(unsigned char *buf, int *idx, int value);
|
||||||
|
|
||||||
extern signed int cc_qsig_asn1_check_ecma_isdn_oid(unsigned char *data, int len);
|
extern signed int cc_qsig_asn1_check_ecma_isdn_oid(unsigned char *data, int len);
|
||||||
extern unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval, int protocol);
|
extern unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval, int protocol);
|
||||||
extern signed int cc_qsig_check_invoke(unsigned char *data, int *idx);
|
extern signed int cc_qsig_check_invoke(unsigned char *data, int *idx);
|
||||||
|
@ -151,12 +155,17 @@ extern unsigned int cc_qsig_add_call_facility_data(unsigned char *data, struct c
|
||||||
extern signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protocol);
|
extern signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protocol);
|
||||||
extern unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
extern unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
||||||
|
|
||||||
|
extern unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*** ECMA QSIG Functions
|
*** ECMA QSIG Functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
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);
|
||||||
|
|
||||||
extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
||||||
|
|
||||||
|
extern void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -88,3 +88,21 @@ unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, un
|
||||||
/* 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;
|
return strsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an string from ASN.1 encoded string
|
||||||
|
*/
|
||||||
|
unsigned int cc_qsig_asn197ade_add_numdigits(char *buf, int buflen, int *idx, unsigned char *data)
|
||||||
|
{
|
||||||
|
int myidx=0;
|
||||||
|
|
||||||
|
if ((1 + buflen) > sizeof(*buf)) {
|
||||||
|
/* String exceeds buffer size */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[myidx++] = buflen;
|
||||||
|
memcpy(&buf[myidx], data, buflen);
|
||||||
|
myidx = 1 + strlen(buf);
|
||||||
|
return myidx;
|
||||||
|
}
|
||||||
|
|
|
@ -26,4 +26,6 @@
|
||||||
extern unsigned int cc_qsig_asn197ade_get_partynumber(char *buf, int buflen, int *idx, unsigned char *data);
|
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);
|
extern unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int *idx, unsigned char *data);
|
||||||
|
|
||||||
|
extern unsigned int cc_qsig_asn197ade_add_numdigits(char *buf, int buflen, int *idx, unsigned char *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -218,13 +218,12 @@ int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_in
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invoke->datalen > 0) { /* may be no error, if there's no data */
|
if (invoke->datalen > 0) { /* may be no error, if there's no data */
|
||||||
memcpy(&buf[myidx], invoke->data, invoke->datalen);
|
memcpy(&buf[myidx], invoke->data, invoke->datalen);
|
||||||
myidx += invoke->datalen;
|
myidx += invoke->datalen;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf[invlenidx] = myidx-1;
|
buf[invlenidx] = myidx - invlenidx - 1;
|
||||||
cc_qsig_update_facility_length(buf, myidx - 1);
|
cc_qsig_update_facility_length(buf, myidx - 1);
|
||||||
*idx = myidx;
|
*idx = myidx;
|
||||||
|
|
||||||
|
@ -602,27 +601,27 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handles outgoing Facilies on Call
|
* Handles outgoing Facilies on capicommand
|
||||||
*/
|
*/
|
||||||
unsigned int cc_qsig_add_call_facility_data(unsigned char *data, struct capi_pvt *i, int facility)
|
unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype)
|
||||||
{
|
{
|
||||||
/* TODO: Check buffers */
|
|
||||||
struct cc_qsig_invokedata invoke;
|
struct cc_qsig_invokedata invoke;
|
||||||
struct cc_qsig_nfe nfe;
|
struct cc_qsig_nfe nfe;
|
||||||
unsigned int dataidx;
|
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||||
|
/* struct capi_pvt *ii = NULL; */
|
||||||
|
unsigned int facidx = 0;
|
||||||
|
|
||||||
/*mg:remember me switch (i->doqsig) {*/
|
cc_qsig_build_facility_struct(fac, &facidx, APDUINTERPRETATION_REJECT, &nfe);
|
||||||
cc_qsig_build_facility_struct(data, &dataidx, APDUINTERPRETATION_IGNORE, &nfe);
|
switch (factype) {
|
||||||
switch(facility) {
|
case 99: /* ECMA-300 simpleCallTransfer */
|
||||||
case 1: /* HACK: Test only */
|
cc_qsig_encode_ecma_sscalltransfer(fac, &facidx, &invoke, i, param);
|
||||||
cc_qsig_encode_ecma_name_invoke(data, &dataidx, &invoke, i, 1);
|
cc_qsig_add_invoke(fac, &facidx, &invoke);
|
||||||
cc_qsig_add_invoke(data, &dataidx, &invoke);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* }*/
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -249,3 +249,78 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Encode Operation: 1.3.12.9.99 ECMA/ISDN/SIMPLECALLTRANSFER
|
||||||
|
*
|
||||||
|
* This function encodes the simple 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 for facility
|
||||||
|
* i is pointer to capi channel
|
||||||
|
* param is parameter from capicommand
|
||||||
|
* returns
|
||||||
|
* always 0
|
||||||
|
*/
|
||||||
|
void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param)
|
||||||
|
{
|
||||||
|
const unsigned char oid[] = {0x2b,0x0c,0x09,0x63}; /* 1.3.12.9.99 */
|
||||||
|
char *cidsrc, *ciddst;
|
||||||
|
int srclen, dstlen;
|
||||||
|
int seqlen = 12;
|
||||||
|
char c[255];
|
||||||
|
int ix = 0;
|
||||||
|
|
||||||
|
cidsrc = strsep(¶m, "|");
|
||||||
|
srclen = strlen(cidsrc);
|
||||||
|
if (srclen > 20) /* HACK: stop action here, maybe we have invalid data */
|
||||||
|
srclen = 20;
|
||||||
|
|
||||||
|
ciddst = strsep(¶m, "|");
|
||||||
|
dstlen = strlen(ciddst);
|
||||||
|
if (dstlen > 20) /* HACK: stop action here, maybe we have invalid data */
|
||||||
|
dstlen = 20;
|
||||||
|
|
||||||
|
seqlen += srclen + dstlen;
|
||||||
|
|
||||||
|
|
||||||
|
c[ix++] = ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED; /* start of SEQUENCE */
|
||||||
|
c[ix++] = seqlen;
|
||||||
|
|
||||||
|
c[ix++] = ASN1_TC_CONTEXTSPEC; /* val 1 - Destination CallerID */
|
||||||
|
c[ix++] = dstlen;
|
||||||
|
memcpy(&c[ix], ciddst, dstlen);
|
||||||
|
ix += dstlen;
|
||||||
|
|
||||||
|
c[ix++] = ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED; /* val 2 - Source Caller ID struct */
|
||||||
|
c[ix++] = 5 + srclen;
|
||||||
|
c[ix++] = ASN1_TC_CONTEXTSPEC; /* CallerID */
|
||||||
|
c[ix++] = srclen;
|
||||||
|
memcpy(&c[ix], cidsrc, srclen);
|
||||||
|
ix += srclen;
|
||||||
|
c[ix++] = ASN1_ENUMERATED; /* Screening Indicator */
|
||||||
|
c[ix++] = 1; /* length */
|
||||||
|
c[ix++] = 1; /* 01 = userProvidedVerifiedAndPassed ...we hope so */
|
||||||
|
|
||||||
|
c[ix++] = ASN1_BOOLEAN; /* val 3 - wait for connect ? */
|
||||||
|
c[ix++] = 1;
|
||||||
|
c[ix++] = 0;
|
||||||
|
|
||||||
|
/* end of SEQUENCE */
|
||||||
|
/* there are optional data possible here */
|
||||||
|
|
||||||
|
invoke->id = 99;
|
||||||
|
invoke->descr_type = ASN1_OBJECTIDENTIFIER;
|
||||||
|
invoke->oid_len = sizeof(oid);
|
||||||
|
memcpy(invoke->oid_bin, oid, sizeof(oid));
|
||||||
|
|
||||||
|
invoke->datalen = ix;
|
||||||
|
memcpy(invoke->data, c, ix);
|
||||||
|
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: %s->%s\n", cidsrc, ciddst);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue