final_realms_fluffos_v1/
final_realms_fluffos_v1/bin/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/ChangeLog.old/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/Win32/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/compat/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/compat/simuls/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/include/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/clone/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/command/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/data/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/etc/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/include/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/inherit/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/inherit/master/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/log/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/compiler/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/efuns/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/single/tests/operators/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/testsuite/u/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/tmp/
final_realms_fluffos_v1/fluffos-2.9-ds2.11/windows/
final_realms_fluffos_v1/lib/baseobs/guilds/
final_realms_fluffos_v1/lib/baseobs/misc/
final_realms_fluffos_v1/lib/baseobs/races/shadows/
final_realms_fluffos_v1/lib/cmds/god/
final_realms_fluffos_v1/lib/cmds/handlers/
final_realms_fluffos_v1/lib/cmds/handlers/cmds/
final_realms_fluffos_v1/lib/d/heaven/
final_realms_fluffos_v1/lib/d/heaven/heaven/ave/
final_realms_fluffos_v1/lib/d/mudlib/
final_realms_fluffos_v1/lib/d/newbie/
final_realms_fluffos_v1/lib/d/newbie/docs/
final_realms_fluffos_v1/lib/d/newbie/drow/armour/
final_realms_fluffos_v1/lib/d/newbie/drow/items/
final_realms_fluffos_v1/lib/d/newbie/drow/mobs/
final_realms_fluffos_v1/lib/d/newbie/drow/oldmobs/
final_realms_fluffos_v1/lib/d/newbie/drow/weapons/
final_realms_fluffos_v1/lib/d/newbie/duergar/weapons/
final_realms_fluffos_v1/lib/d/newbie/dwarf/weapons/
final_realms_fluffos_v1/lib/d/newbie/elf/cafe/
final_realms_fluffos_v1/lib/d/newbie/elf/chars/equip/
final_realms_fluffos_v1/lib/d/newbie/elf/items/armours/
final_realms_fluffos_v1/lib/d/newbie/elf/items/obj/
final_realms_fluffos_v1/lib/d/newbie/elf/items/weapons/
final_realms_fluffos_v1/lib/d/newbie/elf/quick_fix/
final_realms_fluffos_v1/lib/d/newbie/gnome/armour/
final_realms_fluffos_v1/lib/d/newbie/gnome/buildings/
final_realms_fluffos_v1/lib/d/newbie/gnome/items/
final_realms_fluffos_v1/lib/d/newbie/gnome/npcs/clones/
final_realms_fluffos_v1/lib/d/newbie/gnome/rooms/northrooms/
final_realms_fluffos_v1/lib/d/newbie/gnome/weapons/
final_realms_fluffos_v1/lib/d/newbie/goblin/armour/
final_realms_fluffos_v1/lib/d/newbie/goblin/items/
final_realms_fluffos_v1/lib/d/newbie/grads/log/
final_realms_fluffos_v1/lib/d/newbie/grads/npcs/
final_realms_fluffos_v1/lib/d/newbie/grads/rooms/
final_realms_fluffos_v1/lib/d/newbie/grads/rooms/cave1/
final_realms_fluffos_v1/lib/d/newbie/grads/temp/
final_realms_fluffos_v1/lib/d/newbie/guests/weapons/
final_realms_fluffos_v1/lib/d/newbie/half-elf/items/
final_realms_fluffos_v1/lib/d/newbie/half-elf/newroomss/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/castle/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/drows/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/savannah/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/secret/
final_realms_fluffos_v1/lib/d/newbie/half-elf/rooms/town/
final_realms_fluffos_v1/lib/d/newbie/halfling/
final_realms_fluffos_v1/lib/d/newbie/halfling/misc/
final_realms_fluffos_v1/lib/d/newbie/halfling/rooms/cave/
final_realms_fluffos_v1/lib/d/newbie/human/
final_realms_fluffos_v1/lib/d/newbie/human/armour/
final_realms_fluffos_v1/lib/d/newbie/human/monsters/
final_realms_fluffos_v1/lib/d/newbie/human/obj/
final_realms_fluffos_v1/lib/d/newbie/human/weapons/
final_realms_fluffos_v1/lib/d/newbie/lizard/armour/
final_realms_fluffos_v1/lib/d/newbie/lizard/items/
final_realms_fluffos_v1/lib/d/newbie/lizard/underwater/
final_realms_fluffos_v1/lib/d/newbie/lizard/weapons/
final_realms_fluffos_v1/lib/d/newbie/logs/
final_realms_fluffos_v1/lib/d/newbie/new_halfelf/
final_realms_fluffos_v1/lib/d/newbie/new_halfelf/npcs/
final_realms_fluffos_v1/lib/d/newbie/newdrow/npcs/
final_realms_fluffos_v1/lib/d/newbie/newdrow/rooms/
final_realms_fluffos_v1/lib/d/newbie/newelf/
final_realms_fluffos_v1/lib/d/newbie/newelf/chars/
final_realms_fluffos_v1/lib/d/newbie/newelf/npcs/
final_realms_fluffos_v1/lib/d/newbie/newelf/npcs/recopied/
final_realms_fluffos_v1/lib/d/newbie/newelf/obj/
final_realms_fluffos_v1/lib/d/newbie/newelf/quest_docs./
final_realms_fluffos_v1/lib/d/newbie/newken/
final_realms_fluffos_v1/lib/d/newbie/newken/chars/
final_realms_fluffos_v1/lib/d/newbie/newken/misc/
final_realms_fluffos_v1/lib/d/newbie/newken/npcs/
final_realms_fluffos_v1/lib/d/newbie/newken/obj/
final_realms_fluffos_v1/lib/d/newbie/newliz/
final_realms_fluffos_v1/lib/d/newbie/newliz/cave/
final_realms_fluffos_v1/lib/d/newbie/newliz/npcs/
final_realms_fluffos_v1/lib/d/newbie/orc/items/misc/
final_realms_fluffos_v1/lib/d/newbie/orc/items/weapons/
final_realms_fluffos_v1/lib/d/newbie/orc/tower/
final_realms_fluffos_v1/lib/d/vehicle/
final_realms_fluffos_v1/lib/doc/
final_realms_fluffos_v1/lib/doc/driver/
final_realms_fluffos_v1/lib/doc/driver/concepts/
final_realms_fluffos_v1/lib/doc/driver/driver/
final_realms_fluffos_v1/lib/doc/driver/efuns/arrays/
final_realms_fluffos_v1/lib/doc/driver/efuns/bitstrings/
final_realms_fluffos_v1/lib/doc/driver/efuns/communication/
final_realms_fluffos_v1/lib/doc/driver/efuns/core/
final_realms_fluffos_v1/lib/doc/driver/efuns/debugging/
final_realms_fluffos_v1/lib/doc/driver/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/driver/efuns/interactive/
final_realms_fluffos_v1/lib/doc/driver/efuns/mappings/
final_realms_fluffos_v1/lib/doc/driver/efuns/objects/
final_realms_fluffos_v1/lib/doc/driver/efuns/security/
final_realms_fluffos_v1/lib/doc/driver/efuns/strings/
final_realms_fluffos_v1/lib/doc/driver/efuns/system/
final_realms_fluffos_v1/lib/doc/driver/efuns/types/
final_realms_fluffos_v1/lib/doc/driver/lpc/constructs/
final_realms_fluffos_v1/lib/doc/driver/lpc/types/
final_realms_fluffos_v1/lib/doc/driver/platforms/
final_realms_fluffos_v1/lib/doc/lpc/
final_realms_fluffos_v1/lib/doc/mail/
final_realms_fluffos_v1/lib/doc/man/
final_realms_fluffos_v1/lib/doc/man/html/
final_realms_fluffos_v1/lib/doc/man/html/applies/
final_realms_fluffos_v1/lib/doc/man/html/applies/parsing/
final_realms_fluffos_v1/lib/doc/man/html/driver/
final_realms_fluffos_v1/lib/doc/man/html/efuns/
final_realms_fluffos_v1/lib/doc/man/html/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/html/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/html/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/html/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/html/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/html/efuns/general/
final_realms_fluffos_v1/lib/doc/man/html/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/html/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/local/
final_realms_fluffos_v1/lib/doc/man/local/applies/
final_realms_fluffos_v1/lib/doc/man/local/applies/interactive/
final_realms_fluffos_v1/lib/doc/man/local/applies/master/
final_realms_fluffos_v1/lib/doc/man/local/concepts/
final_realms_fluffos_v1/lib/doc/man/local/defines/
final_realms_fluffos_v1/lib/doc/man/local/driver/
final_realms_fluffos_v1/lib/doc/man/local/efuns/
final_realms_fluffos_v1/lib/doc/man/local/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/local/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/local/efuns/calls/
final_realms_fluffos_v1/lib/doc/man/local/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/local/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/man/local/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/local/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/local/efuns/general/
final_realms_fluffos_v1/lib/doc/man/local/efuns/interactive/
final_realms_fluffos_v1/lib/doc/man/local/efuns/internals/
final_realms_fluffos_v1/lib/doc/man/local/efuns/mappings/
final_realms_fluffos_v1/lib/doc/man/local/efuns/mudlib/
final_realms_fluffos_v1/lib/doc/man/local/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/local/efuns/objects/
final_realms_fluffos_v1/lib/doc/man/local/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/local/efuns/sockets/
final_realms_fluffos_v1/lib/doc/man/local/efuns/strings/
final_realms_fluffos_v1/lib/doc/man/local/efuns/system/
final_realms_fluffos_v1/lib/doc/man/local/historical/
final_realms_fluffos_v1/lib/doc/man/local/lfun/QC/
final_realms_fluffos_v1/lib/doc/man/local/lfun/events/
final_realms_fluffos_v1/lib/doc/man/local/lfun/monster/
final_realms_fluffos_v1/lib/doc/man/local/lfun/properties/
final_realms_fluffos_v1/lib/doc/man/local/lpc/
final_realms_fluffos_v1/lib/doc/man/local/lpc/constructs/
final_realms_fluffos_v1/lib/doc/man/local/lpc/types/
final_realms_fluffos_v1/lib/doc/man/local/standards/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/basic/
final_realms_fluffos_v1/lib/doc/man/local/tutorials/intermediate/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/interactive/
final_realms_fluffos_v1/lib/doc/man/mudos/applies/parsing/
final_realms_fluffos_v1/lib/doc/man/mudos/concepts/
final_realms_fluffos_v1/lib/doc/man/mudos/driver/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/arrays/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/buffers/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/calls/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/compile/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/filesystem/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/floats/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/functions/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/general/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mappings/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mixed/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/mudlib/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/numbers/
final_realms_fluffos_v1/lib/doc/man/mudos/efuns/parsing/
final_realms_fluffos_v1/lib/doc/man/mudos/lpc/constructs/
final_realms_fluffos_v1/lib/doc/man/mudos/lpc/types/
final_realms_fluffos_v1/lib/doc/races/
final_realms_fluffos_v1/lib/doc/races/old_race/
final_realms_fluffos_v1/lib/global/virtual/
final_realms_fluffos_v1/lib/global/wiz_backup/
final_realms_fluffos_v1/lib/net/config/
final_realms_fluffos_v1/lib/net/daemon/chars/
final_realms_fluffos_v1/lib/net/inherit/
final_realms_fluffos_v1/lib/net/intermud3/
final_realms_fluffos_v1/lib/net/intermud3/cmds/
final_realms_fluffos_v1/lib/net/intermud3/save/
final_realms_fluffos_v1/lib/net/intermud3/services/
final_realms_fluffos_v1/lib/net/obj/
final_realms_fluffos_v1/lib/net/old/
final_realms_fluffos_v1/lib/net/old/intermud/
final_realms_fluffos_v1/lib/net/old/intermud/adm/
final_realms_fluffos_v1/lib/net/old/intermud/services/
final_realms_fluffos_v1/lib/net/old/intermud/udp/
final_realms_fluffos_v1/lib/net/virtual/
final_realms_fluffos_v1/lib/obj/b_day/
final_realms_fluffos_v1/lib/obj/chars/
final_realms_fluffos_v1/lib/obj/handlers/lists/
final_realms_fluffos_v1/lib/obj/handlers/useless/
final_realms_fluffos_v1/lib/obj/monsters/
final_realms_fluffos_v1/lib/obj/roomgen/
final_realms_fluffos_v1/lib/obj/soul/
final_realms_fluffos_v1/lib/obj/vegetation/
final_realms_fluffos_v1/lib/obj/weapons/oldsys/
final_realms_fluffos_v1/lib/open/
final_realms_fluffos_v1/lib/players/g/
final_realms_fluffos_v1/lib/releasefiles/d/heaven/
final_realms_fluffos_v1/lib/releasefiles/d/mudlib/
final_realms_fluffos_v1/lib/releasefiles/d/newbie/
final_realms_fluffos_v1/lib/releasefiles/doc/
final_realms_fluffos_v1/lib/releasefiles/players/g/
final_realms_fluffos_v1/lib/releasefiles/save/
final_realms_fluffos_v1/lib/releasefiles/save/environ/
final_realms_fluffos_v1/lib/releasefiles/save/roomgen/
final_realms_fluffos_v1/lib/releasefiles/secure/
final_realms_fluffos_v1/lib/releasefiles/w/
final_realms_fluffos_v1/lib/releasefiles/w/god/
final_realms_fluffos_v1/lib/room/
final_realms_fluffos_v1/lib/save/
final_realms_fluffos_v1/lib/save/environ/
final_realms_fluffos_v1/lib/save/roomgen/
final_realms_fluffos_v1/lib/scripts/
final_realms_fluffos_v1/lib/secure/crerem/
final_realms_fluffos_v1/lib/secure/dom/
final_realms_fluffos_v1/lib/secure/log/
final_realms_fluffos_v1/lib/secure/misc/
final_realms_fluffos_v1/lib/std/adnd/
final_realms_fluffos_v1/lib/std/commands/shadows/
final_realms_fluffos_v1/lib/std/creator/
final_realms_fluffos_v1/lib/std/curses/
final_realms_fluffos_v1/lib/std/curses/old_sys/
final_realms_fluffos_v1/lib/std/curses/shadows/
final_realms_fluffos_v1/lib/std/dom/
final_realms_fluffos_v1/lib/std/effects/
final_realms_fluffos_v1/lib/std/effects/healing/
final_realms_fluffos_v1/lib/std/effects/other/
final_realms_fluffos_v1/lib/std/effects/poisons/
final_realms_fluffos_v1/lib/std/environ/
final_realms_fluffos_v1/lib/std/guilds/
final_realms_fluffos_v1/lib/std/guilds/priests/samples/
final_realms_fluffos_v1/lib/std/guilds/wizards/
final_realms_fluffos_v1/lib/std/living/baldy/
final_realms_fluffos_v1/lib/std/living/divstuff/
final_realms_fluffos_v1/lib/std/paran/
final_realms_fluffos_v1/lib/std/poisons/
final_realms_fluffos_v1/lib/std/poisons/shadows/
final_realms_fluffos_v1/lib/std/poisons/weapons/
final_realms_fluffos_v1/lib/std/race_groups/
final_realms_fluffos_v1/lib/std/room/
final_realms_fluffos_v1/lib/std/room/old/
final_realms_fluffos_v1/lib/std/rooms/
final_realms_fluffos_v1/lib/std/shadows/
final_realms_fluffos_v1/lib/std/shadows/test_shad/
final_realms_fluffos_v1/lib/std/socket/
final_realms_fluffos_v1/lib/std/spells/
final_realms_fluffos_v1/lib/std/vaults/
final_realms_fluffos_v1/lib/tmp/
final_realms_fluffos_v1/lib/w/
final_realms_fluffos_v1/lib/w/god/
final_realms_fluffos_v1/old/
final_realms_fluffos_v1/win32/
/*
 * Reads in the nameserver config file and gets all of the
 * ip's from it.
 */
