#ifndef NTP_CONFIG_H
#define NTP_CONFIG_H

#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif /* HAVE_SYS_RESOURCE_H */

#include "ntp_machine.h"
#include "ntp_psl.h"
#include "ntpsim.h"


/*
 * Configuration file name
 */
#ifndef CONFIG_FILE
# ifndef SYS_WINNT
#  define	CONFIG_FILE "/etc/ntp.conf"
# else /* SYS_WINNT */
#  define	CONFIG_FILE	"%windir%\\system32\\drivers\\etc\\ntp.conf"
#  define	ALT_CONFIG_FILE "%windir%\\ntp.conf"
#  define	NTP_KEYSDIR	"%windir%\\system32\\drivers\\etc"
# endif /* SYS_WINNT */
#endif /* not CONFIG_FILE */


/*
 * We keep config trees around for possible saveconfig use.  When
 * built with configure --disable-saveconfig, and when built with
 * debugging enabled, include the free_config_*() routines.  In the
 * DEBUG case, they are used in an atexit() cleanup routine to make
 * postmortem leak check reports more interesting.
 */
#if !defined(FREE_CFG_T) && (!defined(SAVECONFIG) || defined(DEBUG))
#define FREE_CFG_T
#endif

/* Limits */
#define MAXLINE 1024

/* Configuration sources */

#define CONF_SOURCE_FILE		0
#define CONF_SOURCE_NTPQ		1

/* list of servers from command line for config_peers() */
extern	int	cmdline_server_count;
extern	char **	cmdline_servers;

/* set to zero if we're not locking memory */
extern	int	cur_memlock;

typedef struct int_range_tag {
	int	first;
	int	last;
} int_range;

/* generic list node */
typedef struct any_node_tag any_node;
struct any_node_tag {
	any_node *	link;
};

typedef DECL_FIFO_ANCHOR(any_node) any_node_fifo;

/* Structure for storing an attribute-value pair */
typedef struct attr_val_tag attr_val;
struct attr_val_tag {
	attr_val *	link;
	int		attr;
	int		type;	/* T_String, T_Integer, ... */
	int		flag;	/* auxiliary flags */
	union val {
		double		d;	/* T_Double */
		int		i;	/* T_Integer */
		int_range	r;	/* T_Intrange */
		char *		s;	/* T_String */
		u_int		u;	/* T_U_int */
	} value;
};

typedef DECL_FIFO_ANCHOR(attr_val) attr_val_fifo;

/* Structure for nodes on the syntax tree */
typedef struct address_node_tag address_node;
struct address_node_tag {
	address_node *	link;
	char *		address;
	u_short		type;	/* family, AF_UNSPEC (0), AF_INET[6] */
};

typedef DECL_FIFO_ANCHOR(address_node) address_fifo;

typedef struct int_node_tag int_node;
struct int_node_tag {
	int_node *	link;
	int		i;
};

typedef DECL_FIFO_ANCHOR(int_node) int_fifo;

typedef struct string_node_tag string_node;
struct string_node_tag {
	string_node *	link;
	char *		s;
};

typedef DECL_FIFO_ANCHOR(string_node) string_fifo;

typedef struct restrict_node_tag restrict_node;
struct restrict_node_tag {
	restrict_node *	link;
	address_node *	addr;
	address_node *	mask;
	attr_val_fifo *	flag_tok_fifo;
	int/*BOOL*/	remove;
	int		line_no;
	int		column;
	short		ippeerlimit;
	short		srvfuzrft;
};

typedef DECL_FIFO_ANCHOR(restrict_node) restrict_fifo;

typedef struct peer_node_tag peer_node;
struct peer_node_tag {
	peer_node *	link;
	int		host_mode;
	address_node *	addr;
	attr_val_fifo *	peerflags;
	u_char		minpoll;
	u_char		maxpoll;
	u_int32		ttl;
	u_char		peerversion;
	keyid_t		peerkey;
	char *		group;
};

typedef DECL_FIFO_ANCHOR(peer_node) peer_fifo;

typedef struct unpeer_node_tag unpeer_node;
struct unpeer_node_tag {
	unpeer_node *	link;
	associd_t	assocID;
	address_node *	addr;
};

typedef DECL_FIFO_ANCHOR(unpeer_node) unpeer_fifo;

typedef struct auth_node_tag auth_node;
struct auth_node_tag {
	int		control_key;
	int		cryptosw;
	attr_val_fifo *	crypto_cmd_list;
	char *		keys;
	char *		keysdir;
	int		request_key;
	int		revoke;
	attr_val_fifo *	trusted_key_list;
	char *		ntp_signd_socket;
};

typedef struct filegen_node_tag filegen_node;
struct filegen_node_tag {
	filegen_node *	link;
	int		filegen_token;
	attr_val_fifo *	options;
};

typedef DECL_FIFO_ANCHOR(filegen_node) filegen_fifo;

typedef struct setvar_node_tag setvar_node;
struct setvar_node_tag {
	setvar_node *	link;
	char *		var;
	char *		val;
	int		isdefault;
};

typedef DECL_FIFO_ANCHOR(setvar_node) setvar_fifo;

typedef struct nic_rule_node_tag nic_rule_node;
struct nic_rule_node_tag {
	nic_rule_node *	link;
	int		match_class;
	char *		if_name;	/* or numeric address */
	int		action;
};

typedef DECL_FIFO_ANCHOR(nic_rule_node) nic_rule_fifo;

typedef struct addr_opts_node_tag addr_opts_node;
struct addr_opts_node_tag {
	addr_opts_node *link;
	address_node *	addr;
	attr_val_fifo *	options;
};

typedef DECL_FIFO_ANCHOR(addr_opts_node) addr_opts_fifo;

typedef struct sim_node_tag sim_node;
struct sim_node_tag {
	sim_node *		link;
	attr_val_fifo *		init_opts;
	server_info_fifo *	servers;
};

typedef DECL_FIFO_ANCHOR(sim_node) sim_fifo;

/* The syntax tree */
typedef struct config_tree_tag config_tree;
struct config_tree_tag {
	config_tree *	link;

	attr_val	source;
	time_t		timestamp;

	peer_fifo *	peers;
	unpeer_fifo *	unpeers;

	/* Other Modes */
	int		broadcastclient;
	address_fifo *	manycastserver;
	address_fifo *	multicastclient;

	attr_val_fifo *	orphan_cmds;	/* s/b renamed tos_options */

	/* Monitoring Configuration */
	int_fifo *	stats_list;
	char *		stats_dir;
	filegen_fifo *	filegen_opts;

	/* Access Control Configuration */
	attr_val_fifo *	discard_opts;
	attr_val_fifo *	mru_opts;
	restrict_fifo *	restrict_opts;

	addr_opts_fifo *fudge;
	addr_opts_fifo *device;
	attr_val_fifo *	rlimit;
	attr_val_fifo *	tinker;
	attr_val_fifo *	enable_opts;
	attr_val_fifo *	disable_opts;

	auth_node	auth;

	attr_val_fifo *	logconfig;
	string_fifo *	phone;
	setvar_fifo *	setvar;
	int_fifo *	ttl;
	addr_opts_fifo *trap;
	attr_val_fifo *	vars;
	nic_rule_fifo *	nic_rules;
	int_fifo *	reset_counters;
	attr_val_fifo *	pollskewlist;

	sim_fifo *	sim_details;
	int		mdnstries;
};


/* Structure for holding a remote configuration command */
struct REMOTE_CONFIG_INFO {
	char buffer[MAXLINE];
	char err_msg[MAXLINE];
	int pos;
	int err_pos;
	int no_errors;
};


/*
 * context for trap_name_resolved() to call ctlsettrap() once the 
 * name->address resolution completes.
 */
typedef struct settrap_parms_tag {
	sockaddr_u	ifaddr;
	int		ifaddr_nonnull;
} settrap_parms;


/*
** Data Minimization Items
*/

/* Serverresponse fuzz reftime: stored in 'restrict' fifos */


/* get text from T_ tokens */
const char * token_name(int token);

/* generic fifo routines for structs linked by 1st member */
typedef void (*fifo_deleter)(void*);
void *	destroy_gen_fifo(void *fifo, fifo_deleter func);
void *	append_gen_fifo(void *fifo, void *entry);
void *	concat_gen_fifos(void *first, void *second);
#define DESTROY_G_FIFO(pf, func)	\
	((pf) = destroy_gen_fifo((pf), (fifo_deleter)(func)))
#define APPEND_G_FIFO(pf, pe)		\
	((pf) = append_gen_fifo((pf), (pe)))
#define CONCAT_G_FIFOS(first, second)	\
	((first) = concat_gen_fifos((first), (second)))
#define HEAD_PFIFO(pf)			\
	(((pf) != NULL)			\
	      ? HEAD_FIFO(*(pf))	\
	      : NULL)

peer_node *create_peer_node(int hmode, address_node *addr,
			    attr_val_fifo *options);
unpeer_node *create_unpeer_node(address_node *addr);
address_node *create_address_node(char *addr, int type);
void destroy_address_node(address_node *my_node);
attr_val *create_attr_dval(int attr, double value);
attr_val *create_attr_ival(int attr, int value);
attr_val *create_attr_rval(int attr, int first, int last);
attr_val *create_attr_sval(int attr, const char *s);
attr_val *create_attr_uval(int attr, u_int value);
void	  destroy_attr_val(attr_val *node);
filegen_node *create_filegen_node(int filegen_token,
				  attr_val_fifo *options);
string_node *create_string_node(char *str);
restrict_node *create_restrict_node(address_node *	addr,
				    address_node *	mask,
				    short		ippeerlimit,
				    attr_val_fifo *	flag_tok_fifo,
				    int/*BOOL*/		remove,
				    int			nline,
				    int			ncol);
int_node *create_int_node(int val);
addr_opts_node *create_addr_opts_node(address_node *addr,
				      attr_val_fifo *options);
sim_node *create_sim_node(attr_val_fifo *init_opts,
			  server_info_fifo *servers);
setvar_node *create_setvar_node(char *var, char *val, int isdefault);
nic_rule_node *create_nic_rule_node(int match_class, char *if_name,
				    int action);

script_info *create_sim_script_info(double duration,
				    attr_val_fifo *script_queue);
server_info *create_sim_server(address_node *addr, double server_offset,
			       script_info_fifo *script);

extern struct REMOTE_CONFIG_INFO remote_config;
void config_remotely(sockaddr_u *);

#ifdef SAVECONFIG
int dump_config_tree(config_tree *ptree, FILE *df, int comment);
int dump_all_config_trees(FILE *df, int comment);
#endif

#if defined(HAVE_SETRLIMIT)
void ntp_rlimit(int, rlim_t, int, const char *);
#endif

#endif	/* !defined(NTP_CONFIG_H) */
