/*
 * libpri: An implementation of Primary Rate ISDN
 *
 * Written by Mark Spencer <markster@digium.com>
 *
 * Copyright (C) 2001, Digium, Inc.
 * All Rights Reserved.
 * Copyright (C) 2003-2006 Junghanns.NET GmbH
 * Klaus-Peter Junghanns <kpj@junghanns.net>
 */

/*
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2 as published by the
 * Free Software Foundation. See the LICENSE file included with
 * this program for more details.
 */
 
#ifndef _PRI_INTERNAL_H
#define _PRI_INTERNAL_H

#include <stddef.h>
#include <sys/time.h>

#define DBGHEAD __FILE__ ":%d %s: "
#define DBGINFO __LINE__,__PRETTY_FUNCTION__

struct pri_sched {
	struct timeval when;
	void (*callback)(void *data);
	void (*callback2)(void *data, int);
	void *data;
	char hasdata2;
	int data2;
};

struct q921_frame;
enum q931_state;
enum q931_mode;

/* No more than 128 scheduled events */
/* XXX is this sufficient for nfs ??? */
#define MAX_SCHED 128

/* this can be freely configured to support more devices .... ok, 63 would be max! */
#define Q921_MAX_TEIS 16

/* dynamically allocated TEIs start here */
#define Q921_TEI_BASE 64

#define MAX_TIMERS 32

struct pri {
	int fd;				/* File descriptor for D-Channel */
	pri_io_cb read_func;		/* Read data callback */
	pri_io_cb write_func;		/* Write data callback */
	void *userdata;
	struct pri *subchannel;	/* Sub-channel if appropriate */
	struct pri *master;		/* Master channel if appropriate */
	struct pri_sched pri_sched[MAX_SCHED];	/* Scheduled events */
	int debug;			/* Debug stuff */
	int debugfd;
	int state;			/* State of D-channel */
	int switchtype;		/* Switch type */
	int nsf;		/* Network-Specific Facility (if any) */
	int localtype;		/* Local network type (unknown, network, cpe) */
	int remotetype;		/* Remote network type (unknown, network, cpe) */

	int sapi;
	int tei;
	int protodisc;
	unsigned int bri:1;
	unsigned int acceptinbanddisconnect:1;	/* Should we allow inband progress after DISCONNECT? */
	
	/* Q.921 State */
  	int q921_state[Q921_MAX_TEIS];
  	char dchanup;

  	/* TEI registry */
      	char q921_teis[Q921_MAX_TEIS];

      	char q921_tei_check[Q921_MAX_TEIS];
      	unsigned short q921_tei_check_ri[Q921_MAX_TEIS];

  	unsigned int ri;

  	int busy[Q921_MAX_TEIS];			/* Peer is busy */

  	int window[Q921_MAX_TEIS];			/* Max window size */
 	int windowlen[Q921_MAX_TEIS];		/* Fullness of window */
  	int v_s[Q921_MAX_TEIS];			/* Next N(S) for transmission */
  	int v_a[Q921_MAX_TEIS];			/* Last acknowledged frame */
  	int v_r[Q921_MAX_TEIS];			/* Next frame expected to be received */
  	int v_na[Q921_MAX_TEIS];			/* What we've told our peer we've acknowledged */
  	int solicitfbit[Q921_MAX_TEIS];	/* Have we sent an I or S frame with the F-bit set? */
  	int retrans[Q921_MAX_TEIS];		/* Retransmissions */
  	int sabme_retrans[Q921_MAX_TEIS];		/* Retransmissions */

 	int sentrej[Q921_MAX_TEIS];		/* Are we in reject state */

 	/* Various timers */
  	int sabme_timer[Q921_MAX_TEIS];
  	int t203_timer[Q921_MAX_TEIS];
  	int t202_timer[Q921_MAX_TEIS];

 	int t201_timer[Q921_MAX_TEIS];
  	int t200_timer[Q921_MAX_TEIS];


	int cref;			/* Next call reference value */
	
	/* All ISDN Timer values */
	int timers[MAX_TIMERS];

	/* Used by scheduler */
	struct timeval tv;
	int schedev;
	pri_event ev;		/* Static event thingy */
	
	/* Q.921 (Re)transmission queue */
 	struct q921_frame *txqueue[Q921_MAX_TEIS];
	
	/* Q.931 calls */
	q931_call **callpool;
	q931_call *localpool;

	/* do we do overlap dialing */
	int overlapdial;

#ifdef LIBPRI_COUNTERS
	/* q921/q931 packet counters */
	unsigned int q921_txcount;
	unsigned int q921_rxcount;
	unsigned int q931_txcount;
	unsigned int q931_rxcount;
#endif

	unsigned char last_invoke;	/* Last ROSE invoke ID */
	unsigned char sendfacility;

 	int span; /* our fellow pri lives on this zaptel span */

};

struct pri_sr {
	int transmode;
	int channel;
	int exclusive;
	int nonisdn;
	char *caller;
	int callerplan;
	int callerplanani;
	char *callername;
	int callerpres;
	char *called;
	int calledplan;
	int userl1;
	int numcomplete;
	char *redirectingnum;
	int redirectingplan;
	int redirectingpres;
	int redirectingreason;
	int justsignalling;
	const char *useruserinfo;
	char *llc;
	int transferable;
};

