/*
** pat_dns.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 06:43:50 1999 
** Last update Thu Oct 28 20:20:07 1999 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include "pat_dns.h"
#include "pat_ip.h"
#include "pat_ether.h"
#include "pat_data.h"
#include "pat_32.h"
#include "pat_16.h"
#include "pat_8.h"
#include "pat_bytebuf.h"
#include "pat_shortbuf.h"

char				*dnsrttl_itmpl = "\n\
<table _name=dnsrttl[%i%] bgcolor=\"%%dnsrttlColor%%\" width=100%%%%>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(dnsrttl[%i%].ttl)\">%%dnsrttl[%i%].ttl%%</a>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

t_field				dnsrttl_fields[] = 
{
  {"ttl",		0,		&nu32_pat,			NULL},
  NULL_FIELD
};

int	dnsrttl_chan;

PAT_NAME_GENERIC(dnsrttl_pat_name,
		 (VOID_PTR)&dnsrttl_chan,
		 "dnsrttl")

PAT_GET_FIELD_GENERIC(dnsrttl_pat_get_field,
		      dnsrttl_fields)

PAT_SET_FIELD_GENERIC(dnsrttl_pat_set_field,
		      dnsrttl_fields)

PAT_GET_FIELDS_GENERIC(dnsrttl_pat_get_fields,
		       dnsrttl_fields)

PAT_GET_FIELD_PAT_GENERIC(dnsrttl_pat_get_field_pat,
			  dnsrttl_fields)

PAT_GET_TMPL_GENERIC(dnsrttl_pat_get_tmpl,
		     (VOID_PTR)&dnsrttl_chan,
		     dnsrttl_itmpl)

PAT_OFF_GENERIC(dnsrttl_pat_off,
		4)

PAT_SUB_GENERIC(dnsrttl_pat_sub,
		&dnsrdata_pat)

t_pat				dnsrttl_pat = 
{
  dnsrttl_pat_name,		/* t_pat_name_proc		*/
  dnsrttl_pat_off,		/* t_pat_off_proc		*/
  dnsrttl_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dnsrttl_pat_get_field,	/* t_pat_get_field_proc		*/
  dnsrttl_pat_set_field,	/* t_pat_set_field_proc		*/
  dnsrttl_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dnsrttl_pat_get_tmpl,		/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  dnsrttl_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

char				*dnsrdata_itmpl = "\n\
<table _name=dnsrdata[%i%] bgcolor=\"%%dnsrdataColor%%\" width=100%%%%>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<code>\n\
<a href=\"set(dnsrdata[%i%].data)\">%%dnsrdata[%i%].data%%</a>\n\
</code>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

t_field				dnsrdata_fields[] = 
{
  {"data",		0,		&shortbuf_pat,		NULL},
  NULL_FIELD
};

int	dnsrdata_chan;

PAT_NAME_GENERIC(dnsrdata_pat_name,
		 (VOID_PTR)&dnsrdata_chan,
		 "dnsrdata")

PAT_GET_FIELD_GENERIC(dnsrdata_pat_get_field,
		      dnsrdata_fields)

PAT_SET_FIELD_GENERIC(dnsrdata_pat_set_field,
		      dnsrdata_fields)

PAT_GET_FIELDS_GENERIC(dnsrdata_pat_get_fields,
		       dnsrdata_fields)

PAT_GET_FIELD_PAT_GENERIC(dnsrdata_pat_get_field_pat,
			  dnsrdata_fields)

PAT_GET_TMPL_GENERIC(dnsrdata_pat_get_tmpl,
		     (VOID_PTR)&dnsrdata_chan,
		     dnsrdata_itmpl)

PAT_SUB_GENERIC(dnsrdata_pat_sub,
		&dnsqname_pat)