#include "socket.h"
#include "inet.h"
#define SERVER_PORT 2001
#define TIMEOUT (5*60)
#define CONFIG "/net/config/"
#define ME machines[lower_case(mud_name())]
/* #define ME machines[lower_case(MUD_XNAME)] */
#define JUST_ADDR(BING) if ( BING && ( BING != "" ) ) if ( stringp( BING ) ) sscanf( BING, "%s %*d", BING )

#define XNAME 0
#define REVERSE 1
#define LAST_REQ 2
#define SERVICE 3

mapping machines,
        reverse,
        services,
        failed,
        requests,
        service_req,
        sent,
        my_write,
        services;
string *nameservers,
       *pending;
int my_port;
int my_socket, open_server, current_ns;

void load_mappings(string str, string gf);
void setup_nameserver(int port);
void query_nameserver();
void close_callback(int fd);
void write_callback();
void write_service(int fd);

void create() {
  string bing;

  nameservers = ({ });
  service_req = ([ ]);
  machines = ([ ]);
  services = ([ "default" : ([ ]) ]);
  failed = ([ ]);
  reverse = ([ ]);
  pending = ({ });
  sent = ([ ]);
  requests = ([ ]);
  my_write = ([ ]);
  load_mappings(CONFIG+"nameserver", CONFIG+"services");
/* The default... */
/* Commented out by Turrican, since noone connects up there anymore anyway. 
  setup_nameserver(my_port); */
} /* create() */

