// Copyright (C) 2000 Open Source Telecom Corporation.
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#ifndef	__CCXX_BAYONNE_H__
#define	__CCXX_BAYONNE_H__

#ifndef	__CCXX_SCRIPT_H__
#include <cc++/script.h>
#endif

#ifndef	__CCXX_SLOG_H__
#include <cc++/slog.h>
#endif

#ifndef	__CCXX_DSO_H__
#include <cc++/file.h>
#endif

#ifndef	__CCXX_SOCKET_H__
#include <cc++/socket.h>
#endif

#include <stdlib.h>

#ifdef	__FreeBSD__
#undef	read
#undef	write
#undef	readv
#undef	writev
#endif

#ifndef	COMMON_TPPORT_TYPE_DEFINED
typedef	short	tpport_t;
#endif

/* Bayonne uses a universal event record for all driver plugins and
   state handlers.  Not all drivers impliment the entire set of events
   and some drivers have specific events associated with their unique
   characteristcs.  However, most events are considered "universal".
*/

class Trunk;
class Service;
class phTone;

typedef enum {
	MODULE_DELIVERY,
	MODULE_SENDFILE,
	MODULE_SENDFAX,
	MODULE_NOTIFY,
	MODULE_TGI
}	modtype_t;

typedef enum {
	// step change requests
	TRUNK_STEP_HANGUP = 0,
	TRUNK_STEP_SLEEP,
	TRUNK_STEP_ANSWER,
	TRUNK_STEP_COLLECT,
	TRUNK_STEP_PLAY,
	TRUNK_STEP_RECORD,
	TRUNK_STEP_TONE,
	TRUNK_STEP_DIALXFER,
	TRUNK_STEP_FLASH,
	TRUNK_STEP_JOIN,
	TRUNK_STEP_EXIT = TRUNK_STEP_HANGUP
} trunkstep_t;

typedef	enum {
	// notify script from state handler
	TRUNK_SIGNAL_STEP = 0,
	TRUNK_SIGNAL_EXIT,
	TRUNK_SIGNAL_HANGUP=TRUNK_SIGNAL_EXIT,
	TRUNK_SIGNAL_ERROR,
	TRUNK_SIGNAL_TIMEOUT,
	TRUNK_SIGNAL_DTMF,
	TRUNK_SIGNAL_0,
	TRUNK_SIGNAL_1,
	TRUNK_SIGNAL_2,
	TRUNK_SIGNAL_3,
	TRUNK_SIGNAL_4,
	TRUNK_SIGNAL_5,
	TRUNK_SIGNAL_6,
	TRUNK_SIGNAL_7,
	TRUNK_SIGNAL_8,
	TRUNK_SIGNAL_9,
	TRUNK_SIGNAL_STAR,
	TRUNK_SIGNAL_POUND,
	TRUNK_SIGNAL_A,
	TRUNK_SIGNAL_B,
	TRUNK_SIGNAL_C,
	TRUNK_SIGNAL_D,
	TRUNK_SIGNAL_DIALTONE,
	TRUNK_SIGNAL_BUSY,
	TRUNK_SIGNAL_CANCEL,
	TRUNK_SIGNAL_DRIVER
}	trunksignal_t;

typedef enum {
	// primary state handlers

	TRUNK_ENTER_STATE = 100,// newly entered handler state
	TRUNK_EXIT_STATE,	// exiting prior state (unused)
	TRUNK_STOP_STATE,	// request state termination
	TRUNK_NOTIFICATION,	// death notify event
	TRUNK_SERVICE_SUCCESS,	// service completion successful
	TRUNK_SERVICE_FAILURE,	// service completion failed
	TRUNK_SERVICE_LOOKUP,	// lookup transaction
	TRUNK_SERVICE_LOGIN,	// login transaction
	TRUNK_JOIN_REQUEST,	// request a join
	TRUNK_JOIN_ACCEPT,	// accept a join
	TRUNK_JOIN_CANCEL,	// cancel a join

	// tgi/integration control state handlers

	TRUNK_EXIT_SHELL = 200,	// tgi completion event
	TRUNK_START_SCRIPT,	// start of script
	TRUNK_RING_START,	// smdi/integrated answer
	TRUNK_STOP_DISCONNECT,	// integrated hangup notification

	// in the future these will be used

	TRUNK_START_INCOMING = TRUNK_RING_START,
	TRUNK_START_OUTGOING = TRUNK_START_SCRIPT,

	// primary "mode" selection controls

	TRUNK_MAKE_TEST =  300,	// request driver perform line test
	TRUNK_MAKE_BUSY,	// request driver lockout line
	TRUNK_MAKE_IDLE,	// request driver reset line
	TRUNK_MAKE_STEP,	// pass step event internally

	// basic trunk events

	TRUNK_LINE_WINK = 400,	// used for line disconnect notification
	TRUNK_TIMER_EXPIRED,	// driver specific port timer expired
	TRUNK_RINGING_ON,	// some drivers distinguish start/stop
	TRUNK_RINGING_OFF,	// default ring event
	TRUNK_TEST_IDLE,	// some drivers have line test completion
	TRUNK_TEST_FAILURE,	// some drivers notify errors
	TRUNK_ON_HOOK,		// some drivers notify on hook
	TRUNK_OFF_HOOK,		// some drivers notify off hook
	TRUNK_CALLER_ID,	// caller id parse request
	TRUNK_RINGING_DID,	// did digit ring signal
	TRUNK_CALL_DETECT,	// ISDN call detected notification
	TRUNK_CALL_CONNECT,	// ISDN call connection notification
	TRUNK_CALL_RELEASE,	// ISDN call release notification
	TRUNK_CALL_ACCEPT,	// ISDN incoming call accepted
	TRUNK_CALL_RINGING,	// digital T1 incoming call
	TRUNK_CALL_DISCONNECT,	// digital T1 circuit break

	// basic audio processing events

	TRUNK_AUDIO_IDLE = 500,	// audio reset or completion event
	TRUNK_INPUT_PENDING,	// some drivers monitor audio i/o status
	TRUNK_OUTPUT_PENDING,	// some drivers monitor audio i/p status
	TRUNK_AUDIO_BUFFER,	// some drivers return audio buffers
	TRUNK_TONE_IDLE,	// tone generator completion event
	TRUNK_DTMF_KEYDOWN,	// some drivers distinguish tone down
	TRUNK_DTMF_KEYUP,	// default dtmf event
	TRUNK_TONE_START,	// tone detected
	TRUNK_TONE_STOP,	// some drivers have tone completion event
	TRUNK_FSK_DETECT,	// fsk tone detect
	TRUNK_FAX_DETECT,	// fax tone detect
	TRUNK_VOX_DETECT,	// speaker detected
	TRUNK_AUDIO_START,	// some drivers may "vox" compress
	TRUNK_AUDIO_STOP,	// some drivers may "vox" compress
	TRUNK_CPA_DIALTONE,	// dialtone heard on the line
	TRUNK_CPA_BUSYTONE,
	TRUNK_CPA_RINGING,
	TRUNK_CPA_INTERCEPT,
	TRUNK_CPA_NODIALTONE,
	TRUNK_CPA_NORINGBACK,
	TRUNK_CPA_NOANSWER,
	TRUNK_CPA_CONNECT,

	// driver specific events and anomolies

	TRUNK_DRIVER_SPECIFIC=8000	// very oddball events
} trunkevent_t;