t_pat				dnsrdata_pat = 
{
  dnsrdata_pat_name,		/* t_pat_name_proc		*/
  shortbuf_pat_off,		/* t_pat_off_proc		*/
  dnsrdata_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dnsrdata_pat_get_field,	/* t_pat_get_field_proc		*/
  dnsrdata_pat_set_field,	/* t_pat_set_field_proc		*/
  dnsrdata_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dnsrdata_pat_get_tmpl,	/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  dnsrdata_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};


char				*dnsqtype_itmpl = "\n\
<table _name=dnsqtype[%i%] bgcolor=\"%%dnsqtypeColor%%\" width=100%%%%>\n\
<tr>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(dnsqtype[%i%].Type)\">%%dnsqtype[%i%].Type%%</a>(<a href=\"set(dnsqtype[%i%].type)\">%%dnsqtype[%i%].type%%</a>)\n\
</td>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(dnsqtype[%i%].class)\">%%dnsqtype[%i%].class%%</a>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

/* most of these codes are taken from ethereal */
t_assoc		dnsqtype_assocs[] = 
{
  {"a",		(VOID_PTR)1},   /* host address */
  {"ns",	(VOID_PTR)2},   /* authoritative name server */
  {"md",	(VOID_PTR)3},   /* mail destination (obsolete) */
  {"mf",	(VOID_PTR)4},   /* mail forwarder (obsolete) */
  {"cname",	(VOID_PTR)5},   /* canonical name */
  {"soa",	(VOID_PTR)6},   /* start of authority zone */
  {"mb",	(VOID_PTR)7},	/* mailbox domain name (experimental) */
  {"mg",	(VOID_PTR)8},	/* mail group member (experimental) */
  {"mr",	(VOID_PTR)9},	/* mail rename domain name (experimental) */
  {"null",	(VOID_PTR)10},	/* null RR (experimental) */
  {"wks",	(VOID_PTR)11},	/* well known service */
  {"ptr",	(VOID_PTR)12},	/* domain name pointer */	
  {"hinfo",	(VOID_PTR)13},	/* host information */
  {"minfo",	(VOID_PTR)14},	/* mailbox or mail list information */  
  {"mx",	(VOID_PTR)15},	/* mail routing information */
  {"txt",	(VOID_PTR)16},	/* text strings */
  {"rp",	(VOID_PTR)17},	/* responsible person (RFC 1183) */
  {"afsdb",     (VOID_PTR)18},	/* AFS data base location (RFC 1183) */
  {"x25",	(VOID_PTR)19},	/* X.25 address (RFC 1183) */
  {"isdn",	(VOID_PTR)20},	/* ISDN address (RFC 1183) */
  {"rt",	(VOID_PTR)21},	/* route-through (RFC 1183) */
  {"nsap",	(VOID_PTR)22},	/* OSI NSAP (RFC 1706) */
  {"nsap_ptr",	(VOID_PTR)23},	/* PTR for OSI NSAP (RFC 1348 - obsolete) */
  {"sig",	(VOID_PTR)24},	/* digital signature (RFC 2065) */
  {"key",	(VOID_PTR)25},	/* public key (RFC 2065) */
  {"px",	(VOID_PTR)26},	/* pointer to X.400/RFC822 (RFC 1664) */
  {"gpos",	(VOID_PTR)27},	/* geographical position (RFC 1712) */
  {"aaaa",	(VOID_PTR)28},	/* IPv6 address (RFC 1886) */
  {"loc",	(VOID_PTR)29},	/* geographical location (RFC 1876) */
  {"nxt",	(VOID_PTR)30},	/* "next" name (RFC 2065) */
  {"eid",	(VOID_PTR)31},	/* ??? (Nimrod?) */
  {"nimloc",	(VOID_PTR)32},	/* ??? (Nimrod?) */
  {"srv",	(VOID_PTR)33},	/* service location (RFC 2052) */
  {"atma",	(VOID_PTR)34},	/* ??? */
  {"naptr",	(VOID_PTR)35},	/* naming authority pointer (RFC 2168)*/
  {"axfr",	(VOID_PTR)252},
  {"any",	(VOID_PTR)255},
  NULL_ASSOC
};

