#include "debug.h"
#include "p_util.h"

/* Frame types */
#define AST_FRAME_DTMF		1		/* A DTMF digit, subclass is the digit */
#define AST_FRAME_VOICE		2		/* Voice data, subclass is AST_FORMAT_* */
#define AST_FRAME_VIDEO		3		/* Video frame, maybe?? :) */
#define AST_FRAME_CONTROL	4		/* A control frame, subclass is AST_CONTROL_* */
#define AST_FRAME_NULL		5		/* An empty, useless frame */
#define AST_FRAME_IAX		6		/* Inter Aterisk Exchange private frame type */
#define AST_FRAME_TEXT		7		/* Text messages */
#define AST_FRAME_IMAGE		8		/* Image Frames */
#define AST_FRAME_HTML		9		/* HTML Frames */

/* HTML subclasses */
#define AST_HTML_URL		1		/* Sending a URL */
#define AST_HTML_DATA		2		/* Data frame */
#define AST_HTML_BEGIN		4		/* Beginning frame */
#define AST_HTML_END		8		/* End frame */
#define AST_HTML_LDCOMPLETE	16		/* Load is complete */
#define AST_HTML_NOSUPPORT	17		/* Peer is unable to support HTML */
#define AST_HTML_LINKURL	18		/* Send URL and track */
#define AST_HTML_UNLINK		19		/* Request no more linkage */
#define AST_HTML_LINKREJECT	20		/* Reject LINKURL */

/* Data formats for capabilities and frames alike */
#define AST_FORMAT_G723_1	(1 << 0)	/* G.723.1 compression */
#define AST_FORMAT_GSM		(1 << 1)	/* GSM compression */
#define AST_FORMAT_ULAW		(1 << 2)	/* Raw mu-law data (G.711) */
#define AST_FORMAT_ALAW		(1 << 3)	/* Raw A-law data (G.711) */
#define AST_FORMAT_MP3		(1 << 4)	/* MPEG-2 layer 3 */
#define AST_FORMAT_ADPCM	(1 << 5)	/* ADPCM (whose?) */
#define AST_FORMAT_SLINEAR	(1 << 6)	/* Raw 16-bit Signed Linear (8000 Hz) PCM */
#define AST_FORMAT_LPC10	(1 << 7)	/* LPC10, 180 samples/frame */
#define AST_FORMAT_G729A	(1 << 8)	/* G.729a Audio */
#define AST_FORMAT_SPEEX	(1 << 9)	/* Speex Audio, variable */
#define AST_FORMAT_ILBC		(1 << 10)	/* ILBC audio, 50 bytes per 240 samples */

#define AST_FORMAT_MAX_AUDIO 	(1 << 15)	/* Maximum audio format */
#define AST_FORMAT_JPEG			(1 << 16)	/* JPEG Images */
#define AST_FORMAT_PNG			(1 << 17)	/* PNG Images */
#define AST_FORMAT_H261			(1 << 18)	/* H.261 Video */
#define AST_FORMAT_H263			(1 << 19)	/* H.263 Video */

/* Control frame types */
#define AST_CONTROL_HANGUP		1		/* Other end has hungup */
#define AST_CONTROL_RING		2		/* Local ring */
#define AST_CONTROL_RINGING 	3		/* Remote end is ringing */
#define AST_CONTROL_ANSWER		4		/* Remote end has answered */
#define AST_CONTROL_BUSY		5		/* Remote end is busy */
#define AST_CONTROL_TAKEOFFHOOK 6		/* Make it go off hook */
#define AST_CONTROL_OFFHOOK		7		/* Line is off hook */
#define AST_CONTROL_CONGESTION	8		/* Congestion (circuits busy) */
#define AST_CONTROL_FLASH		9		/* Flash hook */
#define AST_CONTROL_WINK		0x0a	/* Wink */
#define AST_CONTROL_OPTION		0x0b	/* Set an option */
#define AST_CONTROL_KEYRADIO	0x0c	/* Key Radio */
#define AST_CONTROL_UNKEYRADIO	0x0d	/* Unkey Radio */
#define AST_CONTROL_CALLPROGRESS	0x0e	/* Call is in progress */
#define AST_CONTROL_CALLPROCEEDING	0x0f	/* Call is proceeding */
#define AST_CONTROL_HOLD		0x10	/* Call is placed on hold */
#define AST_CONTROL_UNHOLD		0x11	/* Call is taken off hold */

