wileymud-1.187b/
wileymud-1.187b/attic/
wileymud-1.187b/attic/bin/
wileymud-1.187b/attic/lib/
wileymud-1.187b/attic/lib/adm/
wileymud-1.187b/attic/lib/man/
wileymud-1.187b/attic/lib/new-wld/
wileymud-1.187b/attic/lib/new-wld/default/
wileymud-1.187b/attic/lib/old/
wileymud-1.187b/attic/lib/wld/
wileymud-1.187b/attic/public_html/
wileymud-1.187b/attic/public_html/gfx/
wileymud-1.187b/attic/src/bin/
wileymud-1.187b/attic/src/etc/
wileymud-1.187b/attic/src/libauth-4.0-p5/
wileymud-1.187b/attic/src/sedna/
wileymud-1.187b/backups/
wileymud-1.187b/bin/
wileymud-1.187b/docs/
wileymud-1.187b/etc/
wileymud-1.187b/lib/
wileymud-1.187b/lib/adm/
wileymud-1.187b/lib/boards/
wileymud-1.187b/lib/log/
wileymud-1.187b/lib/man/
wileymud-1.187b/lib/ply/
wileymud-1.187b/lib/ply/a/
wileymud-1.187b/lib/ply/b/
wileymud-1.187b/lib/ply/c/
wileymud-1.187b/lib/ply/d/
wileymud-1.187b/lib/ply/g/
wileymud-1.187b/lib/ply/k/
wileymud-1.187b/lib/ply/m/
wileymud-1.187b/lib/ply/s/
wileymud-1.187b/lib/ply/t/
wileymud-1.187b/public_html/gfx/
wileymud-1.187b/src/bin/
wileymud-1.187b/src/convert/attic/
wileymud-1.187b/src/convert/obj/
wileymud-1.187b/src/convert/perl/
wileymud-1.187b/src/convert/perl/MudConvert/
wileymud-1.187b/src/convert/perl/MudConvert/DUMP/
wileymud-1.187b/src/convert/perl/MudConvert/Report/
wileymud-1.187b/src/convert/perl/MudConvert/WileyMUD/
wileymud-1.187b/src/convert/perl/output/
wileymud-1.187b/src/convert/perl/output/DUMP/
wileymud-1.187b/src/convert/perl/output/Report/
wileymud-1.187b/src/convert/perl/output/WileyMUD/
wileymud-1.187b/src/etc/
wileymud-1.187b/src/etc/init.d/
wileymud-1.187b/src/etc/rc.d/
wileymud-1.187b/src/etc/rc.d/init.d/
wileymud-1.187b/src/lib/
wileymud-1.187b/src/lib/adm/
wileymud-1.187b/src/lib/boards/
wileymud-1.187b/src/lib/log/
wileymud-1.187b/src/lib/man/
wileymud-1.187b/src/lib/ply/
wileymud-1.187b/src/lib/ply/a/
wileymud-1.187b/src/lib/ply/b/
wileymud-1.187b/src/lib/ply/c/
wileymud-1.187b/src/lib/ply/d/
wileymud-1.187b/src/lib/ply/e/
wileymud-1.187b/src/lib/ply/f/
wileymud-1.187b/src/lib/ply/g/
wileymud-1.187b/src/lib/ply/h/
wileymud-1.187b/src/lib/ply/i/
wileymud-1.187b/src/lib/ply/j/
wileymud-1.187b/src/lib/ply/k/
wileymud-1.187b/src/lib/ply/l/
wileymud-1.187b/src/lib/ply/m/
wileymud-1.187b/src/lib/ply/n/
wileymud-1.187b/src/lib/ply/o/
wileymud-1.187b/src/lib/ply/p/
wileymud-1.187b/src/lib/ply/q/
wileymud-1.187b/src/lib/ply/r/
wileymud-1.187b/src/lib/ply/s/
wileymud-1.187b/src/lib/ply/t/
wileymud-1.187b/src/lib/ply/u/
wileymud-1.187b/src/lib/ply/v/
wileymud-1.187b/src/lib/ply/w/
wileymud-1.187b/src/lib/ply/x/
wileymud-1.187b/src/lib/ply/y/
wileymud-1.187b/src/lib/ply/z/
wileymud-1.187b/src/obj/
wileymud-1.187b/src/utils/
wileymud-1.187b/src/utils/mobmaker/
/*
 *  file: comm.c , Communication module.                   Part of DIKUMUD
 *  Usage: Communication, central game loop.
 *  Copyright (C) 1990, 1991 - see 'license.doc' for complete information.
 *  All Rights Reserved
 *  Using *any* part of DikuMud without having read license.doc is
 *  violating our copyright.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <sys/time.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/un.h>
#include <sys/resource.h>

#include "include/global.h"
#include "include/bug.h"
#include "include/utils.h"
#include "include/interpreter.h"
#include "include/handler.h"
#include "include/db.h"
#include "include/modify.h"
#include "include/whod.h"
#include "include/multiclass.h"
#include "include/weather.h"
#include "include/limits.h"
#include "include/spell_parser.h"
#include "include/sound.h"
#include "include/fight.h"
#include "include/mob_actions.h"
#define _COMM_C
#include "include/comm.h"

#ifdef RFC1413
#include "libident-0.19/ident.h"
#include "libauth-4.0-p5/authuser.h"
#endif

struct descriptor_data *descriptor_list;
struct descriptor_data *next_to_process;

int mud_port;
int slow_death = 0;	/* Shut her down, Martha, she's sucking mud */
int diku_shutdown = 0;	/* clean shutdown */
int diku_reboot = 0;	/* reboot the game after a shutdown */
int DEBUG = 0;
int DEBUG2 = 0;
int no_specials = 0;	/* Suppress ass. of special routines */
long Uptime;		/* time that the game has been up */