t_field				dnsqtype_fields[] = 
{
  {"type",		0,		&nu16_pat,			NULL},
  {"Type",		0,		&nu16assoc_pat,      dnsqtype_assocs},
  {"class",		2,		&nu16_pat,			NULL},
  NULL_FIELD
};

int	dnsqtype_chan;

PAT_NAME_GENERIC(dnsqtype_pat_name,
		 (VOID_PTR)&dnsqtype_chan,
		 "dnsqtype")

PAT_GET_FIELD_GENERIC(dnsqtype_pat_get_field,
		      dnsqtype_fields)

PAT_SET_FIELD_GENERIC(dnsqtype_pat_set_field,
		      dnsqtype_fields)

PAT_GET_FIELDS_GENERIC(dnsqtype_pat_get_fields,
		       dnsqtype_fields)

PAT_GET_FIELD_PAT_GENERIC(dnsqtype_pat_get_field_pat,
			  dnsqtype_fields)

PAT_GET_TMPL_GENERIC(dnsqtype_pat_get_tmpl,
		     (VOID_PTR)&dnsqtype_chan,
		     dnsqtype_itmpl)

PAT_OFF_GENERIC(dnsqtype_pat_off,
		4)
	
PAT_SUB_DECL(dnsqtype_pat_sub)
{
  t_hash_elt	*he;
  t_status	status;
 
  if (optional_id)
    {
      if (he = id_get(optional_id,
		      &dns_nquestions_chan))
	{
	  int		nquestions;
	  t_boolean	again;
	  
	  nquestions = (int)(he->value);
	  if (nquestions == 0)
	    again = FALSE;
	  else
	    {
	      again = TRUE;
	      nquestions--;
	      if ((status = id_override(optional_id,
					&dns_nquestions_chan,
					(VOID_PTR)nquestions)) != 0)
		return (status);
	    }
	  if (again)
	    (*pat_return) = &dnsqname_pat;
	  else
	    (*pat_return) = &dnsrttl_pat;
	}
      else
	(*pat_return) = &dnsqname_pat;
    }
  else
    (*pat_return) = &dnsqname_pat;
  return (0);
}