typedef enum
{
	DSP_MODE_INACTIVE = 0,	// dsp is idle
	DSP_MODE_VOICE,		// standard voice processing
	DSP_MODE_CALLERID,	// caller id support
	DSP_MODE_DATA,		// fsk modem mode
	DSP_MODE_FAX,		// fax support
	DSP_MODE_TDM,		// TDM bus with echo cancellation
	DSP_MODE_VOIP		// VoIP full duplex
} dspmode_t;

typedef enum
{
	TRUNK_MODE_INCOMING = 0,
	TRUNK_MODE_OUTGOING,
	TRUNK_MODE_INACTIVE,
	TRUNK_MODE_UNAVAILABLE
} trunkmode_t;
 
typedef enum
{
	STAT_MAX_INCOMING,
	STAT_MAX_OUTGOING,
	STAT_TOT_INCOMING,
	STAT_TOT_OUTGOING
} statitem_t;

#define TRUNK_CAP_VOICE		0x00000001
#define	TRUNK_CAP_DIAL		0x00000002
#define TRUNK_CAP_SENDFAX	0x00000004
#define	TRUNK_CAP_RECVFAX	0x00000008
#define	TRUNK_CAP_DATA		0x00000010

typedef union
{
	scriptsymbol_t sym;
	char data[sizeof(scriptsymbol_t) + 12];
}	numbersymbol_t;

typedef	union
{
	scriptsymbol_t bin;
	char data[sizeof(scriptsymbol_t) + 32];
}	digitsymbol_t;

typedef	struct
{
	
	int pid;
	unsigned seq;
	void *data;
}	execdata_t;

typedef	union
{
	struct
	{
		int rings;
		int timeout;
	}	answer;
	struct
	{
		char list[256];
		char *name;
		unsigned long offset;
		unsigned long limit;
		unsigned char volume;
	}	play;
	struct
	{
		char *name;
		timeout_t timeout;
		unsigned long offset;
		unsigned short term;
		unsigned char volume;
		unsigned long trim;
		bool append;
	}	record;
	struct
	{
		char digits[65];
		char *digit;
		timeout_t interdigit;
		bool exit;
	}	dialxfer;
	struct
	{
		timeout_t timeout;
		unsigned count;
		unsigned short term;
		unsigned short ignore;
	}	collect;
	struct
	{
		timeout_t wakeup;
		unsigned rings;
		unsigned loops;
	}	sleep;
	struct
	{
		timeout_t wakeup;
		unsigned loops;
		phTone *tone;
	}	tone;
	struct
	{
		timeout_t wakeup;
		Trunk *join;
		phTone *tone;
	}	join;
	struct
	{
		timeout_t offhook;
		timeout_t onhook;
	}	flash;
}	trunkdata_t;

typedef struct
{
	trunkevent_t id;	// event id
	union
	{
		struct
		{
			unsigned digit: 4;
			unsigned duration: 12;
			unsigned e1: 8;
			unsigned e2: 8;
		} dtmf;
		struct
		{
			unsigned tone: 8;
			unsigned energy: 8;
			unsigned duration: 16;
		} tone;
		struct
		{
			unsigned digit:  4;
			unsigned duration: 24;
		} ring;
		struct
		{
			unsigned seq;
			bool result;
			char *data;
		} lookup;
		int status;
		Trunk *trunk;
		void *data;
		char **argv;
		timeout_t duration;
		trunkstep_t step;
		char align[8];
	} parm;
} TrunkEvent;

#pragma pack(1)
typedef	struct
{
	char grp[32];
	char scr[32];
}	schedtmp;

typedef struct
{
	time_t update;
	char name[16];
	unsigned char ports;
	char stat[255];
}	statnode_t;

#pragma pack()	

/* This is used to bind user defined "functions" which may be loaded
   in a DSO module.
*/

typedef char *(*functioncall_t)(scriptsymbol_t *sym, char **args);

typedef struct
{
	char *name;
	functioncall_t function;
} FUNCTIONS;


/**
 * A call statistic class is used to manipulate call stats with a mutex
 * lock to prevent errors during "adjustment" periods.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short call statistic collection object.
 */
class CallStat : public Mutex
{
protected:
	int capacity;
	struct
	{
		int incoming;
		int outgoing;
	}	active, max, lastmax;

	struct
	{
		long incoming;
		long outgoing;
	}	total, lasttotal;

public:
	CallStat();

	/**
	 * Get current call capacity.
	 *
	 * @return capacity of this stat item.
	 */
	inline int getCapacity(void)
		{return capacity;};

	/**
	 * get a stat item.
	 *
	 * @param statitem to request.
	 * @return item value.
	 */
	long getStat(statitem_t item);

	/**
	 * inc active incoming call count.
	 */
	void incIncoming(void);

	/**
	 * dec active incoming call count.
	 */
	void decIncoming(void);

	/**
	 * inc active outging call count.
	 */
	void incOutgoing(void);

	/**
	 * dec active outgoing call count.
	 */
	void decOutgoing(void);

	/**
	 * Update stats, active to last.
	 */
	void Update(void);
};

/**
 * Phrasebook modules are used to convert things like numbers into
 * sets of prompts that form spoken words.  Translations are dso based
 * and are represented by the "languages" plugin.  A translator for
 * spanish may handle not just numbers, dates, etc, but also the
 * selection of masculine and feminine forms of numbers based on
 * usage, etc.  The translator classes provide some basic mechanics
 * for phrasebook tts in Bayonne.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short phrase translations dso base for tts.
 */
class Translator : protected Keydata
{
private:
	friend Translator *getTranslator(char *name);
	static Translator *first;
	Translator *next;

protected:
	/**
	 * Return the language this translator supports.
	 *
	 * @return language supported.
	 */
	virtual char *getName(void) = 0;

	/**
	 * get play buffer object.
	 *
	 * @return put buffer
	 * @param trunk object
	 */
	char *getPlayBuffer(Trunk *trunk);

	void scanDir(const char *language, const char *lib);

	Translator(const char *conf, const char *lib);

public:
	/**
	 * Perform a phrasebook translation of the current script
	 * statement and issue play request.
	 *
	 * @return ccscript error message or NULL.
	 * @param trunk object for phrasebook.
	 */
	virtual char *Speak(Trunk *trunk) = 0;
};

/**
 * A derived instance of this class is used to load "function" modules
 * into Bayonne.  These are not bound to the class structure of the
 * driver and hence are used for inserting "generic" functions rather
 * than functions that depend on a specific derived dialect of the Bayonne
 * script engine.  A single instance of "Function" is derived with a 
 * constructor the calls "Load" as a global objectso that when the DSO
 * is installed, it automatically binds the symbol list of the functions
 * the given DSO is providing.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short bind generic functions from DSO.
 */
class Functions
{
protected:
	/**
	 * Return the name of the DSO function module.  This actually
	 * gaurentees the base class is abstract and can simply
	 * return a string name in the derived class.
	 */
	virtual char *getName(void) = 0;