/* Max version of IAX protocol we support */
#define IAX_PROTO_VERSION 2

/* Subclass for AST_FRAME_IAX */
#define IAX_COMMAND_NEW		1
#define IAX_COMMAND_PING	2
#define IAX_COMMAND_PONG	3
#define IAX_COMMAND_ACK		4
#define IAX_COMMAND_HANGUP	5
#define IAX_COMMAND_REJECT	6
#define IAX_COMMAND_ACCEPT	7
#define IAX_COMMAND_AUTHREQ	8
#define IAX_COMMAND_AUTHREP	9
#define IAX_COMMAND_INVAL	10
#define IAX_COMMAND_LAGRQ	11
#define IAX_COMMAND_LAGRP	12
#define IAX_COMMAND_REGREQ	13	/* Registration request */
#define IAX_COMMAND_REGAUTH	14	/* Registration authentication required */
#define IAX_COMMAND_REGACK	15	/* Registration accepted */
#define IAX_COMMAND_REGREJ	16	/* Registration rejected */
#define IAX_COMMAND_REGREL	17	/* Force release of registration */
#define IAX_COMMAND_VNAK	18	/* If we receive voice before valid first voice frame, send this */
#define IAX_COMMAND_DPREQ	19	/* Request status of a dialplan entry */
#define IAX_COMMAND_DPREP	20	/* Request status of a dialplan entry */
#define IAX_COMMAND_DIAL	21	/* Request a dial on channel brought up TBD */
#define IAX_COMMAND_TXREQ	22	/* Transfer Request */
#define IAX_COMMAND_TXCNT	23	/* Transfer Connect */
#define IAX_COMMAND_TXACC	24	/* Transfer Accepted */
#define IAX_COMMAND_TXREADY	25	/* Transfer ready */
#define IAX_COMMAND_TXREL	26	/* Transfer release */
#define IAX_COMMAND_TXREJ	27	/* Transfer reject */
#define IAX_COMMAND_QUELCH	28	/* Stop audio/video transmission */
#define IAX_COMMAND_UNQUELCH 	29	/* Resume audio/video transmission */
#define IAX_COMMAND_POKE    	30  	/* Like ping, but does not require an open connection */
#define IAX_COMMAND_PAGE	31	/* Paging description */
#define IAX_COMMAND_MWI		32	/* Stand-alone message waiting indicator */
#define IAX_COMMAND_UNSUPPORT	33	/* Unsupported message received */
#define IAX_COMMAND_TRANSFER	34	/* Request remote transfer */
#define IAX_COMMAND_PROVISION	35	/* Provision device */
#define IAX_COMMAND_FWDOWNL	36	/* Download firmware */
#define IAX_COMMAND_FWDATA	37	/* Firmware Data */