t_pat				dnsqtype_pat = 
{
  dnsqtype_pat_name,		/* t_pat_name_proc		*/
  dnsqtype_pat_off,		/* t_pat_off_proc		*/
  dnsqtype_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dnsqtype_pat_get_field,	/* t_pat_get_field_proc		*/
  dnsqtype_pat_set_field,	/* t_pat_set_field_proc		*/
  dnsqtype_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dnsqtype_pat_get_tmpl,	/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  dnsqtype_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

char				*dnsqname_itmpl = "\n\
<table _name=dnsqname[%i%] bgcolor=\"%%dnsqnameColor%%\" width=100%%%%>\n\
<tr>\n\
<td align=center>\n\
<small>\n\
<a href=\"set(dnsqname[%i%].fqname)\">%%dnsqname[%i%].fqname%%</a>\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

t_field				dnsqname_fields[] = 
{
  {"fqname",		0,	&dnsqname_pat,		NULL},
  NULL_FIELD
};

int	dnsqname_chan;

PAT_NAME_GENERIC(dnsqname_pat_name,
		 (VOID_PTR)&dnsqname_chan,
		 "dnsqname")

PAT_GET_FIELD_GENERIC(dnsqname_pat_get_field,
		      dnsqname_fields)
     
PAT_SET_FIELD_GENERIC(dnsqname_pat_set_field,
		      dnsqname_fields)

PAT_GET_FIELDS_GENERIC(dnsqname_pat_get_fields,
		       dnsqname_fields)

PAT_GET_FIELD_PAT_GENERIC(dnsqname_pat_get_field_pat,
			  dnsqname_fields)

PAT_GET_TMPL_GENERIC(dnsqname_pat_get_tmpl,
		     (VOID_PTR)&dnsqname_chan,
		     dnsqname_itmpl)

PAT_OFF_DECL(dnsqname_pat_off)
{
  int			bytebuf_len;
  char			*buf2;
  int			len2;
  t_off			off2;
  t_status		status;

  buf2 = buf;
  len2 = len;
  (*off_return) = 0;
  while (1)
    {
      if (len2 < 1)
	return (ERR_PAT_TRUNC_PAT);
      bytebuf_len = (t_u32)(t_u8)(buf2[0]);
      if ((bytebuf_len & INDIR_MASK) == INDIR_MASK)
	{
	  (*off_return) += 2;
	  return (0);
	}
      if (bytebuf_len == 0)
	{
	  (*off_return) += 1;
	  return (0);
	}
      assert(bytebuf_pat.off_proc);
      if ((status = bytebuf_string_pat.off_proc(data,
						buf2,
						len2,
						&off2)) != 0)
	return (status);
      buf2 += off2;
      len2 -= off2;
      (*off_return) += off2;
    }
}
 
PAT_SUB_GENERIC(dnsqname_pat_sub,
		&dnsqtype_pat)

PAT_EXTRACT_DECL(dnsqname_pat_extract)
{
  int			bytebuf_len;
  char			*buf2;
  int			len2;
  t_off			off2;
  t_status		status;	

  buf2 = buf;
  len2 = len;
  while (1)
    {
      if (len2 < 1)
	return (ERR_PAT_TRUNC_FIELD);
      bytebuf_len = (t_u32)(t_u8)(buf2[0]);
      if ((bytebuf_len & INDIR_MASK) == INDIR_MASK)
	return (ERR_PAT_CANT_HANDLE);
      if (bytebuf_len == 0)
	return (0);
      assert(bytebuf_string_pat.extract_proc);
      if ((status = bytebuf_string_pat.extract_proc(data,
						    buf2,
						    len2,
						    str,
						    max_len)) != 0)
	return (status);
      assert(bytebuf_string_pat.off_proc);
      if ((status = bytebuf_string_pat.off_proc(data,
						buf2,
						len2,
						&off2)) != 0)
	return (status);
      buf2 += off2;
      len2 -= off2;
      if ((status = str_cat_char(str,
				 max_len,
				 '.')) != 0)
	return (status);
    }
}

PAT_INSERT_DECL(dnsqname_pat_insert)
{
  return (ERR_PAT_NI);
}

t_pat				dnsqname_pat = 
{
  dnsqname_pat_name,		/* t_pat_name_proc		*/
  dnsqname_pat_off,		/* t_pat_off_proc		*/
  dnsqname_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dnsqname_pat_get_field,	/* t_pat_get_field_proc		*/
  dnsqname_pat_set_field,	/* t_pat_set_field_proc		*/
  dnsqname_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dnsqname_pat_get_tmpl,	/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  dnsqname_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  dnsqname_pat_extract,		/* t_pat_extract_proc		*/
  dnsqname_pat_insert,		/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};


t_bit_field	dns_qr_bit_field =
{
  0,0
};

t_assoc		dns_qr_assocs[] =
{
  {"-",		(VOID_PTR)0},
  {"QR",	(VOID_PTR)1},
  {NULL,	NULL},
};

t_bit_field_assocs_data	dns_qr_bfad =
{
  &dns_qr_bit_field,
  dns_qr_assocs
};

t_bit_field	dns_opcode_bit_field = 
{
  1,4
};

t_assoc		dns_opcode_assocs[] =
{
  {"query",		(VOID_PTR)0},
  {"inverse_query",	(VOID_PTR)1},
  {"server_status_request",(VOID_PTR)2},
  {NULL,		NULL},	
};

t_bit_field_assocs_data	dns_opcode_bfad =
{
  &dns_opcode_bit_field,
  dns_opcode_assocs
};

t_bit_field	dns_aa_bit_field = 
{
  5,5
};

t_assoc		dns_aa_assocs[] =
{
  {"-",		(VOID_PTR)0},
  {"AA",	(VOID_PTR)1},
  {NULL,	NULL},
};

t_bit_field_assocs_data	dns_aa_bfad =
{
  &dns_aa_bit_field,
  dns_aa_assocs
};

t_bit_field	dns_tc_bit_field = 
{
  6,6
};

t_assoc		dns_tc_assocs[] =
{
  {"-",		(VOID_PTR)0},
  {"TC",	(VOID_PTR)1},
  {NULL,	NULL},
};

t_bit_field_assocs_data	dns_tc_bfad =
{
  &dns_tc_bit_field,
  dns_tc_assocs
};

t_bit_field	dns_rd_bit_field = 
{
  7,7
};

t_assoc		dns_rd_assocs[] =
{
  {"-",		(VOID_PTR)0},
  {"RD",	(VOID_PTR)1},
  {NULL,	NULL},
};

t_bit_field_assocs_data	dns_rd_bfad =
{
  &dns_rd_bit_field,
  dns_rd_assocs
};

t_bit_field	dns_ra_bit_field = 
{
  8,8
};

t_assoc		dns_ra_assocs[] =
{
  {"-",		(VOID_PTR)0},
  {"RA",	(VOID_PTR)1},
  {NULL,	NULL},
};

t_bit_field_assocs_data	dns_ra_bfad =
{
  &dns_ra_bit_field,
  dns_ra_assocs
};

t_bit_field	dns_zero_bit_field = 
{
  9,11
};

t_bit_field	dns_rcode_bit_field = 
{
  11,15
};

t_assoc		dns_rcode_assocs[] =
{
  {"no_error",	(VOID_PTR)0},
  {"name_error",(VOID_PTR)3},
  {NULL,	NULL},
};

t_bit_field_assocs_data	dns_rcode_bfad =
{
  &dns_rcode_bit_field,
  dns_rcode_assocs
};

t_field				dns_fields[] = 
{
  {"id",	OFFSET(t_dns *,id),	
   &nu16_pat,		NULL},
  {"qr",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_qr_bit_field)},
  {"Qr",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_qr_bfad)},
  {"opcode",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_opcode_bit_field)},
  {"Opcode",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_opcode_bfad)},
  {"aa",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_aa_bit_field)},
  {"Aa",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_aa_bfad)},
  {"tc",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_tc_bit_field)},
  {"Tc",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_tc_bfad)},
  {"rd",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_rd_bit_field)},
  {"Rd",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_rd_bfad)},
  {"ra",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_ra_bit_field)},
  {"Ra",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_ra_bfad)},
  {"zero",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_zero_bit_field)},
  {"rcode",	OFFSET(t_dns *,flags),
   &nu16bitfield_pat,	(VOID_PTR)(&dns_rcode_bit_field)},
  {"Rcode",	OFFSET(t_dns *,flags),
   &nu16bitfieldassoc_pat,	(VOID_PTR)(&dns_rcode_bfad)},
  {"nquestions",OFFSET(t_dns *,nquestions),
   &nu16_pat,		NULL},
  {"nanswers",	OFFSET(t_dns *,nanswers),
   &nu16_pat,		NULL},
  {"nauths",	OFFSET(t_dns *,nauths),
   &nu16_pat,		NULL},
  {"nadds",	OFFSET(t_dns *,nadds),
   &nu16_pat,		NULL},
  NULL_FIELD
};