	/**
	 * Load a defined group of functions into the interpreter.
	 *
	 * @param function list.
	 */
	void Load(FUNCTIONS *map);
};

/* Bayonne config file istanciation classes.  In Bayonne these are
   created as keydata objects out of bayonne.conf during process
   startup automatically.  This is Bayonne runtime configuration magic.
*/

/**
 * Load /etc/bayonne [tones] key values for user defined tone sets.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load and build user defined tones.
 */
class KeyTones : protected Keydata
{
public:
	/**
	 * Initialize tone data.
	 */
	KeyTones();
};

/**
 * Load localization rules from [localize].
 * May have defaults appropriate to US.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load localization rules.
 */
class KeyLocal : public Keydata
{
public:
	/**
	 * Load local rule set.
	 */
	KeyLocal();
};

/**
 * Load /etc/bayoone [paths] key value pairs.  Has internal defaults
 * if section or file is missing.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load keypaths path location configuration data.
 */
class KeyPaths : public Keydata
{
public:
	/**
	 * Initialize keypath data.
	 */
	KeyPaths();

	/**
	 * Get the driver and tgi base directories.
	 */
	inline const char *getLibexec(void)
		{return getLast("libexec");};

	/**
	 * Get library tgi exec search path.
	 */
	inline const char *getTgipath(void)
		{return getLast("tgipath");};

	/**
	 * Get prefix for DSO modules at install.
	 */
	inline const char *getLibpath(void)
		{return getLast("libpath");};

	/**
	 * Get the primary working storage for writable messages.
	 */
	inline const char *getDatafiles(void)
		{return getLast("datafiles");};

	/**
	 * Get the runfile directory.
	 */
	inline const char *getRunfiles(void)
		{return getLast("runfiles");};

	/**
	 * Get the spool directory.
	 */
	inline const char *getSpool(void)
		{return getLast("spool");};

	/**
	 * Get the primary script prefix directory.
	 */
	inline const char *getScriptFiles(void)
		{return getLast("scripts");};

	/**
	 * Get the pre-cache directory.
	 */
	inline const char *getCache(void)
		{return getLast("precache");};
};

/**
 * Load /etc/bayonne [network] key value pairs.  These are used to
 * specify dilu access methods and bindings.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load database access bindings.
 */
class KeyNetwork : public Keydata
{
public:
	/**
	 * Initialize keydatabase data.
	 */
	KeyNetwork();

	/**
	 * Get refresh timer in seconds for inter-node activity.
	 *
	 * @return refresh in seconds.
	 */
	unsigned getRefresh(void)
		{return atoi(getLast("refresh"));};

	/**
	 * Get time delay for transactions.
	 *
	 * @return time delay in seconds.
	 */
	unsigned getDatabaseDelay(void)
		{return atoi(getLast("databasedelay"));};

	/**
	 * Get broadcast address to use.
	 *
	 * @return broadcast address.
	 */
	InetHostAddress getBroadcast(void);

	/**
	 * Get bind address to use.
	 *
	 * @return binding address.
	 */
	InetAddress getAddress(void);

	/**
	 * Get port for binding.
	 *
	 * @return port.
	 */
	tpport_t getPort(void);

	/**
	 * Get adapter address for a specific connection.
	 *
	 * @param adapter id.
	 * @return adapter address.
	 */
	InetHostAddress getDatabase(unsigned id);

	/**
	 * Get adapter port address for a specific connection.
	 *
	 * @param adapter id.
	 * @return adapter port.
	 */
	tpport_t getDatabasePort(unsigned id);
};

/**
 * Load /etc/bayonne [mailbox] key value pairs.  These are used to
 * specify default values to initialize newly created mailboxes.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load mailbox definitions.
 */
class KeyMailbox : public Keydata
{
public:
	/**
	 * Initialize keymailbox data.
	 */
	KeyMailbox();

	/**
	 * Get maximum count of allowed messages.
	 *
	 * @return maximum count of allowed messages.
	 */
	inline unsigned getCount(void)
		{return atoi(getLast("count"));};

	/**
	 * Get maximum storage limit for newly created mailbox.
	 *
	 * @return maximum storage limit.
	 */
	inline unsigned getLimit(void)
		{return atoi(getLast("limit"));};

	/**
	 * Get quota of total "voice" message storage permitted on
	 * the filesystem.
	 *
	 * @return maximum storage limit of all mailboxes.
	 */
	inline unsigned getQuota(void)
		{return atoi(getLast("quota"));};

	/**
	 * Get minimum valid message size for recording in seconds.
	 *
	 * @return minumum message size.
	 */
	inline unsigned getMinimum(void)
		{return atoi(getLast("minimum"));};

	/**
	 * Get maximum size of a single message.
	 *
	 * @return maximum recording size in seconds.
	 */
	inline unsigned getMaximum(void)
		{return atoi(getLast("maximum"));};

	/**
	 * Get default initial password until reset.
	 *
	 * @return default initial password.
	 */
	inline const char *getPassword(void)
		{return getLast("password");};
};

/**
 * Load /etc/bayonne [memory] key value pairs.  This is used to
 * configurate space management properties of the runtime environment
 * including audio buffering, page size allocations, etc.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load memory related options.
 */
class KeyMemory : public Keydata
{
public:
	/**
	 * Initialize keymemory data.
	 */
	KeyMemory();

	/**
	 * Get default symbol space size for variables.
	 *
	 * @return number of bytes of storage for new symbols.
	 */
	inline int getSymbolSize(void)
		{return atoi(getLast("symbols"));};

	/**
	 * Get default page allocation size to use for "paged" memory
	 * allocations.
	 *
	 * @return page size for default paging.
	 */
	inline int getPageSize(void)
		{return atoi(getLast("page"));};
};

/**
 * Load /etc/bayonne [audiofeed] key value pairs.  This is used to
 * configure audio feed sources for Bayonne.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Audio feed related options.
 */
class KeyFeed : public Keydata
{
public:
	/**
	 * Initialize keymemory data.
	 */
	KeyFeed();

	/**
	 * Get number of 120ms audio buffers to use.
	 *
	 * @return number of bytes of storage for new symbols.
	 */
	inline unsigned getBuffers(void)
		{return atoi(getLast("buffers"));};
};


/**
 * Load /etc/bayonne [thread] key value pairs.  Has internal defaults
 * if section or file is missing.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load keythreads priority and session count configuration.
 */
class KeyThreads : public Keydata
{
public:
	/**
	 * Initialize keythread data.
	 */
	KeyThreads();

	/**
	 * Get relative priority to run service threads at.
	 *
	 * @return service thread priority (relative).
	 */
	inline int priService(void)
		{return atoi(getLast("services"));};

	/**
	 * Get the relative priority to run scheduler at.
	 *
	 * @return scheduler priority (relative).
	 */
	inline int priScheduler(void)
		{return atoi(getLast("scheduler"));};

	/**
	 * Get the relative priority to run gui at.
	 *
	 * @return gui priority (relative).
	 */
	inline int priGUI(void)
		{return atoi(getLast("gui"));};

