lpmoo-1.2/etc/
lpmoo-1.2/mudlib/
lpmoo-1.2/mudlib/etc/
lpmoo-1.2/mudlib/include/
lpmoo-1.2/mudlib/include/moo/
lpmoo-1.2/mudlib/lpc/
lpmoo-1.2/mudlib/std/auto/
lpmoo-1.2/mudlib/std/bfuns/
/*
 * NAME:	dns.c
 * DESCRIPTION:	domain name translation system
 */

inherit "/std/string";

private	mapping	addrs;		/* hostname -> IP mapping */
private	mapping	names;		/* IP -> hostname mapping */

private	object	server;		/* connection to server process */
private int	reset_handle;	/* for remove_call_out */

# define CYCLE  (60 * 60 * 24)	/* how often to clear the cache */

/*
 * NAME:	create()
 * DESCRIPTION:	initialize data
 */
static
void create(void)
{
  addrs = ([ ]);
  names = ([ ]);

  reset_handle = call_out("reset", CYCLE);
}

/*
 * NAME:	reset()
 * DESCRIPTION:	clear cache
 */
void reset(void)
{
  int i;
  string *keys;

  remove_call_out(reset_handle);

  /* leave pending requests intact */

  keys = map_indices(addrs);
  for (i = sizeof(keys); i--; )
    if (stringp(addrs[keys[i]]))
      addrs[keys[i]] = 0;

  keys = map_indices(names);
  for (i = sizeof(keys); i--; )
    if (stringp(names[keys[i]]))
      names[keys[i]] = 0;

  reset_handle = call_out("reset", CYCLE);
}

/*
 * NAME:	open()
 * DESCRIPTION:	designate the DNS server object
 */
void open(void)
{ server = previous_object(); }

/*
 * NAME:	call()
 * DESCRIPTION:	invoke a function (via delayed call_out)
 */
static varargs
void call(object obj, string func, mixed args...)
{
  if (obj != 0)
    call_other(obj, func, args...);
}

/*
 * NAME:	answer()
 * DESCRIPTION:	return a result via callback
 */
static
void answer(mixed *list, string reply)
{
  int i;

  for (i = sizeof(list); i--; )
    call_out("call", 0, list[i][0], list[i][1], reply);
}

/*
 * NAME:	receive_message()
 * DESCRIPTION:	the server has sent a reply
 */
void receive_message(string line)
{
  string name, canon, addr;
  mixed list;

  if (sscanf(line, "HOST %s = %s = %s", name, canon, addr) == 3)
    {
      list = addrs[tolower(name)];
      addrs[tolower(name)] = addrs[tolower(canon)] = addr;

      if (arrayp(list))
	answer(list, addr);

      list = names[addr];
      names[addr] = canon;

      if (arrayp(list))
	answer(list, canon);
    }
  else if (sscanf(line, "NONAME %s", addr) == 1)
    {
      list = names[addr];
      names[addr] = 0;
      if (arrayp(list))
	answer(list, 0);
    }
  else if (sscanf(line, "NOADDR %s", name) == 1)
    {
      list = addrs[tolower(name)];
      addrs[tolower(name)] = 0;
      if (arrayp(list))
	answer(list, 0);
    }
}

/*
 * NAME:	add_request()
 * DESCRIPTION:	append a request for notification
 */
static
void add_request(mapping where, string what, object obj, string func)
{
  if (arrayp(where[what]))
    where[what] += ({ ({ obj, func }) });
  else
    where[what]  = ({ ({ obj, func }) });
}

/*
 * NAME:	get_name()
 * DESCRIPTION:	return the hostname for an IP address, if any
 */
varargs
string get_name(string addr, string func)
{
  mixed name;

  if (sscanf(addr, "%*d.%*d.%*d.%*d") != 4)
    return addr;  /* lookup canonical name? */

  if (stringp(name = names[addr]))
    return name;
  else
    {
      if (server == 0)
	return 0;

      server->notify("NAME? " + addr);
      if (func != 0)
	add_request(names, addr, previous_object(), func);

      return "";
    }
}

/*
 * NAME:	get_addr()
 * DESCRIPTION:	return the IP address for a hostname, if any
 */
varargs
string get_addr(string name, string func)
{
  mixed addr;

  if (sscanf(name, "%*d.%*d.%*d.%*d") == 4)
    return name;

  if (stringp(addr = addrs[tolower(name)]))
    return addr;
  else
    {
      if (server == 0)
	return 0;

      server->notify("ADDR? " + name);
      if (func != 0)
	add_request(addrs, tolower(name), previous_object(), func);

      return "";
    }
}

mapping dump_names(void)
{ return names; }

mapping dump_addrs(void)
{ return addrs; }