/* IAX Information elements */
#define IAX_IE_CALLED_NUMBER		0x01	/* Number/extension being called - string */
#define IAX_IE_CALLING_NUMBER		0x02	/* Calling number - string */
#define IAX_IE_CALLING_ANI			0x03	/* Calling number ANI for billing  - string */
#define IAX_IE_CALLING_NAME			0x04	/* Name of caller - string */
#define IAX_IE_CALLED_CONTEXT		0x05	/* Context for number - string */
#define IAX_IE_USERNAME				0x06	/* Username (peer or user) for authentication - string */
#define IAX_IE_PASSWORD				0x07	/* Password for authentication - string */
#define IAX_IE_CAPABILITY			0x08	/* Actual codec capability - unsigned int */
#define IAX_IE_FORMAT				0x09	/* Desired codec format - unsigned int */
#define IAX_IE_LANGUAGE				0x0a	/* Desired language - string */
#define IAX_IE_VERSION				0x0b	/* Protocol version - short */
#define IAX_IE_ADSICPE				0x0c	/* CPE ADSI capability - short */
#define IAX_IE_DNID					0x0d	/* Originally dialed DNID - string */
#define IAX_IE_AUTHMETHODS			0x0e	/* Authentication method(s) - short */
#define IAX_IE_CHALLENGE			0x0f	/* Challenge data for MD5/RSA - string */
#define IAX_IE_MD5_RESULT			0x10	/* MD5 challenge result - string */
#define IAX_IE_RSA_RESULT			0x11	/* RSA challenge result - string */
#define IAX_IE_APPARENT_ADDR		0x12	/* Apparent address of peer - struct sockaddr_in */
#define IAX_IE_REFRESH				0x13	/* When to refresh registration - short */
#define IAX_IE_DPSTATUS				0x14	/* Dialplan status - short */
#define IAX_IE_CALLNO				0x15	/* Call number of peer - short */
#define IAX_IE_CAUSE				0x16	/* Cause - string */
#define IAX_IE_IAX_UNKNOWN			0x17	/* Unknown IAX command - byte */
#define IAX_IE_MSGCOUNT				0x18	/* How many messages waiting - short */
#define IAX_IE_AUTOANSWER			0x19	/* Request auto-answering -- none */
#define IAX_IE_MUSICONHOLD			0x1a	/* Request musiconhold with QUELCH -- none or string */
#define IAX_IE_TRANSFERID			0x1b	/* Transfer Request Identifier -- int */
#define IAX_IE_RDNIS				0x1c	/* Referring DNIS -- string */
#define IAX_IE_PROVISIONING			0x1d	/* Provisioning info */
#define IAX_IE_AESPROVISIONING		0x1e	/* AES Provisioning info */
#define IAX_IE_DATETIME				0x1f	/* Date/Time */
#define IAX_IE_DEVICETYPE			0x20	/* Device Type -- string */
#define IAX_IE_SERVICEIDENT			0x21	/* Service Identifier -- string */
#define IAX_IE_FIRMWAREVER			0x22	/* Firmware revision -- u16 */
#define IAX_IE_FWBLOCKDESC			0x23	/* Firmware block description -- u32 */
#define IAX_IE_FWBLOCKDATA			0x24	/* Firmware block of data -- raw */
#define IAX_IE_PROVVER				0x25	/* Provisioning Version (u32) */
#define IAX_IE_CALLINGPRES			0x26	/* Calling presentation  */
#define IAX_IE_CALLINGTON			0x27	/* Calling type of number */
#define IAX_IE_CALLINGTNS			0x28	/* Calling transit network select */
#define IAX_IE_SAMPLINGRATE			0x29	/* Supported sampling rates */
#define IAX_IE_CAUSECODE			0x2a	/* Hangup cause */
#define IAX_IE_ENCRYPTION			0x2b	/* Encryption format */
#define IAX_IE_ENCKEY				0x2c	/* 128-bit AES encryption key */
#define IAX_IE_CODECPREFS			0x2d	/* CODEC Negotiation */
#define IAX_IE_RRJITTER				0x2e	/* Received jitter, as in rfc1889 */
#define IAX_IE_RRLOSS				0x2f	/* Received loss, as in rfc1889 */
#define IAX_IE_RRPKTS				0x30	/* total number of frames received on a call, per rfc1889 */
#define IAX_IE_RRDELAY				0x31	/* Max playout delay for received frames in ms */
#define IAX_IE_RRDROPPED			0x32	/* Dropped frames (presumably by jitterbuffer) */
#define IAX_IE_RROOO				0x33	/* Frames received Out of Order */
#define IAX_IE_NUM					0x34

#define IAX_AUTH_PLAINTEXT			(1 << 0)
#define IAX_AUTH_MD5				(1 << 1)
#define IAX_AUTH_RSA				(1 << 2)

#define IAX_DPSTATUS_EXISTS			(1 << 0)
#define IAX_DPSTATUS_CANEXIST		(1 << 1)
#define IAX_DPSTATUS_NONEXISTANT	(1 << 2)
#define IAX_DPSTATUS_IGNOREPAT		(1 << 14)
#define IAX_DPSTATUS_MATCHMORE		(1 << 15)

/* Full frames are always delivered reliably */
#define IAX_FULLFR_SCALLNO	0		/* Source call number -- high bit must be 1 */
#define IAX_FULLFR_DCALLNO	2		/* Destination call number -- high bit is 1 if retransmission */
#define IAX_FULLFR_TSTAMP	4		/* 32-bit timestamp in milliseconds (from 1st transmission) */
#define IAX_FULLFR_OSEQNO	8		/* Packet number (outgoing) */
#define IAX_FULLFR_ISEQNO	9		/* Packet number (next incoming expected) */
#define IAX_FULLFR_TYPE		10		/* Frame type */
#define IAX_FULLFR_CSUB		11		/* Compressed subclass */
#define IAX_FULLFR_DATA		12


/* Mini header is used only for voice frames -- delivered unreliably */
/* Frametype implicitly VOICE_FRAME */
/* subclass implicit from last ast_iax2_full_hdr */
#define IAX_MINIFR_SCALLNO	0	/* Source call number -- high bit must be 0, rest must be non-zero */
#define IAX_MINIFR_TSTAMP	2	/* 16-bit Timestamp (high 16 bits from last ast_iax2_full_hdr) */
#define IAX_MINIFR_DATA		4

#define IAX_DEFAULT_REG_EXPIRE  60	/* By default require re-registration once per minute */
#define IAX_FLAG_FULL		0x8000
#define IAX_FLAG_RETRANS	0x8000
#define IAX_FLAG_SC_LOG		0x80
#define IAX_MAX_SHIFT		0x1F
#define IAX_MAX_RETRIES		5
#define IAX_UDP_TOS			0x50	// Precedence 010, low-delay

#define IAX_REG_SESSION		0
#define IAX_START_SESSION	1
#define IAX_SESSION_NUM		5
#define IAX_SESSION_ERROR	255

#define SESSION_STATE_IDLE		0
#define SESSION_STATE_USED		1
#define SESSION_STATE_FINALACK	2
#define SESSION_STATE_TIMEWAIT	3

#define IAX_TRANS_STATE_NONE		0
#define IAX_TRANS_STATE_REQUESTED	1
#define IAX_TRANS_STATE_CONNECTING	2
#define IAX_TRANS_STATE_READY		3
#define IAX_TRANS_STATE_RELEASED	4

#define IAX_MAX_CALL	2
#define IAX_CALL_ERROR	0xff
#define IAX_TRANSFERID_LEN	4

#define IAX_CALL_STATE_IDLE		0
#define IAX_CALL_STATE_CONNECTING	1
#define IAX_CALL_STATE_CONNECTED	2
#define IAX_CALL_STATE_TRANSFERRING	3

/* variable definitions */
#ifdef _IAX2_GLOBALS
#define _IAX2_EXT	
#else
#define _IAX2_EXT	extern
#endif

_IAX2_EXT XSHORT Iax2_iCallNo;

_IAX2_EXT XCHAR Iax2_iCallSess[IAX_MAX_CALL];
_IAX2_EXT XCHAR Iax2_iCallState[IAX_MAX_CALL];
_IAX2_EXT XCHAR Iax2_iIsCaller[IAX_MAX_CALL];
_IAX2_EXT XCHAR Iax2_iAudioType[IAX_MAX_CALL];
_IAX2_EXT XCHAR Iax2_iCallTimer[IAX_MAX_CALL];
_IAX2_EXT XCHAR Iax2_iCurCall;
_IAX2_EXT XCHAR Iax2_iCallIndex;

_IAX2_EXT XCHAR Sess_iState[IAX_SESSION_NUM];		// state of this session 
_IAX2_EXT XLONG Sess_lLastSent[IAX_SESSION_NUM];		// Last transmitted timestamp
_IAX2_EXT XLONG Sess_lOffset[IAX_SESSION_NUM];		// Time value that we base our transmission on
_IAX2_EXT XSHORT Sess_iCallNo[IAX_SESSION_NUM];		// Our call number
_IAX2_EXT XSHORT Sess_iPeerCallNo[IAX_SESSION_NUM];	// Peer's call number
_IAX2_EXT XCHAR Sess_iOSeqNo[IAX_SESSION_NUM];		// Our next outgoing sequence number
_IAX2_EXT XCHAR Sess_iRSeqNo[IAX_SESSION_NUM];		// Next sequence number they have not yet acknowledged
_IAX2_EXT XCHAR Sess_iISeqNo[IAX_SESSION_NUM];		// Our last received incoming sequence number
_IAX2_EXT XCHAR Sess_iTimer[IAX_SESSION_NUM];
_IAX2_EXT XCHAR Sess_iQuelch[IAX_SESSION_NUM];		// Is voice quelched (e.g. hold) 
_IAX2_EXT XCHAR Sess_pPeerIP[IAX_SESSION_NUM][IP_ALEN];
_IAX2_EXT XSHORT Sess_iPeerPort[IAX_SESSION_NUM];

_IAX2_EXT XCHAR Sess_iTransState[IAX_SESSION_NUM];	// Transfer state
_IAX2_EXT XCHAR Sess_iTransSession[IAX_SESSION_NUM];	// Transfer to session id (use on release)
// This is for when a TXCNT comes in and we have to decide that we're ready on the primary session
_IAX2_EXT XCHAR Sess_iTransOriginalSession[IAX_SESSION_NUM]; 
_IAX2_EXT XSHORT Sess_iTransCallNo[IAX_SESSION_NUM]; 
_IAX2_EXT XCHAR Sess_pTransferID[IAX_SESSION_NUM][IAX_TRANSFERID_LEN];

/* end variable definitions */

/* functions in iax_comp.c */
void iax2_ie_start();
void iax2_ie_add_xraw(UCHAR iType, PXCHAR pData, UCHAR iLen);
void iax2_ie_add_craw(UCHAR iType, PCCHAR pData, UCHAR iLen);
void iax2_ie_add_byte(UCHAR iType, UCHAR iData);
void iax2_ie_add_short(UCHAR iType, USHORT iData);
void iax2_ie_add_long(UCHAR iType, ULONG iData);
void iax2_ie_add_xstr(UCHAR iType, PXCHAR pStr);
void iax2_ie_add_cstr(UCHAR iType, PCCHAR pStr);
USHORT iax2_ie_get_len();
void iax2_debug_string(UCHAR iType, UCHAR iSubClass);


/* functions in iax_session.c */
void iax2_dbg_send(USHORT iLen, UCHAR iSession);
void iax2_rel_send(USHORT iLen, UCHAR iSession);
void iax2_open_socket(UCHAR iSession, PXCHAR pDstIP, USHORT iDstPort);
void iax2_session_startup();
void iax2_session_free(UCHAR iIndex);
void iax2_session_init(UCHAR iIndex);
UCHAR iax2_session_new();
UCHAR iax2_session_find_full(USHORT iSrcCallNo, USHORT iDstCallNo);
UCHAR iax2_session_find_new(USHORT iSrcCallNo);
UCHAR iax2_session_find_mini(USHORT iSrcCallNo);
void iax2_session_rxerror(UCHAR iIndex);
void iax2_session_set_state(UCHAR iIndex, UCHAR iState);
void iax2_session_finalack(UCHAR iIndex);
void iax2_session_handle_timer();
void iax2_session_fill(UCHAR iIndex, UCHAR iType, UCHAR iSubClass);
void iax2_session_send_packet(UCHAR iIndex, UCHAR iType, UCHAR iCommand, USHORT iDataLen);

/* functions in iax_rx.c */
void iax2_frame_startup();
void iax2_frame_free(UCHAR iIndex);
void iax2_frame_save(UCHAR iSession, USHORT iLen, UCHAR iOSeqNo);
void iax2_frame_handle_timer();
void iax2_frame_cancel(UCHAR iSession, UCHAR iOSeqNo);
void iax2_frame_rexmit(UCHAR iSession, UCHAR iOSeqNo);
void iax2_frame_txacked(UCHAR iSession);

/* functions in iax_voice.c */
void iax2_voice_init();
ULONG iax2_uncompress_subclass(UCHAR iSubClass);
UCHAR iax2_compress_subclass(ULONG iSubClass);
UCHAR iax2_get_codec(ULONG lFormat);
ULONG iax2_get_capability();
ULONG iax2_get_format(UCHAR iCodecType);
UCHAR iax2_audio_match(UCHAR iType);
void iax2_recv_voice(PXCHAR pData, USHORT iLen);

/* functions in iax2.c */
void iax2_call_end(UCHAR iCallIndex);