	/**
	 * Get number of milliseconds to delay each script step.
	 *
	 * @return millisecond delay interval.
	 */
	inline int getStepDelay(void)
		{return atoi(getLast("stepdelay"));};

	/**
	 * Get the minimal step interval.
	 *
	 * @return millisecond minimal interval.
	 */
	inline int getStepInterval(void)
		{return atoi(getLast("stepinterval"));};

	/**
	 * Get the reset delay required for settling the DSP.
	 *
	 * @return millisecond delay from dsp reset.
	 */
	inline int getResetDelay(void)
		{return atoi(getLast("resetdelay"));};

	/**
	 * Get default stack size for threads.
	 *
	 * @return stack size in "k" increments.
	 */
	size_t getStack(void);

	/**
	 * Get count of service pool threads to use.
	 *
	 * @return thread count for service pool.
	 */
	int getServices(void);

	/**
	 * Get the execution priority of the resolver thread.
	 *
	 * @return priority of resolver.
	 */
	int priResolver(void);

	/**
	 * Get the execution interval of the resolver thread, or
	 * 0 if no resolver scheduler.
	 *
	 * @return number of minutes for interval.
	 */
	int getResolver(void);

	/**
	 * Get relative priority to run audio streams at.
	 *
	 * @return audio thread priority (relative).
	 */
	inline int priAudio(void)
		{return atoi(getLast("audio"));};

	/**
	 * Get relative priority to run audio feeds at.
	 *
	 * @return audio feed priority (relative).
	 */
	inline int priFeed(void)
		{return atoi(getLast("feed"));};

	/**
	 * Get relative priority to run gateway (TGI) sessions at.
	 *
	 * @return tgi gateway process priority (niceness).
	 */
	inline int priGateway(void)
		{return atoi(getLast("gateways"));};

	/**
	 * Get the relative priority to run network management sessions.
	 *
	 * @return priority for management threads.
	 */
	inline int priManager(void)
		{return atoi(getLast("managers"));};

	/**
	 * Get the relative priority for network service thread.
	 *
	 * @return priority for lookup thread.
	 */
	inline int priNetwork(void)
		{return atoi(getLast("network"));};

	/**
	 * Scheduler execution interval.
	 *
	 * @return scheduler interval in minutes.
	 */
	inline int getInterval(void)
		{return atoi(getLast("interval"));};

	/**
	 * Scheduler network node rebroadcast frequency.
	 *
	 * @return node broadcast update interval in seconds.
	 */
	inline int getRefresh(void)
		{return atoi(getLast("refresh"));};

	/**
	 * Get number of tgi gateway proccesses to make available.
	 *
	 * @return number of tgi gateway processes.
	 */
	int getGateways(void);
	
	/**
	 * Get default Bayonne system priority (niceness) to start
	 * under before we adjust any relative priorities.
	 *
	 * @return primary "nice" process priority.
	 */
	inline int getPriority(void)
		{return atoi(getLast("priority"));};

	/**
	 * Get scheduling policy to use.
	 *
	 * @return policy id, or "0" for default.
	 */
	int getPolicy(void);

	/**
	 * Get memory locking and local pages.
	 *
	 * @return number of k of stack to pre-allocate.
	 */
	inline int getPages(void)
		{return atoi(getLast("pages"));};
};

/**
 * This keydata object holds audit related configuration data such as
 * the logpath to use for audit logs, address of servers, etc.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Audit module configuration data.
 */
class Auditdata : public Keydata
{
private:
	friend class Audit;

	Auditdata();
};

/**
 * Trunk "groups" provide keydata configuration information that apply
 * to a group of trunk ports represented under a common "group" identity.
 * These are initially given a [trunks] section for default group values
 * followed by a specific entry.  The [server] groups key lists the active
 * trunk groups.  A special default group is also created.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Trunk group configuration.
 */
class TrunkGroup : public Keydata, public CallStat
{
private:
	friend class KeyServer;
	friend class Scheduler;
	friend class Audit;
	static TrunkGroup *first;
	TrunkGroup *next;
	char schedule[65];

	void setSchedule(const char *str);

public:
	/**
	 * Create a trunk group data key from the bayonne.conf file.
	 *
	 * @param name of trunk group to load.
	 */
	TrunkGroup(char *name = NULL);

	/**
	 * Get the name of this trunk group.
	 *
	 * @return name of trunk group.
	 */
	inline const char *getName(void)
		{return getLast("name");};

	/**
	 * Get the number of rings before answering.
	 *
	 * @return number of rings to answer.
	 */
	inline int getAnswer(void)
		{return atoi(getLast("answer"));};

	/**
	 * Get the time delay of each ring.
	 *
	 * @return ring time between rings.
	 */
	inline int getRingTime(void)
		{return atoi(getLast("ringtime"));};

	/**
	 * Get disconnect gaurd time before answering.
	 *
	 * @return gaurd time in milliseconds.
	 */
	inline int getHangup(void)
		{return atoi(getLast("hangup"));};

	/**
	 * Get default hook flash time for this trunk group.
	 *
	 * @return hookflash time in milliseconds.
	 */
	inline timeout_t getFlash(void)
		{return atol(getLast("flash"));};

	/**
	 * Get dialtone wait time for this trunk group.
	 *
	 * @return dialtone wait time in milliseconds.
	 */
	inline timeout_t getDialtone(void)
		{return atol(getLast("dialtone"));};

	/**
	 * Get dialing speed in milliseconds.
	 *
	 * @return dialspeed in milliseconds.
	 */
	inline timeout_t getDialspeed(void)
		{return atol(getLast("dialspeed"));};

	/**
	 * Get the name of the script to "schedule" for this group.
	 *
	 * @return name of scheduled script.
	 * @param buffer to copy schedule information into.
	 */
	const char *getSchedule(char *buf);

	/**
	 * Used when mapping trunk groups to activated trunks.
	 */
	inline void incCapacity(void)
		{++capacity;};
};

/**
 * This class is a cache for server specific configuration information
 * which may be configured from /etc/bayonne.conf [server].
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short load server configuration data.
 */
class KeyServer : public Keydata
{
private:
	unsigned uid, gid;

public:
	/**
	 * Load active server configuration.
	 */
	KeyServer();

	/**
	 * Get the name of the node identifier.
	 *
	 * @return node id.
	 */
	inline const char *getNode(void)
		{return getLast("node");};

	/**
	 * Get tgi token seperator.
	 *
	 * @return token seperator.
	 */
	inline const char *getToken(void)
		{return getLast("token");};

	/**
	 * Search for a specific named trunk group.
	 *
	 * @return pointer to TrunkGroup record.
	 * @param name of trunk group to find.
	 */
	TrunkGroup *getGroup(char *name);

	/**
	 * Load all active trunk group records.
	 */
	void loadGroups(void);

	/**
	 * Get default trunk group schedule name.
	 *
	 * @return schedule name.
	 */
	inline const char *getDefault(void)
		{return getLast("default");};

	/**
	 * get group id.
	 *
	 * @return gid
	 */
	inline unsigned getGid(void)
		{return gid;};

	/**
	 * get user id.
	 *
	 * @return uid
	 */
	inline unsigned getUid(void)
		{return uid;};

	/**
	 * Get number of nodes.
	 *
	 * @return node count.
	 */
	inline int getNodeCount(void)
		{return atoi(getLast("nodes"));};
};

/**
 * This class is used to load and manage "plugin" modules as called for
 * in /etc/bayonne.conf [plugins].
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Load and manage plugins support.
 */
class Plugins : public Keydata
{
public:
	/**
	 * Load plugins key data and initialize.
	 */
	Plugins();

	/**
	 * Unload all active DSO modules for plugins.
	 */
	~Plugins();

	/**
	 * Get the name of the driver API being used.
	 *
	 * @return driver api name.
	 */
	char *getDriverName(void);

	/**
	 * Load a debug module or stub interface.
	 */
	void loadDebug(void);

	/**
	 * Attempt to load a DSO IVR API driver subsystem on top of the
	 * Bayonne server.  On failure a DSO exception is thrown.
	 */
	DSO *loadDriver(void);

	/**
	 * Load automatic application extensions module.
	 */
	void loadExtensions(void);

	/**
	 * Attempt to load DSO based generic functions into the server.
	 */
	void loadFunctions(void);

	/**
	 * Attempt to load DSO based protocol modules into the server.
	 */
	void loadModules(void);

	/**
	 * Attempt to load DSO based audio feed modules into the server.
	 */
	void loadFeeds(void);

	/**
	 * Attempt to load TGI based resident interpreters.
	 */
	void loadTGI(void);

	/**
	 * Attempt to load DSO network management interfaces.
	 */
	void loadManagers(void);

	/**
	 * Attempt to load DSO based TTS translation modules into server.
	 */
	void loadTranslators(void);

	/**
	 * Attemot to load DSO based audit logging facilities into server.
	 */
	void loadAuditing(void);
};

/**
 * We derive a Bayonne server version of ScriptCommand, aaScript,
 * which holds most common elements of the script engine for Bayonne
 * use.  Individual drivers may further derive sub-dialects.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne script dialect.
 */
class aaScript : public ScriptCommand 
{
private:
	friend class Functions;

#pragma pack(1)
	typedef struct _functions
	{
		struct _functions *next;
		functioncall_t function;
		char name[1];
	}	functions_t;
#pragma pack()

	functions_t *functions[KEYWORD_INDEX_SIZE];

protected:
	/**
	 * New GetTrapMask() used to set DTMF bit when dtmf digits
	 * are also requested in ^traps.
	 *
	 * @return trap mask to apply.
	 * @param trap name being evaluated.
	 */
	unsigned long getTrapMask(const char *trapname);

	/**
	 *
	 * Add a generic function to the interpreter.
	 *
	 * @param name of function.
	 * @param function handler.
	 */
	void addFunction(char *name, functioncall_t function);

public:
	/**
	 * Get a function call handler by name.
	 *
 	 * @return handler for function.
	 * @param name of function.
	 */
	functioncall_t getFunction(char *name);

	/**
	 * Default scripting environment.
	 */
	aaScript();
};

/**
 * We derive a Bayonne compiler and script image container, aaImage,
 * to hold active script sets for the trunk class script engine.  This
 * class is almost never further derived in drivers, though the driver
 * "getScript" method is used to load it.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne script image.
 */
class aaImage : public ScriptImage
{
protected:
	/**
	 * Used to parse and determine if a given directory file
	 * should be "compiled".  Usually tests for *.scr.
	 *
	 * @return true if this file should be compiled.
	 * @param file name to test.
	 */
	virtual bool isScript(char *scriptname);

	/**
	 * Used to scan and compile a script collection from a specified
	 * directory.
	 *
	 * @param directory to scan.
	 */
	void scanDir(char *path);

public:
	/**
	 * Default image compiler.
	 */
	aaImage(aaScript *script);
};

/**
 * We derive a Bayonne server version of ScriptInterp, "Trunk",
 * which holds most common elements of the script engine for Bayonne
 * use.  This is also the base of the channel port structure for
 * Bayonne.  Drivers will further derive this as "DriverTrunk".
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne channel port script engine.
 */
class Trunk : public ScriptInterp
{
private:
	friend class aaScript;
	friend class Translator;
	friend class ScriptInterface;
	friend class Service;
	friend class Fifo;
	friend class PortManager;

	char *cdrv[33];
	int cdrc;
	numbersymbol_t numbers[5];

	bool scrLibonce(void);
	bool scrLibexec(void);
	bool scrHangup(void);
	bool scrDebug(void);
	bool scrImport(void);
	bool scrExport(void);
	bool scrFunction(void);
	bool scrAlog(void);
	bool scrAudit(void);
	bool scrPause(void);
	bool scrSleep(void);
	bool scrWait(void);
	bool scrTone(void);
	bool scrAnswer(void);
	bool scrCollect(void);
	bool scrFlash(void);
	bool scrPlay(void);
	bool scrRecord(void);
	bool scrAppend(void);
	bool scrDial(void);
	bool scrTransfer(void);
	bool scrSpeak(void);
	bool scrLookup(void);
	bool scrUpdate(void);
	bool scrDeliver(void);
	bool scrSendfile(void);
	bool scrNotify(void);
	bool scrSendfax(void);

protected:
	static ScriptSymbol globals;
	static char digit[16];
	ScriptInterface *script;
	TrunkGroup *group;
	PortManager *manager;
	int id;
	time_t start, idle;

	int rings;
	int digits;

	Service *thread;
	trunkdata_t data;
	execdata_t tgi;
	digitsymbol_t dtmf;

	struct
	{
		bool offhook: 1;
		bool dtmf: 1;
		bool script: 1;
		bool reset: 1;
		bool timer : 1;
		bool audio: 1;
		bool once : 1;
		unsigned temp : 4;
		trunkmode_t trunk: 2;
		dspmode_t dsp: 4;
	} flags;

	/**
	 * Our default mask includes timeout.
	 *
	 * @return default mask.
	 */
	unsigned long getTrapDefault(void)
		{return 0x00000007;};

	/**
	 * This is used to initialize constant variables in the symbol
	 * space.  These are assumed to be constant for the current
	 * session as variables are purged between sessions.
	 *
	 * @param symbol name.
	 * @param symbol value.
	 */
	void setConstant(const char *id, const char *data);

	/**
	 * This provides an interface to internal symbol definitions.
	 *
	 * @return symbol entry.
	 * @param symbol name.
	 * @param allocation size if not found.
 	 */
	scriptsymbol_t *getEntry(const char *symname, int size);

	/**
	 * A derived Commit handler, allows "clear %digits", etc.
	 *
	 * @param symbol entry.
 	 */
	void Commit(scriptsymbol_t *sym);

	/**
	 * Get a "timeout" option.  This is like getValue, however
	 * the default timeout supplied is from the constant table.
	 *
	 * @return default timeout in seconds.
	 */
	int getTimeout(void);

	/**
	 * Get a "interdigit" timeout option.  This is like getValue,
	 * however the interdigit value supplied is from the const table.
	 *
	 * @return interdigit timeout in seconds.
	 */
	int getInterdigit(void);

	/**
 	 * Get a dtmf bit "mask".
	 *
	 * @return dtmf bit mask of digits.
	 */
	unsigned short getDigitMask(void);

	/**
	 * Notify the script subsystem of a completion event.
	 *
	 * @param completion event signal id.
	 */
	bool TrunkSignal(trunksignal_t);

	/**
	 * This function sets dtmf detection based on the script
	 * interpreter's current trap mask.  This is often used as
	 * the initial handler for setting dtmf detection when
	 * entering each trunk driver's state.
	 */
	virtual void setDTMFDetect(void);

	/**
	 * Set actual dtmf detection in the derived trunk class driver.
	 * This typically is called by the "initial" state handler when
	 * entering a trunk driver call processing state when an implicit
	 * setting is required (such as "collect", which forces enable).
	 *
	 * @param true to enable DTMF detection.
	 */
	virtual void setDTMFDetect(bool enable)
		{flags.dtmf = enable;};

	/**
	 * This is used to reset service threads and generally cleanup
	 * the session handler.  It is a virtual since driver specific
	 * implimentations may vary.
	 */
	virtual void stopServices(void);

	/**
	 * Used to perform state transitions when trunk is in "step"
	 * state, from the Bayonne script engine.  This call is used
         * rather than "postEvent" with TRUNK_MAKE_STEP since the Bayonne
	 * engine is already in the context of the callback thread
	 * and invoked from a postEvent initiated call.  Hence, this
	 * saves the overhead rather of a recursive postEvent call.
	 *
	 * @param new state to use.
	 */
	virtual void TrunkStep(trunkstep_t step) = 0;

	/**
	 * This is used to determine if the trunk is currently "idle"
	 * and for how long.
	 *
	 * @return number of seconds idle.
 	 */
	virtual unsigned long getIdleTime(void) = 0;

	/**
	 * This is used to post a step update back to the script engine.
	 */
	bool ScriptStep(void);

	/**
	 * We override ScriptInterp::Attach with our own that adds
	 * additional support.  This attach initializes a series of
	 * required and default "variables" for the script interpreter.
	 *
	 * @return true on success
	 * @param name of script to start.
	 */
	bool Attach(const char *scrname);

	/**
	 * We override ScriptInterp::Detach with our own that adds
	 * additional support to purge the variable pool.
	 */
	void Detach(void);

	/**
	 * Get the interpter mask or manager mask.
	 */
	unsigned long getMask(void);

	Trunk(int port);
public:
	/**
	 * Get driver capabilities.
	 *
	 * @return capability mask.
	 */
	virtual unsigned long getCapabilities(void)
		{return TRUNK_CAP_VOICE | TRUNK_CAP_DIAL;};

	/**
	 * Get the device logical name number.
	 *
	 * @param Buffer to store name.
	 */
	virtual void getName(char *buffer) = 0;

	/**
	 * Invoke a runtime state handler for a trunk driver.  This
	 * must be in an event in the derived TrunkDriver class.
	 *
	 * @return true if event claimed.
	 * @param derived method to call.
	 */
	virtual bool postEvent(TrunkEvent *event) = 0;

	/**
	 * Compute the DTMF digit id of a character.
	 *
	 * @return dtmf digit or -1.
	 */
	int getDigit(char digit);

};

/**
 * A port manager is able to process calls in place of ccscript.
 * This allows ports and the driver state engine to be directly
 * controlled by an external dso if nessisary.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Channel port control manager.
 */
class PortManager
{
private:
	Trunk *trunk;

protected:
	~PortManager()
		{trunk->manager = NULL;};

	/**
	 * Create a trunk manager and bind to a given trunk object.
	 *
	 * @param trunk to bind to.
	 */
	PortManager(Trunk *trk);

	/**
	 * Step a trunk in the same callback thread context.
	 *
	 * @param step to execute.
	 */
	inline void postStep(trunkstep_t step)
		{trunk->TrunkStep(step);};

	/**
	 * Post an event to the trunk.
	 *
	 * @return true if complete.
	 * @param trunk event record.
	 */
	inline bool postEvent(TrunkEvent *event)
		{return trunk->postEvent(event);};

	/**
	 * Return the trunk data segment.
	 *
	 * @return trunk data segment.
	 */
	inline trunkdata_t *getData(void)
		{return &trunk->data;};

	/**
	 * Return the trunk exec segment.
	 *
	 * @return trunk exec segment.
	 */
	inline execdata_t *getExec(void)
		{return &trunk->tgi;};
public:
	/**
	 * Accept a step request.
	 */
	virtual bool Step(void) = 0;

	/**
	 * Provide a signal mask.
	 *
	 * @return mask
	 */
	virtual unsigned long getMask(void) = 0;
	
	/**
	 * Accept a signal event.
	 *
	 * @return true if not blocked.
	 * @param signal event.
	 */
	virtual bool postSignal(trunksignal_t signal) = 0;

	/**
	 * Notify an accept has occured.
	 *
	 * @return true if accepting.
	 * @param name of script.
	 */
	virtual bool postAccept(const char *name) = 0;

	/**
	 * Notify a detach has occured.
	 */
	virtual void postDetach(void) = 0;
};

/**
 * The system fifo is a class that both handles a fifo "control interface"
 * and that can process string commands as events through the Bayonne
 * driver.  The Fifo is used by tgi and may be used by other system
 * services.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne fifo command executive.
 */
class Fifo : public fifostream, public Mutex
{
protected:
	bool exitPid(char **args);
	bool waitPid(char **args);
	bool setSymbol(char **argv);
	bool putSymbol(char **argv);
	bool submit(char **argv);
	bool login(char **argv);
	bool startScript(int id, char **argv);
	bool ringScript(int id, char **argv);
	bool busyLine(char **argv);
	bool idleLine(char **argv);
	bool hangupLine(char **argv);

public:
	/**
	 * Issue a "command" request either from the fifo port itself
	 * or from a service thread.
	 *
	 * @return true if command successful.
	 * @param request string as would be passed by fifo.
	 */
	bool Command(const char *cmdstring);
};

/**
 * The FifoHandler is a base class for DSO modules that can receive and
 * process fifo "command" requests.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short fifo command processor extensions.
 */
class FifoHandler
{
private:
	friend class Fifo;

	static FifoHandler *first;
	FifoHandler *next;
protected:
	/**
	 * This is used to impliment a fifo command handler.
	 *
	 * @return true if command handled by derived class.
	 * @param command arguments array.
	 */
	virtual bool Command(char **argv) = 0;

	/**
	 * Interlink this fifo handler to the command chain.
	 */
	FifoHandler();
};

/**
 * The audit class is associated with the "audit" dso object which is used
 * to distribute audit reports.  Audit reports can include call detail
 * information as a call "terminates", and also "alog" commands.  These
 * are handled by a DSO so that alternate processing can be supplied,
 * such as seperate threads or even broadcast to an audit "server" as
 * may be needed by very high port capacity systems.  The default dso
 * simply appends to an audit file.  In fact, multiple audit dso's can
 * be "stacked".
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne audit logging interface.
 */
class Audit : public Mutex
{
private:
	friend void audit(char *detail);
	friend class Scheduler;

