QSIG:
- more code cleanup - removed some major bugs - added support for Call Transfer feature [working, but not complete - feature will be changed later] - decoding of path replacement added [only decoding, no action yet] - enhanced QSIG dialstring
This commit is contained in:
parent
638108e55e
commit
aae199cb8c
126
chan_capi.c
126
chan_capi.c
|
@ -145,7 +145,9 @@ static char *commandtdesc = "CAPI command interface.\n"
|
|||
"\"3pty_begin|${MYHOLDVAR})\" Three-Party-Conference (3PTY) with active and held call\n"
|
||||
"\"receivefax|filename|stationID|headline\" receive a CAPIfax\n"
|
||||
"\"sendfax|filename.sff|stationID|headline\" send a CAPIfax\n"
|
||||
"\"qsig_ct|cidsrc|ciddst\" QSIG call transfer\n"
|
||||
"\"qsig_ssct|cidsrc|ciddst\" QSIG single step call transfer\n"
|
||||
"\"qsig_ct|cidsrc|ciddst|marker|waitconnect\" QSIG call transfer\n"
|
||||
"\"qsig_callmark|marker\" marks a QSIG call for later identification\n"
|
||||
"Variables set after fax receive:\n"
|
||||
"FAXSTATUS :0=OK, 1=Error\n"
|
||||
"FAXREASON :B3 disconnect reason\n"
|
||||
|
@ -1192,6 +1194,19 @@ static void interface_cleanup(struct capi_pvt *i)
|
|||
i->rtp = NULL;
|
||||
}
|
||||
|
||||
/* some QSIG stuff */
|
||||
if (i->qsigfeat) {
|
||||
i->qsig_data.callmark = 0;
|
||||
i->qsig_data.partner_ch = NULL;
|
||||
i->qsig_data.calltransfer_active = 0;
|
||||
i->qsig_data.calltransfer_onring = 0;
|
||||
if (i->qsig_data.pr_propose_cid)
|
||||
free(i->qsig_data.pr_propose_cid);
|
||||
if (i->qsig_data.pr_propose_pn)
|
||||
free(i->qsig_data.pr_propose_pn);
|
||||
|
||||
}
|
||||
|
||||
i->owner = NULL;
|
||||
return;
|
||||
}
|
||||
|
@ -3090,6 +3105,10 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
case 0x001c: /* Facility Q.932 */
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element FACILITY\n",
|
||||
i->vname);
|
||||
if (i->qsigfeat) { /* chances are high, that we got an QSIG Facility */
|
||||
unsigned int qsiginvoke;
|
||||
qsiginvoke = cc_qsig_handle_capi_facilityind( (unsigned char*) INFO_IND_INFOELEMENT(CMSG), i);
|
||||
}
|
||||
break;
|
||||
case 0x001e: /* Progress Indicator */
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element PI %02x %02x\n",
|
||||
|
@ -3196,6 +3215,10 @@ static void capidev_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsig
|
|||
local_queue_frame(i, &fr);
|
||||
if (i->owner)
|
||||
ast_setstate(i->owner, AST_STATE_RINGING);
|
||||
|
||||
if (i->qsigfeat) {
|
||||
/* TODO: some checks, if there's any work here */
|
||||
}
|
||||
break;
|
||||
case 0x8002: /* CALL PROCEEDING */
|
||||
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: info element CALL PROCEEDING\n",
|
||||
|
@ -4898,6 +4921,32 @@ static int pbx_capi_3pty_begin(struct ast_channel *c, char *param)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a QSIG Single Step Call Transfer
|
||||
*/
|
||||
static int pbx_capi_qsig_ssct(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_ssct requires source number and destination number\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cc_qsig_do_facility(fac, c, param, 99, 0);
|
||||
|
||||
INFO_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0);
|
||||
INFO_REQ_PLCI(&CMSG) = i->PLCI;
|
||||
INFO_REQ_FACILITYDATAARRAY(&CMSG) = fac;
|
||||
|
||||
_capi_put_cmsg(&CMSG);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a QSIG Call Transfer
|
||||
*/
|
||||
|
@ -4906,22 +4955,82 @@ 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);
|
||||
struct capi_pvt *ii = NULL;
|
||||
unsigned int callmark;
|
||||
char *marker;
|
||||
|
||||
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");
|
||||
cc_log(LOG_WARNING, "capi qsig_ct requires call marker, source number, destination number and await_connect info\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cc_qsig_do_facility(fac, c, param, 99);
|
||||
marker = strsep(¶m, "|");
|
||||
|
||||
callmark = atoi(marker);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: using call marker %i(%s)\n", callmark, marker);
|
||||
|
||||
cc_mutex_lock(&iflock);
|
||||
for (ii = iflist; ii; ii = ii->next) {
|
||||
if (ii->qsig_data.callmark == callmark)
|
||||
break;
|
||||
}
|
||||
cc_mutex_unlock(&iflock);
|
||||
|
||||
if (!ii) {
|
||||
cc_log(LOG_WARNING, "capi qsig_ct call marker not found!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cc_qsig_do_facility(fac, c, param, 12, 0);
|
||||
|
||||
INFO_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(),0);
|
||||
INFO_REQ_PLCI(&CMSG) = ii->PLCI;
|
||||
INFO_REQ_FACILITYDATAARRAY(&CMSG) = fac;
|
||||
|
||||
_capi_put_cmsg(&CMSG);
|
||||
|
||||
cc_qsig_do_facility(fac, c, param, 12, 1);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a QSIG Call Transfer
|
||||
*/
|
||||
static int pbx_capi_qsig_callmark(struct ast_channel *c, char *param)
|
||||
{
|
||||
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_callmark requires an call identifier\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
i->qsig_data.callmark = atoi(param);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate a QSIG Call Transfer
|
||||
*/
|
||||
static int pbx_capi_qsig_getplci(struct ast_channel *c, char *param)
|
||||
{
|
||||
struct capi_pvt *i = CC_CHANNEL_PVT(c);
|
||||
char buffer[10];
|
||||
|
||||
snprintf(buffer, sizeof(buffer)-1, "%d", i->PLCI);
|
||||
cc_verbose(4, 1, VERBOSE_PREFIX_4 "QSIG_GETPLCI: %s\n", buffer);
|
||||
pbx_builtin_setvar_helper(c, "QSIG_PLCI", buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -4944,9 +5053,12 @@ static struct capicommands_s {
|
|||
{ "holdtype", pbx_capi_holdtype, 1 },
|
||||
{ "retrieve", pbx_capi_retrieve, 0 },
|
||||
{ "ect", pbx_capi_ect, 1 },
|
||||
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
||||
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
||||
{ NULL, NULL, 0 }
|
||||
{ "3pty_begin", pbx_capi_3pty_begin, 1 },
|
||||
{ "qsig_ssct", pbx_capi_qsig_ssct, 1 },
|
||||
{ "qsig_ct", pbx_capi_qsig_ct, 1 },
|
||||
{ "qsig_callmark",pbx_capi_qsig_callmark, 1 },
|
||||
{ "qsig_getplci", pbx_capi_qsig_getplci, 1 },
|
||||
{ NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
19
chan_capi.h
19
chan_capi.h
|
@ -231,6 +231,22 @@ struct cc_capi_gains {
|
|||
#define CAPI_WAITEVENT_B3_DOWN 0x00020000
|
||||
#define CAPI_WAITEVENT_ANSWER_FINISH 0x00030000
|
||||
|
||||
/* Private qsig data for capi device */
|
||||
struct cc_qsig_data {
|
||||
int calltransfer_active;
|
||||
int calltransfer;
|
||||
int calltransfer_onring;
|
||||
unsigned int callmark;
|
||||
|
||||
/* Path Replacement */
|
||||
char *pr_propose_cid; /* Call identity */
|
||||
char *pr_propose_pn; /* Party Number */
|
||||
|
||||
/* Partner Channel - needed for many features */
|
||||
struct capi_pvt *partner_ch;
|
||||
unsigned int partner_plci;
|
||||
};
|
||||
|
||||
/* ! Private data for a capi device */
|
||||
struct capi_pvt {
|
||||
cc_mutex_t lock;
|
||||
|
@ -378,7 +394,8 @@ struct capi_pvt {
|
|||
|
||||
/* Q.SIG features */
|
||||
int qsigfeat;
|
||||
|
||||
struct cc_qsig_data qsig_data;
|
||||
|
||||
/*! Next channel in list */
|
||||
struct capi_pvt *next;
|
||||
};
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
#define APDUINTERPRETATION_CLEARCALL 0x01
|
||||
#define APDUINTERPRETATION_REJECT 0x02
|
||||
|
||||
/* const char* APDU_STR[] = { "IGNORE APDU", "CLEARCALL-IF-UNKNOWN", "REJECT APDU" }; */
|
||||
|
||||
|
||||
/* ASN.1 Identifier Octet - Data types */
|
||||
#define ASN1_TYPE_MASK 0x1f
|
||||
#define ASN1_BOOLEAN 0x01
|
||||
|
@ -86,8 +89,10 @@
|
|||
#define CNIP_NAMEUSERPROVIDED 0x00 /* Name is User-provided, unvalidated */
|
||||
#define CNIP_NAMEUSERPROVIDEDV 0x01 /* Name is User-provided and validated */
|
||||
|
||||
/* QSIG Operations += 1000 */
|
||||
#define CCQSIG__ECMA__NAMEPRES 1000 /* Setting an own constant for ECMA Operation/Namepresentation, others will follow */
|
||||
#define CCQSIG__ECMA__LEGINFO2 1011 /* LEG INFORMATION2 */
|
||||
#define CCQSIG__ECMA__PRPROPOSE 1004 /* Path Replacement Propose */
|
||||
#define CCQSIG__ECMA__LEGINFO2 1021 /* LEG INFORMATION2 */
|
||||
|
||||
/*
|
||||
* INVOKE Data struct, contains data for further operations
|
||||
|
@ -139,7 +144,7 @@ extern int cc_qsig_add_invoke(unsigned char * buf, unsigned int *idx, struct cc_
|
|||
|
||||
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 char cc_qsig_asn1_get_oid(unsigned char *data, int *idx);
|
||||
extern unsigned char *cc_qsig_asn1_oid2str(unsigned char *data, int size);
|
||||
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);
|
||||
|
||||
|
@ -149,13 +154,14 @@ extern signed int cc_qsig_check_invoke(unsigned char *data, int *idx);
|
|||
extern signed int cc_qsig_get_invokeid(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke);
|
||||
extern signed int cc_qsig_fill_invokestruct(unsigned char *data, int *idx, struct cc_qsig_invokedata *invoke, int apduval);
|
||||
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_facility_data(unsigned char *data, struct capi_pvt *i, int facility);
|
||||
|
||||
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_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype);
|
||||
extern unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype, int info1);
|
||||
|
||||
/*
|
||||
*** ECMA QSIG Functions
|
||||
|
@ -166,6 +172,10 @@ extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *id
|
|||
|
||||
extern void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
||||
|
||||
extern void cc_qsig_op_ecma_isdn_prpropose(struct cc_qsig_invokedata *invoke, struct capi_pvt *i);
|
||||
extern void cc_qsig_encode_ecma_prpropose(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param);
|
||||
|
||||
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);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -119,9 +119,11 @@ unsigned int cc_qsig_asn1_get_integer(unsigned char *data, int *idx)
|
|||
/*
|
||||
* Returns an Human Readable OID from ASN.1 Encoded OID
|
||||
*/
|
||||
unsigned char cc_qsig_asn1_get_oid(unsigned char *data, int *idx)
|
||||
unsigned char *cc_qsig_asn1_oid2str(unsigned char *data, int size)
|
||||
{
|
||||
/* TODO: Add code */
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -152,7 +154,9 @@ void cc_qsig_update_facility_length(unsigned char * buf, unsigned int idx)
|
|||
*/
|
||||
int cc_qsig_build_facility_struct(unsigned char * buf, unsigned int *idx, int apdu_interpr, struct cc_qsig_nfe *nfe)
|
||||
{
|
||||
int myidx = 1; /* we start with Index 1 - Byte 0 is Length of Facilitydataarray */
|
||||
int myidx = *idx; /* we start with Index 1 - Byte 0 is Length of Facilitydataarray */
|
||||
if (!myidx)
|
||||
myidx++;
|
||||
|
||||
buf[myidx++] = 0x1c;
|
||||
buf[myidx++] = 0; /* Byte 2 length of Facilitydataarray */
|
||||
|
@ -243,19 +247,27 @@ unsigned int cc_qsig_check_facility(unsigned char *data, int *idx, int *apduval,
|
|||
/* First byte after Facility Length */
|
||||
if (data[myidx] == (unsigned char)(0x80 | protocol)) {
|
||||
myidx++;
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Supplementary Services\n");
|
||||
if (data[myidx++] == (unsigned char)COMP_TYPE_NFE) {
|
||||
/* Todo: Check Entities? */
|
||||
myidx = myidx + data[myidx] + 1;
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Supplementary Services");
|
||||
if (data[myidx] == (unsigned char)COMP_TYPE_NFE) {
|
||||
myidx++;
|
||||
/* TODO: Check Entities? */
|
||||
myidx += data[myidx] + 1;
|
||||
*idx = myidx;
|
||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (idc #1 %i)\n",idx); */
|
||||
if ((data[myidx++] == (unsigned char)COMP_TYPE_APDU_INTERP)) {
|
||||
myidx = myidx + data[myidx];
|
||||
*apduval = data[myidx];
|
||||
/* ToDo: implement real reject or clear call ? */
|
||||
*idx = ++myidx;
|
||||
return 1;
|
||||
}
|
||||
cc_verbose(1, 1, ", has NFE struct");
|
||||
}
|
||||
if ((data[myidx] == (unsigned char)COMP_TYPE_APDU_INTERP)) {
|
||||
myidx++;
|
||||
myidx += data[myidx];
|
||||
*apduval = data[myidx++];
|
||||
/* TODO: implement real reject or clear call ? */
|
||||
*idx = myidx;
|
||||
/* cc_verbose(1, 1, ", has APDU %s", APDU_STR[*apduval]); */
|
||||
}
|
||||
cc_verbose(1, 1, ".\n");
|
||||
return 1;
|
||||
} else {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: received protocol 0x%#x not configured!\n", (data[myidx] ^= 0x80));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -272,13 +284,13 @@ signed int cc_qsig_check_invoke(unsigned char *data, int *idx)
|
|||
{
|
||||
int myidx = *idx;
|
||||
|
||||
if (data[myidx] == (unsigned char)COMP_TYPE_INVOKE) {
|
||||
/* is an INVOKE_IDENT */
|
||||
*idx = myidx + 1; /* Set index to length byte of component */
|
||||
if (data[myidx++] == (unsigned char)COMP_TYPE_INVOKE) {
|
||||
/* is an INVOKE */
|
||||
*idx = myidx; /* Set index to length byte of component */
|
||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_4 "CONNECT_IND (Invoke Length %i)\n", data[myidx+1]); */
|
||||
return data[myidx + 1]; /* return component length */
|
||||
}
|
||||
*idx = ++myidx;
|
||||
*idx += data[myidx]; /* we can end here, if it is an Invoke Result or Error */
|
||||
return -1; /* what to do now? got no Invoke */
|
||||
}
|
||||
|
||||
|
@ -414,6 +426,17 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
|||
switch (invoke->descr_type) {
|
||||
case ASN1_INTEGER:
|
||||
invokedescrtype = 1;
|
||||
switch (invoke->type) {
|
||||
case 0:
|
||||
return CCQSIG__ECMA__NAMEPRES;
|
||||
case 4:
|
||||
return CCQSIG__ECMA__PRPROPOSE;
|
||||
case 21:
|
||||
return CCQSIG__ECMA__LEGINFO2;
|
||||
default:
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ECMA-ISDN QSIG INVOKE (%i)\n", invoke->type);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ASN1_OBJECTIDENTIFIER:
|
||||
invokedescrtype = 2;
|
||||
|
@ -423,6 +446,8 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
|||
switch (invoke->oid_bin[3]) {
|
||||
case 0: /* ECMA QSIG Name Presentation */
|
||||
return CCQSIG__ECMA__NAMEPRES;
|
||||
case 4:
|
||||
return CCQSIG__ECMA__PRPROPOSE;
|
||||
case 21:
|
||||
return CCQSIG__ECMA__LEGINFO2;
|
||||
default: /* Unknown Operation */
|
||||
|
@ -445,15 +470,33 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco
|
|||
switch (invoke->type) {
|
||||
case 0:
|
||||
return CCQSIG__ECMA__NAMEPRES;
|
||||
case 4:
|
||||
return CCQSIG__ECMA__PRPROPOSE;
|
||||
case 21:
|
||||
return CCQSIG__ECMA__LEGINFO2;
|
||||
default:
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled QSIG INVOKE (%i)\n", invoke->type);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ISO QSIG INVOKE (%i)\n", invoke->type);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case ASN1_OBJECTIDENTIFIER:
|
||||
invokedescrtype = 2;
|
||||
datalen = invoke->oid_len;
|
||||
if ((datalen) == 4) {
|
||||
if (!cc_qsig_asn1_check_ecma_isdn_oid(invoke->oid_bin, datalen)) {
|
||||
switch (invoke->oid_bin[3]) {
|
||||
case 0: /* ECMA QSIG Name Presentation */
|
||||
return CCQSIG__ECMA__NAMEPRES;
|
||||
case 4:
|
||||
return CCQSIG__ECMA__PRPROPOSE;
|
||||
case 21:
|
||||
return CCQSIG__ECMA__LEGINFO2;
|
||||
default: /* Unknown Operation */
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG: Unhandled ISO QSIG INVOKE (%i)\n", invoke->oid_bin[3]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Unidentified INVOKE OP\n");
|
||||
|
@ -477,6 +520,9 @@ unsigned int cc_qsig_handle_invokeoperation(int invokeident, struct cc_qsig_invo
|
|||
case CCQSIG__ECMA__NAMEPRES:
|
||||
cc_qsig_op_ecma_isdn_namepres(invoke, i);
|
||||
break;
|
||||
case CCQSIG__ECMA__PRPROPOSE:
|
||||
cc_qsig_op_ecma_isdn_prpropose(invoke, i);
|
||||
break;
|
||||
case CCQSIG__ECMA__LEGINFO2:
|
||||
cc_qsig_op_ecma_isdn_leginfo2(invoke, i);
|
||||
break;
|
||||
|
@ -496,7 +542,7 @@ unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i)
|
|||
int action_unkn_apdu; /* What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU) */
|
||||
|
||||
int invoke_len; /* Length of Invoke APDU */
|
||||
unsigned int invoke_op; /* Invoke Operation ID */
|
||||
unsigned int invoke_op = 0; /* Invoke Operation ID */
|
||||
struct cc_qsig_invokedata invoke;
|
||||
int invoketmp1;
|
||||
|
||||
|
@ -512,6 +558,7 @@ unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i)
|
|||
if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_ROSE)) {
|
||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */
|
||||
while ((facidx-1)<faclen) {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking INVOKE at index %i\n", facidx);
|
||||
invoke_len=cc_qsig_check_invoke(data, &facidx);
|
||||
if (invoke_len>0) {
|
||||
if (cc_qsig_get_invokeid(data, &facidx, &invoke)==0) {
|
||||
|
@ -549,6 +596,108 @@ unsigned int cc_qsig_handle_capiind(unsigned char *data, struct capi_pvt *i)
|
|||
}
|
||||
}
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Facility done at index %i from %i\n", facidx, faclen);
|
||||
return invoke_op;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handles incoming Facility Indications from CAPI
|
||||
*/
|
||||
unsigned int cc_qsig_handle_capi_facilityind(unsigned char *data, struct capi_pvt *i)
|
||||
{
|
||||
int faclen = 0;
|
||||
int facidx = 0;
|
||||
int action_unkn_apdu; /* What to do with unknown Invoke-APDUs (0=Ignore, 1=clear call, 2=reject APDU) */
|
||||
|
||||
int invoke_len; /* Length of Invoke APDU */
|
||||
unsigned int invoke_op; /* Invoke Operation ID */
|
||||
struct cc_qsig_invokedata invoke;
|
||||
int invoketmp1;
|
||||
|
||||
|
||||
if (!data) {
|
||||
return 0;
|
||||
}
|
||||
faclen = data[facidx++];
|
||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND (Got Facility IE, Length=%#x)\n", faclen); */
|
||||
while (facidx < faclen) {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking Facility at index %i\n", facidx);
|
||||
switch (i->qsigfeat) {
|
||||
case QSIG_TYPE_ALCATEL_ECMA:
|
||||
if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_ROSE)) {
|
||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */
|
||||
while ((facidx-1)<faclen) {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Checking INVOKE at index %i\n", facidx);
|
||||
invoke_len=cc_qsig_check_invoke(data, &facidx);
|
||||
if (invoke_len>0) {
|
||||
if (cc_qsig_get_invokeid(data, &facidx, &invoke)==0) {
|
||||
invoketmp1=cc_qsig_fill_invokestruct(data, &facidx, &invoke, action_unkn_apdu);
|
||||
invoke_op=cc_qsig_identifyinvoke(&invoke, i->qsigfeat);
|
||||
if (invoke_op) {
|
||||
cc_qsig_handle_invokeoperation(invoke_op, &invoke, i);
|
||||
} else {
|
||||
// facidx += invoke_len;
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Invoke not identified!\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Not an Invoke */
|
||||
}
|
||||
}
|
||||
} else { /* kill endlessloop */
|
||||
facidx += faclen;
|
||||
}
|
||||
break;
|
||||
case QSIG_TYPE_HICOM_ECMAV2:
|
||||
if (cc_qsig_check_facility(data, &facidx, &action_unkn_apdu, Q932_PROTOCOL_EXTENSIONS)) {
|
||||
/* cc_verbose(1, 1, VERBOSE_PREFIX_3 "CONNECT_IND ROSE Supplementary Services (APDU Interpretation: %i)\n", action_unkn_apdu); */
|
||||
while ((facidx-1)<faclen) {
|
||||
invoke_len=cc_qsig_check_invoke(data, &facidx);
|
||||
if (invoke_len>0) {
|
||||
if (cc_qsig_get_invokeid(data, &facidx, &invoke)==0) {
|
||||
invoketmp1=cc_qsig_fill_invokestruct(data, &facidx, &invoke, action_unkn_apdu);
|
||||
invoke_op=cc_qsig_identifyinvoke(&invoke, i->qsigfeat);
|
||||
if (invoke_op) {
|
||||
cc_qsig_handle_invokeoperation(invoke_op, &invoke, i);
|
||||
} else {
|
||||
// facidx += invoke_len;
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Invoke not identified!\n");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Not an Invoke */
|
||||
}
|
||||
}
|
||||
} else { /* kill endlessloop */
|
||||
facidx += faclen;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Unknown QSIG protocol configured (%i)\n", i->qsigfeat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_3 "Facility done at index %i from %i\n", facidx, faclen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int identify_qsig_setup_callfeature(char *param)
|
||||
{
|
||||
char *p = param;
|
||||
switch (*p) {
|
||||
case 't':
|
||||
cc_verbose(1, 1, "Call Transfer");
|
||||
p++;
|
||||
if (*p == 'r') {
|
||||
cc_verbose(1, 1, " on ALERT");
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
default:
|
||||
cc_verbose(1, 1, "unknown (%c)\n", *p);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -564,6 +713,7 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
|
|||
|
||||
const unsigned char xprogress[] = {0x1e,0x02,0xa0,0x90};
|
||||
char *p = NULL;
|
||||
char *pp = NULL;
|
||||
int add_externalinfo = 0;
|
||||
|
||||
if ((p = pbx_builtin_getvar_helper(c, "QSIG_SETUP"))) {
|
||||
|
@ -572,18 +722,47 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
|
|||
while ((p) && (*p)) {
|
||||
switch (*p) {
|
||||
case 'X': /* add PROGRESS INDICATOR for external calls*/
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4, "Sending QSIG external PROGRESS IE.\n");
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Sending QSIG external PROGRESS IE.\n");
|
||||
add_externalinfo = 1;
|
||||
while (((char)*p!=',')&&(*p)) /* Remove next values until separator (,), stop if zero */
|
||||
p++;
|
||||
pp = strsep (&p, "/");
|
||||
pp = NULL;
|
||||
break;
|
||||
case 'C':
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "QSIG Call Feature requested: ");
|
||||
p++;
|
||||
switch(identify_qsig_setup_callfeature(p)) {
|
||||
case 1: /* Call transfer */
|
||||
p++;
|
||||
pp = strsep(&p, "/");
|
||||
if (!pp) {
|
||||
cc_log(LOG_WARNING, "QSIG Call Feature needs plci as parameter!\n");
|
||||
} else {
|
||||
i->qsig_data.calltransfer = 1;
|
||||
i->qsig_data.partner_plci = atoi(pp);
|
||||
cc_verbose(1, 1, " for plci %#x\n", i->qsig_data.partner_plci);
|
||||
}
|
||||
break;
|
||||
case 2: /* Call transfer on ring */
|
||||
p += 2;
|
||||
pp = strsep(&p, "/");
|
||||
if (!pp) {
|
||||
cc_log(LOG_WARNING, "QSIG Call Feature needs plci as parameter!\n");
|
||||
} else {
|
||||
i->qsig_data.calltransfer_onring = 1;
|
||||
i->qsig_data.partner_plci = atoi(pp);
|
||||
cc_verbose(1, 1, " for plci %#x\n", i->qsig_data.partner_plci);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pp = strsep(&p, "/");
|
||||
break;
|
||||
}
|
||||
pp = NULL;
|
||||
break;
|
||||
default:
|
||||
cc_log(LOG_WARNING, "Unknown parameter '%c' in QSIG_SETUP, ignoring.\n", *p);
|
||||
while (((char)*p!=',')&&(*p))
|
||||
p++;
|
||||
p++;
|
||||
}
|
||||
if (*p) /* this is not the end */
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,7 +784,7 @@ unsigned int cc_qsig_add_call_setup_data(unsigned char *data, struct capi_pvt *i
|
|||
/*
|
||||
* Handles outgoing Facilies on capicommand
|
||||
*/
|
||||
unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype)
|
||||
unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, char *param, unsigned int factype, int info1)
|
||||
{
|
||||
struct cc_qsig_invokedata invoke;
|
||||
struct cc_qsig_nfe nfe;
|
||||
|
@ -615,6 +794,11 @@ unsigned int cc_qsig_do_facility(unsigned char *fac, struct ast_channel *c, cha
|
|||
|
||||
cc_qsig_build_facility_struct(fac, &facidx, APDUINTERPRETATION_REJECT, &nfe);
|
||||
switch (factype) {
|
||||
case 12: /* ECMA-178 callTransfer */
|
||||
cc_qsig_encode_ecma_calltransfer(fac, &facidx, &invoke, i, param, info1);
|
||||
cc_qsig_add_invoke(fac, &facidx, &invoke);
|
||||
|
||||
break;
|
||||
case 99: /* ECMA-300 simpleCallTransfer */
|
||||
cc_qsig_encode_ecma_sscalltransfer(fac, &facidx, &invoke, i, param);
|
||||
cc_qsig_add_invoke(fac, &facidx, &invoke);
|
||||
|
|
|
@ -233,16 +233,16 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap
|
|||
}
|
||||
|
||||
snprintf(tempstr, 5, "%i", divReason);
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVREASON", tempstr);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVREASON", tempstr);
|
||||
snprintf(tempstr, 5, "%i", orgDivReason);
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVREASON", tempstr);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVREASON", tempstr);
|
||||
snprintf(tempstr, 5, "%i", divCount);
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVCOUNT", tempstr);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVCOUNT", tempstr);
|
||||
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVNUM", divertNum);
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVNUM", origCalledNum);
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_DIVNAME", divertName);
|
||||
pbx_builtin_setvar_helper(i->owner, "QSIG_LI2_ODIVNAME", origCalledName);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNUM", divertNum);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVNUM", origCalledNum);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNAME", divertName);
|
||||
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVNAME", origCalledName);
|
||||
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_LEG_INFO2: %i(%i), %ix %s->%s, %s->%s\n", divReason, orgDivReason, divCount, origCalledNum, divertNum, origCalledName, divertName);
|
||||
|
||||
|
@ -252,9 +252,92 @@ void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct cap
|
|||
|
||||
|
||||
/*
|
||||
* Encode Operation: 1.3.12.9.99 ECMA/ISDN/SIMPLECALLTRANSFER
|
||||
* Encode Operation: 1.3.12.9.12 ECMA/ISDN/CALLTRANSFER
|
||||
*
|
||||
* This function encodes the simple call transfer facility
|
||||
* This function encodes 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 for facility
|
||||
* i is pointer to capi channel
|
||||
* param is parameter from capicommand
|
||||
* info this facility is part of 2, 0 is facility 1, 1 is facility 2
|
||||
* returns
|
||||
* always 0
|
||||
*/
|
||||
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)
|
||||
{
|
||||
const unsigned char oid[] = {0x2b,0x0c,0x09,0xc}; /* 1.3.12.9.12 */
|
||||
char *cid, *ccanswer;
|
||||
int icanswer = 0;
|
||||
int cidlen = 0;
|
||||
int seqlen = 13;
|
||||
char c[255];
|
||||
int ix = 0;
|
||||
|
||||
if (info) {
|
||||
cid = strsep(¶m, "|");
|
||||
cidlen = strlen(cid);
|
||||
if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */
|
||||
cidlen = 20;
|
||||
} else {
|
||||
char *tmp = strsep(¶m, "|");
|
||||
tmp = NULL;
|
||||
cid = strsep(¶m, "|");
|
||||
cidlen = strlen(cid);
|
||||
if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */
|
||||
cidlen = 20;
|
||||
|
||||
ccanswer = strsep(¶m, "|");
|
||||
if (ccanswer[0])
|
||||
icanswer = ccanswer[0] - 0x30;
|
||||
}
|
||||
|
||||
seqlen += cidlen;
|
||||
|
||||
|
||||
c[ix++] = ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED; /* start of SEQUENCE */
|
||||
c[ix++] = seqlen;
|
||||
|
||||
c[ix++] = ASN1_ENUMERATED; /* End Designation */
|
||||
c[ix++] = 1; /* length */
|
||||
c[ix++] = info;
|
||||
|
||||
c[ix++] = ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED; /* val 2 - Source Caller ID struct */
|
||||
c[ix++] = 5 + cidlen;
|
||||
c[ix++] = ASN1_TC_CONTEXTSPEC; /* CallerID */
|
||||
c[ix++] = cidlen;
|
||||
memcpy(&c[ix], cid, cidlen);
|
||||
ix += cidlen;
|
||||
c[ix++] = ASN1_ENUMERATED; /* Screening Indicator */
|
||||
c[ix++] = 1; /* length */
|
||||
c[ix++] = 1; /* 01 = userProvidedVerifiedAndPassed ...we hope so */
|
||||
|
||||
c[ix++] = ASN1_ENUMERATED; /* val 3 - wait for connect ? */
|
||||
c[ix++] = 1;
|
||||
c[ix++] = icanswer;
|
||||
|
||||
/* end of SEQUENCE */
|
||||
/* there are optional data possible here */
|
||||
|
||||
invoke->id = 12;
|
||||
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: %i->%s\n", info, cid);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode Operation: 1.3.12.9.99 ECMA/ISDN/SINGLESTEPCALLTRANSFER
|
||||
*
|
||||
* This function encodes the single step call transfer facility
|
||||
*
|
||||
* We create an invoke struct with the complete encoded invoke.
|
||||
*
|
||||
|
@ -311,7 +394,7 @@ void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx,
|
|||
c[ix++] = 1;
|
||||
c[ix++] = 0;
|
||||
|
||||
/* end of SEQUENCE */
|
||||
/* end of SEQUENCE */
|
||||
/* there are optional data possible here */
|
||||
|
||||
invoke->id = 99;
|
||||
|
@ -321,6 +404,101 @@ void cc_qsig_encode_ecma_sscalltransfer(unsigned char * buf, unsigned int *idx,
|
|||
|
||||
invoke->datalen = ix;
|
||||
memcpy(invoke->data, c, ix);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_CT: %s->%s\n", cidsrc, ciddst);
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_SSCT: %s->%s\n", cidsrc, ciddst);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle Operation: 1.3.12.9.19 ECMA/ISDN/PATH REPLACEMENT PROPOSE
|
||||
*
|
||||
* This function decodes the PATH REPLACEMENT PROPOSE facility
|
||||
* The datas will be copied in the some capi_pvt channel variables
|
||||
*
|
||||
* parameters
|
||||
* invoke struct, which contains encoded data from facility
|
||||
* i is pointer to capi channel
|
||||
* returns
|
||||
* nothing
|
||||
*/
|
||||
void cc_qsig_op_ecma_isdn_prpropose(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
|
||||
{
|
||||
|
||||
unsigned int datalength;
|
||||
unsigned int seqlength = 0;
|
||||
int myidx = 0;
|
||||
/* TODO: write more code */
|
||||
|
||||
char callid[4+1];
|
||||
char reroutingnr[ASN197ADE_NUMDIGITS_STRSIZE+1];
|
||||
int temp = 0;
|
||||
|
||||
callid[0] = 0;
|
||||
reroutingnr[0] = 0;
|
||||
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG PATH REPLACEMENT PROPOSE (id# %#x)\n", invoke->id);
|
||||
|
||||
if (invoke->data[myidx++] != (ASN1_SEQUENCE | ASN1_TC_UNIVERSAL | ASN1_TF_CONSTRUCTED)) { /* 0x30 */
|
||||
/* We do not handle this, because it should start with an sequence tag */
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - not a sequence\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* This facility is encoded as SEQUENCE */
|
||||
seqlength = invoke->data[myidx++];
|
||||
datalength = invoke->datalen;
|
||||
if (datalength < (seqlength+1)) {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - buffer error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (invoke->data[myidx++] == ASN1_NUMERICSTRING) {
|
||||
int strsize;
|
||||
strsize = cc_qsig_asn1_get_string((unsigned char*)&callid, sizeof(callid), &invoke->data[myidx]);
|
||||
myidx += strsize +1;
|
||||
} else {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - NUMERICSTRING expected\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (invoke->data[myidx++] == ASN1_TC_CONTEXTSPEC)
|
||||
temp = cc_qsig_asn1_get_string((unsigned char*)&reroutingnr, sizeof(reroutingnr), &invoke->data[myidx]);
|
||||
|
||||
if (temp) {
|
||||
myidx += temp;
|
||||
} else {
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - partyNumber expected (%i)\n", myidx);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
i->qsig_data.pr_propose_cid = strdup(callid);
|
||||
i->qsig_data.pr_propose_pn = strdup(reroutingnr);
|
||||
|
||||
cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG_PATHREPLACEMENT_PROPOSE Call identity: %s, Party number: %s (%i)\n", callid, reroutingnr, temp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode Operation: 1.3.12.9.19 ECMA/ISDN/PATH REPLACEMENT PROPOSE
|
||||
*
|
||||
* This function encodes the path replacement propose
|
||||
*
|
||||
* 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_prpropose(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param)
|
||||
{
|
||||
/* TODO: write code */
|
||||
const unsigned char oid[] = {0x2b,0x0c,0x09,0x13}; /* 1.3.12.9.99 */
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue