/*
 * Gnophone: A client for the Asterisk PBX
 *
 * Copyright (C) 2000, Linux Support Services, Inc.
 *
 * Written by Mark Spencer
 *
 * Linux/UNIX version distributed under the terms of
 * the GNU General Public License
 *
 * phonecore.c: Core telephony thread.  This is something of a wrapper
 * around libiax to keep the audio stuff separated into a high performancce
 * thread.  There really should be a better way to do this though.
 *
 */

#ifndef _PHONECORE_H
#define _PHONECORE_H

#include <netinet/in.h>
#include "io.h"
#include "asched.h"

#define CHUNK_MS 20
#define CHUNKLEN 160

#define PC_MAX_REGS	4

/* Receive an image event in the "image" subset */
#define PC_EVENT_IMAGE		1
/* Audio received, reports audio level in audio -- call pc_audio_ready() when you get this. */
#define PC_EVENT_AUDIO  	2
/* A DTMF digit was received from the far end -- see "dtmf" subset */
#define PC_EVENT_DTMF		4
/* A Hangup is received from the far end */
#define PC_EVENT_HANGUP		5
/* Remote side answered the phone */
#define PC_EVENT_ANSWER		6
/* Remote side rejected you call */
#define PC_EVENT_REJECT		7
/* Other side accepted the call (but hasn't answered yet) */
#define PC_EVENT_ACCEPT	    8
/* Authentication is requested, you need to call an auth_reply */
#define PC_EVENT_AUTHRQ		9
/* Go to the given URL, call load complete when done */
#define PC_EVENT_URL		11
/* The other side is now ringing */
#define PC_EVENT_RINGA		12
/* A request was received to make an incoming call */
#define PC_EVENT_CONNECT	14
/* Lag reply -- tells you how much lag there is in the connection */
#define PC_EVENT_LAGREP 39
/* Text received to be displayed on the screen */
#define PC_EVENT_TEXT	42
/* Unlink your web browser */
#define PC_EVENT_UNLINK 40
/* Your request to link browsers was rejected */
#define PC_EVENT_LINKREJECT 41
/* This is the remote address of the peer you're calling */
#define PC_EVENT_ADDR 		27

/* When recieved registration has been updated ,also note event will contain
 * preferred caller id */
#define PC_EVENT_REGREP		13
/* Generated by pc_* frontends -- don't use directly */
#define PC_EVENT_LOADCOMPLETE 3
#define PC_EVENT_AUTHRP		10
#define PC_EVENT_SELECT		15
#define PC_EVENT_NEW		16
#define PC_EVENT_NEW_REPLY	17
#define PC_EVENT_SELAUDIO		18
#define PC_EVENT_AUDIO_REPLY	19
#define PC_EVENT_AUDIO_READY 21

#define PC_EVENT_AUDIO_DIGIT	22
#define PC_EVENT_AUDIO_RING		23
#define PC_EVENT_AUDIO_RINGING	24
#define PC_EVENT_AUDIO_SHUTUP	25
#define PC_EVENT_AUDIO_DEACTIVATE	26
#define PC_EVENT_CONFERENCE	28
#define PC_EVENT_UNCONFERENCE 29

#define PC_EVENT_ONHOOK 30
#define PC_EVENT_OFFHOOK 31

#define PC_EVENT_DIAL 32

#define PC_EVENT_DIAL_TBD 33
#define PC_EVENT_DPREQ 34
#define PC_EVENT_DPREP 35
#define PC_EVENT_COMPLETE 36
#define PC_EVENT_TRANSFER 37

#define PC_EVENT_OPTION_SET	43
#define PC_EVENT_OPTION_GET	44
#define PC_EVENT_OPTION_VAL	45

#define PC_EVENT_AUDIO_DIALTONE 46
#define PC_EVENT_AUDIO_BUSY 47

#define PC_EVENT_PEER_INFO 48
#define PC_EVENT_PEER_INFO_REQ (PC_EVENT_PEER_INFO+1)

#define PC_REG_SUCCESS	1
#define PC_REG_REJECT	2
#define PC_REG_TIMEOUT	3

/* No more than 32 calls simulataneously */
#define PC_MAX_CALLS		32

struct text_event {
	unsigned char text[8192];
};

struct image_event {
	int datalen;
	
	/* No images more than 16k */
	unsigned char data[8192];
};

struct audio_event {
	/* Audio level change */
	int level;
};

struct dpreq_event {
	unsigned char dest[256];
};

struct dprep_event {
	unsigned char number[256];
	int exists;
	int canexist;
	int nonexistant;
	int ignorepat;
};

struct lagrep_event {
	int lag;
	int jitter;
};

struct dtmf_event {
	char dtmf;
};

struct dial_event {
	char digit;
};

struct hangup_event {
	char why[256];
};

struct reject_event {
	char why[256];
};

struct connect_event {
	char callerid[256];
	char dest[256];
	char language[256];
	struct sockaddr_in addr;
	char dnid[256];
};

struct addr_event {
	struct sockaddr_in addr;
};

struct authrequest {
	int authmethods;
	char challenge[256];
	char username[256];
};

struct url_event {
	char url[1024];
	int link;
};

struct registration_reply {
	int status;
	char them[256];
	char ourip[256];
	char callerid[256];
	short ourport;
	int refresh;
};

struct transfer {
	char newip[256];
	int newport;
};

struct audio_select {
	int chan;
	int response;
};

struct auth_reply {
	char password[256];
	char challenge[256];
	int methods;
};

struct new_reply {
	int id;
};