void load_mappings(string filen, string ser) {
  string file, *bits;
  string name, address, flags, tmp;
  int i, port, de_port;

  file = read_file(filen);
  if (file) {
/* Need to do it twice me thinks.  Other wise odd sized bits would loose. */
    file = implode(explode(file, " ") - ({ "" }), " ");
    bits = explode(file, "\n");
    for (i=0;i<sizeof(bits);i++) {
/* Do we have a comment? */
      if (bits[i][0] == '#' || !strlen(bits[i]))
        continue;
/* Ok, addresses are of the form, mudname address flags */
/* flags are NS for nameserver.  (All that is named at the moment) */
      flags = "";
      if (sscanf(bits[i], "%s %s", name, address) == 2) {
        port = SERVER_PORT;
        if (sscanf(address, "%s:%d%s", address, port, flags) != 3)
          sscanf(address, "%s %s", address, flags);
        else
          sscanf(flags, " %s", flags);
        switch (lower_case(flags)) {
          case "ns" :
            nameservers += ({ address+" "+port });
            break;
        }
   /* name = lower_case(name);  */
        name = replace(name, ".", " ");
        machines[name] = address+" "+port;
/* Case for multiple muds? frog is lets sleeze it... */
        reverse[address] = name;
        reverse[address+" "+port] = name;
      }
    }
  }
  file = read_file(ser);
  if (file) {
    file = implode(explode(file, " ") - ({ "" }), " ");
    file = lower_case(file);
    bits = explode(file, "\n");
    for (i=0;i<sizeof(bits);i++) {
      if (bits[i][0] == '#' || !strlen(bits[i]))
        continue;
/* The pattern is, name, port */
      if (sscanf(bits[i], "%s %s %s", name, address, tmp)) {
/* name = lower_case(name); */
        if (name != "default") {
          name = machines[name];
          de_port = SERVER_PORT;
          sscanf(name, "%s %d", file, de_port);
        } else
          de_port = 0;
/* Can only set up things about known muds... */
        if (!name) continue;
        if (!services[name])
          services[name] = ([ ]);
        if (tmp[0] == '-') {
          sscanf(tmp[1..100], "%d", port);
          services[name][address] = de_port+port;
        } else if (tmp[0] == '+') {
          sscanf(tmp[1..100], "%d", port);
          services[name][address] = de_port+port;
        } else if (sscanf(tmp, "%d", port) == 1)
          if (name == "default")
            services[name][address] = ({ port });
          else
            services[name][address] = port;
      }
    }
  }
/* Setup the nameserver ports.   They have to be in the config files. */
  for (i=0;i<sizeof(nameservers);i++) {
    sscanf(nameservers[i], "%s %d", tmp, my_port);
    if (services[tmp] && services[tmp]["nameserver"])
      my_port = services[tmp]["nameserver"];
    else if (services["default"] && pointerp(services["default"]["nameserver"]))
      my_port = services["default"]["nameserver"][0];
    else if (services["default"] && services["default"]["nameserver"])
      my_port += services["default"]["nameserver"];
    nameservers[i] = tmp+" "+my_port;
  }
  my_port = SERVER_PORT;
   if ( ME )
      sscanf( ME, "%s %d", file, my_port );
  tmp = machines[mud_name()];
  if (services[tmp] && services[tmp]["nameserver"])
    my_port = services[tmp]["nameserver"];
  else if (services["default"] && pointerp(services["default"]["nameserver"]))
    my_port = services["default"]["nameserver"][0];
  else if (services["default"] && services["default"]["nameserver"])
    my_port += services["default"]["nameserver"];
} /* load_mappings() */

