/*
	CVSNT Generic API
    Copyright (C) 2004 Tony Hoyle and March-Hare Software Ltd

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
/* Unix specific */
#define BIND_8_COMPAT /* OSX otherwise it uses its own internal definitions */
#include <sys/types.h>

#include <config.h>
#include "../lib/api_system.h"

#ifdef HAVE_MDNS
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <resolv.h>
#include <errno.h>
#include <netdb.h>
#endif

#include "../ServerIO.h"
#include "../cvs_string.h"

#if defined __HP_aCC

ssize_t res_query(
 char *dname,
 int c,
 int type,
 u_char *answer,
 int anslen
);

ssize_t res_search(
 char *dname,
 int c,
 int type,
 u_char *answer,
 int anslen
);

ssize_t res_mkquery(
 int op,
 const char *dname,
 int c,
 int type,
 const char *data,
 int datalen,
 const char *newrr,
 char *buf,
 int buflen
);

ssize_t res_send(
 const char *msg,
 ssize_t msglen,
 char *answer,
 int anslen
);

int res_init();

ssize_t dn_comp(
 u_char *comp_dn,
 ssize_t ssize_length,
 u_char **dnptrs,
 u_char *exp_dn,
 int  i_length
);

ssize_t dn_expand(
 const u_char *msg,
 const u_char *eomorig,
 const u_char *comp_dn,
 u_char *exp_dn,
 int  i_length
);


int set_resfield(
 int i_field,
 void *ptr_value
);

int get_resfield(
 int i_field,
 void *ptr_value,
 size_t i_value
);

void herror(char *s);
#endif


#include "../DnsApi.h"

CDnsApi::CDnsApi()
{
	m_pdnsBase=m_pdnsCurrent=NULL;
}

CDnsApi::~CDnsApi()
{
	Close();
}

bool CDnsApi::Lookup(const char *name, int rrType)
{
	Close();
#ifndef HAVE_MDNS
	return false;
#else
	m_pdnsBase = new u_char[16384];
	HEADER *h = (HEADER*)m_pdnsBase;
	int ret = res_query((char *)name, C_IN, rrType, m_pdnsBase, 16384);
	if(ret>0)
	{
		/* qdcount should always be 1 for an answer */
		if(ntohs(h->qdcount)>1)
			return false;
		m_nCount = ntohs(h->ancount);
		printf("ancount=%d\n",m_nCount);
		m_pdnsEnd = m_pdnsBase + ret;
		m_pdnsCurrent = m_pdnsBase+sizeof(HEADER);
		if(h->qdcount)
		{
			if(!GetHeader(true))
			{
				printf("getheader failed\n");
				m_pdnsCurrent = NULL;
				return false;
			}
			if(!Next())
			{	
				printf("next failed\n");
				return false;
			}
		}
	}
	return (ret<=0)?false:true;
#endif
}

bool CDnsApi::GetHeader(bool query)
{
#ifndef HAVE_MDNS
	return false;
#else
	u_char *p = m_pdnsCurrent;
	int n=dn_expand(m_pdnsCurrent, m_pdnsEnd, p, 
#if defined __HP_aCC
					(u_char *)m_dnsName, 
#else
					m_dnsName, 
#endif
					sizeof(m_dnsName));
	if(n<1)
	{
		printf("dn_expand failed\n");
		return false;
	}
	p+=n;
	GETSHORT(m_type, p); 
	GETSHORT(m_class, p);
	/* The first response record (query) does *not* appear to have
	 * these fields - this appears to violate the RFC */
	if(!query)
	{
		GETLONG(m_ttl, p); 
		GETSHORT(m_rdlength, p);
	}
	else
	{
		m_ttl = 0;
		m_rdlength = 0;
	}
	m_prdata = p;
	m_class &=0x7FFF;
	printf("name=%s\n",m_dnsName);
	printf("type=%d\n",m_type);
	printf("class=%d\n",m_class);
	printf("ttl=%d\n",m_ttl);
	printf("rdlength=%d\n",m_rdlength);
	return true;
#endif
}

bool CDnsApi::Next()
{
	if(!m_pdnsCurrent)
		return false;

	if(!m_nCount--)
	{
		printf("count=0\n");
		m_pdnsCurrent = NULL;
		return false;
	}

	m_pdnsCurrent = m_prdata + m_rdlength;

	if(!GetHeader(false))
	{
		printf("getheader failed\n");
		m_pdnsCurrent = NULL;
		return false;
	}

	return true;
}

bool CDnsApi::Close()
{
	if(m_pdnsBase)
		delete m_pdnsBase;
	m_pdnsBase=m_pdnsCurrent=NULL;
	return true;
}

const char *CDnsApi::GetRRName()
{
	if(!m_pdnsCurrent)
		return NULL;
	return m_dnsName;
}

const char *CDnsApi::GetRRPtr()
{
#ifndef HAVE_MDNS
	return NULL;
#else
	printf("GetRRPtr\n");
	if(!m_pdnsCurrent)
		return NULL;

	if(m_type!=DNS_TYPE_PTR)
		return NULL;

	if(dn_expand(m_pdnsCurrent, m_pdnsEnd, m_prdata, 
#if defined __HP_aCC
					(u_char *)m_dnsTmp, 
#else
					m_dnsTmp, 
#endif
					sizeof(m_dnsTmp))<1)
		return NULL;
	return m_dnsTmp;
#endif
}

const char *CDnsApi::GetRRTxt()
{
#ifndef HAVE_MDNS
	return NULL;
#else
	printf("GetRRTxt\n");
	if(!m_pdnsCurrent)
		return NULL;

	if(m_type!=DNS_TYPE_TEXT)
		return NULL;

	if(dn_expand(m_pdnsCurrent, m_pdnsEnd, m_prdata, 
#if defined __HP_aCC
					(u_char *)m_dnsTmp, 
#else
					m_dnsTmp, 
#endif
					sizeof(m_dnsTmp))<1)
		return NULL;
	return m_dnsTmp;
#endif
}

CDnsApi::SrvRR *CDnsApi::GetRRSrv()
{
#ifndef HAVE_MDNS
	return NULL;
#else
	printf("GetRRSrv\n");
	if(!m_pdnsCurrent)
		return NULL;

	if(m_type!=DNS_TYPE_SRV)
		return NULL;

	u_char *p = m_prdata;
	GETSHORT(tmpSrv.priority, p);
	GETSHORT(tmpSrv.weight, p); 
	GETSHORT(tmpSrv.port, p); 
	int n = dn_expand(m_pdnsCurrent, m_pdnsEnd, p, 
#if defined __HP_aCC
						(u_char *)m_dnsTmp, 
#else
						m_dnsTmp, 
#endif
						sizeof(m_dnsTmp));
	if(n<1)
		return NULL;
	p+=n;
	tmpSrv.server = m_dnsTmp;
	return &tmpSrv;
#endif
}


syntax highlighted by Code2HTML, v. 0.9.1