- added code for QSIG number handling
 - cleanup code for CallTransfer - more some more cleanup has to follow
 - deactivated pathReplacementon on call transfer - there's a bug somewhere
This commit is contained in:
MelwareDE 2007-06-12 20:02:36 +00:00
parent d1ad040c4b
commit 04e1dab784
8 changed files with 223 additions and 28 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
/*

View File

@ -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,13 +575,62 @@ 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 ;
}

View File

@ -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,6 +502,7 @@ 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
@ -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
}

56
chan_capi_qsig_ecma.h Normal file
View File

@ -0,0 +1,56 @@
/*
* (QSIG)
*
* Implementation of QSIG extensions for CHAN_CAPI
*
* Copyright 2006-2007 (c) Mario Goegel
*
* 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 "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