QSIG:
- 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:
parent
d1ad040c4b
commit
04e1dab784
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 ;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue