#ifndef __ldapdns_h
#define __ldapdns_h

#include <lber.h>
#include <ldap.h>
#include <netdb.h>

#include <pthread.h>

#include <sys/time.h>
#include <time.h>

#include "list.h"
#include "str.h"
#include "bin.h"
#include "ht.h"

#include "ip.h"

typedef struct dns_ctx_s dns_ctx;
typedef struct ldap_ctx_s ldap_ctx;

struct ldap_ctx_s {
	int n;
	int	protocol_version;	/* 2 or 3 */
	pthread_t id;
	LDAP	*ldap_con;

	int load;
	pthread_mutex_t load_lock;

	pthread_mutex_t lock;

	volatile int message_wait;
	volatile int message_sent;
	pthread_cond_t active;
};

struct dns_ctx_s {
	int		n;
	ldap_ctx	*c;	/* current handler */

	int		phase;
	time_t		lastt;
/* here are the following phases
 */
#define PHASE_IDLE		0
#define PHASE_ZONESEARCH	1
#define PHASE_ATTRSEARCH	2
#define PHASE_AXFRFIRST		3
#define PHASE_AXFRSEARCH	4
#define PHASE_NSUPDATE		5
#define PHASE_SIMPLESEARCH	6
	/* set if we're a subrequest */
	int		subreq;
	int		subreq_valid;
	list_t		subreq_tries;
	list_t		subreq_done;
	char		*subreq_in;
	char		*subreq_in_alloc;
	char		*subreq_in_zone;
	int		answers;
	int		soahack;

	/* protocol */
	char		dns_message_id[2];
	int		protnum;
#define PROT_DNS		0
#define PROT_NETBIOS		1

	/* locking constraint */
	pthread_mutex_t lock;

	/* where the request comes from */
	int		sock;
	unsigned char		ip[IP_LEN];
	int		port;

	/* reassembled from TCP */
	unsigned short	tcplen, tcppos;

	/* original request name */
	char		*request_name_zone;
	char		*request_name_alloc;
	char		*request_name;
	char		*request_attr;
	char		request_record[2];

	/* maximum size of udp request; we don't support big tcp reqs either */
	char		request_buf[513];
	int		request_len;
	int		request_pos;

	/* in message-waiting block */
	int		message_id;
	LDAPMessage	*message;
	//LDAPMessage	*message_entry;

	/* static for the connection */
	int		wantdie;
	list_t		NS;
	unsigned long	serial, refresh, retry, expire, minimum;
	unsigned long	ttl;

	/* used per-round */
	list_t		DNSRecord;
	list_t		A,CNAME,ADM,MX,SRV,TXT,PTR,Generic;
	int		adlen;
	char 		*search_base;


	/* helper for restarting phase-2 queries */
	int		attr_wild;

	/* update helper */
	char		*update;
	list_t		sec_prereq;
	list_t		sec_update;

	/* used in zone transfers */
	char		*axfr_base;
	int		axfr;
	list_t		ns;
	int		still_using_message;

	list_t saved_NS;
	unsigned long saved_soa[6];
	int saved_wantdie;
	int saved_adlen;

	/* and response */
	bin_t		response;
	int		response_tc;
	int		response_dpos;
	ht		response_names;
	int		response_ls;

	/* this is the switch mechanism */
	char		*swm;

	/* this implements a doubly-linked list */
	dns_ctx	*next, *prev;
};

extern dns_ctx *handler;

void inline ldapdns_list_unique(list_t *p);

#define name_to_dns(a,b) name_to_dns_fix(a,b,0)
void name_to_dns_fix(str_t retbuf, char *name, int splithow);
void dns_to_name(str_t retbuf, char *dns, int joinhow);

void name_to_ldap(str_t retbuf, char *name);
void ldap_to_name(str_t retbuf, char *dn);

void join_name_parts(str_t retbuf, list_t p);
void join_dns_parts(str_t retbuf, list_t p);
list_t ldap_into_parts(char *dn);
static void inline join_ldap_parts(str_t retbuf, list_t p)
{
	str_t tmp;

	str_init(tmp);
	join_name_parts(tmp, p);
	name_to_ldap(retbuf, str(tmp));
	free(tmp->buf);
	free(tmp);
}

list_t split_name_parts(char *name);
list_t split_dns_parts(char *dns);
static list_t inline split_ldap_parts(char *dn) {
	str_t tmp;
	list_t p;

	ldap_to_name(tmp, dn);
	p = split_name_parts(str(tmp));
	free(tmp->buf);
	free(tmp);

	return p;
}

int response_query(dns_ctx *, char *dnsenc, char rr[2], char cc[2]);
int response_notify(dns_ctx *, char *dnsenc, char rr[2], char cc[2]);
int response_rstart(dns_ctx *, char *dnsenc, char rr[2], unsigned int ttl);

int response_addname(dns_ctx *, char *dnsenc);
int response_addbytes(dns_ctx *, unsigned char *, int);

int response_addulong(dns_ctx *, unsigned long);
int response_addushort(dns_ctx *, unsigned short);
int response_addnameptr(dns_ctx *c, unsigned int u);

void response_id(dns_ctx *, const char id[2]);
void response_tc(dns_ctx *);
void response_aa(dns_ctx *, int setting);
void response_rcode(dns_ctx *, int code);
void response_nxdomain(dns_ctx *);
void response_servfail(dns_ctx *);
void response_refuse(dns_ctx *);

void response_axfr(dns_ctx *c);
int response_axstart(dns_ctx *c, int soa, char *q, char qt[2], char qc[2], unsigned int ttl);
void response_axfinish(dns_ctx *c);

int response_rfinish(dns_ctx *, int section);

unsigned int dns_packet_copy(dns_ctx *c, char *out,unsigned int outlen);
unsigned int dns_packet_skipname(dns_ctx *c);
unsigned int dns_packet_getname(dns_ctx *c, char **d);
unsigned int dns_domain_length(const char *dn);
int dns_domain_copy(char **out,char *in);
void dns_domain_lower(char *q);

int inline ldap_load_dns_attributes(dns_ctx *c, char **dn, int zonef);


/* user-level */
void tp_initialize(void);
void inline tp_housekeeping(long *);
int inline tp_write(dns_ctx *c);
int inline tp_read(dns_ctx *c);
void tp_close(dns_ctx *c);

#endif


syntax highlighted by Code2HTML, v. 0.9.1