struct registration_request {
	char server[256];
	char peer[256];
	char secret[256];
	int refresh;
};

struct option_event {
	char name[256];
	int datalen;
	int result;
	char data[4096];
};

struct peer_info {
	int callnos[PC_MAX_CALLS];
	int calls;
};

/* This is remarkably like the IAX events but oh well */
typedef struct pc_event {
	int len;
	int callno;
	int event;
	union {
		struct addr_event addr;
		struct image_event image;
		struct audio_event audio;
		struct dtmf_event dtmf;
		struct dial_event dial;
		struct reject_event reject;
		struct hangup_event hangup;
		struct authrequest authrequest;
		struct registration_reply regreply;
		struct registration_request regrequest;
		struct url_event url;
		struct connect_event connect;
		struct auth_reply authreply;
		struct new_reply newreply;
		struct audio_select asel;
		struct dpreq_event dpreq;
		struct dprep_event dprep;
		struct lagrep_event lag;
		struct text_event text;
		struct transfer transfer;
		struct option_event option;
		struct peer_info peer_info;
	} e;
} pc_event;

#define SOURCE_GUI		0
#define SOURCE_PC		1
#define SOURCE_PRI_OUT	2	/* Priority out */
#define SOURCE_PRI_IN	3	/* Priority in */

#define KEY \
	"This paragraph is Copyright (C) 2000, Linux Support Services, Inc.  \
In order for your module to load, it must return this key via a function \
called \"key\".  Any code which includes this paragraph must be licensed under \
the GNU General Public License version 2 or later (at your option).   Linux \
Support Services, Inc. reserves the right to allow other parties to license \
this paragraph under other terms as well."

extern int pc_write_event(int src, pc_event *e);

static inline int pc_simple_event(int src, int callno, int event)
{
	pc_event e;
	e.len = sizeof(pc_event);
	e.callno = callno;
	e.event = event;
	return pc_write_event(src, &e);
}

static inline int pc_send_unlink(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_UNLINK);
}

static inline int pc_send_link_reject(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_UNLINK);
}

static inline int pc_load_complete(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_LOADCOMPLETE);
}

static inline int pc_answer(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_ANSWER);
}

static inline int pc_ring_announce(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_RINGA);
}

static inline int pc_accept(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_ACCEPT);
}

static inline int pc_select(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_SELECT);
}

static inline int pc_conference(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_CONFERENCE);
}

static inline int pc_unconference(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_UNCONFERENCE);
}

static inline int pc_dial_tbd(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_DIAL_TBD);
}

static inline int  pc_audio_ready(void)
{
	return pc_simple_event(SOURCE_GUI, -1, PC_EVENT_AUDIO_READY);
}

static inline int pc_link_reject(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_LINKREJECT);
}

static inline int pc_unlink(int callno)
{
	return pc_simple_event(SOURCE_GUI, callno, PC_EVENT_UNLINK);
}

extern int pc_send_linked_url(int callno, char *url);

extern int pc_send_text(int callno, char *text);

/* Initialize phonecore (modules is a ';' delimited list of modules to load, or NULL to load all) */
extern int pc_init(char *modules);

extern void pc_cleanup(void);

extern int pc_send_dtmf(int callno, char digit);

extern int pc_send_dpreq(int callno, char *digits);

extern int pc_hangup(int callno, char *why);

extern int pc_audio_ack(int callno);

extern int pc_reject(int callno, char *why);

extern int pc_auth_reply(int callno, char *password, char *challenege, int authmethods);

extern int pc_call(int pcid, char *callerid, char *destination, char *lang);

extern int pc_complete(int callno, char *dest);

extern int pc_session_new(void);

extern int pc_get_fd(void);

extern int pc_select_audio(int chan);

extern int pc_peer_info(struct peer_info *);

extern void pc_dump_event(struct pc_event *e);

extern int pc_send_image(int callno, char *filename);

extern void *phonecore_thread(void *unused);

extern int pc_deny_link(int callno);

extern int pc_set_option(char *name, char *value, int len);
extern int pc_get_option(char *name, char *value, int *len);

pc_event *pc_get_event(void);

extern int pc_audio_ringing(void);
extern int pc_audio_ring(void);
extern int pc_audio_shutup(void);
extern int pc_audio_dialtone(void);
extern int pc_audio_busy(void);

/* PC Internal use only */
extern int *pc_io_add(int fd, ast_io_cb callback, short events, void *data);
extern int pc_io_remove(int *id);
extern int pc_sched_add(int when, ast_sched_cb callback, void *data);
extern int pc_sched_del(int id);
extern int pc_send_sound(short *a, int len, int repeat);
extern int pc_send_digit(char digit);

static inline int __pc_answer(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_ANSWER);
}

static inline int __pc_ring_announce(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_RINGA);
}

static inline int __pc_accept(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_ACCEPT);
}

static inline int __pc_send_unlink(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_UNLINK);
}

static inline int __pc_send_link_reject(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_UNLINK);
}

static inline int pc_onhook(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_ONHOOK);
}

static inline int pc_offhook(int src, int callno)
{
	return pc_simple_event(src, callno, PC_EVENT_OFFHOOK);
}
extern int pc_transfer(int src, int callno, char *newip, int newport);

extern int __pc_reject(int src, int callno, char *why);
extern int pc_write_event(int src, pc_event *e);

extern int pc_read_event(int src, pc_event *e);

extern int pc_addr(int src, int callno, struct sockaddr_in addr);

extern int pc_dial(int src, char digit);

		
#endif /* _PHONECORE_H */
