/* * (CAPI*) * * An implementation of Common ISDN API 2.0 for Asterisk * * Copyright (C) 2005-2007 Cytronics & Melware * Copyright (C) 2007 Mario Goegel * * Armin Schindler * Mario Goegel * * This program is free software and may be modified and * distributed under the terms of the GNU Public License. */ #include #include #include #include #include #include #include "chan_capi20.h" #include "chan_capi.h" #include "chan_capi_utils.h" #include "chan_capi_qsig.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_verbose(1, 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 */ i->owner->cid.cid_name = strdup(callername); /* Save name to callerid */ 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_verbose(1, 1, VERBOSE_PREFIX_4 " * deleting previously received name.\n", nametype, namelength, callername); free(i->qsig_data.dnameid); } i->qsig_data.dnameid = strdup(callername); /* save name as destination in qsig specific fields */ /* there's no similarly field in asterisk */ break; default: break; } cc_verbose(1, 1, 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) { unsigned char namebuf[51]; unsigned char data[255]; int dataidx = 0; int namelen = 0; if (i->owner->cid.cid_name) namelen = strlen(i->owner->cid.cid_name); if (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, i->owner->cid.cid_name, namelen); } invoke->id = 1; invoke->descr_type = -1; /* Let others do the work: qsig_add_invoke */ invoke->type = 0; /* Invoke Operation Number, if OID it's the last byte*/ if (namelen>0) { data[dataidx++] = 0x80 | (nametype % 4); /* We send only simple Name, Namepresentation allowed */ data[dataidx++] = namelen; memcpy(&data[dataidx], namebuf, namelen); dataidx += namelen; } else { data[dataidx++] = 0x84; /* Name not available */ data[dataidx++] = 0; } invoke->datalen = dataidx; memcpy(invoke->data, data, dataidx); cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending \"%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]; 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_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG LEG INFO2 (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 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_verbose(1, 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_verbose(1, 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 = cc_qsig_asn197ade_get_partynumber(divertNum, ASN197ADE_NUMDIGITS_STRSIZE, &myidx, invoke->data); if (temp) { myidx += temp; } break; case 2: temp = cc_qsig_asn197ade_get_partynumber(origCalledNum, ASN197ADE_NUMDIGITS_STRSIZE, &myidx, invoke->data); if (temp) { myidx += temp; } break; case 3: /* Redirecting Name */ myidx++; temp = cc_qsig_asn197no_get_name(divertName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data); if (temp) { myidx += temp; } break; case 4: /* origCalled Name */ myidx++; temp = cc_qsig_asn197no_get_name(origCalledName, ASN197NO_NAME_STRSIZE, &temp2, &myidx, invoke->data); if (temp) { myidx += temp; } 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); 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 " * Got QSIG_LEG_INFO2: %i(%i), %ix %s->%s, %s->%s\n", divReason, orgDivReason, divCount, origCalledNum, divertNum, 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, "|"); 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; } } else { /* cid = 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 = strdup(i->cid); cidlen = strlen(cid); if (ii) { /* send callers name to user B */ if (ii->owner->cid.cid_name) { name = ast_strdupa(ii->owner->cid.cid_name); namelength = strlen(name); } } } 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 = 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_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_CT: %i->%s\n", info, cid); if (cid) 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 */ char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i) { 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" }; int ct_status = 0; char ct_target[ASN197ADE_NUMDIGITS_STRSIZE+1] = { 0 }; char ct_name[ASN197NO_NAME_STRSIZE+1] = { "EMPTY" }; int ct_enddesignation = 0; int ct_numberpresentation = 0; unsigned int namelength = 0; int temp = 0; #define ct_err(x...) { cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - "x); return NULL; } cc_verbose(1, 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) { ct_enddesignation = cc_qsig_asn1_get_integer(data, &myidx); } else { ct_err("no endDesignation information.\n"); } if (data[myidx] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { /* Parameter 0: partyNumber - transferee number */ myidx ++; temp = cc_qsig_asn197ade_get_partynumber(ct_target, ASN197ADE_NUMDIGITS_STRSIZE+1, &myidx, data); if (temp) myidx += temp + 1; /* HACK: this has to be moved to _get_presentednumberscreened */ if (data[myidx++] == ASN1_ENUMERATED) { ct_numberpresentation = cc_qsig_asn1_get_integer(data, &myidx); } else { ct_err("screeningIndicator is missing.\n"); return NULL; } } else { myidx += 2; /* HACK: I've seen an IMPLICIT ade "numberNotAvailableDueToInterworking NULL" */ } /* TODO: remove this code snippet, when it's 100% working */ /* if (data[myidx++] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { */ /* Parameter 0: partyNumber - transferee number */ /* if (!data[myidx++]) /* length = 0 */ /* ct_err("No destination received.\n"); if (data[myidx++] != ASN1_TC_CONTEXTSPEC) ct_err("No destination received.\n"); temp = cc_qsig_asn1_get_string((unsigned char*)&ct_target, sizeof(ct_target), &data[myidx]); if (temp) { myidx += temp + 1; } else { cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - partyNumber expected (%i)\n", myidx); return NULL; } if (data[myidx++] == ASN1_ENUMERATED) { ct_numberpresentation = cc_qsig_asn1_get_integer(data, &myidx); } else { cc_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - wrong encoded #2.\n"); return NULL; } }*/ if (myidx < datalength) { if (data[myidx] == ASN1_TC_APPLICATION) { /* ignore special Application Parameters - have no info about content */ myidx++; cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - ignoring application data (%i bytes).\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 (myidx < datalength) { if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */ ct_status = cc_qsig_asn1_get_integer(data, &myidx); } } cc_verbose(1, 1, VERBOSE_PREFIX_4 " * Got QSIG CALL TRANSFER endDesignation: %i partyNumber: %s (ScreeningInd: %i), partyName: \"%s\", Call state: %s\n", ct_enddesignation, ct_target, ct_numberpresentation, ct_name, ct_status_txt[ct_status]); return strdup(ct_target); #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, "|"); srclen = strlen(cidsrc); if (srclen > 20) /* HACK: stop action here, maybe we have invalid data */ srclen = 20; ciddst = strsep(¶m, "|"); dstlen = strlen(ciddst); if (dstlen > 20) /* HACK: stop action here, maybe we have invalid data */ dstlen = 20; seqlen += srclen + dstlen; c[ix++] = ASN1_SEQUENCE | ASN1_TF_CONSTRUCTED; /* start of SEQUENCE */ c[ix++] = seqlen; c[ix++] = ASN1_TC_CONTEXTSPEC; /* val 1 - Destination CallerID */ c[ix++] = dstlen; memcpy(&c[ix], ciddst, dstlen); ix += dstlen; c[ix++] = ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED; /* val 2 - Source Caller ID struct */ c[ix++] = 5 + srclen; c[ix++] = ASN1_TC_CONTEXTSPEC; /* CallerID */ c[ix++] = srclen; memcpy(&c[ix], cidsrc, srclen); ix += srclen; c[ix++] = ASN1_ENUMERATED; /* Screening Indicator */ c[ix++] = 1; /* length */ c[ix++] = 1; /* 01 = userProvidedVerifiedAndPassed ...we hope so */ c[ix++] = ASN1_BOOLEAN; /* val 3 - wait for connect ? */ c[ix++] = 1; c[ix++] = 0; /* end of SEQUENCE */ /* there are optional data possible here */ invoke->id = 99; invoke->descr_type = -1; invoke->type = 99; invoke->datalen = ix; memcpy(invoke->data, c, ix); cc_verbose(1, 1, 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_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 " * 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) { /* TODO: write code */ int invokeop = 4; char *callid, *reroutingnr; int cidlen, rrnlen; int seqlen = 4; char c[255]; int ix = 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; 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; /* 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_verbose(1, 1, VERBOSE_PREFIX_4 " * Sending QSIG_PATHREPLACEMENT_PROPOSE: Call identity: %s, Party number: %s\n", callid, reroutingnr); return; }