diff --git a/chan_capi.c b/chan_capi.c index 510568b..5c3e853 100644 --- a/chan_capi.c +++ b/chan_capi.c @@ -32,6 +32,7 @@ #include "chan_capi.h" #include "chan_capi_rtp.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197ade.h" #include "chan_capi_qsig_asn197no.h" #include "chan_capi_utils.h" diff --git a/chan_capi_qsig.h b/chan_capi_qsig.h index 0e21689..fe22f46 100644 --- a/chan_capi_qsig.h +++ b/chan_capi_qsig.h @@ -101,6 +101,8 @@ #define CCQSIG_TIMER_WAIT_PRPROPOSE 1 /* Wait x seconds */ +/* Common QSIG structs */ + /* * INVOKE Data struct, contains data for further operations */ @@ -136,6 +138,7 @@ struct cc_qsig_nfe { struct cc_qsig_entityaddr dst_addr; /* same here for destination */ }; +/* struct cc_qsig_calltransfer */ /* @@ -182,20 +185,5 @@ extern void interface_cleanup_qsig(struct capi_pvt *i); extern void pbx_capi_qsig_unload_module(struct capi_pvt *i); extern void pbx_capi_qsig_handle_info_indication(_cmsg *CMSG, unsigned int PLCI, unsigned int NCCI, struct capi_pvt *i); -/* - *** ECMA QSIG Functions - */ - -extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); -extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype); - -extern 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); -extern char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); #endif diff --git a/chan_capi_qsig_asn197ade.c b/chan_capi_qsig_asn197ade.c index a9e882a..5955d26 100644 --- a/chan_capi_qsig_asn197ade.c +++ b/chan_capi_qsig_asn197ade.c @@ -27,6 +27,7 @@ #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" /* @@ -116,3 +117,71 @@ unsigned int cc_qsig_asn197ade_add_numdigits(char *buf, int buflen, int *idx, un myidx = 1 + strlen(buf); return myidx; } + +/* + * Returns an "PresentedNumberScreened" from an string, encoded as in addressing-data-elements-asn1-97 + * data is pointer to PresentedNumberScreened struct + * return: + * index counter + */ +unsigned int cc_qsig_asn197ade_get_pns(unsigned char *data, int *idx, struct asn197ade_numberscreened *ns) +{ /* sample data: a0 08 80 03>513<0a 01 00 */ + int myidx = *idx; + char buf[ASN197ADE_NUMDIGITS_STRSIZE+1]; + unsigned int buflen = sizeof(buf); + unsigned res; + + ns->partyNumber = NULL; + ns->screeningInd = userProvidedNotScreened; + int numtype; + + numtype = (data[myidx++] & 0x0F); /* defines type of Number */ + + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * num type %i\n", numtype); */ + switch (numtype){ + case 0: + /* myidx points now to length */ + res = cc_qsig_asn197ade_get_partynumber(buf, buflen, &myidx, data); + if (!res) + return 0; + + myidx += res; + if (strlen(buf)) { + ns->partyNumber = strdup(buf); + } + + /* get screening indicator */ + if (data[myidx] == ASN1_ENUMERATED) { + myidx++; + ns->screeningInd = cc_qsig_asn1_get_integer(data, &myidx); + } + + break; + case 1: /* presentation restricted */ + myidx += data[myidx] + 1; /* this val should be zero */ + break; + case 2: /* number not available due to interworking */ + myidx += data[myidx] + 1; /* this val should be zero */ + break; + case 3: + /* myidx points now to length */ + res = cc_qsig_asn197ade_get_partynumber(buf, buflen, &myidx, data); + if (!res) + return 0; + + myidx += res; + if (strlen(buf)) { + ns->partyNumber = strdup(buf); + } + + /* get screening indicator */ + if (data[myidx] == ASN1_ENUMERATED) { + myidx++; + ns->screeningInd = cc_qsig_asn1_get_integer(data, &myidx); + } + + break; + }; + + return myidx - *idx; +} diff --git a/chan_capi_qsig_asn197ade.h b/chan_capi_qsig_asn197ade.h index b47ae73..51af7ea 100644 --- a/chan_capi_qsig_asn197ade.h +++ b/chan_capi_qsig_asn197ade.h @@ -23,7 +23,7 @@ #define ASN197ADE_NUMDIGITS_STRSIZE 20 struct asn197ade_numberscreened { - unsigned char *partyNumber; + char *partyNumber; enum { userProvidedNotScreened, userProvidedVerifiedAndPassed, @@ -37,4 +37,6 @@ extern unsigned int cc_qsig_asn197ade_get_numdigits(char *buf, int buflen, int * extern unsigned int cc_qsig_asn197ade_add_numdigits(char *buf, int buflen, int *idx, unsigned char *data); +extern unsigned int cc_qsig_asn197ade_get_pns(unsigned char *data, int *idx, struct asn197ade_numberscreened *ns); + #endif diff --git a/chan_capi_qsig_asn197no.c b/chan_capi_qsig_asn197no.c index 16f0825..4bc989a 100644 --- a/chan_capi_qsig_asn197no.c +++ b/chan_capi_qsig_asn197no.c @@ -27,6 +27,7 @@ #include "chan_capi.h" #include "chan_capi_utils.h" #include "chan_capi_qsig.h" +#include "chan_capi_qsig_ecma.h" #include "chan_capi_qsig_asn197no.h" /* diff --git a/chan_capi_qsig_core.c b/chan_capi_qsig_core.c index cf8f532..23b0f80 100644 --- a/chan_capi_qsig_core.c +++ b/chan_capi_qsig_core.c @@ -24,6 +24,7 @@ #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" @@ -574,14 +575,63 @@ signed int cc_qsig_identifyinvoke(struct cc_qsig_invokedata *invoke, int protoco } +/* + * find the interface (pvt) the PLCI belongs to + */ +static struct capi_pvt *capi_find_interface_bynumber(char * num) +{ + struct capi_pvt *i; + + if (!num) + return NULL; + + for (i = capi_iflist; i; i = i->next) { + if (strcmp(i->cid, num) == 0 || + strcmp(i->dnid, num) == 0) + return i; + } + +#if 0 + cc_mutex_lock(&nullif_lock); + for (i = nulliflist; i; i = i->next) { + if (strcmp(i->cid, num) == 0 || + strcmp(i->dnid, num) == 0) + break; + } + cc_mutex_unlock(&nullif_lock); +#endif + + return i; +} + static void pbx_capi_qsig_handle_ctc(struct cc_qsig_invokedata *invoke, struct capi_pvt *i) { - char *destination = cc_qsig_decode_ecma_calltransfer(invoke, i); + struct cc_qsig_ctcomplete ctc; + struct capi_pvt *ii; - if (destination) { - free(destination); +#define CLEAR_CTC { if (ctc.redirectionNumber.partyNumber) free(ctc.redirectionNumber.partyNumber);\ + if (ctc.basicCallInfoElements) free(ctc.basicCallInfoElements); \ + if (ctc.redirectionName) free(ctc.redirectionName); \ + if (ctc.argumentExtension) free(ctc.argumentExtension); } + + int res = cc_qsig_decode_ecma_calltransfer(invoke, i, &ctc); + + if (!res) + return; + + if (ctc.redirectionNumber.partyNumber && (ctc.endDesignation == 2)) { /* TODO: activate this - have a bug in incoming PathReplacement handling */ + ii = capi_find_interface_bynumber(ctc.redirectionNumber.partyNumber); + if (ii) { + cc_verbose(1, 1, VERBOSE_PREFIX_3 "QSIG: Call Transfer partner channel for %s found at channel %s\n", ctc.redirectionNumber.partyNumber, ii->vname); + + CLEAR_CTC + + ast_channel_masquerade(i->owner, ii->owner); + } } + CLEAR_CTC + return ; } diff --git a/chan_capi_qsig_ecma.c b/chan_capi_qsig_ecma.c index 2674186..5e18a47 100644 --- a/chan_capi_qsig_ecma.c +++ b/chan_capi_qsig_ecma.c @@ -24,6 +24,7 @@ #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" @@ -427,7 +428,7 @@ void cc_qsig_encode_ecma_calltransfer(unsigned char * buf, unsigned int *idx, st * returns * transfer to destination number */ -char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i) +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; @@ -444,7 +445,15 @@ char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct 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; } + 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_verbose(1, 1, VERBOSE_PREFIX_4 " * not Handling QSIG CALL TRANSFER - "x); return 0; } cc_verbose(1, 1, VERBOSE_PREFIX_4 "Handling QSIG CALL TRANSFER (id# %#x)\n", invoke->id); @@ -461,11 +470,20 @@ char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct } if (data[myidx++] == ASN1_ENUMERATED) { - ct_enddesignation = cc_qsig_asn1_get_integer(data, &myidx); + 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 0 if (data[myidx] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { /* Parameter 0: partyNumber - transferee number */ myidx ++; @@ -484,7 +502,8 @@ char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct } else { myidx += 2; /* HACK: I've seen an IMPLICIT ade "numberNotAvailableDueToInterworking NULL" */ } - +#endif + /* TODO: remove this code snippet, when it's 100% working */ #if 0 if (data[myidx++] == (ASN1_TC_CONTEXTSPEC | ASN1_TF_CONSTRUCTED | 0)) { /* Parameter 0: partyNumber - transferee number */ @@ -514,9 +533,15 @@ char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct 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]); + /* TODO: check size -> could be bigger than 256 bytes - MSB is set then */ + ctc->basicCallInfoElements = malloc(data[myidx]); + if (ctc->basicCallInfoElements) { + memcpy(ctc->basicCallInfoElements, &data[myidx+1], data[myidx] ); + } else { + cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - couldn't allocate memory for basicCallInfoElements.\n", (int)data[myidx]); + } + /* cc_verbose(1, 1, VERBOSE_PREFIX_4 " * QSIG CALL TRANSFER - ignoring application data (%i bytes).\n", (int)data[myidx]); */ myidx += data[myidx] + 1; } } @@ -524,18 +549,21 @@ char *cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct 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 = strdup(ct_name); } } if (myidx < datalength) { if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */ - ct_status = cc_qsig_asn1_get_integer(data, &myidx); + ctc->callStatus = 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]); + cc_verbose(1, 1, 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 strdup(ct_target); + return 1; #undef ct_err } diff --git a/chan_capi_qsig_ecma.h b/chan_capi_qsig_ecma.h new file mode 100644 index 0000000..ac76d62 --- /dev/null +++ b/chan_capi_qsig_ecma.h @@ -0,0 +1,56 @@ +/* + * (QSIG) + * + * Implementation of QSIG extensions for CHAN_CAPI + * + * Copyright 2006-2007 (c) Mario Goegel + * + * Mario Goegel + * + * This program is free software and may be modified and + * distributed under the terms of the GNU Public License. + */ + +#include "chan_capi_qsig_asn197ade.h" + +#ifndef PBX_QSIG_ECMA_H +#define PBX_QSIG_ECMA_H + +/* ECMA Features structs */ + +/* Call Transfer Complete struct */ +struct cc_qsig_ctcomplete { + enum { + primaryEnd, /* 0 */ + secondaryEnd /* 1 */ + } endDesignation; + + struct asn197ade_numberscreened redirectionNumber; + char *basicCallInfoElements; /* OPTIONAL: ASN1_APPLICATION Type */ + char *redirectionName; /* OPTIONAL */ + enum { + answered, + alerting + } callStatus; /* DEFAULT: answered */ + char *argumentExtension; /* OPTIONAL: ASN1_SEQUENCE - manufacturer specific extension */ +}; + + +/* + *** ECMA QSIG Functions + */ + +extern void cc_qsig_op_ecma_isdn_namepres(struct cc_qsig_invokedata *invoke, struct capi_pvt *i); +extern int cc_qsig_encode_ecma_name_invoke(unsigned char * buf, unsigned int *idx, struct cc_qsig_invokedata *invoke, struct capi_pvt *i, int nametype); + +extern 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); +extern unsigned int cc_qsig_decode_ecma_calltransfer(struct cc_qsig_invokedata *invoke, struct capi_pvt *i, struct cc_qsig_ctcomplete *ctc); + +#endif