int maxdesc;
int avail_descs;
int tics = 0;			       /* for extern checkpointing */
int pulse = 0;
int pulse_update = PULSE_UPDATE + PULSE_VARIABLE;
int pulse_river = PULSE_RIVER;
int pulse_teleport = PULSE_TELEPORT;
int pulse_nature = PULSE_NATURE;
int pulse_sound = PULSE_SOUND;
int pulse_zone = PULSE_ZONE;
int pulse_mobile = PULSE_MOBILE;
int pulse_violence = PULSE_VIOLENCE;
int pulse_reboot = PULSE_REBOOT;
int pulse_dump = PULSE_DUMP;

int main(int argc, char **argv) {
  int port;
  char buf[512];
  int pos = 1;
  char *dir;

  if (DEBUG)
    dlog("main");
  port = DFLT_PORT;
  dir = DFLT_DIR;
  WizLock = FALSE;

  while ((pos < argc) && (*(argv[pos]) == '-')) {
    switch (*(argv[pos] + 1)) {
    case 'w':
      WizLock = TRUE;
      log("WizLock is SET.");
      break;
    case 'D':
      DEBUG = TRUE;
      log("Debugging is on.");
      break;
    case 'l':
      log("Lawful mode no longer available.");
      break;
    case 'd':
      if (*(argv[pos] + 2))
	dir = argv[pos] + 2;
      else if (++pos < argc)
	dir = argv[pos];
      else {
	log("Directory arg expected after option -d.");
	exit(0);
      }
      break;
    case 's':
      no_specials = 1;
      log("Suppressing assignment of special routines.");
      break;
    default:
      sprintf(buf, "Unknown option -% in argument string.",
	      *(argv[pos] + 1));
      log(buf);
      break;
    }
    pos++;
  }

  if (pos < argc)
    if (!isdigit(*argv[pos])) {
      fprintf(stderr, "Usage: %s [-l] [-s] [-d pathname] [ port # ]\n",
	      argv[0]);
      exit(0);
    } else if ((port = atoi(argv[pos])) <= 1024) {
      printf("Illegal port #\n");
      exit(0);
    }

  Uptime = time(0);
  sprintf(buf, "Running game on port %d.", port);
  mud_port= port;
  log(buf);

  if (chdir(dir) < 0) {
    perror("chdir");
    exit(0);
  }
  sprintf(buf, "Using %s as data directory.", dir);
  log(buf);

  srandom(time(0));
  run_the_game(port);
  return(42);		       /* what's so great about HHGTTG, anyhow? */
}

/* Init sockets, run game, and cleanup sockets */
void run_the_game(int port) {
  int s;
  void signal_setup(void);
  void coma(int);

  descriptor_list = NULL;

  log("Signal trapping.");
  signal_setup();

  log("Opening mother connection.");
  s = init_socket(port);
  boot_db();

  init_whod(port);
  log("Entering game loop.");
  game_loop(s);

  close_sockets(s);
  close_whod();

  if (diku_reboot) {
    log("Rebooting.");
    exit(0);
  }
  log("Normal termination of game.");
}

