/*
 * Easy qi api header
 *
 * $Id: qick.h,v 2.3 2000/08/18 19:27:34 dgc Exp $
 *
 */

#include <stdio.h>
#include <sys/types.h>
#include <regex.h>

#ifdef QICK_INTERNAL
# include <qiapi.h>
#endif

#define QI_SERVER	"ns"	/* Some fair default */

/* Default for various initializers. */
#define MAX_Q_PS	128	/* Max auths per process per server */
#define MAX_Q_PP	512	/* Max auths per process (total) */
#define MAX_CXN_ATTEMPTS	6	/* Max connect attempts per query */
#define CXN_DELAY	30	/* Seconds between connect attempts */
#define MAX_LIFETIME	86400	/* Maximum lifetime */

/* Linux lacks a proper REG_OK declaration */
#ifndef REG_OK
# define REG_OK		0	/* success (non-standard) */
#endif

extern char *null_string_value;
#define S(x)	(x) == NULL ? null_string_value : (x)

/*
 * Some list stuff -- generic list operations.
 */
typedef struct list_s {
	void		*l_datum;
	struct list_s	*l_next;
} list_t;

/*
 * These macros should be used so that your application doesn't need
 * to know the internals of the list.
 */
#define LIST_DATUM(list)	(list)->l_datum
#define LIST_NEXT(list)		(list)->l_next

#define LIST_SET(list, to)	(list)->l_datum = (to)
#define LIST_LINK(list, to)	(list)->l_next = (to)

#define LIST_FOREACH(list, in) \
	for ((list) = (in); (list) != NULL; (list) = LIST_NEXT(list))

#define LIST_FOREACH_NO_INC(list, in) \
	for ((list) = (in); (list) != NULL; /* no increment */ )

#define LIST_END(listp, begin) \
	for ((listp) = &(begin); *(listp) != NULL; *(listp) = LIST_NEXT(*(listp)))

#define LIST_NEW		(list_t *) malloc(sizeof(list_t))

/*
 * End of list stuff
 */


/* A handle on a qi server cxn. */
typedef struct qi_s {
	char	*qi_host;
	FILE	*qi_to,
		*qi_from;
	char	*qi_alias;	/* last alias to login */
	int	 qi_fd;
	char	 qi_err[1024];
	int	 qi_count;
	int	 qi_max_queries;
	int	 qi_cxn_max_attempts;
	int	 qi_cxn_delay;
	int	 qi_preenc;
} qi_t;

/* Context for a process's qick usage -- global. */
typedef struct qick_s {
	list_t	*q_servers;
	list_t	*q_last;
	list_t	*q_current;	/* for qi_first() & qi_next() */
	list_t	*q_policies;
	int	 q_count;
	int	 q_max_queries;
	int	 q_lifetime;
	int	 q_die;
	char	 q_err[1024];
} qick_t;

/*
 * A qi message.  Almost a QIR (from qiapi.h), but we don't want to
 * bother translating the field names to numbers.
 */
typedef struct qim_s {
	int	 qim_code,
		 qim_subcode;
	char	*qim_field,
		*qim_value;
} qim_t;

/*
 * For chaining response fields together
 */
typedef struct qif_s {
	char		*qif_field;
	char		*qif_value;
	struct qif_s	*qif_next;
} qif_t;

/*
 * A complete response chain.
 */
typedef struct qir_s {
	int		 qir_index;
	qif_t		*qir_message;
	struct qir_s	*qir_next;
} qir_t;

/*
 * A regular expression policy term block.
 */
typedef struct qi_regex_s {
	char	*rx_field;
	char	*rx_ere;
	int	 rx_flags;
	regex_t	 rx_regex;
} qi_regex_t;

/*
 * A policy head.
 */
typedef struct qip_s {
	char		*qip_name;
	struct qit_s	*qip_first;
	struct qit_s	*qip_last;
	char		 qip_err[1024];
} qip_t;

/*
 * A policy term.
 */
typedef struct qit_s {
	int		 qit_type;
	union {
		char			*u_query;
		struct qip_s		*u_link;
		struct qi_regex_s	*u_ere;
		int			 u_op;
	}		 qit_u;
	struct qip_s	*qit_top;
	struct qit_s	*qit_next;

#define qit_query	 qit_u.u_query
#define qit_link	 qit_u.u_link
#define qit_ere		 qit_u.u_ere
#define qit_op		 qit_u.u_op
} qit_t;

/*
 * Policy term types.
 */
#define QI_POLICY_OP	0
#define QI_POLICY_ERE	1
#define QI_POLICY_LINK	3
#define QI_POLICY_QUERY	4

/*
 * Policy operators.
 */
#define QI_POLICY_NOOP	0
#define QI_POLICY_AND	3
#define QI_POLICY_OR	4
#define QI_POLICY_NOT	5
#define QI_POLICY_XOR	6

/*
 * Policy chain eval. results.
 */
#define QI_POLICY_FALSE		0
#define QI_POLICY_TRUE		1
#define QI_POLICY_UNDERFLOW	2
#define QI_POLICY_OVERFLOW	3

/*
 * Regex evaluation flags -- cloned out of regex.h
 */
#define QI_POLICY_RE_BASIC	(REG_EXTENDED | REG_NOSUB | REG_NEWLINE)
#define QI_POLICY_RE_EXTENDED	(REG_EXTENDED)
#define QI_POLICY_RE_NOSUB	(REG_NOSUB)
#define QI_POLICY_RE_NEWLINE	(REG_NEWLINE)
#define QI_POLICY_RE_ICASE	(REG_ICASE)
#define QI_POLICY_RE_NOTBOL	(REG_NOTBOL)
#define QI_POLICY_RE_NOTEOL	(REG_NOTEOL)

/*
 * Depth of the policy evaluation stack.
 */
#define QI_POLICY_STACK_DEPTH	32

#ifdef DEBUG
# define qi_debug _qi_debug
#else
# define qi_debug
#endif

/*
 * Constants for the crypto functions.
 */
#define QI_CRYPT_ROTOR_SIZE	256
#define QI_CRYPT_PASS_SIZE	13

/*
 * Context for qi crypto stuff.
 */
typedef struct qi_crypt_ctx_s {
	char	 ctx_r1[QI_CRYPT_ROTOR_SIZE],
		 ctx_r2[QI_CRYPT_ROTOR_SIZE],
		 ctx_r3[QI_CRYPT_ROTOR_SIZE];
	char	 ctx_crypt[QI_CRYPT_ROTOR_SIZE];
} qi_crypt_ctx_t;

/*
 * Prototypes will help you to save the world.
 */

/* From crypt.c. */
	char *		qi_crypt(char *dest, int dlen, char *pass,
				 char *chal, int pre);

/* From policy.c. */
	/* Policy ops */
	qip_t *		qip_new(qick_t *qick, char *name);
	void		qip_free(qip_t *qip);
	qit_t *		qit_new(void);
	void		qit_free(qit_t *qit);
	char *		qip_name(qip_t *qip, char *name);
	qit_t *		qit_setop(qit_t *qit, int op);
	qit_t *		qit_setquery(qit_t *qit, char *query);
	qit_t *		qit_setmatch(qit_t *qit, char *field,
				  char *ere, int icase, char *err, int elen);
	qit_t *		qit_setlink(qit_t *qit, qip_t *link);
	qit_t *		qit_cat(qit_t *qit, qit_t *next);
	qit_t *		qip_extend(qip_t *qip, qit_t *qit);
	int		qip_exec(qip_t *qip, qir_t *qir);
	int		qip_trace(qip_t *qip, qir_t *qir);
	qip_t *		qip_default(qick_t *qick);
	char *		qip_error(qip_t *qip, char *set);
	qip_t *		qip_find(qick_t *qick, char *name);



/* From qick.c. */
	/* Initialize everything; get a handle on reality. */
	qick_t *	qick_init(void);

	/* True if the library thinks it's time to close up. */
	int		qick_suicidal(qick_t *qick);

	/* Get/set error conditions. */
	char *		qick_error(qick_t *qick, char *set);
	char *		qi_error(qi_t *qi, char *set);

	/* Set server options. */
	int		qi_preencrypt(qi_t *qi, int bool);

	/* Allocate a new qir object. */
	qir_t *		qir_new(void); /* Server reply; contains many qif */
	qif_t *		qif_new(void); /* A field/value pair */
	qim_t *		qim_new(void); /* A server message */

	/* Free current object and all descendent objects. */
	void		qir_free(qir_t *qir);
	void		qif_free(qif_t *qif);
	void		qim_free(qim_t *qim);

	/* Get handles on servers. */
	qi_t *		qi_find(qick_t *qick, char *host);	/* Old */
	qi_t *		qi_server(qick_t *qick, char *host);	/* New or old */
	qi_t *		qi_first(qick_t *qick);
	qi_t *		qi_next(qick_t *qick);

	/* If -DDEBUG, print trace dumps of objects hierarchies. */
	void		qir_trace(qir_t *qir);
	void		qif_trace(qif_t *qif);

	/* Turns a qi server code into a diagnostic message. */
	char *		qi_get_reply_code(int code);

	/* Try a user/pass pair, return TRUE or FALSE. */
	int		qi_pwcheck(qi_t *qi, char *user, char *pass);
	int		qi_login(qi_t *qi, char *user, char *pass);
	int		qi_logout(qi_t *qi);
	qi_t *		qi_auth(qick_t *qick, char *user, char *pass);
	char *		qi_auth_svr(qi_t *qi, char *user, char *pass);

	/* Extract data from objects */
	char *		qi_field(qir_t *qir, char *field);


/* From qio.c. */
	/* Do debugging logs. */
	void		_qi_debug(char *fmt, ...);

	/* Stop talking to qi */
	void		qi_reset(qi_t *qi);
	void		qi_quit(qi_t *qi);
	void		qi_quit_all(qick_t *qick);

	/* R/W ops on server.  Support stdargs. */
	int		qi_write(qi_t *qi, char *fmt, ...);
	qim_t *		qi_read(qi_t *qi, qim_t *qimp);

/* From query.c. */
	/* "Queries" specify a server; "lookups" use any server. */
	/* Free-form (stdargs) */
	qir_t *		qi_query(qi_t *qi, char *query, ...);
	qir_t *		qi_lookup(qick_t *qick, char *query, ...);

	/* Single field, returning whole directory entry */
	qir_t *		qi_query_field(qi_t *qi, char *field, char *value);
	qir_t *		qi_lookup_field(qick_t *qick,
					char *field, char *value);

	/* Single field, returning single field's value */
	char *		qi_query_simple(qi_t *qi, char *field, char *value,
					char *get);
	char *		qi_lookup_simple(qick_t *qick,
					 char *field, char *value, char *get);

/* From parse.c. */
	qip_t *		qip_parse(qick_t *qick, char *name,
					int wc, char *wv[]);
	qip_t *		qip_parse_simple(qick_t *qick, char *name,
					int wc, char *wv[]);
	int		qip_split(char ***wv, char *s);