/*
 * Ok, we lookup in our nice array, if we get a hit we returns that name
 * if not, we try the first name server.  Bit of a problem here though.
 *
 * Means the return time is not deterministic.
 * Oh well.  They will have to live with it.
 * Keep a failed array so we don't try the same name several million times.
 */
void do_request(int type, string name, string func, mixed args, string *ser) {
  if (!ser) ser = ({ });
  if (!requests[type])
    requests[type] = ([ ]);
  if (!requests[type][name]) {
    pending += ({ type, name });
    if (current_ns == 0)
      requests[type][name] = ({ sizeof(nameservers)-1, ser });
    else
      requests[type][name] = ({ current_ns - 1, ser });
  } else
    requests[type][name][1] += ser;
  requests[type][name] += ({ ({ previous_object(), func, args }) });
  query_nameserver();
} /* do_request() */

void service_request(string name, string host, mixed ob, string func,
                     mixed args) {
  int fd, i;

  if (!service_req[host]) {
/* We need to open one... */
    fd = socket_create(STREAM, "got_service", "close_service");
    i = socket_connect(fd, host+" "+SERVER_PORT,
                       "got_service", "write_service");
    if (i < 0) {
      JUST_ADDR(host);
      call_other(ob, func, name, host, 0, args);
      return ;
    }
    service_req[fd] = host;
    service_req[host] = ({ fd, 2, ({ ob, func, name, args }) });
    return ;
  }
  service_req[host] += ({ ({ ob, func, name, args }) });
  write_service(service_req[host][0]);
} /* service_request() */

void got_service(int fd, string mess) {
  string name, host, str, host2;
  int port, i;
  mixed *bit;

  sscanf(mess, "%s^%d", name, port);
  host = service_req[fd];
  if (!host) return ;
  for (i=2;i<sizeof(service_req[host]);i++)
    if (service_req[host][i][2] == name) {
      bit = service_req[host][i];
      services[host][bit[2]] = port;
      host2 = host;
      JUST_ADDR(host2);
      call_other(bit[0], bit[1], bit[2], host2, port, bit[3]);
      service_req[host] = delete(service_req[host], i, 1);
      if (service_req[host][1] >= i)
        service_req[host][1]--;
      i--;
    }
  if (sizeof(service_req[host]) == 2) {
/* Just the control info... */
    map_delete(service_req, host);
    map_delete(service_req, fd);
    socket_close(fd);
  }
} /* got_service() */

void close_service(int fd) {
  int i;
  string host, host2;
  mixed *bit;

/* This means we fluffed it... */
  host2 = host = service_req[fd];
  if (!host) return ;
  JUST_ADDR(host2);
  for (i=2;i<sizeof(service_req[host]);i++) {
    bit = service_req[host][i];
    call_other(bit[0], bit[1], bit[2], host2, 0, bit[3]);
  }
  map_delete(service_req, host);
  map_delete(service_req, fd);
} /* close_service() */

