/* dns.c: -*- C -*-  Functions for handling DNS resolution. */

/*  Copyright (c) 1998 Brian J. Fox
    Author: Brian J. Fox (bfox@ai.mit.edu) Mon Mar 23 12:32:50 1998.

    This file is part of <Meta-HTML>(tm), a system for the rapid
    deployment of Internet and Intranet applications via the use of
    the Meta-HTML language.

    Copyright (c) 1995, 1996, Brian J. Fox (bfox@ai.mit.edu).
    Copyright (c) 1996, Universal Access Inc. (http://www.ua.com).

    Meta-HTML is free software; you can redistribute it and/or modify
    it under the terms of the UAI Free Software License as published
    by Universal Access Inc.; either version 1, or (at your option) any
    later version.

    This program 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
    UAI Free Software License for more details.

    You should have received a copy of the UAI Free Software License
    along with this program; if you have not, you may obtain one by
    writing to:

    Universal Access Inc.
    129 El Paseo Court
    Santa Barbara, CA
    93101  */

#include "language.h"
#include <arpa/nameser.h>
#include <resolv.h>

#if defined (__cplusplus)
extern "C"
{
#endif

#if !defined (h_errno)
extern int h_errno;
#endif

static void pf_dns_lookup (PFunArgs);

static PFunDesc ftab[] =
{
  /*   tag	     complex? debug_level	   code    */
  { "DNS::LOOKUP",	0,	 0,		pf_dns_lookup },
  { (char *)NULL,	0,	 0,		(PFunHandler *)NULL }
};

void
module_initialize (void)
{
  static int called = 0;

  if (!called)
    {
      register int i;
      Symbol *sym, *funcnames;

      called++;
      funcnames = symbol_intern ("modules::syms-of-dns");

      /* Install the names and pointers. */
      for (i = 0; ftab[i].tag != (char *)NULL; i++)
	{
	  sym = symbol_intern_in_package (mhtml_function_package, ftab[i].tag);
	  symbol_add_value (funcnames, ftab[i].tag);
	  sym->type = symtype_FUNCTION;
	  sym->values = (char **)(&ftab[i]);
	}
    }
}

void _init (void) { module_initialize (); }

static void
dns_interp (char *answer, char **copy, int address_p)
{
  HEADER *header = (HEADER *)answer;

  if ((header->rcode == 0) && (header->ancount > 0))
    {
      unsigned char *cp = answer + sizeof (HEADER);
      int qdcount = header->qdcount;
      int ancount = header->ancount;
      unsigned char *eom = ;

      while (qdcount-- > 0)
	cp += dn_skipname (cp, eom) + QFIXEDSZ;

      if (address_p
      *copy = strdup (answer);
    }
  else
    {
      herror ("HERROR");
      if (h_errno == -1)
	page_syserr ("dns::lookup: System Error: %s", strerror (errno));
      else if (h_errno != NO_DATA)
	page_syserr ("dns::lookup: Resolver Error: %d", h_errno);
    }
}

/* <dns::lookup addr-or-host &key type>
   Returns an alist of info about this address/host.
   TYPE defaults to ALL. */
#define dns_TYPE_T_CNAME	0x01
#define dns_TYPE_T_A		0x02
#define dns_TYPE_T_MX		0x04
#define dns_TYPE_T_ALL 	(dns_TYPE_T_CNAME | dns_TYPE_T_A | dns_TYPE_T_MX)

static void
pf_dns_lookup (PFunArgs)
{
  char *dname = mhtml_evaluate_string (get_positional_arg (vars, 0));
  char *typearg = mhtml_evaluate_string (get_value (vars, "type"));
  int type_flag = 0;
  unsigned char answer[1024];
  char *hostname = (char *)NULL;
  char *hostaddr = (char *)NULL;
  char *mailhost = (char *)NULL;
  char *mailaddr = (char *)NULL;
  int error_result;
  char *result = (char *)NULL;
  HEADER *header;

  if (!empty_string_p (typearg))
    {
      if ((strcasecmp (typearg, "CNAME") == 0) ||
	  (strcasecmp (typearg, "NAME") == 0) ||
	  (strcasecmp (typearg, "HOSTNAME") == 0))
	type_flag |= dns_TYPE_T_CNAME;

      if ((strcasecmp (typearg, "A") == 0) ||
	  (strcasecmp (typearg, "ADDR") == 0) ||
	  (strcasecmp (typearg, "HOSTADDR") == 0))
	type_flag |= dns_TYPE_T_A;

      if ((strcasecmp (typearg, "MX") == 0) ||
	  (strcasecmp (typearg, "MAIL") == 0) ||
	  (strcasecmp (typearg, "MAILHOST") == 0))
	type_flag |= dns_TYPE_T_MX;
    }

  if (type_flag == 0)
    type_flag = dns_TYPE_T_ALL;

  answer[0] = '\0';
  answer[1024] = '\0';

  if (dname != (char *)NULL)
    {
      if (type_flag & dns_TYPE_T_CNAME)
	{
	  error_result = res_search
	    (dname, C_IN, T_CNAME, answer, sizeof (answer));
	  hostname = strdup (answer);
	  handle_error_result (h_errno, answer, &hostname, 0);
	}

      if (type_flag & dns_TYPE_T_A)
	{
	  error_result = res_search
	    (dname, C_IN, T_A, answer, sizeof (answer));
	  handle_error_result (h_errno, answer, &hostaddr, 1);
	}

      if (type_flag & dns_TYPE_T_MX)
	{
	  error_result = res_search
	    (dname, C_IN, T_MX, answer, sizeof (answer));
	  handle_error_result (h_errno, answer, &mailhost, 0);

	  if (mailhost != (char *)NULL)
	    {
	      error_result = res_search
		(mailhost, C_IN, T_A, answer, sizeof (answer));
	      handle_error_result (h_errno, answer, &mailaddr, 1);
	    }
	}

      if ((hostname != (char *)NULL) ||
	  (hostaddr != (char *)NULL) ||
	  (mailhost != (char *)NULL) ||
	  (mailaddr != (char *)NULL))
	{
	  Package *p = symbol_get_package ((char *)NULL);

	  if (hostname != (char *)NULL)
	    {
	      forms_set_tag_value_in_package (p, "hostname", hostname);
	      free (hostname);
	    }

	  if (hostaddr != (char *)NULL)
	    {
	      forms_set_tag_value_in_package (p, "hostaddr", hostaddr);
	      free (hostaddr);
	    }

	  if (mailhost != (char *)NULL)
	    {
	      forms_set_tag_value_in_package (p, "mailhost", mailhost);
	      free (mailhost);
	    }

	  if (mailaddr != (char *)NULL)
	    {
	      forms_set_tag_value_in_package (p, "mailaddr", mailaddr);
	      free (mailaddr);
	    }

	  result = package_to_alist (p, 0);
	  symbol_destroy_package (p);
	}
    }

  if (result != (char *)NULL)
    {
      int len = strlen (result);
      bprintf_insert (page, start, "%s", result);
      *newstart = start + len;
      free (result);
    }

  xfree (dname);
  xfree (typearg);
}

#if defined (__cplusplus)
}
#endif