char				*dns_itmpl = "\n\
<table _name=dns[%i%] width=100%%%% bgcolor=\"%%dnsColor%%\">\n\
<tr>\n\
<td align=center width=50%%%%><a href=\"set(dns[%i%].id)\">%%dns[%i%].id%%</a></td>\n\
<td align=center width=3%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Qr)\">%%dns[%i%].Qr%%</a>\n\
</_tiny>\n\
</td>\n\
<td align=center width=12%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Opcode)\">%%dns[%i%].Opcode%%</a>(<a href=\"set(dns[%i%].opcode)\">%%dns[%i%].opcode%%</a>)\n\
</_tiny>\n\
</td>\n\
<td align=center width=3%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Aa)\">%%dns[%i%].Aa%%</a>\n\
</_tiny>\n\
</td>\n\
<td align=center width=3%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Tc)\">%%dns[%i%].Tc%%</a>\n\
</_tiny>\n\
</td>\n\
<td align=center width=3%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Rd)\">%%dns[%i%].Rd%%</a>\n\
</_tiny>\n\
</td>\n\
<td align=center width=3%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Ra)\">%%dns[%i%].Ra%%</a>\n\
</_tiny>\n\
</td>\n\
<td align=center width=9%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].zero)\">%%dns[%i%].zero%%</a>\n\
</_tiny>\n\
</td>\n\
<td align=center width=12%%%%>\n\
<_tiny>\n\
<a href=\"set(dns[%i%].Rcode)\">%%dns[%i%].Rcode%%</a>(<a href=\"set(dns[%i%].rcode)\">%%dns[%i%].rcode%%</a>)\n\
</_tiny>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=50%%%%><a href=\"set(dns[%i%].nquestions)\">%%dns[%i%].nquestions%%</a></td>\n\
<td align=center width=50%%%%><a href=\"set(dns[%i%].nanswers)\">%%dns[%i%].nanswers%%</a></td>\n\
</tr>\n\
<tr>\n\
<td align=center width=50%%%%><a href=\"set(dns[%i%].nauths)\">%%dns[%i%].nauths%%</a></td>\n\
<td align=center width=50%%%%><a href=\"set(dns[%i%].nadds)\">%%dns[%i%].nadds%%</a></td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int				dns_nquestions_chan;