/* Accept new connects, relay commands, and call 'heartbeat-functs' */
void game_loop(int s) {
  fd_set input_set, output_set, exc_set;
  struct timeval last_time, now, timespent, timeout, null_time;
  static struct timeval opt_time;
  char comm[MAX_INPUT_LENGTH];
  char promptbuf[256];
  struct descriptor_data *point, *next_point;
  int mask;
  struct room_data *rm;
  struct char_data *mount;

  pulse = 0;
  null_time.tv_sec = 0;
  null_time.tv_usec = 0;

  opt_time.tv_usec = OPT_USEC;	       /* Init time values */
  opt_time.tv_sec = 0;

  gettimeofday(&last_time, (struct timezone *)0);
  maxdesc = s;
  avail_descs = getdtablesize() - 2; /* !! Change if more needed !! */

  mask = sigmask(SIGUSR1) | sigmask(SIGUSR2) | sigmask(SIGINT) |
    sigmask(SIGPIPE) | sigmask(SIGALRM) | sigmask(SIGTERM) |
    sigmask(SIGURG) | sigmask(SIGXCPU) | sigmask(SIGHUP);

  /* Main loop */
  while (!diku_shutdown) {
    FD_ZERO(&input_set);
    FD_ZERO(&output_set);
    FD_ZERO(&exc_set);
    FD_SET(s, &input_set);
    for (point = descriptor_list; point; point = point->next) {
      if (point->descriptor != 0) {
	FD_SET(point->descriptor, &input_set);
	FD_SET(point->descriptor, &exc_set);
	FD_SET(point->descriptor, &output_set);
      }
    }

    gettimeofday(&now, (struct timezone *)0);
    timespent = timediff(&now, &last_time);
    timeout = timediff(&opt_time, &timespent);
    last_time.tv_sec = now.tv_sec + timeout.tv_sec;
    last_time.tv_usec = now.tv_usec + timeout.tv_usec;
    if (last_time.tv_usec >= 1000000) {
      last_time.tv_usec -= 1000000;
      last_time.tv_sec++;
    }
    sigsetmask(mask);
    whod_loop();
    if (select(maxdesc + 1, &input_set, &output_set, &exc_set, &null_time) < 0) {
      perror("Select poll");
      return;
    }
    if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, &timeout) < 0) {
      perror("Select sleep");
      /*exit(1); */
    }
    sigsetmask(0);

    /* Respond to whatever might be happening */

    /* New connection? */
    if (FD_ISSET(s, &input_set))
      if (new_descriptor(s) < 0)
	perror("New connection");

    /* kick out the freaky folks */
    for (point = descriptor_list; point; point = next_point) {
      next_point = point->next;
      if (FD_ISSET(point->descriptor, &exc_set)) {
	FD_CLR(point->descriptor, &input_set);
	FD_CLR(point->descriptor, &output_set);
	close_socket(point);
      }
    }

    for (point = descriptor_list; point; point = next_point) {
      next_point = point->next;
      if (FD_ISSET(point->descriptor, &input_set))
	if (process_input(point) < 0)
	  close_socket(point);
    }

    /* process_commands; */
    for (point = descriptor_list; point; point = next_to_process) {
      next_to_process = point->next;
      if ((--(point->wait) <= 0) && get_from_q(&point->input, comm)) {
	if (point->character && point->connected == CON_PLAYING &&
	    point->character->specials.was_in_room != NOWHERE) {
	  if (point->character->in_room != NOWHERE)
	    char_from_room(point->character);
	  char_to_room(point->character, point->character->specials.was_in_room);
	  point->character->specials.was_in_room = NOWHERE;
	  act("$n has returned.", TRUE, point->character, 0, 0, TO_ROOM);
	}
	point->wait = 1;
	if (point->character)
	  point->character->specials.timer = 0;
	point->prompt_mode = 1;

	if (point->str)
	  string_add(point, comm);
	else if (!point->connected)
	  if (point->showstr_point)
	    show_string(point, comm);
	  else
	    command_interpreter(point->character, comm);
	else
	  nanny(point, comm);
      }
    }

    for (point = descriptor_list; point; point = next_point) {
      next_point = point->next;
      if (FD_ISSET(point->descriptor, &output_set) && point->output.head)
	if (process_output(point) < 0)
	  close_socket(point);
	else
	  point->prompt_mode = 1;
    }

    /* give the people some prompts  */
    for (point = descriptor_list; point; point = point->next) {
      if (point->prompt_mode) {
	if (point->str)
	  write_to_descriptor(point->descriptor, "] ");
	else if (!point->connected)
	  if (point->showstr_point)
	    write_to_descriptor(point->descriptor, "*** Press return or q ***");
	  else {
            bzero(promptbuf, 256);
	    if (IS_IMMORTAL(point->character) && IS_PC(point->character)) {
	      if (MOUNTED(point->character)) {
		mount = MOUNTED(point->character);
		sprintf(promptbuf, "[%s has %d/%dh %d/%dv]\n\r",
			GET_SDESC(mount),
			GET_HIT(mount), GET_MAX_HIT(mount),
			GET_MOVE(mount), GET_MAX_MOVE(mount));
	      }
              if (IS_SET(point->character->specials.act, PLR_STEALTH))
                sprintf(promptbuf + strlen(promptbuf), "S");
              if (point->character->invis_level > 0)
                sprintf(promptbuf + strlen(promptbuf), "I=%d: ",
                        point->character->invis_level);
	      rm = real_roomp(point->character->in_room);
	      sprintf(promptbuf + strlen(promptbuf),
                      "#%d - %s [#%d]> ", rm->zone, zone_table[rm->zone].name,
                      rm->number);
	      write_to_descriptor(point->descriptor, promptbuf);
/* OLD mobs didn't have classes.. this doesn't work anymore */
	    } else if( IS_NPC(point->character) &&
              (IS_SET(point->character->specials.act, ACT_POLYSELF) ||
               IS_SET(point->character->specials.act, ACT_POLYOTHER))) {
	      sprintf(promptbuf, "P %d/%dh %d/%dv > ",
		      GET_HIT(point->character),
		      GET_MAX_HIT(point->character),
		      GET_MOVE(point->character),
		      GET_MAX_MOVE(point->character));
	      write_to_descriptor(point->descriptor, promptbuf);
            } else if( IS_NPC(point->character) &&
                       IS_SET(point->character->specials.act, ACT_SWITCH)) {
	      sprintf(promptbuf, "*%s[#%d] in [#%d] %d/%dh %d/%dm %d/%dv > ",
		      NAME(point->character),
                      MobVnum(point->character),
		      point->character->in_room,
		      GET_HIT(point->character),
		      GET_MAX_HIT(point->character),
		      GET_MANA(point->character),
		      GET_MAX_MANA(point->character),
		      GET_MOVE(point->character),
		      GET_MAX_MOVE(point->character));
	      write_to_descriptor(point->descriptor, promptbuf);
	    } else {
	      if (MOUNTED(point->character)) {
		if (HasClass(point->character, CLASS_RANGER) ||
		    IS_AFFECTED(MOUNTED(point->character), AFF_CHARM)) {
		  mount = MOUNTED(point->character);
		  sprintf(promptbuf, "[%s has %d/%dh %d/%dv]\n\r",
			  GET_SDESC(mount),
			  GET_HIT(mount), GET_MAX_HIT(mount),
			  GET_MOVE(mount), GET_MAX_MOVE(mount));
	        }
              }
	      sprintf(promptbuf + strlen(promptbuf), "%d/%dh %d/%dm %d/%dv > ",
		      GET_HIT(point->character),
		      GET_MAX_HIT(point->character),
		      GET_MANA(point->character),
		      GET_MAX_MANA(point->character),
		      GET_MOVE(point->character),
		      GET_MAX_MOVE(point->character));
	      write_to_descriptor(point->descriptor, promptbuf);
	    }
	  }
	point->prompt_mode = 0;
      }
    }