void write_service(int fd) {
  string host;
  int pos;

  host = service_req[fd];
  if (!host) {
/* How did this get here? */
    socket_close(fd);
    return ;
  }
/* Anything left to write? */
  if ((pos = service_req[host][1]) > sizeof(service_req[host]))
    return ;
/* Yep! */
  if (socket_write(fd, SERVICE+"^"+service_req[host][pos][2]+"^0") < 0)
    return ;
  service_req[host][1]++;
} /* write_service() */

void lookup_mud(string name, string finitio, mixed args, string *ser) {
  string host;
  int port;

/* name = lower_case(name); */
  if (machines[lower_case(name)]) {
    host = machines[lower_case(name)];
/*
    JUST_ADDR(host);
 */
    call_other(previous_object(), finitio, name, host, args);
    return ;
  }
  if ((failed[XNAME] && failed[XNAME][name]) || !sizeof(nameservers)) {
    call_other(previous_object(), finitio, name, 0, args);
    return ;
  }
/*
 * If it is a number, it has already been looked up so...  we just return
 * it..
 */
  if (name[0] >= '1' && name[0] <= '9') {
    if (sscanf(name, "%s %d") == 2)
      call_other(previous_object(), finitio, name, host, args);
    else
/* Stick junk on the end.  They must know what they are doing... */
      call_other(previous_object(), finitio, name, host+" 4001", args);
    return ;
  }
/* Ok, ask any name servers we know about */
  do_request(XNAME, name, finitio, args, ser);
} /* lookup_mud() */

void reverse_lookup(string address, string func, mixed args, string *ser) {
  string *bits;
  int i;

  bits = keys(machines);
  if ((i=member_array(address, bits)) != -1) {
    bits = values(machines);
    call_other(previous_object(), func, address, bits[i], args);
    return ;
  }
  if ((failed[REVERSE] && failed[REVERSE][address]) || !sizeof(nameservers)) {
    call_other(previous_object(), func, address, 0, args);
    return ;
  }
/* Ok, now we be a nice little frog and setup a nameserver lookup thingy. */
  do_request(REVERSE, address, func, args, ser);
} /* reverse_lookup() */

void lookup_service(string name, string host, string func, string args) {
  string blue;

  name = lower_case(name);
  host = lower_case(host);
  if (host[0] < '0' || host[0] > '9') {
/* Need to lookup the host first... */
    this_object()->lookup_mud(host, "finish_hostlookup",
                           ({ previous_object(), func, name, args }), ({ }));
    return ;
  }
  if (services["default"][name]) {
    string hname;
    int port;

    port = SERVER_PORT;
    sscanf(host, "%s %d", hname, port);
    if (pointerp(services["default"][name]))
      call_other(previous_object(), func, name, hname,
                                          services["default"][name][0], args);
    else
      call_other(previous_object(), func, name, hname,
                                          port+services["default"][name], args);
    return ;
  }
  if (!host || host == ME || !services[host]) {
    host = ME;
    JUST_ADDR(host);
    if (!services[ME] || !services[ME][name])
      call_other(previous_object(), func, name, host, 0, args);
    else
      call_other(previous_object(), func, name, host, services[ME][name], args);
    return ;
  }
/* Irk!  Now we need to look the damn thing up :( */
  if (services[host][name]) {
    blue = host;
    JUST_ADDR(blue);
    call_other(previous_object(), func, name, blue, services[host][name], args);
    return ;
  }
  service_request(name, host, previous_object(), func, args);
} /* lookup_service() */