/* Internal switch types */
#define PRI_SWITCH_GR303_EOC_PATH	19
#define PRI_SWITCH_GR303_TMC_SWITCHING	20

struct apdu_event {
	int message;			/* What message to send the ADPU in */
	void (*callback)(void *data);	/* Callback function for when response is received */
	void *data;			/* Data to callback */
	unsigned char apdu[255];			/* ADPU to send */
	int apdu_len; 			/* Length of ADPU */
	int sent;  			/* Have we been sent already? */
	struct apdu_event *next;	/* Linked list pointer */
};

/* q931_call datastructure */

struct q931_call {
	struct pri *pri;	/* PRI */
	int cr;				/* Call Reference */
	int forceinvert;	/* Force inversion of call number even if 0 */
	q931_call *next;
	/* Slotmap specified (bitmap of channels 31/24-1) (Channel Identifier IE) (-1 means not specified) */
	int slotmap;
	/* An explicit channel (Channel Identifier IE) (-1 means not specified) */
	int channelno;
	/* An explicit DS1 (-1 means not specified) */
	int ds1no;
	/* Whether or not the ds1 is explicitly identified or implicit.  If implicit
	   the bchan is on the same span as the current active dchan (NFAS) */
	int ds1explicit;
	/* Channel flags (0 means none retrieved) */
	int chanflags;
	
	int alive;			/* Whether or not the call is alive */
	int acked;			/* Whether setup has been acked or not */
	int con_acked;			/* Whether CONNECT has been CONNECT_ACKNOWLEDGEd or not */
	int sendhangupack;	/* Whether or not to send a hangup ack */
	int proc;			/* Whether we've sent a call proceeding / alerting */
 	int alert;			/* Whether we've sent an alerting */

 	int tei;
 	q921_call *phones;
	
	int ri;				/* Restart Indicator (Restart Indicator IE) */

	/* Bearer Capability */
	int transcapability;
	int transmoderate;
	int transmultiple;
	int userl1;
	int userl2;
	int userl3;
	int rateadaption;
	
	int sentchannel;
	int justsignalling;		/* for a signalling-only connection */

	int progcode;			/* Progress coding */
	int progloc;			/* Progress Location */	
	int progress;			/* Progress indicator */
	int progressmask;		/* Progress Indicator bitmask */
	
	int notify;				/* Notification */
	
	int causecode;			/* Cause Coding */
	int causeloc;			/* Cause Location */
	int cause;				/* Cause of clearing */
	
	int peercallstate;		/* Call state of peer as reported */
	int ourcallstate;		/* Our call state */
	int sugcallstate;		/* Status call state */
	
	int callerplan;
	int callerplanani;
	int callerpres;			/* Caller presentation */
	char callerani[256];	/* Caller */
	char callernum[256];
	char callername[256];
 	int callerplanuser;
 	int callerpresuser;

	char keypad_digits[64];		/* Buffer for digits that come in KEYPAD_FACILITY */

	int ani2;               /* ANI II */
	
	int calledplan;
	int nonisdn;
	char callednum[256];	/* Called Number */
	int complete;			/* no more digits coming */
	int newcall;			/* if the received message has a new call reference value */

	int retranstimer;		/* Timer for retransmitting DISC */
	int t308_timedout;		/* Whether t308 timed out once */

	int redirectingplan;
	int redirectingpres;
	int redirectingreason;	      
	char redirectingnum[256];	/* Number of redirecting party */
	char redirectingname[256];	/* Name of redirecting party */

 	int t303timer;
 	int t303running;

	/* Filled in cases of multiple diversions */
	int origcalledplan;
	int origcalledpres;
	int origredirectingreason;	/* Original reason for redirect (in cases of multiple redirects) */
	char origcalledname[256];	/* Original name of person being called */
	char origcallednum[256];	/* Orignal number of person being called */

	int useruserprotocoldisc;
	char useruserinfo[256];
	char callingsubaddr[256];	/* Calling parties sub address */

 	char callid[10];	/* call identity for SUSPEND/RESUME */
 	char digits[256];	/* additional digits received via info msgs (cpn or keypad) */
 	char display[256];	/* display ie received in info msgs or for sending */

 	/* euroisdn facility fun */
 	int facility; /* FACILTIY received */
 	int aoc;
	
	long aoc_units;				/* Advice of Charge Units */

	struct apdu_event *apdus;	/* APDU queue for call */

	char llc[16]; /* low layer compatibility */
	int transferable;
	unsigned int rlt_call_id;	/* RLT call id */
};

extern int pri_schedule_event(struct pri *pri, int ms, void (*function)(void *data), void *data);

extern int pri_schedule_event2(struct pri *pri, int ms, void (*function)(void *data, int data2), void *data, int data2);

extern pri_event *pri_schedule_run(struct pri *pri);

extern void pri_schedule_del(struct pri *pri, int ev);

extern pri_event *pri_mkerror(struct pri *pri, char *errstr);

extern void pri_message(struct pri *pri, char *fmt, ...);

extern void pri_error(struct pri *pri, char *fmt, ...);

void libpri_copy_string(char *dst, const char *src, size_t size);

#endif