/*
 * PULSE handling.... periodic events
 */

    if ((++pulse) > PULSE_MAX)
      pulse= 0;

    if ((--pulse_zone) <= 0) {
      pulse_zone= PULSE_ZONE;
      zone_update();
    }
    if ((--pulse_teleport) <= 0) {
      pulse_teleport= PULSE_TELEPORT;
      Teleport(pulse);
    }
    if ((--pulse_nature) <= 0) {
      pulse_nature= PULSE_NATURE;
      check_all_nature(pulse);
    }
    if ((--pulse_violence) <= 0) {
      pulse_violence= PULSE_VIOLENCE;
      perform_violence(pulse);
    }
    if ((--pulse_mobile) <= 0) {
      pulse_mobile= PULSE_MOBILE;
      mobile_activity();
    }
    if ((--pulse_river) <= 0) {
      pulse_river= PULSE_RIVER;
      down_river(pulse);
    }
    if ((--pulse_sound) <= 0) {
      pulse_sound= PULSE_SOUND;
      MakeSound(pulse);
    }
    if ((--pulse_update) <= 0) {
      pulse_update= PULSE_UPDATE + number(0, PULSE_VARIABLE);
      weather_and_time(1);
      affect_update();
      point_update(pulse);
    }
    if ((--pulse_reboot) <= 0) {
      pulse_reboot= PULSE_REBOOT;
      check_reboot();
    }
    if ((--pulse_dump) <= 0) {
      pulse_dump= PULSE_DUMP;
      dump_player_list();
    }
    tics++;	       /* tics since last checkpoint signal */
  }
}

/*
 * general utility stuff (for local use)
 */
int get_from_q(struct txt_q *queue, char *dest) {
  struct txt_block *tmp;

  if (!queue) {
    log("Input from non-existant queue?");
    return 0;
  }
  if (!queue->head)
    return 0;
  tmp = queue->head;
  strcpy(dest, queue->head->text);
  queue->head = queue->head->next;
  free(tmp->text);
  free(tmp);
  return 1;
}

void write_to_q(char *txt, struct txt_q *queue) {
  struct txt_block *new;

  if (!queue) {
    log("Output message to non-existant queue");
    return;
  }
  CREATE(new, struct txt_block, 1);
  CREATE(new->text, char, strlen(txt) + 1);
  strcpy(new->text, txt);

  if (!queue->head) {
    new->next = NULL;
    queue->head = queue->tail = new;
  } else {
    queue->tail->next = new;
    queue->tail = new;
    new->next = NULL;
  }
}

struct timeval timediff(struct timeval *a, struct timeval *b) {
  struct timeval result, tmp;

  tmp = *a;

  if ((result.tv_usec = tmp.tv_usec - b->tv_usec) < 0) {
    result.tv_usec += 1000000;
    --(tmp.tv_sec);
  }
  if ((result.tv_sec = tmp.tv_sec - b->tv_sec) < 0) {
    result.tv_usec = 0;
    result.tv_sec = 0;
  }
  return result;
}

/* Empty the queues before closing connection */
void flush_queues(struct descriptor_data *d) {
  char dummy[MAX_STRING_LENGTH];

  while (get_from_q(&d->output, dummy));
  while (get_from_q(&d->input, dummy));
}

/*
 * socket handling
 */

int init_socket(int port) {
  int s;
  char *opt;
  char hostname[MAX_HOSTNAME + 1];
  struct sockaddr_in sa;
  struct hostent *hp;
  int i, gotsocket;

  bzero(&sa, sizeof(struct sockaddr_in));

  gethostname(hostname, MAX_HOSTNAME);
  hp = gethostbyname(hostname);
  if (hp == NULL) {
    perror("gethostbyname");
    exit(1);
  }
  sa.sin_family = hp->h_addrtype;
  sa.sin_port = htons(port);
  s = socket(AF_INET, SOCK_STREAM, 0);
  if (s < 0) {
    perror("Init-socket");
    exit(1);
  }
  if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
    perror("setsockopt REUSEADDR");
    exit(1);
  }

  for(i= 60; i> 0; i--) {
    if (bind(s, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
      gotsocket= 0;
      fprintf(stderr, "Socket in use... retrying...\n");
      sleep(1);
    } else {
      gotsocket= 1;
      break;
    }
  }
  if(!gotsocket) {
    perror("bind");
    close(s);
    exit(1);
  }
  listen(s, 3);
  return (s);
}