	static Audit *first;
	Audit *next;

protected:
	static Auditdata keys;

	/**
	 * Post an audit record detail line as built by "audit"
	 *
	 * @param detail line.
	 */
	virtual void Report(char *detail) = 0;

	/**
	 * Proccess current call stats, invoked by scheduler.
	 */
	virtual void Stats(void) = 0;

	/**
	 * A quick access to the trunk group members.
	 *
	 * @return trunkgroup first.
	 */
	inline TrunkGroup *getFirst(void)
		{return TrunkGroup::first;};

	/**
	 * A quick access to the next trunk group member.
	 *
	 * @return trunkgroup next.
	 * @param trunk group.
	 */
	inline TrunkGroup *getNext(TrunkGroup *grp)
		{return grp->next;};

	/**
	 * Constructor protected for abstract class.
	 */
	Audit();
};

/**
 * The driver class represents an abstract means of accessing the
 * internals of a Bayonne driver plug-in module.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Bayonne driver interface class.
 */
class Driver : public aaScript
{
protected:
	friend class TrunkGroup;

	TrunkGroup **groups;
	char *status;
	bool active;

public:
	/**
	 * Create an instance of the driver.
	 */
	Driver();

	/**
	 * Start a driver; start service threads, build device nodes,
	 * etc.
	 * 
	 * @return number of active device ports.
	 */
	virtual int Start(void) = 0;

	/**
	 * Shutdown the driver, service threads, etc.
	 */
	virtual void Stop(void) = 0;

	/**
	 * Get a local copy of the status string.
	 *
	 * @param local status buffer.
	 */
	void getStatus(char *buffer);

	/**
	 * Load a script image.  Usually this is not driver specific,
	 * though it can be made to be so.
	 *
	 * @return ScriptImage base abstract.
	 */
	virtual aaImage *getImage(void);

	/**
	 * Get total number of port identifiers (timeslots) used by
	 * the current driver.
	 *
	 * @return trunk timeslots/ports allocated.
	 */
	virtual int getTrunkCount(void) = 0;

	/**
	 * Get active number of ports actually deployed by the current
	 * driver.
	 *
	 * @return actual trunks used.
	 */
	virtual int getTrunkUsed(void) 
		{return getTrunkCount();};

	/**
	 * Get the trunk group of an identified port.
	 * 
	 * @return trunk group pointer.
	 * @param id
	 */
	TrunkGroup *getTrunkGroup(int id)
		{return groups[id];}; 
	
	/**
	 * Get an individual port from the driver by timeslot/id.
	 *
	 * @return trunk port object.
	 */
	virtual Trunk *getTrunkPort(int id) = 0;
};

/**
 * New DSO class for installing a "debugging"/regression test plugin.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short Regression test/debug DSO interface.
 */
class Debug : protected Mutex
{
public:
	/**
	 * Register DSO debug object.
	 */
	Debug();

	/**
	 * Regression test interface called in server startup.
	 *
	 * @return true to force exit after test.
	 */
	virtual bool DebugTest(void)
		{return false;};

	/**
	 * Debug interface for event processing "taps".
	 */
	virtual void DebugEvent(Trunk *trunk, TrunkEvent *event)
		{return;};

	/**
	 * Debug interface for state handler entry "taps".
	 */
	virtual void DebugState(Trunk *trunk, char *state)
		{return;};

	/**
	 * Debug service loop code "tap".
	 */
	virtual void DebugService(Trunk *trunk, char *msg)
		{return;};

	/**
	 * Debug interface for "debug" script step.
	 */
	virtual void DebugScript(Trunk *trunk, char *msg)
		{return;};

	/**
	 * Debug interface for script step "tap".
	 */
	virtual void DebugStep(Trunk *trunk, scriptline_t *line)
		{DebugState(trunk, "step");};

	/**
	 * Debug interface for fifo "debug" statement.
	 */
	virtual bool DebugFifo(char **argv)
		{return true;};
};

/**
 * Services are threads used to support a trunk class, such as audio
 * services used for audio, etc.
 *
 * @author David Sugar <dyfet@ostel.com>
 * @short service thread support.
 */
class Service : public Semaphore, public Thread
{
private:
	char filename[256];

protected:
	volatile bool stopped;
	Trunk *trunk;
	TrunkGroup *group;
	trunkdata_t *data;

	/**
	 * Signal "successful" completion result.
	 */
	void Success(void);

	/**
	 * Signal "failure" completion result.
	 */
	void Failure(void);

	/**
	 * get a audio sample file name.
	 *
	 * @return name of file path.
	 * @param partial name to try.
	 */
	char *getPrompt(char *name); 

	/**
	 * Get next name of entry in play list.
	 *
	 * @return name of next prompt.
	 */
	char *getPlayfile(void);

	/**
	 * Mark required dsp reset.
	 */
	inline void dspReset(void)
		{trunk->flags.reset = true;};

	/**
	 * Set audio marker.
	 */
	inline void setAudio(void)
		{trunk->flags.audio = true;};

	/**
	 * Clear audio marker.
	 */
	inline void clrAudio(void)
		{trunk->flags.audio = false;};

public:
	/**
	 * Create a service thread on an existing trunk object.
	 *
	 * @param trunk object to use.
	 * @param process priority.
	 */
	Service(Trunk *trunk, int pri);

	/**
	 * request to stop a service and obtain default "delay" time
	 * to use for reset interval.
	 *
	 * @return delay in milliseconds.
	 */
	virtual timeout_t Stop(void);

	/**
	 * Indicate if the service thread is exiting and/or can be
	 * deleted now.  If false, then it will be cleaned by the
	 * scheduler thread.
	 *
	 * @return false if held to scheduler.
	 */
	virtual bool isExiting(void)
		{return true;};

	/**
	 * Termination of service.
	 */
	virtual ~Service()
		{Terminate();}

};

/**
 * Server classes are used for threaded entities such as network
 * management interfaces, which may be started and stopped under
 * server control.  Sometimes server is mixed into other dso
 * classes to stabilize start/stop of service threads.
 *
 * @short threaded server service.
 * @author David Sugar <dyfet@ostel.com>
 */
class Server : public Thread
{
private:
	static Server *first;
	Server *next;
	friend void startServers(void);
	friend void stopServers(void);

protected:
	Server(int pri);

	/**
	 * Used for stopServers call interface.
	 */
	virtual void Stop(void)
		{Terminate();};
};

/**
 * The Sync class is used to create dso objects which have entites
 * that are repetitivly called through the scheduler thread.  These
 * are sometimes used to update disk based databases from memory, or
 * perform other interval timed operations.
 */
class Sync
{
private:
	friend class Scheduler;

	static Sync *first;
	Sync *next;
	time_t runtime;

protected:
	/**
	 * Abstract class, protected constructor.
	 */
	Sync(void);

	/**
	 * Return if ready for update.  If not, the current update
	 * interval may be skipped entirely.
	 */
	virtual bool isScheduled(void) = 0;

	/**
	 * Return execution interval of this sync object.  How many
	 * xx minutes before attempting a new sync.
	 */
	virtual unsigned getInterval(void)
		{return 10;};

	/**
	 * Operation to perform when scheduled.
	 */
	virtual void Schedule(void) = 0;