void finish_hostlookup(string host, string found, mixed *args) {
  if (!found) {
    call_other(args[0], args[1], args[2], found, 0, args[3]);
    return ;
  }
  if (services["default"][args[2]]) {
    string hname;
    int port;

    port = SERVER_PORT;
    sscanf(found, "%s %d", hname, port);
    if (pointerp(services["default"][args[2]]))
      call_other(args[0], args[1], args[2], hname,
                             services["default"][args[2]][0], args[3]);
   else
      call_other(args[0], args[1], args[2], hname,
                             services["default"][args[2]]+port, args[3]);
    return ;
  }
  if (services[found] && services[found][args[2]]) {
    host = found;
    JUST_ADDR(host);
    call_other(args[0], args[1], args[2], host, services[found][args[2]],
                                 args[3]);
    return ;
  }
  service_request(args[2], found, args[0], args[1], args[3]);
} /* finish_hostlookup() */

/*
 * This will open a connection to a nameserver and ask it, hey!  Do you
 * know about this name?
 *
 * This same port is used for service lookups.  So we need a nice flag
 * We also keep a list of places we have been.  To stop loops.
 */
void query_nameserver() {
  int i;
  if (open_server) {
    write_callback();
    return ;
  }
  open_server = socket_create(STREAM, "got_address", "close_callback");
  i = socket_connect(open_server, nameservers[current_ns],
                     "got_address", "write_callback");
  if (i < 0)
    close_callback(0);
/*
  else
    write_callback();
 */
} /* query_nameserver() */

void finish_request(int type, string first, mixed ret) {
  mixed *bing;
  int i;

  if (!requests[type])
    return ;
  if (!requests[type][first])
    return ;
  bing = requests[type][first];
  for (i=2;i<sizeof(bing);i++)
    catch(call_other(bing[i][0], bing[i][1], first, ret, bing[i][2]));
  map_delete(requests[type], first);
  if (!sizeof(requests[type]))
    map_delete(requests, type);
} /* finish_request() */

/*
 * This will only get called if our lookup failed.  See if we asked
 * the last name server, if so.  Sulk.
 */
int check_finish(int type, string first) {
  if (!requests[type] || !requests[type][first])
    return 1; /* Finished */
  if (requests[type][first][0] == current_ns) {
    finish_request(type, first, 0);
    return 1;
  }
} /* check_finish() */

void got_address(int fd, mixed message) {
  int i;
  int type;
  string name, res, tmp;

  sscanf(message, "%d^%s^%s", type, name, res);
  if (sent[type]) {
    sent[type] = (mixed *)sent[type] - ({ name });
    if (!sizeof(sent[type]))
      map_delete(sent, type);
  }
  switch (type) {
    case XNAME :
      if (res== "0") {
/* Frog! We failed!  Sulk. */
/* Sigh....  We failed tell em about the bad news */
        if (check_finish(type, name)) {
          if (!failed[type])
            failed[type] = ([ ]);
          failed[type][name] = 1;
        }
        break;
      }
/* We got an answer!  Yes! */
      tmp = res;
/*  We want more than just an address for this bit.  We just want an 
 * address with services...
      JUST_ADDR(tmp);
 */
      finish_request(type, name, tmp);
      machines[name] = res;
      break;
    case REVERSE :
      if (res == "0") {
        if (check_finish(type, name)) {
          if (!failed[type])
            failed[type] = ([ ]);
          failed[type][name] = 1;
        }
        break;
      }
      finish_request(type, name, res);
      machines[res] = name;
      break;
  }
/* Wait till we give up on this nameserver and move onto the next */
  if (!sizeof(sent) && !sizeof(pending)) {
/* Replyed to all of them */
    socket_close(open_server);
/* Does this call the close function? */
    close_callback(open_server);
  }
} /* got_address() */

void setup_nameserver(int port) {
  int i;

  my_socket = socket_create(STREAM, "read_callback", "interaction_close");
  socket_bind(my_socket, port);
  i = socket_listen(my_socket, "connect_callback");
} /* setup_nameserver() */

void write_callback() {
  string * path, s;
/*
 * Put all of the nameservers in the path as we will ask them all eventually.
 */
  path = ({ });
  if (!sizeof(pending))
    return ;
  if (requests[pending[0]])
    {
    /*
    path = requests[pending[0]][1] + nameservers + 
           ({ machines[mud_name()] });
    */
    path += (string *)requests[pending[0]][1];
    path += nameservers;
    path += ({ machines[mud_name()] });
    }
  else
    path = nameservers + ({ machines[mud_name()] });
    if (socket_write(open_server, (s=(pending[0]+"^"+pending[1]+"^"
                                +implode(path, "$")))) >= 0) {
    if (sent[pending[0]])
      sent[pending[0]] += ({ pending[1] });
    else
      sent[pending[0]] = ({ pending[1] });
    pending = pending[2..1000];
  }
} /* write_callback() */