int new_connection(int s) {
  struct sockaddr_in isa;
  int i, t;

  i = sizeof(isa);
  getsockname(s, (struct sockaddr *)&isa, &i);
  if ((t = accept(s, (struct sockaddr *)&isa, &i)) < 0) {
    perror("Accept");
    return (-1);
  }
  nonblock(t);
  return t;
}

int new_descriptor(int s) {
  struct sockaddr_in isa;
  struct hostent *host;
  int i;
  int remote_port;
  long remote_addr;
  char buf[8192];
  int badger = 0;

  int desc, old_maxdesc;
  struct descriptor_data *newd;
  int index;

  long tc;
  struct tm *t_info;

  char *timed_con[] =
  {
    "\n"
  };

  char *bannished[] =
  {
    "grog.lab.cc.wmich.edu",
    "grog2.lab.cc.wmich.edu",
    "grog3.lab.cc.wmich.edu",
    "s01.lab.cc.wmich.edu",
    "s02.lab.cc.wmich.edu",
    "s03.lab.cc.wmich.edu",
    "s04.lab.cc.wmich.edu",
    "s05.lab.cc.wmich.edu",
    "s06.lab.cc.wmich.edu",
    "s07.lab.cc.wmich.edu",
    "s08.lab.cc.wmich.edu",
    "s09.lab.cc.wmich.edu",
    "s10.lab.cc.wmich.edu",
    "s11.lab.cc.wmich.edu",
    "s12.lab.cc.wmich.edu",
    "s14.lab.cc.wmich.edu",
    "s15.lab.cc.wmich.edu",
    "s16.lab.cc.wmich.edu",
    "s17.lab.cc.wmich.edu",
    "s18.lab.cc.wmich.edu",
    "s19.lab.cc.wmich.edu",
    "s20.lab.cc.wmich.edu",
    "s21.lab.cc.wmich.edu",
    "s22.lab.cc.wmich.edu",
    "s23.lab.cc.wmich.edu",
    "s24.lab.cc.wmich.edu",
    "s25.lab.cc.wmich.edu",
    "s26.lab.cc.wmich.edu",
    "s27.lab.cc.wmich.edu",
    "s28.lab.cc.wmich.edu",
    "s29.lab.cc.wmich.edu",
    "s30.lab.cc.wmich.edu",
    "s31.lab.cc.wmich.edu",
    "s32.lab.cc.wmich.edu",
    "s33.lab.cc.wmich.edu",
    "s34.lab.cc.wmich.edu",
    "s35.lab.cc.wmich.edu",
    "s36.lab.cc.wmich.edu",
    "s37.lab.cc.wmich.edu",
    "s38.lab.cc.wmich.edu",
    "s39.lab.cc.wmich.edu",
    "s40.lab.cc.wmich.edu",
    "s41.lab.cc.wmich.edu",
    "s42.lab.cc.wmich.edu",
    "s43.lab.cc.wmich.edu",
    "\n"
  };

  tc = time(0);
  t_info = localtime(&tc);

  old_maxdesc = maxdesc;

  i = sizeof(isa);
  getsockname(s, (struct sockaddr *)&isa, &i);
  if ((desc = accept(s, (struct sockaddr *)&isa, &i)) < 0) {
    perror("Accept");
    return (-1);
  }
  nonblock(desc);

  if ((maxdesc + 1) >= avail_descs) {
    write_to_descriptor(desc, "Sorry.. full...\n\r");
    close(desc);
    return (0);
  } else if (desc > maxdesc)
    maxdesc = desc;

  CREATE(newd, struct descriptor_data, 1);

  remote_port= ntohs(isa.sin_port);
  remote_addr= isa.sin_addr.s_addr;

  newd->username[0]= '\0';
#ifdef RFC1413
  {
    char *ack;
    unsigned long inlocal, inremote;
    unsigned short local, remote;

    if((ack= ident_id(desc, 10))) {
      strncpy(newd->username, ack, 16);
    } else if(auth_fd2(desc, &inlocal, &inremote, &local, &remote) >= 0) {
      if((ack= auth_tcpuser3(inlocal, inremote, local, remote, 10))) {
        strncpy(newd->username, ack, 16);
        badger= 1;
      } else
        badger= 2;
    } else
      badger= 2;
  }
#endif
  if(!newd->username[0])
    strcpy(newd->username, "adork");

  if(!(host= gethostbyaddr((char *)&remote_addr, sizeof(remote_addr), AF_INET)))

    sprintf(newd->host, "%u.%u.%u.%u",
            (int)(((char *)&remote_addr)[0])&255, (int)(((char *)&remote_addr)[1])&255,
            (int)(((char *)&remote_addr)[2])&255, (int)(((char *)&remote_addr)[3])&255);
  else
    strncpy(newd->host, host->h_name, 49);

  /* init desc data */
  newd->descriptor = desc;
  newd->connected = 1;
  newd->wait = 1;
  newd->prompt_mode = 0;
  *newd->buf = '\0';
  newd->str = 0;
  newd->showstr_head = 0;
  newd->showstr_point = 0;
  *newd->last_input = '\0';
  newd->output.head = NULL;
  newd->input.head = NULL;
  newd->next = descriptor_list;
  newd->character = 0;
  newd->original = 0;
  newd->snoop.snooping = 0;
  newd->snoop.snoop_by = 0;

#ifdef RFC1413
  switch(badger) {
    case 1:
      write_to_descriptor(desc, "\n\r **** Tell your sys-admin to upgrade to the SHINY NEW telnet using RFC1413 ****\n\r\n\r");
      break;
    case 2:
      write_to_descriptor(desc, "\n\r **** Tell your sys-admin to practice safe telnet by using RFC1413 ****\n\r\n\r");
      break;
    default:
      break;
  }
#endif

  /* prepend to list */

  if (((t_info->tm_hour + 1) > 8) && ((t_info->tm_hour + 1) < 21))
    for (index = 0; timed_con[index] != "\n"; index++) {
      if (!strncmp(timed_con[index], newd->host, 49)) {
	sprintf(buf, "TIMED site connecting:%s\n", newd->host);
	log(buf);
	sprintf(buf, "\n\rThis site is blocked from : 9 am - 9 pm\n\r");
	write_to_descriptor(desc, buf);
	sprintf(buf, "You may connect after 9 pm from :[%s]\n\r",
		newd->host);
	write_to_descriptor(desc, buf);
	maxdesc = old_maxdesc;
	free(newd);
	close(desc);
	return (0);
      }
    }
  for (index = 0; bannished[index] != "\n"; index++) {
    if (!strncmp(bannished[index], newd->host, 49)) {
      sprintf(buf, "BANNISHED site connecting:%s\n", newd->host);
      log(buf);
      sprintf(buf, "\n\rDue to your System Administrators request, or for some\n\r");
      write_to_descriptor(desc, buf);
      sprintf(buf, "other reason, we are refusing all connections from:[%s]\n\r",
	      newd->host);
      write_to_descriptor(desc, buf);
      maxdesc = old_maxdesc;
      free(newd);
      close(desc);
      return (0);
    }
  }

  descriptor_list = newd;
  SEND_TO_Q(greetings, newd);
  SEND_TO_Q("By what name do you wish to be known? ", newd);
  return (0);
}

