You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
866 lines
25 KiB
866 lines
25 KiB
/*
|
|
* An implementation of Common ISDN API 2.0 for Asterisk
|
|
*
|
|
* Copyright (C) 2005-2008 Cytronics & Melware
|
|
* Copyright (C) 2007 Mario Goegel
|
|
*
|
|
* Armin Schindler <armin@melware.de>
|
|
* Mario Goegel <m.goegel@gmx.de>
|
|
*
|
|
* This program is free software and may be modified and
|
|
* distributed under the terms of the GNU Public License.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "chan_capi_platform.h"
|
|
#include "chan_capi20.h"
|
|
#include "chan_capi.h"
|
|
#include "chan_capi_utils.h"
|
|
#include "chan_capi_qsig.h"
|
|
#include "chan_capi_qsig_ecma.h"
|
|
#include "chan_capi_qsig_asn197ade.h"
|
|
#include "chan_capi_qsig_asn197no.h"
|
|
|
|
|
|
/*
|
|
* Handle Operation: 1.3.12.9.0-3 ECMA/ISDN/NAMEPRESENTATION
|
|
*
|
|
* This function decodes the namepresentation facility
|
|
* The name will be copied in the cid.cid_name field of the asterisk channel struct
|
|
*
|
|
* parameters
|
|
* invoke struct, which contains encoded data from facility
|
|
* i is pointer to capi channel
|
|
* returns
|
|
* nothing
|
|
*/
|
|
void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
|
|
{
|
|
char callername[51]; /* ECMA defines max length to 50 */
|
|
unsigned int namelength = 0;
|
|
unsigned int datalength;
|
|
int myidx = 0;
|
|
char *nametype = NULL;
|
|
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 "Handling Name Operation (id# %#x)\n", invoke->id);
|
|
|
|
callername[0] = 0;
|
|
datalength = invoke->datalen;
|
|
|
|
myidx = cc_qsig_asn197no_get_name(callername, ASN197NO_NAME_STRSIZE, &namelength, &myidx, invoke->data );
|
|
|
|
if (namelength == 0) {
|
|
return;
|
|
}
|
|
|
|
/* TODO: Maybe we do some charset conversions */
|
|
|
|
switch (invoke->type) {
|
|
case 0: /* Calling Name */
|
|
nametype = "CALLING NAME";
|
|
break;
|
|
case 1: /* Called Name */
|
|
nametype = "CALLED NAME";
|
|
break;
|
|
case 2: /* Connected Name */
|
|
nametype = "CONNECTED NAME";
|
|
break;
|
|
case 3: /* Busy Name */
|
|
nametype = "BUSY NAME";
|
|
break;
|
|
}
|
|
|
|
switch (invoke->type) {
|
|
case 0: /* Calling Name */
|
|
#ifdef CC_AST_HAS_VERSION_1_8
|
|
ast_set_callerid(i->owner, NULL, callername, NULL);
|
|
#else
|
|
i->owner->cid.cid_name = ast_strdup(callername); /* Save name to callerid */
|
|
#endif
|
|
break;
|
|
case 1: /* Called Name */
|
|
case 2: /* Connected Name */
|
|
case 3: /* Busy Name */
|
|
if (i->qsig_data.dnameid) { /* this facility may come more than once - if so, then update this value */
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * deleting previously received name.\n", nametype, namelength, callername);
|
|
ast_free(i->qsig_data.dnameid);
|
|
}
|
|
i->qsig_data.dnameid = ast_strdup(callername); /* save name as destination in qsig specific fields */
|
|
/* there's no similarly field in asterisk */
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Got %s: \"%s\" (%i byte(s))\n", nametype, callername, namelength);
|
|
|
|
/* if there was an sequence tag, we have more informations here, but we will ignore it at the moment */
|
|
|
|
}
|
|
|
|
/*
|
|
* Encode Operation: 1.3.12.9.0-3 ECMA/ISDN/NAMEPRESENTATION
|
|
*
|
|
* 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_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype, const 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);
|
|
}
|
|
namebuf[namelen] = 0;
|
|
|
|
invoke->id = 1;
|
|
invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */
|
|
invoke->type = (nametype % 4); /* Invoke Operation Number, if OID it's the last byte*/
|
|
|
|
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_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Sending \"%s\": (%i byte(s))\n", namebuf, namelen);
|
|
|
|
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_qsig_verbose( 0, 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
|
|
*
|
|
* This function decodes the LEG INFORMATION2 facility
|
|
* The datas will be copied in the some Asterisk channel variables -> see README.qsig
|
|
*
|
|
* parameters
|
|
* invoke struct, which contains encoded data from facility
|
|
* i is pointer to capi channel
|
|
* returns
|
|
* nothing
|
|
*/
|
|
void cc_qsig_op_ecma_isdn_leginfo2(struct cc_qsig_invokedata *invoke, struct capi_pvt *i)
|
|
{
|
|
|
|
unsigned int datalength;
|
|
unsigned int seqlength = 0;
|
|
int myidx = 0;
|
|
|
|
unsigned int parameter = 0;
|
|
unsigned int divCount = 0;
|
|
unsigned int divReason = 0;
|
|
unsigned int orgDivReason = 0;
|
|
char tempstr[5];
|
|
char divertNum[ASN197ADE_NUMDIGITS_STRSIZE+1];
|
|
char origCalledNum[ASN197ADE_NUMDIGITS_STRSIZE+1];
|
|
struct asn197ade_numberscreened divertPNS, origPNS;
|
|
char divertName[ASN197NO_NAME_STRSIZE+1];
|
|
char origCalledName[ASN197NO_NAME_STRSIZE+1];
|
|
unsigned int temp = 0;
|
|
unsigned int temp2 = 0;
|
|
|
|
divertNum[0] = 0;
|
|
origCalledNum[0] = 0;
|
|
divertNum[0] = 0;
|
|
divertName[0] = 0;
|
|
origCalledName[0] = 0;
|
|
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 "Handling QSIG LEG INFO2 (id# %#x)\n", invoke->id);
|
|
|
|
origPNS.partyNumber = NULL;
|
|
divertPNS.partyNumber = NULL;
|
|
|
|
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_qsig_verbose( 1, VERBOSE_PREFIX_4 " * not Handling QSIG LEG INFO2 - not a sequence\n");
|
|
return;
|
|
}
|
|
|
|
/* This facility is encoded as SEQUENCE */
|
|
seqlength = invoke->data[myidx++];
|
|
datalength = invoke->datalen;
|
|
if (datalength < (seqlength+1)) {
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * not Handling QSIG LEG INFO2 - buffer error\n");
|
|
return;
|
|
}
|
|
|
|
if (invoke->data[myidx++] == ASN1_INTEGER)
|
|
divCount = cc_qsig_asn1_get_integer(invoke->data, &myidx);
|
|
|
|
if (invoke->data[myidx++] == ASN1_ENUMERATED)
|
|
divReason = cc_qsig_asn1_get_integer(invoke->data, &myidx);
|
|
|
|
while (myidx < datalength) {
|
|
parameter = (invoke->data[myidx++] & 0x0f);
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * Found parameter %i\n", parameter);
|
|
switch (parameter) {
|
|
case 0:
|
|
myidx++; /* Ignore Length of enumeration tag*/
|
|
if (invoke->data[myidx++] == ASN1_ENUMERATED)
|
|
orgDivReason = cc_qsig_asn1_get_integer(invoke->data, &myidx);
|
|
break;
|
|
case 1:
|
|
temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */
|
|
cc_qsig_asn197ade_get_pns(invoke->data, &myidx, &divertPNS);
|
|
myidx += temp;
|
|
break;
|
|
case 2:
|
|
temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */
|
|
cc_qsig_asn197ade_get_pns(invoke->data, &myidx, &origPNS);
|
|
myidx += temp;
|
|
break;
|
|
case 3:
|
|
/* Redirecting Name */
|
|
temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */
|
|
cc_qsig_asn197no_get_name(divertName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data);
|
|
myidx += temp + 1;
|
|
break;
|
|
case 4:
|
|
/* origCalled Name */
|
|
temp = invoke->data[myidx++]; /* keep the length of this info - maybe we don't get all data now */
|
|
cc_qsig_asn197no_get_name(origCalledName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data);
|
|
myidx += temp + 1;
|
|
break;
|
|
default:
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * unknown parameter %i\n", parameter);
|
|
break;
|
|
}
|
|
}
|
|
|
|
snprintf(tempstr, 5, "%i", divReason);
|
|
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);
|
|
snprintf(tempstr, 5, "%i", divCount);
|
|
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVCOUNT", tempstr);
|
|
|
|
if (divertPNS.partyNumber)
|
|
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNUM", divertPNS.partyNumber);
|
|
if (origPNS.partyNumber)
|
|
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVNUM", origPNS.partyNumber);
|
|
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNAME", divertName);
|
|
pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_ODIVNAME", origCalledName);
|
|
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Got QSIG_LEG_INFO2: %i(%i), %ix %s->%s, %s->%s\n", divReason, orgDivReason, divCount, origPNS.partyNumber, divertPNS.partyNumber, origCalledName, divertName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Encode Operation: 1.3.12.9.12 ECMA/ISDN/CALLTRANSFER
|
|
*
|
|
* 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)
|
|
{
|
|
char *cid, *ccanswer;
|
|
char *name = NULL;
|
|
int icanswer = 0;
|
|
int cidlen = 0;
|
|
int namelength = 0;
|
|
int seqlen = 13;
|
|
char c[255];
|
|
int ix = 0;
|
|
|
|
if (param) { /* got Call Transfer Parameters */
|
|
if (info) {
|
|
cid = strsep(¶m, COMMANDSEPARATOR);
|
|
cidlen = strlen(cid);
|
|
if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */
|
|
cidlen = 20;
|
|
} else {
|
|
char *tmp = strsep(¶m, COMMANDSEPARATOR);
|
|
tmp = NULL;
|
|
cid = strsep(¶m, COMMANDSEPARATOR);
|
|
cidlen = strlen(cid);
|
|
if (cidlen > 20) /* HACK: stop action here, maybe we have invalid data */
|
|
cidlen = 20;
|
|
|
|
ccanswer = strsep(¶m, COMMANDSEPARATOR);
|
|
if (ccanswer[0])
|
|
icanswer = ccanswer[0] - 0x30;
|
|
}
|
|
} else {
|
|
/* cid = ast_strdup(i->owner->cid.cid_num);*/ /* Here we get the Asterisk extension */
|
|
if (info) { /* info is >0 on outbound channel (second facility) */
|
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
|
|
|
cid = ast_strdup(i->cid);
|
|
cidlen = strlen(cid);
|
|
|
|
if (ii) {
|
|
/* send callers name to user B */
|
|
#ifdef CC_AST_HAS_VERSION_1_8
|
|
if (ii->owner->caller.id.name.valid ) {
|
|
name = ast_strdupa(S_COR(ii->owner->caller.id.name.valid, ii->owner->caller.id.name.str, ""));
|
|
namelength = strlen(name);
|
|
}
|
|
#else
|
|
if (ii->owner->cid.cid_name) {
|
|
name = ast_strdupa(ii->owner->cid.cid_name);
|
|
namelength = strlen(name);
|
|
}
|
|
#endif
|
|
}
|
|
} else { /* have to build first facility - send destination number back to inbound channel */
|
|
struct capi_pvt *ii = capi_find_interface_by_plci(i->qsig_data.partner_plci);
|
|
cid = ast_strdup(ii->dnid);
|
|
cidlen = strlen(cid);
|
|
|
|
if (ii) {
|
|
/* send destination name to user A */
|
|
if (ii->qsig_data.dnameid) {
|
|
name = ast_strdupa(ii->qsig_data.dnameid);
|
|
namelength = strlen(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!info)
|
|
icanswer = i->qsig_data.calltransfer_onring % 1;
|
|
}
|
|
|
|
seqlen += cidlen;
|
|
if (namelength)
|
|
seqlen += 4 + namelength;
|
|
|
|
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) + 0; /* val 0 - 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 */
|
|
|
|
{
|
|
if (namelength) {
|
|
c[ix++] = (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED) + 1; /* val 1 - Source Caller ID struct */
|
|
c[ix++] = 2 + namelength;
|
|
c[ix++] = ASN1_OCTETSTRING; /* CallerID */
|
|
c[ix++] = namelength;
|
|
memcpy(&c[ix], name, namelength);
|
|
ix += namelength;
|
|
}
|
|
}
|
|
|
|
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 = -1;
|
|
invoke->type = 12; /* Invoke Operation Code */
|
|
|
|
invoke->datalen = ix;
|
|
memcpy(invoke->data, c, ix);
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Sending QSIG_CT: %i->%s\n", info, cid);
|
|
|
|
if (cid)
|
|
ast_free(cid);
|
|
|
|
}
|
|
|
|
/*
|
|
* 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
|
|
*/
|
|
unsigned int cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i, struct cc_qsig_ctcomplete *ctc)
|
|
{
|
|
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" };
|
|
char ct_name[ASN197NO_NAME_STRSIZE+1] = { "EMPTY" };
|
|
unsigned int namelength = 0;
|
|
int temp = 0;
|
|
|
|
ctc->endDesignation = primaryEnd;
|
|
ctc->redirectionNumber.partyNumber = NULL;
|
|
ctc->redirectionNumber.screeningInd = userProvidedNotScreened;
|
|
ctc->basicCallInfoElements = NULL;
|
|
ctc->redirectionName = NULL;
|
|
ctc->callStatus = answered;
|
|
ctc->argumentExtension = NULL; /* unhandled yet */
|
|
|
|
#define ct_err(x...) { cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - "x); return 0; }
|
|
|
|
cc_qsig_verbose( 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) {
|
|
ctc->endDesignation = cc_qsig_asn1_get_integer(data, &myidx);
|
|
} else {
|
|
ct_err("no endDesignation information.\n");
|
|
}
|
|
|
|
temp = cc_qsig_asn197ade_get_pns(data, &myidx, &ctc->redirectionNumber);
|
|
|
|
if (!temp) {
|
|
ct_err("error on decoding PresentedNumberScreened value.\n");
|
|
}
|
|
myidx += temp;
|
|
|
|
if (myidx < datalength) {
|
|
if (data[myidx] == ASN1_TC_APPLICATION) {
|
|
myidx++;
|
|
/* TODO: check size -> could be bigger than 256 bytes - MSB is set then */
|
|
ctc->basicCallInfoElements = ast_malloc(data[myidx]);
|
|
if (ctc->basicCallInfoElements) {
|
|
memcpy(ctc->basicCallInfoElements, &data[myidx+1], data[myidx] );
|
|
} else {
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - couldn't allocate memory for basicCallInfoElements.\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 (namelength)
|
|
ctc->redirectionName = ast_strdup(ct_name);
|
|
}
|
|
}
|
|
|
|
if (myidx < datalength) {
|
|
if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */
|
|
ctc->callStatus = cc_qsig_asn1_get_integer(data, &myidx);
|
|
}
|
|
}
|
|
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Got QSIG CALL TRANSFER endDesignation: %i partyNumber: %s (ScreeningInd: %i), partyName: \"%s\", Call state: %s\n",
|
|
ctc->endDesignation, ctc->redirectionNumber.partyNumber, ctc->redirectionNumber.screeningInd, ctc->redirectionName, ct_status_txt[ctc->callStatus]);
|
|
|
|
return 1;
|
|
#undef ct_err
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*
|
|
* 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)
|
|
{
|
|
char *cidsrc, *ciddst;
|
|
int srclen, dstlen;
|
|
int seqlen = 12;
|
|
char c[255];
|
|
int ix = 0;
|
|
|
|
cidsrc = strsep(¶m, COMMANDSEPARATOR);
|
|
srclen = strlen(cidsrc);
|
|
if (srclen > 20) /* HACK: stop action here, maybe we have invalid data */
|
|
srclen = 20;
|
|
|
|
ciddst = strsep(¶m, COMMANDSEPARATOR);
|
|
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 = -1;
|
|
invoke->type = 99;
|
|
|
|
invoke->datalen = ix;
|
|
memcpy(invoke->data, c, ix);
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Sending 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_qsig_verbose( 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_qsig_verbose( 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_qsig_verbose( 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_qsig_verbose( 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_qsig_verbose( 1, VERBOSE_PREFIX_4 " * not Handling QSIG REPLACEMENT PROPOSE - partyNumber expected (%i)\n", myidx);
|
|
return;
|
|
}
|
|
|
|
|
|
i->qsig_data.pr_propose_cid = ast_strdup(callid);
|
|
i->qsig_data.pr_propose_pn = ast_strdup(reroutingnr);
|
|
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Got 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)
|
|
{
|
|
int invokeop = 4;
|
|
|
|
char *callid, *reroutingnr;
|
|
int cidlen, rrnlen;
|
|
int seqlen = 4;
|
|
char c[255];
|
|
int ix = 0;
|
|
|
|
int res = 0;
|
|
int ii = 0;
|
|
struct rose_component *comp = NULL, *compstk[10];
|
|
int compsp = 0;
|
|
|
|
if (!i->qsig_data.pr_propose_cid)
|
|
return ;
|
|
|
|
if (!i->qsig_data.pr_propose_pn)
|
|
return ;
|
|
|
|
callid = i->qsig_data.pr_propose_cid;
|
|
reroutingnr = i->qsig_data.pr_propose_pn;
|
|
|
|
cidlen = strlen(callid);
|
|
rrnlen = strlen(reroutingnr);
|
|
seqlen += cidlen + rrnlen;
|
|
|
|
|
|
#if 0
|
|
c[ix++] = ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED; /* start of SEQUENCE */
|
|
c[ix++] = seqlen;
|
|
|
|
c[ix++] = ASN1_NUMERICSTRING; /* val 1 - CallID */
|
|
c[ix++] = cidlen;
|
|
memcpy(&c[ix], callid, cidlen);
|
|
ix += cidlen;
|
|
|
|
c[ix++] = ASN1_TC_CONTEXTSPEC; /* val 2 - Rerouting number*/
|
|
c[ix++] = rrnlen;
|
|
memcpy(&c[ix], reroutingnr, rrnlen);
|
|
ix += rrnlen;
|
|
#else
|
|
ASN1_ADD_SIMPLE(comp, (ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED), c, ii);
|
|
ASN1_PUSH(compstk, compsp, comp);
|
|
|
|
res = cc_qsig_asn1_add_string2(ASN1_NUMERICSTRING, &c[ii], sizeof(c) - ii, 20, callid, cidlen);
|
|
if (res < 0)
|
|
return;
|
|
ii += res;
|
|
|
|
res = cc_qsig_asn1_add_string2(ASN1_TC_CONTEXTSPEC, &c[ii], sizeof(c) - ii, 20, reroutingnr, rrnlen);
|
|
if (res < 0)
|
|
return;
|
|
ii += res;
|
|
|
|
ASN1_FIXUP(compstk, compsp, c, ii);
|
|
ix = ii;
|
|
#endif
|
|
|
|
/* end of SEQUENCE */
|
|
/* there are optional data possible here */
|
|
|
|
invoke->id = invokeop;
|
|
invoke->descr_type = -1;
|
|
invoke->type = invokeop;
|
|
|
|
invoke->datalen = ix;
|
|
memcpy(invoke->data, c, ix);
|
|
|
|
cc_qsig_verbose( 0, VERBOSE_PREFIX_4 " * Sending QSIG_PATHREPLACEMENT_PROPOSE: Call identity: %s, Party number: %s\n", callid, reroutingnr);
|
|
|
|
return;
|
|
}
|
|
|
|
void cc_qsig_encode_ecma_ccnr_req(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, char *param)
|
|
{
|
|
int invokeop = 27;
|
|
|
|
int ii = 0;
|
|
unsigned char c[256];
|
|
struct rose_component *comp = NULL, *compstk[10];
|
|
int compsp = 0;
|
|
int ix = 0;
|
|
|
|
ASN1_ADD_SIMPLE(comp, (ASN1_TF_CONSTRUCTED | ASN1_SEQUENCE), c, ii);
|
|
ASN1_PUSH(compstk, compsp, comp);
|
|
|
|
|
|
|
|
#if 0 /* Constructed data - ECMAv1 HICOM/HIPATH */
|
|
ASN1_ADD_SIMPLE(comp, (ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTOR | ASN1_TAG_1), buffer, i);
|
|
ASN1_PUSH(compstk, compsp, comp);
|
|
res = asn1_string_encode(ASN1_OCTETSTRING, &buffer[i], sizeof(buffer)-i, 50, c->callername, namelen);
|
|
if (res < 0)
|
|
return -1;
|
|
i += res;
|
|
ASN1_FIXUP(compstk, compsp, buffer, i);
|
|
#endif
|
|
|
|
invoke->id = invokeop;
|
|
invoke->descr_type = -1;
|
|
invoke->type = invokeop;
|
|
|
|
invoke->datalen = ix;
|
|
memcpy(invoke->data, c, ix);
|
|
cc_qsig_verbose( 1, VERBOSE_PREFIX_4 " * Sending QSIG_CCNR_REQ\n");
|
|
|
|
return ;
|
|
}
|