void connect_callback(int fd) {
  int connected;

  if ((connected = socket_accept(fd, "read_callback",
                                     "my_write_callback")) < 0) {
    return ;
  }
  my_write[connected] = 1;
  call_out("time_out", TIMEOUT, connected);
} /* connect_callback() */

void time_out(int fd) {
  socket_close(fd);
  map_delete(my_write, fd);
} /* time_out() */

void my_write_callback(int fd) {
  if (!my_write[fd])
    my_write[fd] = 1;
  if (intp(my_write[fd]))
    return ;
  if (socket_write(fd, my_write[fd][0]) >= 0)
    my_write[fd] = my_write[fd][1..1000];
  if (!sizeof(my_write[fd]))
    map_delete(my_write, fd);
} /* my_write_callback() */

void interaction_close(int fd) {
  map_delete(my_write, fd);
} /* interaction_close() */

void send_back(int fd, string mess) {
  if (my_write[fd] && intp(my_write[fd])) {
/* Its ready to be sent to. */
    if (socket_write(fd, mess) < 0) {
/* Hmm.  bit of the old fail there... */
      my_write[fd] = ({ mess });
      return ;
    }
    map_delete(my_write, fd);
    return ;
  }
  my_write[fd] += ({ mess });
} /* send_back() */

void read_callback(int fd, mixed message, mixed blue) {
  string *bits;
  int i, type;
  string name, path;
  string *new_p;

  if (message[0] >= 'A' && message[0] <= 'Z') {
/* They are talking to our service.  Oblige them. */
    sscanf(message, "%s^%s", name, path);
    INETD->service_contact(fd, name, path);
    return ;
  }
  sscanf(message, "%d^%s^%s", type, name, path);
  new_p = explode(path, "$");
  switch (type) {
    case XNAME :
/* Name lookup */
      if (machines[name]) {
        send_back(fd, type+"^"+name+"^"+machines[name]);
        return ;
      }
/*
 * Ok, we don't know about it.  Do we know about any other nameservers
 * not in the asked list?
 */
      if (sizeof(nameservers - new_p)) {
/* There are some! */
        lookup_mud(name, "tell_other_server", ({ fd, type }),
                   new_p);
      } else {
        send_back(fd, type+"^"+name+"^"+machines[name]);
      }
      return ;
    case REVERSE :
/* Reverse name lookup */
      bits = keys(machines);
      if ((i = member_array(name, bits)) != -1) {
        bits = values(machines);
        send_back(fd, type+"^"+name+"^"+bits[i]);
        return ;
      }
      if (sizeof(nameservers - new_p)) {
        reverse_lookup(name, "tell_other_server", ({ fd, type }),
                       new_p);
      } else {
        send_back(fd, type+"^"+name+"^0");
      }
      return ;
    case SERVICE :
/* Service lookup */
      if (!services[ME])
        send_back(fd, type+"^"+name+"^0");
      else
        send_back(fd, type+"^"+name+"^"+services[ME][name]);
      return ;
  } 
} /* read_callback() */

void tell_other_server(string name, string address, mixed *fd) {
/*
 * Don't bother checking if it is still around.  Just shove stuff down it.
 * it wont complain.
 */
  socket_write(fd[0], fd[1]+"^"+name+"^"+address);
} /* tell_other_server() */

void close_callback(int fd) {
  int i, j;
  mixed *tmp;

/*
 * This should be one of our outstanding connections to the rest of
 * of the world
 */
  current_ns++;
  if (current_ns >= sizeof(nameservers))
    current_ns = 0;
  pending = ({ });
  for (i=0;i<LAST_REQ;i++) {
    if (!requests[i]) continue;
    tmp = keys(requests[i]);
    for (j=0;j<sizeof(tmp);j++) {
/* Check for fail */
      if (!check_finish(i, tmp[j]) &&
          member_array(nameservers[current_ns], requests[i][tmp[j]][1]) == -1)
        pending += ({ i, tmp[j] });
    }
    if (!sizeof(requests[i]))
      map_delete(requests, i);
  }
  if (sizeof(pending)) {
    open_server = 0;
    query_nameserver();
  } else if (sizeof(requests))
/* We still have some unfinished bisness. */
    close_callback(open_server);
  else
    open_server = 0;
} /* close_callback() */

mapping query_services() { return services + ([ ]); }
mapping query_failed() { return failed + ([ ]); }
string *query_nameservers() { return nameservers + ({ }); }
mapping query_machines() { return machines + ([ ]); }