int process_output(struct descriptor_data *t) {
  char i[MAX_STRING_LENGTH + 1];

  if (DEBUG)
    dlog("process_output");
  if (!t->prompt_mode && !t->connected)
    if (write_to_descriptor(t->descriptor, "\n\r") < 0)
      return (-1);

  /* Cycle thru output queue */
  while (get_from_q(&t->output, i)) {
    if ((t->snoop.snoop_by) && (t->snoop.snoop_by->desc)) {
      write_to_q("S* ", &t->snoop.snoop_by->desc->output);
      write_to_q(i, &t->snoop.snoop_by->desc->output);
    }
    if (write_to_descriptor(t->descriptor, i))
      return (-1);
  }

  if (!t->connected && !(t->character && !IS_NPC(t->character) &&
		   IS_SET(t->character->specials.act, PLR_COMPACT)))
    if (write_to_descriptor(t->descriptor, "\n\r") < 0)
      return (-1);

  return (1);
}

int write_to_descriptor(int desc, char *txt) {
  int sofar, thisround, total;

  total = strlen(txt);
  sofar = 0;

  do {
    thisround = write(desc, txt + sofar, total - sofar);
    if (thisround < 0) {
      if (errno == EWOULDBLOCK)
	break;
      perror("Write to socket");
      return (-1);
    }
    sofar += thisround;
  }
  while (sofar < total);

  return (0);
}

int process_input(struct descriptor_data *t) {
  int sofar, thisround, begin, squelch, i, k, flag;
  char tmp[MAX_INPUT_LENGTH + 2], buffer[MAX_INPUT_LENGTH + 60];
  long now_time;

  sofar = 0;
  flag = 0;
  begin = strlen(t->buf);

  /* Read in some stuff */
  do {
    if ((thisround = read(t->descriptor, t->buf + begin + sofar,
		    MAX_STRING_LENGTH - (begin + sofar) - 1)) > 0) {
      sofar += thisround;
    } else {
      if (thisround < 0) {
	if (errno != EWOULDBLOCK) {
	  perror("Read1 - ERROR");
	  return (-1);
	} else {
	  break;
	}
      } else {
	log("EOF encountered on socket read.");
	return (-1);
      }
    }
  } while (!ISNEWL(*(t->buf + begin + sofar - 1)));

  *(t->buf + begin + sofar) = 0;

  /* if no newline is contained in input, return without proc'ing */
  for (i = begin; !ISNEWL(*(t->buf + i)); i++)
    if (!*(t->buf + i))
      return (0);

  /* input contains 1 or more newlines; process the stuff */
  for (i = 0, k = 0; *(t->buf + i);) {
    if (!ISNEWL(*(t->buf + i)) && !(flag = (k >= (MAX_INPUT_LENGTH - 2))))
      if (*(t->buf + i) == '\b') {     /* backspace */
	if (k) {		       /* more than one char ? */
	  if (*(tmp + --k) == '$')
	    k--;
	  i++;
	} else {
	  i++;			       /* no or just one char.. Skip backsp */
	}
      } else {
	if (isascii(*(t->buf + i)) && isprint(*(t->buf + i))) {
	  /* 
	   * trans char, double for '$' (printf)        
	   */
	  if ((*(tmp + k) = *(t->buf + i)) == '$')
	    *(tmp + ++k) = '$';
	  k++;
	  i++;
	} else {
	  i++;
	}
    } else {
      *(tmp + k) = 0;
      if (*tmp == '!')
	strcpy(tmp, t->last_input);
      else
	strcpy(t->last_input, tmp);

      write_to_q(tmp, &t->input);

      now_time = time(0);
      t->idle_time = now_time;
      if ((t->snoop.snoop_by) && (t->snoop.snoop_by->desc)) {
	write_to_q("% ", &t->snoop.snoop_by->desc->output);
	write_to_q(tmp, &t->snoop.snoop_by->desc->output);
	write_to_q("\n\r", &t->snoop.snoop_by->desc->output);
      }
      if (flag) {
	sprintf(buffer,
		"Line too long. Truncated to:\n\r%s\n\r", tmp);
	if (write_to_descriptor(t->descriptor, buffer) < 0)
	  return (-1);

	/* skip the rest of the line */
	for (; !ISNEWL(*(t->buf + i)); i++);
      }
      /* find end of entry */
      for (; ISNEWL(*(t->buf + i)); i++);

      /* squelch the entry from the buffer */
      for (squelch = 0;; squelch++)
	if ((*(t->buf + squelch) =
	     *(t->buf + i + squelch)) == '\0')
	  break;
      k = 0;
      i = 0;
    }
  }
  return (1);
}