int	dns_chan;

PAT_NAME_GENERIC(dns_pat_name,
		 (VOID_PTR)&dns_chan,
		 "dns")

PAT_GET_FIELD_GENERIC(dns_pat_get_field,
		      dns_fields)

PAT_SET_FIELD_GENERIC(dns_pat_set_field,
		      dns_fields)

PAT_GET_FIELDS_GENERIC(dns_pat_get_fields,
		       dns_fields)

PAT_GET_FIELD_PAT_GENERIC(dns_pat_get_field_pat,
			  dns_fields)

PAT_GET_TMPL_GENERIC(dns_pat_get_tmpl,
		     (VOID_PTR)&dns_chan,
		     dns_itmpl)

PAT_OFF_GENERIC(dns_pat_off,
		DNS_HLEN)

PAT_SUB_DECL(dns_pat_sub)
{
  t_status		status;	
  t_dns			*dns;
  t_hash_elt		*he;
  t_buf			b;

  if (optional_id)
    {
      if (he = id_get(optional_id,
		      &dns_nquestions_chan))
	return (ERR_PAT_CHAN_IN_USE);
      if (len < DNS_HLEN)
	return (ERR_PAT_TRUNC_PAT);
      dns = (t_dns *)(buf);
      if ((status = id_add(optional_id,
			   &dns_nquestions_chan,
		   (VOID_PTR)((t_u32)(safe_ntohs(&dns->nquestions))))) != 0)
	return (status);
    }
  (*pat_return) = &dnsqname_pat;
  return (0);
}
 
t_pat				dns_pat = 
{
  dns_pat_name,			/* t_pat_name_proc		*/
  dns_pat_off,			/* t_pat_off_proc		*/
  dns_pat_sub,			/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dns_pat_get_field,		/* t_pat_get_field_proc		*/
  dns_pat_set_field,		/* t_pat_set_field_proc		*/
  dns_pat_get_fields,		/* t_pat_get_fields_proc	*/
  dns_pat_get_tmpl,		/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  dns_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};