	/**
	 * Return name used in slog event when scheduling item.
	 */
	virtual char *getName(void) = 0;
};

/**
 * The tone class is used to build sampled single and dual frequency
 * tones that may be fed to the telephony device.  Tones are defined
 * in the "tones" section of bayonne.conf.
 *
 * @short generated sample tone.
 * @author David Sugar.
 */
class phTone
{
private:
	friend phTone *getphTone(const char *name);
	static phTone *first;
	static int ulaw[256];
	phTone *next;
	char name[33];
	unsigned char *samples;
	timeout_t duration;
	unsigned freq1, freq2;

public:
	/**
	 * Create single frequency tone.
	 *
	 * @param name of tone.
	 * @param duration in milliseconds.
	 * @param frequency of tone.
	 */
	phTone(const char *name, timeout_t duration, unsigned f);

	/**
	 * Create dual frequency tone.
	 *
	 * @param name of tone.
	 * @param duration in milliseconds.
	 * @param first frequency.
	 * @param second frequency.
	 */
	phTone(const char *name, timeout_t duration, unsigned f1, unsigned f2);

	~phTone();

	/**
	 * If the telephony card is capable of generating it's own
	 * tones, then it can use the clear method to remove any
	 * allocated memory for sampled data.
	 */
	void Clear(void);

	/**
	 * Fetch the sample area of the tone.
	 *
	 * @return sample area.
	 */
	inline unsigned char *getSamples(void)
		{return samples;};

	/**
	 * Get the duration of the tone.
	 *
	 * @return duration of tone.
	 */
	inline timeout_t getDuration(void)
		{return duration;};
};

/**
 * This class is used for interfacing to DSO loaded TGI interpreters.
 *
 * @short TGI interpreter module.
 * @author David Sugar <dyfet@ostel.com>
 */
class TGI
{
private:
	static TGI *first;
	TGI *next;

protected:
	TGI();

	/**
	 * Check a file extension to see if it belongs to a first
	 * stage tgi script interpreter (avoids second fork).
	 *
	 * @return true if claimed.
	 * @param extension.
	 */
	virtual bool getExtension(char *ext)
		{return false;};

public:
	/**
	 * Check command for interpreter and, if is, execute it.  If
	 * so it doesn't return but uses "exit".  This is a "second"
	 * stage tgi mod interface and is effective for single session
	 * interpreter libraries.
	 *
	 * @param script name resolved.
	 * @param argument list.
	 */
	virtual void Script(char *cmd, char **args)
		{return;};

	/**
	 * Execute a first stage interpreter, uses local functions.
	 *
	 * @return shell exit code.
	 * @param fifo file descriptor.
	 * @param port number.
	 * @param unparsed command string.
	 */
	virtual int Parse(int fd, int port, char *cmd)
		{return -1;};	

	friend void getInterp(char *cmd, char **args);
	friend TGI *getInterp(char *cmd);
};
	
/**
 * Modules are used for protocol modules and detached threads used to
 * service key Bayonne protocols and interfaces.  These are done as
 * loadable modules and may be replaced with application specific
 * interfaces.
 *
 * @short Module interface class.
 * @author David Sugar <dyfet@ostel.com>
 */
class Module
{
private:
	static Module *first;
	Module *next;

protected:
	Module();

	/**
	 * Get the "type" identifer of this module.
	 *
	 * @return type id.
	 */
	virtual modtype_t getType(void) = 0;

	/**
	 * Get the "name" identifer of this module.
	 *
	 * @return name string.
	 */
	virtual char *getName(void) = 0;

public:
	/**
	 * Execute the script request.  Usually this involves creating
	 * a detached service thread.
	 *
	 * @return error message or NULL.
	 * @param trunk object to reference.
	 */
	virtual char *Dispatch(Trunk *trunk) = NULL;

public:
	friend Module *getModule(modtype_t mod, const char *name = NULL);
};

/**
 * Sessions are used for "garbage collected" entities which may be
 * detached and removed after an expiration time rather than falling
 * out of scope immediately.  This process is managed by the scheduler
 * thread.
 *
 * @short Garbage collectable objects.
 * @author David Sugar <dyfet@ostel.com>
 */
class Session
{
private:
	friend class Scheduler;
	static Mutex mutex;
	static Session *first;
	static Session *last;
	Session *next, *prev;
	static void Clean(void);

protected:
	Session();
	virtual ~Session()
		{Unlink();};

	/**
	 * Unlink the session object.
	 */
	void Unlink(void);

	/**
	 * Indicate if and when this session is to be "garbage collected"
	 * by UNIX timestamp.
	 *
	 * @return 0 if still running, else garbage collection period.
	 */
	virtual time_t getExpires(void) = 0;
};

/**
 * Audio feeds provide a means for buffering audio for distribution thru
 * one or more telephony ports.  These feeds are used either for one-way
 * conferences or to source music on hold/bgm features for a given caller.
 *
 * @short feed audio to multiple ports.
 * @author David Sugar <dufet@ostel.com>
 */
class AudioFeed : private ThreadLock
{
private:
	static AudioFeed *first;
	AudioFeed *next;
	unsigned char *buffers;
	volatile unsigned char *current;
	size_t feedsize, bufsize;
	bool active;

protected:
	const char *name;

public:
	AudioFeed(const char *name, unsigned buffers);
	~AudioFeed();
	bool Enable(void);
	void Disable(void);
	unsigned char *getBuffer(unsigned char *prior = NULL, unsigned size = 120);
	void putBuffer(unsigned char *buffer, unsigned size = 120);

	friend AudioFeed *getAudioFeed(const char *name);
};

/**
 * Protocols are used for processing transactional requests such as
 * those performed thru modules, but thru a TCP protocol.  These support
 * the resolver thread.
 *
 * @short resolved network protocol session interface.
 * @author David Sugar <dyfet@ostel.com>
 */
class Protocol : public Keydata, public InetHostAddress, public ThreadLock
{
private:
	friend class Resolver;
	static Protocol *first;
	Protocol *next;
	Semaphore *sessions;
	tpport_t port;

	void Update(InetHostAddress addr);
public:
	Protocol(const char *keypath, tpport_t port);
	~Protocol();

	/**
	 * Get inet host address for this service.
	 *
	 * @return inet host address of server.
	 */
	InetHostAddress getAddress(void);

	/**
	 * Get inet port address of this service.
	 *
	 * @return inet port address of service.
	 */
	inline tpport_t getPort(void)
		{return port;};

	/**
	 * Get client connection limiting semaphore that is used as the
	 * starting semaphore for the client connection thread.
	 *
	 * @return semaphore session limiter.
	 */
	inline Semaphore *getSessions(void)
		{return sessions;};
};

extern KeyServer keyserver;
extern KeyThreads keythreads;
extern KeyMemory keymemory;
extern KeyPaths keypaths;
extern KeyLocal keylocal;
extern KeyNetwork keynetwork;
extern KeyMailbox keymailbox;
extern KeyTones keytones;
extern KeyFeed keyfeed;
extern Plugins plugins;
extern Driver *driver;
extern Debug *debug;
extern Fifo fifo;
#endif