void close_sockets(int s) {
  log("Closing all sockets.");
  while (descriptor_list)
    close_socket(descriptor_list);
  close(s);
}

void close_socket(struct descriptor_data *d) {
  struct descriptor_data *tmp;
  char buf[100];

  void do_save(struct char_data *ch, char *argument, int cmd);

  if (!d)
    return;

  close(d->descriptor);
  flush_queues(d);
  if (d->descriptor == maxdesc)
    --maxdesc;

  /* Forget snooping */

  if (d->snoop.snooping)
    d->snoop.snooping->desc->snoop.snoop_by = 0;

  if (d->snoop.snoop_by) {
    cprintf(d->snoop.snoop_by, "Your victim is no longer among us.\n\r");
    d->snoop.snoop_by->desc->snoop.snooping = 0;
  }
  if (d->character)
    if (d->connected == CON_PLAYING) {
      do_save(d->character, "", 0);
      act("$n has lost $s link.", TRUE, d->character, 0, 0, TO_ROOM);
      sprintf(buf, "Closing link to: %s.", GET_NAME(d->character));
      log(buf);
      if (IS_NPC(d->character)) {
	if (d->character->desc)
	  d->character->orig = d->character->desc->original;
      }
      d->character->desc = 0;
    } else {
      if (GET_NAME(d->character)) {
	sprintf(buf, "Losing player: %s.", GET_NAME(d->character));
	log(buf);
      }
      free_char(d->character);
  } else
    log("Losing descriptor without char.");

  if (next_to_process == d)	       /* to avoid crashing the process loop */
    next_to_process = next_to_process->next;

  if (d == descriptor_list)	       /* this is the head of the list */
    descriptor_list = descriptor_list->next;
  else {			       /* This is somewhere inside the list */
    /* Locate the previous element */
    for (tmp = descriptor_list; (tmp->next != d) && tmp;
	 tmp = tmp->next);

    tmp->next = d->next;
  }
  if (d->showstr_head)
    free(d->showstr_head);
  free(d);
}

void nonblock(int s) {
  if (fcntl(s, F_SETFL, O_NDELAY) == -1) {
    perror("Noblock");
    exit(1);
  }
}

/*
 * Public routines for system-to-player-communication
 */

/*
 * This acts as an interface to write_to_q(), but it uses variable arguments
 * to eliminate multiple calls to sprintf().
 */
void dprintf(struct descriptor_data *d, char *Str,...) {
  va_list arg;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str && d) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    write_to_q(Result, &d->output);
  }
}

/*
 * This works like send_to_char(), but it uses variable arguments to
 * eliminate multiple calls to sprintf().
 */
void cprintf(struct char_data *ch, char *Str,...) {
  va_list arg;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str && ch && ch->desc) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    write_to_q(Result, &ch->desc->output);
  }
}

/*
 * This one is an interface to replace send_to_room().
 */
void rprintf(int room, char *Str,...) {
  va_list arg;
  struct char_data *i;
  struct room_data *rr;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str && room >= 0 && (rr = real_roomp(room))) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = rr->people; i; i = i->next_in_room)
      if (i->desc)
	write_to_q(Result, &i->desc->output);
  }
}

/*
 * This one is everyone in the zone specified.
 */
void zprintf(int zone, char *Str,...) {
  va_list arg;
  struct descriptor_data *i;
  char Result[MAX_STRING_LENGTH];
  struct room_data *rr;

  if (Str && *Str && zone >= 0) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = descriptor_list; i; i = i->next)
      if (!i->connected)
        if(i->character)
          if((rr= real_roomp(i->character->in_room)))
            if(rr->zone == zone)
	      write_to_q(Result, &i->output);
  }
}

/*
 * And this one sends to EVERYBODY int the game!!!!!
 */
void aprintf(char *Str,...) {
  va_list arg;
  struct descriptor_data *i;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = descriptor_list; i; i = i->next)
      if (!i->connected)
	write_to_q(Result, &i->output);
  }
}

/*
 * Here is send_to_outdoor()
 */
