/*
 * (CAPI*)
 *
 * An implementation of Common ISDN API 2.0 for Asterisk
 *
 * Copyright (C) 2005-2007 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 <asterisk/channel.h>
#include <asterisk/options.h>
#include <asterisk/pbx.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_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, 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 = (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_verbose(1, 1, 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_verbose(1, 1, 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_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 = 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;
				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;
				break;
			default:
				cc_verbose(1, 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);
	
 	pbx_builtin_setvar_helper(i->owner, "_QSIG_LI2_DIVNUM", divertPNS.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_verbose(1, 1, 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(&param, "|");
			cidlen = strlen(cid);
			if (cidlen > 20)	/* HACK: stop action here, maybe we have invalid data */
				cidlen = 20;
		} else {
			char *tmp = strsep(&param, "|");
			tmp = NULL;
			cid = strsep(&param, "|");
			cidlen = strlen(cid);
			if (cidlen > 20)	/* HACK: stop action here, maybe we have invalid data */
				cidlen = 20;
			
			ccanswer = strsep(&param, "|");
			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
 */
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_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);

	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 = 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]);
			}
			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 = strdup(ct_name);
		}
	}
	
	if (myidx < datalength) {
		if (data[myidx++] == ASN1_ENUMERATED) { /* Call Status */
			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", 
		   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(&param, "|");
	srclen = strlen(cidsrc);
	if (srclen > 20)	/* HACK: stop action here, maybe we have invalid data */
		srclen = 20;
	
	ciddst = strsep(&param, "|");
	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;
}
