- 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:
MelwareDE 2007-04-15 17:41:36 +00:00
parent 638108e55e
commit aae199cb8c
5 changed files with 550 additions and 49 deletions

View File

@ -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(&param, "|");
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 }
};
/*

View File

@ -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;
};

View File

@ -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

View File

@ -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);

View File

@ -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(&param, "|");
cidlen = strlen(cid);
if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */
cidlen = 20;
} else {
char *tmp = strsep(&param, "|");
tmp = NULL;
cid = strsep(&param, "|");
cidlen = strlen(cid);
if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */
cidlen = 20;
ccanswer = strsep(&param, "|");
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;
}