void oprintf(char *Str,...) {
  va_list arg;
  struct descriptor_data *i;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = descriptor_list; i; i = i->next)
      if (!i->connected && i->character && OUTSIDE(i->character))
	write_to_q(Result, &i->output);
  }
}

/*
 * Send to everyone except the given character.
 */
void eprintf(struct char_data *ch, char *Str,...) {
  va_list arg;
  struct descriptor_data *i;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = descriptor_list; i; i = i->next)
      if (ch && ch->desc != i && !i->connected)
	write_to_q(Result, &i->output);
  }
}

/*
 * This one is for send_to_room_except()
 */
void reprintf(int room, struct char_data *ch, char *Str,...) {
  va_list arg;
  struct char_data *i;
  struct room_data *rr;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str && room >= 0 && (rr = real_roomp(room))) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = rr->people; i; i = i->next_in_room)
      if (i != ch && i->desc)
	write_to_q(Result, &i->desc->output);
  }
}

/*
 * This one is for send_to_room_except()
 */
void re2printf(int room, struct char_data *ch1, struct char_data *ch2, char *Str,...) {
  va_list arg;
  struct char_data *i;
  struct room_data *rr;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str && room >= 0 && (rr = real_roomp(room))) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = rr->people; i; i = i->next_in_room)
      if (i != ch1 && i != ch2 && i->desc)
	write_to_q(Result, &i->desc->output);
  }
}

/*
 * IMMORTAL printf.
 */
void iprintf(char *Str,...) {
  va_list arg;
  struct descriptor_data *i;
  char Result[MAX_STRING_LENGTH];

  if (Str && *Str) {
    bzero(Result, MAX_STRING_LENGTH);
    va_start(arg, Str);
    vsprintf(Result, Str, arg);
    va_end(arg);
    for (i = descriptor_list; i; i = i->next)
      if (!i->connected && i->character && IS_IMMORTAL(i->character))
	write_to_q(Result, &i->output);
  }
}

void save_all() {
  struct descriptor_data *i;

  for (i = descriptor_list; i; i = i->next)
    if (i->character)
      save_char(i->character, NOWHERE);
}

/* higher-level communication */

void act(char *str, int hide_invisible, struct char_data *ch,
	 struct obj_data *obj, void *vict_obj, int type) {
  register char *strp, *point, *i = NULL;
  struct char_data *to;
  char buf[MAX_STRING_LENGTH];

  if (!str)
    return;
  if (!*str)
    return;

  if (type == TO_VICT)
    to = (struct char_data *)vict_obj;
  else if (type == TO_CHAR)
    to = ch;
  else {
    if(!ch)
      return;
    if(!real_roomp(ch->in_room))
      return;
    if(!(to = real_roomp(ch->in_room)->people))
      return;
  }

  for (; to; to = to->next_in_room) {
    if (to->desc && ((to != ch) || (type == TO_CHAR)) &&
	(CAN_SEE(to, ch) || !hide_invisible) && AWAKE(to) &&
	!((type == TO_NOTVICT) && (to == (struct char_data *)vict_obj))) {
      for (strp = str, point = buf;;)
	if (*strp == '$') {
	  switch (*(++strp)) {
	  case 'n':
	    i = PERS(ch, to);
	    break;
	  case 'N':
	    i = PERS((struct char_data *)vict_obj, to);
	    break;
	  case 'm':
	    i = HMHR(ch);
	    break;
	  case 'M':
	    i = HMHR((struct char_data *)vict_obj);
	    break;
	  case 's':
	    i = HSHR(ch);
	    break;
	  case 'S':
	    i = HSHR((struct char_data *)vict_obj);
	    break;
	  case 'e':
	    i = HSSH(ch);
	    break;
	  case 'E':
	    i = HSSH((struct char_data *)vict_obj);
	    break;
	  case 'o':
	    i = OBJN(obj, to);
	    break;
	  case 'O':
	    i = OBJN((struct obj_data *)vict_obj, to);
	    break;
	  case 'p':
	    i = OBJS(obj, to);
	    break;
	  case 'P':
	    i = OBJS((struct obj_data *)vict_obj, to);
	    break;
	  case 'a':
	    i = SANA(obj);
	    break;
	  case 'A':
	    i = SANA((struct obj_data *)vict_obj);
	    break;
	  case 'T':
	    i = (char *)vict_obj;
	    break;
	  case 'F':
	    i = fname((char *)vict_obj);
	    break;
	  case '$':
	    i = "$";
	    break;
	  default:
	    log("Illegal $-code to act():");
	    log(str);
	    break;
	  }

	  while ((*point = *(i++)))
	    ++point;

	  ++strp;

	} else if (!(*(point++) = *(strp++)))
	  break;

      *(--point) = '\n';
      *(++point) = '\r';
      *(++point) = '\0';

      write_to_q(CAP(buf), &to->desc->output);
    }
    if ((type == TO_VICT) || (type == TO_CHAR))
      return;
  }
}

void dump_player_list(void) {
  FILE *pfd;
  int i;

  log("Dumping player list");
  if(!(pfd= fopen(PLAYER_FILE, "w"))) {
    bug("Cannot save player data for new user!");
  } else {
    fprintf(pfd, "%d\n", actual_players);
    for(i= 0; i< number_of_players; i++)
      if(list_of_players[i])
        fprintf(pfd, "%s", list_of_players[i]);
    fclose(pfd);
  }
}