[comp.sources.games] v11i009: tinymud2 - user-extendible multi-user adventure

billr@saab.CNA.TEK.COM (Bill Randle) (07/30/90)

Submitted-by: James Aspnes <asp@cs.cmu.edu>
Posting-number: Volume 11, Issue 9
Archive-name: tinymud2/Part05
Supersedes: tinymud: Volume 8, Issue 80-83



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 10)."
# Contents:  interface.c joinspl.sh wiz.c
# Wrapped by billr@saab on Fri Jul 27 15:27:46 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'interface.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'interface.c'\"
else
echo shar: Extracting \"'interface.c'\" \(33958 characters\)
sed "s/^X//" >'interface.c' <<'END_OF_FILE'
X/* Concentrator upgraded June 1990 Robert Hood */
X
X/* modifed Concentrator to match Fuzzy & Randoms 1.5.4 changes = 6/90 Fuzzy */
X
X/* modified interface.c to support LOTS of people, using a concentrator */
X/* May 1990, Robert Hood */
X
X/* #define CHECKC	/* consistency checking */
X
X#include <stdio.h>
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <signal.h>
X#include <sys/ioctl.h>
X#include <sys/wait.h>
X#include <fcntl.h>
X#include <sys/errno.h>
X#include <ctype.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X#include "config.h"
X#include "db.h"
X#include "interface.h"
X
X#define BUFSIZE 0xFFFF
X
Xstruct text_block
X{
X  int             nchars;
X  struct text_block *nxt;
X  char           *start;
X  char           *buf;
X};
X
Xstruct text_queue
X{
X  struct text_block *head;
X  struct text_block **tail;
X};
X
Xstruct descriptor_data
X{
X  int             descriptor;
X  int             num;
X  int             connected;
X  dbref           player;
X  char           *output_prefix;
X  char           *output_suffix;
X  int             output_size;
X  struct text_queue output;
X  struct text_queue input;
X  char           *raw_input;
X  char           *raw_input_at;
X  long            connected_at;
X  long            last_time;
X  int             quota;
X  struct sockaddr_in address;	       /* added 3/6/90 SCG */
X  char           *hostname;	       /* 5/18/90 - Fuzzy */
X  struct descriptor_data *next;
X};
X
X#define MALLOC(result, type, number) do {			\
X	if (!((result) = (type *) malloc ((number) * sizeof (type))))	\
X		panic("Out of memory");				\
X	} while (0)
X
X#define FREE(x) (free((void *) x))
X
Xstruct message
X{
X  char           *data;
X  short           len;
X  struct message *next;
X};
X
Xstruct conc_list
X{
X  struct conc_list *next;
X  int             sock, current, status;
X  struct descriptor_data *firstd;
X  struct message *first, *last;
X  char           *incoming, *outgoing;
X  int             ilen, olen;
X}              *firstc = 0;
X
Xvoid            queue_message(struct conc_list * c, char *data, int len);
Xvoid            start_log();
Xstruct timeval  timeval_sub(struct timeval now, struct timeval then);
Xstruct timeval  msec_add(struct timeval t, int x);
Xstruct timeval  update_quotas(struct timeval last, struct timeval current);
Xvoid            main_loop();
Xint             notify(dbref player, const char *msg);
Xvoid            process_output(struct conc_list * c);
Xint             process_input(struct descriptor_data * d, char *buf, int got);
Xvoid            process_commands();
Xvoid            dump_users(struct descriptor_data * e, char *user);
Xvoid            free_text_block(struct text_block * t);
Xvoid            main(int argc, char **argv);
Xvoid            set_signals();
Xint             msec_diff(struct timeval now, struct timeval then);
Xvoid            clearstrings(struct descriptor_data * d);
Xvoid            shutdownsock(struct descriptor_data * d);
Xstruct descriptor_data *initializesock(struct sockaddr_in * a);
Xstruct text_block *make_text_block(const char *s, int n);
Xvoid            add_to_queue(struct text_queue * q, const char *b, int n);
Xint             flush_queue(struct text_queue * q, int n);
Xint             queue_write(struct descriptor_data * d, const char *b, int n);
Xint             queue_string(struct descriptor_data * d, const char *s);
Xvoid            freeqs(struct descriptor_data * d);
Xvoid            welcome_user(struct descriptor_data * d);
Xvoid            do_motd(dbref);
Xchar           *strsave(const char *s);
Xvoid            save_command(struct descriptor_data * d, const char *command);
Xvoid            set_userstring(char **userstring, const char *command);
Xint             do_command(struct descriptor_data * d, char *command);
Xvoid            check_connect(struct descriptor_data * d, const char *msg);
Xvoid            parse_connect(const char *msg, char *command, char *user, char *pass);
Xvoid            close_sockets();
Xvoid            emergency_shutdown(void);
Xvoid            boot_off(dbref player);
Xint             bailout(int sig, int code, struct sigcontext * scp);
Xchar           *time_format_1(long dt);
Xchar           *time_format_2(long dt);
X#ifdef CONNECT_MESSAGES
Xvoid            announce_connect(dbref);
Xvoid            announce_disconnect(dbref);
X#endif				       /* CONNECT_MESSAGES */
Xint             sigshutdown(int, int, struct sigcontext *);
X
Xint             logsynch();
Xchar           *logfile = LOG_FILE;
X
Xint             debug;
Xvoid            chg_userid();
Xvoid            file_date(struct descriptor_data * d, const char *file);
X
Xstatic const char *connect_fail = "Either that player does not exist, or has a different password.\n";
X#ifndef REGISTRATION
Xstatic const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
X#endif				       /* REGISTRATION */
Xstatic const char *flushed_message = "<Output Flushed>\n";
Xstatic const char *shutdown_message = "Going down - Bye\n";
X
Xint             sock;
Xint             shutdown_flag = 0;
X
Xint             port = TINYPORT;
Xint             intport = INTERNAL_PORT;
X
X
Xstart_port()
X{
X  int             temp;
X  struct sockaddr_in sin;
X
X  sock = socket(AF_INET, SOCK_STREAM, 0);
X  if (sock < 1)
X  {
X    perror("socket");
X    exit(-1);
X  }
X  temp = 1;
X  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&temp, sizeof(temp));
X  sin.sin_family = AF_INET;
X  sin.sin_port = htons(intport);
X  sin.sin_addr.s_addr = htonl(INADDR_ANY);
X
X  temp = bind(sock, (struct sockaddr *) & sin, sizeof(sin));
X  if (temp < 0)
X  {
X    perror("bind");
X    exit(-1);
X  }
X  temp = listen(sock, 5);
X  if (temp < 0)
X  {
X    perror("listen");
X    exit(-1);
X  }
X}
X
Xstruct timeval
X                timeval_sub(struct timeval now, struct timeval then)
X{
X                  now.tv_sec -= then.tv_sec;
X  now.tv_usec -= then.tv_usec;
X  if (now.tv_usec < 0)
X  {
X    now.tv_usec += 1000000;
X    now.tv_sec--;
X  }
X  return now;
X}
X
Xstruct timeval
X                msec_add(struct timeval t, int x)
X{
X                  t.tv_sec += x / 1000;
X  t.tv_usec += (x % 1000) * 1000;
X  if (t.tv_usec >= 1000000)
X  {
X    t.tv_sec += t.tv_usec / 1000000;
X    t.tv_usec = t.tv_usec % 1000000;
X  }
X  return t;
X}
X
Xstruct timeval
X                update_quotas(struct timeval last, struct timeval current)
X{
X  int             nslices;
X  struct descriptor_data *d;
X  struct conc_list *c;
X
X  nslices = msec_diff(current, last) / COMMAND_TIME_MSEC;
X
X  if (nslices > 0)
X  {
X    for (c = firstc; c; c = c->next)
X      for (d = c->firstd; d; d = d->next)
X      {
X	d->quota += COMMANDS_PER_TIME * nslices;
X	if (d->quota > COMMAND_BURST_SIZE)
X	  d->quota = COMMAND_BURST_SIZE;
X      }
X  }
X  return msec_add(last, nslices * COMMAND_TIME_MSEC);
X}
X
Xint
X                notify(dbref player2, const char *msg)
X{
X  struct descriptor_data *d;
X  struct conc_list *c;
X  int             retval = 0;
X
X#ifdef COMPRESS
X  extern const char *uncompress(const char *);
X
X  msg = uncompress(msg);
X#endif				       /* COMPRESS */
X  for (c = firstc; c; c = c->next)
X    for (d = c->firstd; d; d = d->next)
X    {
X      if (d->connected && d->player == player2)
X      {
X	queue_string(d, msg);
X	queue_write(d, "\n", 1);
X	retval++;
X      }
X    }
X  return (retval);
X}
X
Xint
X                process_input(d, buf, got)
X  struct descriptor_data *d;
X  char           *buf;
X  int             got;
X{
X  char           *p, *pend, *q, *qend;
X
X  d->last_time = time(0);
X  if (!d->raw_input)
X  {
X    MALLOC(d->raw_input, char, MAX_COMMAND_LEN);
X    d->raw_input_at = d->raw_input;
X  }
X  p = d->raw_input_at;
X  pend = d->raw_input + MAX_COMMAND_LEN - 1;
X  for (q = buf, qend = buf + got; q < qend; q++)
X  {
X    if (*q == '\n')
X    {
X      *p = '\0';
X      if (p > d->raw_input)
X	save_command(d, d->raw_input);
X      p = d->raw_input;
X    } else
X    if (p < pend && isascii(*q) && isprint(*q))
X    {
X      *p++ = *q;
X    }
X  }
X  if (p > d->raw_input)
X  {
X    d->raw_input_at = p;
X  } else
X  {
X    FREE(d->raw_input);
X    d->raw_input = 0;
X    d->raw_input_at = 0;
X  }
X  return 1;
X}
X
Xvoid            process_commands()
X{
X  int             nprocessed;
X  struct descriptor_data *d, *dnext, *dlast;
X  struct conc_list *c;
X  struct text_block *t;
X  char            header[4];
X
X  do
X  {
X    nprocessed = 0;
X    for (c = firstc; c; c = c->next)
X    {
X      dlast = 0;
X      for (d = c->firstd; d; d = dnext)
X      {
X	dnext = d->next;
X	if (d->quota > 0 && (t = d->input.head))
X	{
X	  d->quota--;
X	  nprocessed++;
X	  if (!do_command(d, t->start))
X	  {
X	    header[0] = 0;
X	    header[1] = 2;
X	    header[2] = d->num;
X	    queue_message(c, header, 3);
X	    if (dlast)
X	      dlast->next = dnext;
X	    else
X	      c->firstd = dnext;
X	    shutdownsock(d);
X	    FREE(d);
X	    break;
X	  } else
X	  {
X	    d->input.head = t->nxt;
X	    if (!d->input.head)
X	      d->input.tail = &d->input.head;
X	    free_text_block(t);
X	  }
X	}
X	dlast = d;
X      }
X    }
X  } while (nprocessed > 0);
X}
X
Xvoid dump_users(struct descriptor_data * e, char *user)
X{
X  static struct conc_list *rwclist[NOFILE];
X  static struct descriptor_data *rwdlist[NOFILE];
X  int             ccount, dcount, dloop, cloop;
X
X  struct descriptor_data *d;
X  struct conc_list *c;
X  long            now;
X  int             counter = 0;
X  static int	  maxcounter = 0;
X  int             wizard, reversed, tabular;
X  char            buf[1024];
X
X
X# ifdef DO_WHOCHECK
X  writelog("WHO CHECK %d\n", sizeof(rwclist));
X  writelog("WHO CHECK %d\n", sizeof(rwdlist));
X# endif
X
X  while (*user && isspace(*user))
X    user++;
X  if (!*user)
X    user = NULL;
X
X  reversed = e->connected && Flag(e->player, REVERSED_WHO);
X  tabular = e->connected && Flag(e->player, TABULAR_WHO);
X
X  time(&now);
X
X  queue_string(e, tabular ? "Player Name          On For Idle\n" :
X	       "Current Players:\n");
X#ifdef GOD_MODE
X  wizard = e->connected && God(e->player);
X#else  GOD_MODE
X  wizard = e->connected && Wizard(e->player);
X#endif GOD_MODE
X
X  if (reversed)
X  {
X    ccount = 0;
X    for (c = firstc; c; c = c->next)
X      rwclist[ccount++] = c;
X    for (cloop = ccount - 1; cloop >= 0; --cloop)
X    {
X      dcount = 0;
X      for (d = rwclist[cloop]->firstd; d; d = d->next)
X	rwdlist[dcount++] = d;
X      for (dloop = dcount - 1; dloop >= 0; --dloop)
X      {
X	d = rwdlist[dloop];
X	if (d->connected &&
X	    ++counter && /* Count everyone connected */
X	    (!user || string_prefix(db[d->player].name, user)))
X	{
X	  if (tabular)
X	  {
X	    sprintf(buf, "%-16s %10s %4s",
X		    db[d->player].name,
X		    time_format_1(now - d->connected_at),
X		    time_format_2(now - d->last_time));
X
X	    if (wizard)
X	      sprintf(buf, "%s  %s", buf, d->hostname);
X	  } else
X	  {
X	    sprintf(buf, "%s idle %d seconds",
X		    db[d->player].name, now - d->last_time);
X	    if (wizard)
X	      sprintf(buf, "%s from host %s", buf, d->hostname);
X	  }
X	  strcat(buf, "\n");
X	  queue_string(e, buf);
X	}
X      }
X    }
X  } else
X  {
X    for (c = firstc; c; c = c->next)
X    {
X      for (d = c->firstd; d; d = d->next)
X      {
X	if (d->connected &&
X	    ++counter && /* Count everyone connected */
X	    (!user || string_prefix(db[d->player].name, user)))
X	{
X	  if (tabular)
X	  {
X	    sprintf(buf, "%-16s %10s %4s",
X		    db[d->player].name,
X		    time_format_1(now - d->connected_at),
X		    time_format_2(now - d->last_time));
X
X	    if (wizard)
X	      sprintf(buf, "%s  %s", buf, d->hostname);
X	  } else
X	  {
X	    sprintf(buf, "%s idle %d seconds",
X		    db[d->player].name, now - d->last_time);
X	    if (wizard)
X	      sprintf(buf, "%s from host %s", buf, d->hostname);
X	  }
X	  strcat(buf, "\n");
X	  queue_string(e, buf);
X	}
X      }
X    }
X  }
X  
X  if (counter > maxcounter)
X  { maxcounter = counter;
X    if (counter > 30)
X    { writelog ("%d users logged in\n", counter); }
X  }
X  
X  sprintf(buf, "%d user%s connected\n", counter,
X	  counter == 1 ? " is" : "s are");
X  queue_string(e, buf);
X}
X
Xvoid free_text_block(struct text_block * t)
X{
X                  FREE(t->buf);
X  FREE((char *)t);
X}
X
X#ifndef BOOLEXP_DEBUGGING
Xvoid main(int argc, char **argv)
X{
X  int             pid;
X
X  if (argc < 3)
X  {
X    fprintf(stderr, "Usage: %s infile dumpfile [port iport logfile]\n", *argv);
X    exit(1);
X
X  }
X  if (argc > 3)
X    port = atoi(argv[3]);
X  if (argc > 4)
X    intport = atoi(argv[4]);
X  if (argc > 5)
X    logfile = argv[5];
X
X  start_log();
X
X  if (init_game(argv[1], argv[2]) < 0)
X  {
X    writelog("INIT: Couldn't load %s\n", argv[1]);
X    exit(2);
X  }
X  pid = vfork();
X  if (pid < 0)
X  {
X    perror("fork");
X    exit(-1);
X  }
X  if (pid == 0)
X  {
X    char            pstr[32], istr[32], clvl[32];
X
X    /* Add port argument to concentrator */
X    sprintf(pstr, "%d", port);
X    sprintf(istr, "%d", intport);
X    sprintf(clvl, "%d", 1);
X    execl("concentrate", "conc", pstr, istr, clvl, 0);
X  }
X  set_signals();
X  start_port(port);
X  main_loop();
X  close_sockets();
X  dump_database();
X  exit(0);
X}
X
X#endif
X
Xvoid start_log()
X{
X#ifdef DETACH
X  if              (!debug)
X  {
X    int             i;
X
X    if (fork() != 0)
X      exit(0);
X
X    i = open("/dev/tty", O_RDWR, 0);
X    if (i != -1)
X    {
X      ioctl(i, TIOCNOTTY, 0);
X      close(i);
X    }
X  }
X  freopen(logfile, "a", stderr);
X  setbuf(stderr, NULL);
X#endif				       /* DETACH */
X}
X
Xvoid set_signals(void)
X{
X  int             dump_status(void);
X  signal(SIGPIPE, SIG_IGN);
X
X  signal(SIGINT, (void *)sigshutdown);
X  signal(SIGTERM, (void *)sigshutdown);
X
X#ifdef DETACH
X  signal(SIGUSR2, (void *)logsynch);
X#else				       /* DETACH */
X  signal(SIGUSR2, (void *)bailout);
X#endif				       /* DETACH */
X
X  if (debug)
X    return;
X
X# ifdef NOCOREDUMP
X  signal(SIGQUIT, (void *)bailout);
X  signal(SIGILL, (void *)bailout);
X  signal(SIGTRAP, (void *)bailout);
X  signal(SIGIOT, (void *)bailout);
X  signal(SIGEMT, (void *)bailout);
X  signal(SIGFPE, (void *)bailout);
X  signal(SIGBUS, (void *)bailout);
X  signal(SIGSEGV, (void *)bailout);
X  signal(SIGSYS, (void *)bailout);
X  signal(SIGTERM, (void *)bailout);
X  signal(SIGXCPU, (void *)bailout);
X  signal(SIGXFSZ, (void *)bailout);
X  signal(SIGVTALRM, (void *)bailout);
X# endif
X}
X
Xint
X                msec_diff(struct timeval now, struct timeval then)
X{
X                  return ((now.tv_sec - then.tv_sec) * 1000
X		       +               (now.tv_usec - then.tv_usec) / 1000);
X}
X
Xvoid
X                clearstrings(struct descriptor_data * d)
X{
X  if              (d->output_prefix)
X  {
X                    FREE(d->output_prefix);
X    d->output_prefix = 0;
X  }
X  if (d->output_suffix)
X  {
X    FREE(d->output_suffix);
X    d->output_suffix = 0;
X  }
X}
X
Xvoid
X                shutdownsock(struct descriptor_data * d)
X{
X  if              (d->connected)
X  {
X                    writelog("DISCONNECT descriptor %d,%d player %s(%d)\n", d->descriptor, d->num, db[d->player].name, d->player);
X#ifdef CONNECT_MESSAGES
X    announce_disconnect(d->player);
X#endif				       /* CONNECT_MESSAGES */
X  } else
X  {
X    writelog("DISCONNECT descriptor %d,%d never connected\n", d->descriptor, d->num);
X  }
X  clearstrings(d);
X  freeqs(d);
X}
X
Xstruct descriptor_data *
X                initializesock(struct sockaddr_in * a)
X{
X  struct descriptor_data *d;
X
X  MALLOC(d, struct descriptor_data, 1);
X  d->connected = 0;
X  d->output_prefix = 0;
X  d->output_suffix = 0;
X  d->output_size = 0;
X  d->output.head = 0;
X  d->output.tail = &d->output.head;
X  d->input.head = 0;
X  d->input.tail = &d->input.head;
X  d->raw_input = 0;
X  d->raw_input_at = 0;
X  d->quota = COMMAND_BURST_SIZE;
X  d->last_time = 0;
X  d->address = *a;		       /* This will be the address of the
X				        * concentrator */
X  d->hostname = "";		       /* This will be set during connect */
X
X  welcome_user(d);
X  return d;
X}
X
Xstruct text_block *
X                make_text_block(const char *s, int n)
X{
X  struct text_block *p;
X
X  MALLOC(p, struct text_block, 1);
X  MALLOC(p->buf, char, n);
X  bcopy(s, p->buf, n);
X  p->nchars = n;
X  p->start = p->buf;
X  p->nxt = 0;
X  return p;
X}
X
Xvoid
X                add_to_queue(struct text_queue * q, const char *b, int n)
X{
X  struct text_block *p;
X
X  if (n == 0)
X    return;
X
X  p = make_text_block(b, n);
X  p->nxt = 0;
X  *q->tail = p;
X  q->tail = &p->nxt;
X}
X
Xint
X                flush_queue(struct text_queue * q, int n)
X{
X  struct text_block *p;
X  int             really_flushed = 0;
X
X  n += strlen(flushed_message);
X
X  while (n > 0 && (p = q->head))
X  {
X    n -= p->nchars;
X    really_flushed += p->nchars;
X    q->head = p->nxt;
X    free_text_block(p);
X  }
X  p = make_text_block(flushed_message, strlen(flushed_message));
X  p->nxt = q->head;
X  q->head = p;
X  if (!p->nxt)
X    q->tail = &p->nxt;
X  really_flushed -= p->nchars;
X  return really_flushed;
X}
X
Xint
X                queue_write(struct descriptor_data * d, const char *b, int n)
X{
X  int             space;
X
X  space = MAX_OUTPUT - d->output_size - n;
X  if (space < 0)
X    d->output_size -= flush_queue(&d->output, -space);
X  add_to_queue(&d->output, b, n);
X  d->output_size += n;
X  return n;
X}
X
Xint
X                queue_string(struct descriptor_data * d, const char *s)
X{
X                  return queue_write(d, s, strlen(s));
X}
X
Xvoid
X                freeqs(struct descriptor_data * d)
X{
X  struct text_block *cur, *next;
X
X  cur = d->output.head;
X  while (cur)
X  {
X    next = cur->nxt;
X    free_text_block(cur);
X    cur = next;
X  }
X  d->output.head = 0;
X  d->output.tail = &d->output.head;
X
X  cur = d->input.head;
X  while (cur)
X  {
X    next = cur->nxt;
X    free_text_block(cur);
X    cur = next;
X  }
X  d->input.head = 0;
X  d->input.tail = &d->input.head;
X
X  if (d->raw_input)
X    FREE(d->raw_input);
X  d->raw_input = 0;
X  d->raw_input_at = 0;
X}
X
Xvoid
X                welcome_user(struct descriptor_data * d)
X{
X  queue_string(d, WELCOME_MESSAGE);
X  file_date(d, NEWS_FILE);
X# ifdef CONNECT_FILE
X  do_connect_msg(d, CONNECT_FILE);
X# endif
X}
X
Xvoid
X                goodbye_user(struct descriptor_data * d)
X{
X                  queue_string(d, LEAVE_MESSAGE);
X}
X
Xchar           *
X                strsave(const char *s)
X{
X  char           *p;
X
X  MALLOC(p, char, strlen(s) + 1);
X
X  if (p)
X    strcpy(p, s);
X  return p;
X}
X
Xvoid
X                save_command(struct descriptor_data * d, const char *command)
X{
X                  add_to_queue(&d->input, command, strlen(command) + 1);
X}
X
Xvoid
X                set_userstring(char **userstring, const char *command)
X{
X  if              (*userstring)
X  {
X                    FREE(*userstring);
X    *userstring = 0;
X  }
X  while (*command && isascii(*command) && isspace(*command))
X    command++;
X  if (*command)
X    *userstring = strsave(command);
X}
X
Xint
X                do_command(struct descriptor_data * d, char *command)
X{
X  if              (!strcmp(command, QUIT_COMMAND))
X  {
X                    goodbye_user(d);
X    return 0;
X  } else
X  if (!strncmp(command, WHO_COMMAND, strlen(WHO_COMMAND)))
X  {
X    if (d->output_prefix)
X    {
X      queue_string(d, d->output_prefix);
X      queue_write(d, "\n", 1);
X    }
X    dump_users(d, command + strlen(WHO_COMMAND));
X    if (d->output_suffix)
X    {
X      queue_string(d, d->output_suffix);
X      queue_write(d, "\n", 1);
X    }
X  } else
X    if (d->connected &&
X	!strncmp(command, PREFIX_COMMAND, strlen(PREFIX_COMMAND)))
X  {
X#ifdef ROBOT_MODE
X    if (!Robot(d->player))
X    {
X#ifndef TINKER
X      notify(d->player,
X	     "Only robots can use OUTPUTPREFIX; contact a Wizard.");
X#else TINKER
X      notify(d->player,
X	     "Only robots can use OUTPUTPREFIX; contact a Tinker.");
X#endif TINKER
X      return 1;
X    }
X    if (!d->connected)
X      return 1;
X#endif ROBOT_MODE
X    set_userstring(&d->output_prefix, command + strlen(PREFIX_COMMAND));
X  } else
X    if (d->connected &&
X	!strncmp(command, SUFFIX_COMMAND, strlen(SUFFIX_COMMAND)))
X  {
X#ifdef ROBOT_MODE
X    if (!Robot(d->player))
X    {
X#ifndef TINKER
X      notify(d->player,
X	     "Only robots can use OUTPUTSUFFIX; contact a Wizard.");
X#else TINKER
X      notify(d->player,
X	     "Only robots can use OUTPUTSUFFIX; contact a Tinker.");
X#endif TINKER
X      return 1;
X    }
X#endif ROBOT_MODE
X    set_userstring(&d->output_suffix, command + strlen(SUFFIX_COMMAND));
X  } else
X  {
X    if (d->connected)
X    {
X      if (d->output_prefix)
X      {
X	queue_string(d, d->output_prefix);
X	queue_write(d, "\n", 1);
X      }
X      process_command(d->player, command);
X      if (d->output_suffix)
X      {
X	queue_string(d, d->output_suffix);
X	queue_write(d, "\n", 1);
X      }
X    } else
X    {
X      check_connect(d, command);
X    }
X  }
X  return 1;
X}
X
Xvoid
X                check_connect(struct descriptor_data * d, const char *msg)
X{
X  char            command[MAX_COMMAND_LEN];
X  char            user[MAX_COMMAND_LEN];
X  char            password[MAX_COMMAND_LEN];
X  dbref           player;
X
X  parse_connect(msg, command, user, password);
X
X  if (!strncmp(command, "co", 2))
X  {
X    player = connect_player(user, password);
X    if (player == NOTHING)
X    {
X      queue_string(d, connect_fail);
X      writelog("FAILED CONNECT %s on descriptor %d,%d\n", user, d->descriptor, d->num);
X    } else
X    {
X      writelog("CONNECTED %s(%d) on descriptor %d,%d %s\n",
X	       db[player].name, player, d->descriptor, d->num, d->hostname);
X      d->connected = 1;
X      d->connected_at = time(NULL);
X      d->player = player;
X      do_motd(player);
X      do_look_around(player);
X#ifdef CONNECT_MESSAGES
X      announce_connect(player);
X#endif				       /* CONNECT_MESSAGES */
X    }
X  } else
X  if (!strncmp(command, "cr", 2))
X  {
X#ifndef REGISTRATION
X    player = create_player(user, password);
X    if (player == NOTHING)
X    {
X      queue_string(d, create_fail);
X      writelog("FAILED CREATE %s on descriptor %d,%d %s\n",
X	       user, d->descriptor, d->num, d->hostname);
X    } else
X    {
X      writelog("CREATED %s(%d) on descriptor %d,%d %s\n",
X	       db[player].name, player, d->descriptor, d->num, d->hostname);
X      d->connected = 1;
X      d->connected_at = time(0);
X      d->player = player;
X      do_motd(player);
X      do_look_around(player);
X#ifdef CONNECT_MESSAGES
X      announce_connect(player);
X#endif				       /* CONNECT_MESSAGES */
X    }
X#else
X    queue_string(d, REGISTER_MESSAGE);
X#endif				       /* REGISTRATION */
X  } else
X  {
X    welcome_user(d);
X  }
X}
X
Xvoid
X                parse_connect(const char *msg, char *command, char *user, char *pass)
X{
X  char           *p;
X
X  while (*msg && isascii(*msg) && isspace(*msg))
X    msg++;
X  p = command;
X  while (*msg && isascii(*msg) && !isspace(*msg))
X    *p++ = *msg++;
X  *p = '\0';
X  while (*msg && isascii(*msg) && isspace(*msg))
X    msg++;
X  p = user;
X  while (*msg && isascii(*msg) && !isspace(*msg))
X    *p++ = *msg++;
X  *p = '\0';
X  while (*msg && isascii(*msg) && isspace(*msg))
X    msg++;
X  p = pass;
X  while (*msg && isascii(*msg) && !isspace(*msg))
X    *p++ = *msg++;
X  *p = '\0';
X}
X
Xvoid
X                close_sockets(void)
X{
X  struct descriptor_data *d, *dnext;
X  struct conc_list *c;
X  char            header[4];
X
X  for (c = firstc; c; c = c->next)
X  {
X    /* conc.c now handles printing the Going Down - Bye message */
X    shutdown(c->sock, 0);
X    close(c->sock);
X  }
X  close(sock);
X}
X
Xvoid
X                emergency_shutdown(void)
X{
X                  close_sockets();
X}
X
Xint
X                bailout(int sig, int code, struct sigcontext * scp)
X{
X  long           *ptr;
X  int             i;
X
X  writelog("BAILOUT: caught signal %d code %d", sig, code);
X  ptr = (long *)scp;
X  for (i = 0; i < sizeof(struct sigcontext); i++)
X    writelog("  %08lx\n", *ptr);
X  panic("PANIC on spurious signal");
X  _exit(7);
X  return 0;
X}
X
Xchar           *
X                time_format_1(long dt)
X{
X  register struct tm *delta;
X  static char     buf[64];
X
X  delta = gmtime(&dt);
X  if (delta->tm_yday > 0)
X  {
X    sprintf(buf, "%dd %02d:%02d",
X	    delta->tm_yday, delta->tm_hour, delta->tm_min);
X  } else
X  {
X    sprintf(buf, "%02d:%02d",
X	    delta->tm_hour, delta->tm_min);
X  }
X  return buf;
X}
X
Xchar           *
X                time_format_2(long dt)
X{
X  register struct tm *delta;
X  static char     buf[64];
X
X  delta = gmtime(&dt);
X  if (delta->tm_yday > 0)
X  {
X    sprintf(buf, "%dd", delta->tm_yday);
X  } else
X  if (delta->tm_hour > 0)
X  {
X    sprintf(buf, "%dh", delta->tm_hour);
X  } else
X  if (delta->tm_min > 0)
X  {
X    sprintf(buf, "%dm", delta->tm_min);
X  } else
X  {
X    sprintf(buf, "%ds", delta->tm_sec);
X  }
X  return buf;
X}
X
X#ifdef CONNECT_MESSAGES
Xvoid
X                announce_connect(dbref player)
X{
X  dbref           loc;
X  char            buf[BUFFER_LEN];
X
X  if ((loc = getloc(player)) == NOTHING)
X    return;
X  if (Dark(player) || Dark(loc))
X    return;
X
X  sprintf(buf, "%s has connected.", db[player].name);
X
X  notify_except(db[loc].contents, player, buf);
X}
X
Xvoid
X                announce_disconnect(dbref player)
X{
X  dbref           loc;
X  char            buf[BUFFER_LEN];
X
X  if ((loc = getloc(player)) == NOTHING)
X    return;
X  if (Dark(player) || Dark(loc))
X    return;
X
X  sprintf(buf, "%s has disconnected.", db[player].name);
X
X  notify_except(db[loc].contents, player, buf);
X}
X
X#endif				       /* CONNECT_MESSAGES */
X
Xint
X                sigshutdown(int sig, int code, struct sigcontext * scp)
X{
X                  writelog("SHUTDOWN: on signal %d code %d\n", sig, code);
X  shutdown_flag = 1;
X  return 0;
X}
X
X#ifdef DETACH
Xint
X                logsynch()
X{
X                  freopen(logfile, "a", stderr);
X  setbuf(stderr, NULL);
X  writelog("log file reopened\n");
X  return 0;
X}
X
X#endif				       /* DETACH */
X
X#include <sys/stat.h>
X
Xvoid
X                file_date(struct descriptor_data * d, char *file)
X{
X  static char     buf[80];
X  extern char    *ctime(long *clock);
X  struct stat     statb;
X  char           *tstring;
X  char           *cp;
X
X  if (stat(file, &statb) == -1)
X    return;
X
X  tstring = ctime(&statb.st_mtime);
X  if ((cp = (char *)index(tstring, '\n')) != NULL)
X    *cp = '\0';
X
X  strcpy(buf, "News last updated ");
X  strcat(buf, tstring);
X  strcat(buf, "\n\n");
X
X  queue_string(d, (char *)buf);
X}
X
Xvoid            main_loop()
X{
X  struct message *ptr;
X  int             found, newsock, lastsock, len, loop;
X  int             accepting;
X  struct timeval  tv;
X  struct sockaddr_in sin;
X  fd_set          in, out;
X  char            data[1025], *p1, *p2, buffer[1025], header[4];
X  struct conc_list *c, *tempc, *nextc, *lastc;
X  struct descriptor_data *d, *tempd, *nextd;
X  struct timeval  last_slice, current_time;
X  struct timeval  next_slice;
X  struct timeval  slice_timeout;
X  short           templen;
X
X  accepting = 1;
X  lastsock = sock + 1;
X  while (!shutdown_flag)
X  {
X    gettimeofday(&current_time, (struct timezone *) 0);
X    last_slice = update_quotas(last_slice, current_time);
X
X    process_commands();
X
X    if (shutdown_flag)
X      break;
X
X    next_slice = msec_add(last_slice, COMMAND_TIME_MSEC);
X    slice_timeout = timeval_sub(next_slice, current_time);
X
X    FD_ZERO(&in);
X    FD_ZERO(&out);
X
X    FD_SET(sock, &in);
X    for (c = firstc; c; c = c->next)
X      process_output(c);
X    for (c = firstc; c; c = c->next)
X      if (c->sock)
X      {
X	if (c->ilen < BUFSIZE)
X	  FD_SET(c->sock, &in);
X	len = c->first ? c->first->len : 0;
X	while (c->first && ((c->olen + len + 2) < BUFSIZE))
X	{
X	  templen = c->first->len;
X	  bcopy(&templen, c->outgoing + c->olen, 2);
X	  bcopy(c->first->data, c->outgoing + c->olen + 2, len);
X	  c->olen += len + 2;
X	  ptr = c->first;
X	  c->first = ptr->next;
X	  FREE(ptr->data);
X	  FREE(ptr);
X	  if (c->last == ptr)
X	    c->last = 0;
X	  len = c->first ? c->first->len : 0;
X	}
X	if (c->olen)
X	  FD_SET(c->sock, &out);
X      }
X    tv.tv_sec = 1000;
X    tv.tv_usec = 0;
X
X    found = select(lastsock, &in, &out, (fd_set *) 0, &tv);
X    if (found < 0)
X      continue;
X    if (accepting && FD_ISSET(sock, &in))
X    {
X      len = sizeof(sin);
X      newsock = accept(sock, (struct sockaddr *) & sin, &len);
X      if (newsock >= 0)
X      {
X	if (newsock >= lastsock)
X	  lastsock = newsock + 1;
X	if (fcntl(newsock, F_SETFL, FNDELAY) == -1)
X	{
X	  perror("make_nonblocking: fcntl");
X	}
X	MALLOC(tempc, struct conc_list, 1);
X	tempc->next = firstc;
X	tempc->firstd = 0;
X	tempc->first = 0;
X	tempc->last = 0;
X	tempc->status = 0;
X	/* Imcomming and outgoing I/O buffers */
X	MALLOC(tempc->incoming, char, BUFSIZE);
X	tempc->ilen = 0;
X	MALLOC(tempc->outgoing, char, BUFSIZE);
X	tempc->olen = 0;
X	firstc = tempc;
X	firstc->sock = newsock;
X	writelog("CONCENTRATOR CONNECT: sock %d, addr %x\n", newsock, sin.sin_addr.s_addr);
X      }
X    }
X    for (c = firstc; c; c = nextc)
X    {
X      nextc = c->next;
X#ifdef CHECKC
X      if (!(c->sock))
X	writelog("CONSISTENCY CHECK: Concentrator found with null socket #\n");
X#endif
X      if ((FD_ISSET(c->sock, &in)) && (c->ilen < BUFSIZE))
X      {
X	int             i;
X	len = recv(c->sock, c->incoming + c->ilen,
X		   BUFSIZE - c->ilen, 0);
X	if (len == 0)
X	{
X	  struct message *mptr, *tempm;
X	  writelog("CONCENTRATOR DISCONNECT: %d\n", c->sock);
X	  close(c->sock);
X	  d = c->firstd;
X	  while (d)
X	  {
X	    shutdownsock(d);
X	    tempd = d;
X	    d = d->next;
X	    FREE(tempd);
X	  }
X	  if (firstc == c)
X	    firstc = firstc->next;
X	  else
X	    lastc->next = c->next;
X	  FREE(c->incoming);
X	  FREE(c->outgoing);
X	  mptr = c->first;
X	  while (mptr)
X	  {
X	    tempm = mptr;
X	    mptr = mptr->next;
X	    FREE(mptr->data);
X	    FREE(mptr);
X	  }
X	  FREE(c);
X	  break;
X	} else
X	if (len < 0)
X	{
X	  writelog("recv: %s\n", strerror(errno));
X	} else
X	{
X	  int             num;
X
X	  c->ilen += len;
X	  while (c->ilen > 2)
X	  {
X	    bcopy(c->incoming, &templen, 2);
X#ifdef CHECKC
X	    if (templen < 1)
X	      writelog("CONSISTENCY CHECK: Message recived with lenght < 1\n");
X#endif
X	    if (c->ilen >= (templen + 2))
X	    {
X	      num = *(c->incoming + 2);
X	      /* Is it coming from the command user #? */
X	      if (num == 0)
X	      {
X		/* Proccess commands */
X		switch (*(c->incoming + 3))
X		{
X		case 1:	       /* connect */
X		  d = initializesock(&sin);
X		  d->descriptor = c->sock;
X		  d->next = c->firstd;
X		  c->firstd = d;
X		  d->num = *(c->incoming + 4);
X		  MALLOC(d->hostname, char,
X			 templen - 5);
X		  bcopy(c->incoming + 9, d->hostname,
X			templen - 6);
X		  *(d->hostname + templen - 7) = 0;
X#ifdef DEBUG
X		  writelog("USER CONNECT %d,%d from host %s\n", c->sock, d->num, d->hostname);
X#endif
X		  break;
X		case 2:	       /* disconnect */
X		  tempd = 0;
X		  d = c->firstd;
X		  num = *(c->incoming + 4);
X		  while (d)
X		  {
X		    if (d->num == num)
X		    {
X		      writelog("USER ABORTED CONNECTION %d,%d\n", c->sock, d->num);
X		      shutdownsock(d);
X		      if (c->firstd == d)
X			c->firstd = d->next;
X		      else
X			tempd->next = d->next;
X		      FREE(d);
X		      break;
X		    }
X		    tempd = d;
X		    d = d->next;
X		  }
X#ifdef CHECKC
X		  if (!d)
X		    writelog("CONSISTENCY CHECK: Disconnect Received for unknown user %d,%d\n", c->sock, num);
X#endif
X		  break;
X
X		  /*
X		   * This take a message from a concentrator, and logs it in
X		   * the log file 
X		   */
X		case 4:
X		  {
X		    char            buffer[2048];
X		    bcopy(c->incoming + 4, buffer,
X			  templen - 2);
X		    *(buffer + templen - 1) = 0;
X		    writelog(buffer);
X		    break;
X		  }
X#ifdef CHECKC
X		default:
X		  writelog("CONSISTENCY CHECK: Received unknown command from concentrator\n");
X#endif
X		}
X	      } else
X	      {
X		d = c->firstd;
X		while (d)
X		{
X		  if (d->num == num)
X		  {
X		    process_input(d, c->incoming + 3,
X				  templen - 1);
X		    break;
X		  }
X		  d = d->next;
X		}
X#ifdef CHECKC
X		if (!d)
X		  writelog("CONSISTENCY CHECK: Message received for unknown user %d,%d\n", c->sock, num);
X#endif
X	      }
X	      bcopy(c->incoming + templen + 2, c->incoming,
X		    (c->ilen - templen - 2));
X	      c->ilen = c->ilen - templen - 2;
X	    } else
X	      break;
X	  }
X	}
X      }
X      lastc = c;
X    }
X    /* Send data loop */
X    for (c = firstc; c; c = c->next)
X    {
X      if (FD_ISSET(c->sock, &out))
X      {
X	if (c->olen)
X	{
X	  len = send(c->sock, c->outgoing, c->olen, 0);
X	  if (len > 0)
X	  {
X	    c->olen -= len;
X	    bcopy(c->outgoing + len, c->outgoing, c->olen);
X	  }
X	}
X      }
X    }
X  }
X}
X
Xvoid            process_output(struct conc_list * c)
X{
X  struct descriptor_data *d;
X  struct text_block **qp, *cur;
X  short           templen;
X
X  for (d = c->firstd; d; d = d->next)
X  {
X    qp = &d->output.head;
X    cur = *qp;
X    if (cur)
X    {
X      if (cur->nchars < 512)
X      {
X	if ((c->olen + cur->nchars + 3) < BUFSIZE)
X	{
X	  templen = cur->nchars + 1;
X	  bcopy(&templen, c->outgoing + c->olen, 2);
X	  *(c->outgoing + c->olen + 2) = d->num;
X	  strncpy(c->outgoing + c->olen + 3, cur->start, cur->nchars);
X	  d->output_size -= cur->nchars;
X	  c->olen += cur->nchars + 3;
X	  if (!cur->nxt)
X	    d->output.tail = qp;
X	  *qp = cur->nxt;
X	  free_text_block(cur);
X	}
X      } else
X      {
X	if ((c->olen + 512 + 3) < BUFSIZE)
X	{
X	  templen = 512 + 1;
X	  bcopy(&templen, c->outgoing + c->olen, 2);
X	  *(c->outgoing + c->olen + 2) = d->num;
X	  strncpy(c->outgoing + c->olen + 3, cur->start, 512);
X	  d->output_size -= 512;
X	  c->olen += 512 + 3;
X	  cur->nchars -= 512;
X	  cur->start += 512;
X	}
X      }
X    }
X  }
X}
X
Xvoid            boot_off(dbref player)
X{
X  struct conc_list *c;
X  struct descriptor_data *d, *lastd;
X  char            header[4];
X
X  for (c = firstc; c; c = c->next)
X  {
X    lastd = 0;
X    for (d = c->firstd; d; d = d->next)
X    {
X      if (d->connected && d->player == player)
X      {
X	header[0] = 0;
X	header[1] = 2;
X	header[2] = d->num;
X	queue_message(c, header, 3);
X	process_output(c);
X	if (lastd)
X	  lastd->next = d->next;
X	else
X	  c->firstd = d->next;
X	shutdownsock(d);
X	FREE(d);
X	return;
X      }
X      lastd = d;
X    }
X  }
X}
X
Xvoid            queue_message(struct conc_list * c, char *data, int len)
X{
X  struct message *ptr;
X
X  MALLOC(ptr, struct message, 1);
X  MALLOC(ptr->data, char, len);
X  ptr->len = len;
X  bcopy(data, ptr->data, len);
X  ptr->next = 0;
X  if (c->last == 0)
X    c->first = ptr;
X  else
X    c->last->next = ptr;
X  c->last = ptr;
X}
X
Xint do_connect_msg(struct descriptor_data * d, const char *filename)
X{
X  FILE           *f;
X  char            buf[BUFFER_LEN];
X  char           *p;
X
X  if ((f = fopen(filename, "r")) == NULL)
X  {
X    return (0);
X  } else
X  {
X    while (fgets(buf, sizeof buf, f))
X    {
X      queue_string(d, (char *)buf);
X
X    }
X    fclose(f);
X    return (1);
X  }
X}
END_OF_FILE
if test 33958 -ne `wc -c <'interface.c'`; then
    echo shar: \"'interface.c'\" unpacked with wrong size!
fi
# end of 'interface.c'
fi
if test -f 'joinspl.sh' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'joinspl.sh'\"
else
echo shar: Extracting \"'joinspl.sh'\" \(333 characters\)
sed "s/^X//" >'joinspl.sh' <<'END_OF_FILE'
X#! /bin/sh
X#
X# join split lines in the config.h and small.db files
X#
Xecho creating config.h
Xsed -f comb.sed config_h.spl >config.h
Xecho creating small.db
Xsed -f comb.sed smalldb.spl >small.db
Xrm config_h.spl smalldb.spl
X#
X# build tinymud.ps from its three parts
X#
Xcreating tinymud.ps
Xcat tinymud.ps.xa? >tinymud.ps
Xrm tinymud.ps.xa?
END_OF_FILE
if test 333 -ne `wc -c <'joinspl.sh'`; then
    echo shar: \"'joinspl.sh'\" unpacked with wrong size!
fi
chmod +x 'joinspl.sh'
# end of 'joinspl.sh'
fi
if test -f 'wiz.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'wiz.c'\"
else
echo shar: Extracting \"'wiz.c'\" \(16849 characters\)
sed "s/^X//" >'wiz.c' <<'END_OF_FILE'
X#include "copyright.h"
X
X/* Wizard-only commands */
X
X
X#include "db.h"
X#include "config.h"
X#include "interface.h"
X#include "match.h"
X#include "externs.h"
X
Xvoid do_teleport(dbref player, const char *arg1, const char *arg2)
X{
X    dbref victim;
X    dbref destination;
X    const char *to;
X
X#ifdef RESTRICTED_TELEPORT
X    if(!Wizard(player)) {
X#ifndef TINKER
X	notify(player, "Only a Wizard may teleport at will.");
X#else TINKER
X	notify(player, "Only a Tinker may teleport at will.");
X#endif TINKER
X	return;
X    }
X#endif /* RESTRICTED_TELEPORT */
X
X    /* get victim, destination */
X    if(*arg2 == '\0') {
X	victim = player;
X	to = arg1;
X    } else {
X	init_match(player, arg1, NOTYPE);
X	match_neighbor();
X	match_possession();
X	match_me();
X	match_absolute();
X	match_player();
X
X	if((victim = noisy_match_result()) == NOTHING) {
X	    return;
X	}
X	to = arg2;
X    }
X
X    /* get destination */
X    init_match(player, to, TYPE_PLAYER);
X    match_here();
X    match_absolute();
X    if(Wizard(player)) {
X	match_neighbor();
X	match_me();
X	match_player();
X    }
X
X    switch(destination = match_result()) {
X      case NOTHING:
X	notify(player, "Send it where?");
X	break;
X      case AMBIGUOUS:
X	notify(player, "I don't know which destination you mean!");
X	break;
X      default:
X	/* check victim, destination types, teleport if ok */
X	if(Typeof(destination) == TYPE_EXIT
X	   || Typeof(destination) == TYPE_THING
X	   || Typeof(victim) == TYPE_EXIT
X	   || Typeof(victim) == TYPE_ROOM
X	   || (Typeof(victim) == TYPE_PLAYER
X	       && Typeof(destination) != TYPE_ROOM)) {
X	    notify(player, "Bad destination.");
X#ifndef RESTRICTED_TELEPORT
X	} else if(!Wizard(player)
X		  && !(Typeof(victim) == TYPE_THING
X		       && Typeof(destination) == TYPE_ROOM
X		       && (controls(player, victim)
X			   || (Typeof(db[victim].location) == TYPE_ROOM
X			       && controls(player, db[victim].location)))
X		       && (can_link_to(player, TYPE_PLAYER, destination)))) {
X	    notify(player, "Permission denied.");
X#endif /* RESTRICTED_TELEPORT */		  
X	} else if(Typeof(victim) == TYPE_PLAYER) {
X	    notify(victim, "You feel a wrenching sensation...");
X	    enter_room(victim, destination);
X	    notify(player, "Teleported.");
X	} else {
X	    /* check for non-sticky dropto */
X	    if(Typeof(destination) == TYPE_ROOM
X	       && db[destination].location != NOTHING
X	       && !(db[destination].flags & STICKY)) {
X		/* destination has immediate dropto */
X		destination = db[destination].location;
X	    }
X
X	    /* do the move */
X	    moveto(victim, destination);
X	    notify(player, "Teleported.");
X	}
X    }
X}
X
Xvoid do_mass_teleport(dbref player, const char *arg1)
X{
X    dbref victim;
X    dbref destination;
X    char buf[BUFFER_LEN];
X    int moved = 0;
X
X    if(!God(player)) {
X#ifndef TINKER
X	notify(player, "Only God can do a mass teleport.");
X#else TINKER
X	notify(player, "Only the Master Tinker can do a mass teleport.");
X#endif TINKER
X	return;
X    }
X
X    /* get destination */
X    init_match(player, arg1, TYPE_ROOM);
X    match_here();
X    match_absolute();
X
X    if ((destination = match_result()) == NOTHING) {
X	notify(player, "Please specify a destination to send everyone to.");
X	return;
X    }
X    
X    switch (Typeof(destination)) {
X      case NOTHING:
X	notify(player, "Send them where?");
X	break;
X
X      case TYPE_ROOM:
X        for (victim = 0; victim < db_top; victim++) {
X	    if (victim != player && Typeof(victim) == TYPE_PLAYER) {
X	        notify(victim,
X		 "You and everyone around you feels a wrenching sensation...");
X		moveto(victim, destination);
X		look_room(victim, destination);
X		moved++;
X	    }
X	}
X	sprintf (buf, "Teleported %d players to %s.",
X		 moved, unparse_object (player, destination));
X	notify(player, "Teleported.");
X        break;
X	
X      default:
X	notify(player, "Mass teleports are legal to rooms only.");
X    }
X}
X
Xvoid do_force(dbref player, const char *what, char *command)
X{
X    dbref victim;
X
X    if(!Wizard(player)) {
X	writelog ("FORCE: failed, priv, player %s(%d), who '%s', what '%s'\n",
X		  db[player].name, player, what, command);
X#ifndef TINKER
X	notify(player, "Only Wizards may use this command.");
X#else TINKER
X	notify(player, "Only Tinkers may use this command.");
X#endif TINKER
X	return;
X    }
X
X    /* get victim */
X    if((victim = lookup_player(what)) == NOTHING) {
X	writelog ("FORCE: failed, victim, player %s(%d), who '%s', what '%s'\n",
X		  db[player].name, player, what, command);
X	notify(player, "That player does not exist.");
X	return;
X    }
X
X#ifdef GOD_PRIV
X    if(God(victim)) {
X#ifndef TINKER
X	writelog ("FORCE: failed, wizard, player %s(%d), who '%s', what '%s'\n",
X#else TINKER
X	writelog ("FORCE: failed, tinker, player %s(%d), who '%s', what '%s'\n",
X#endif TINKER
X		  db[player].name, player, what, command);
X#ifndef TINKER
X	notify(player, "You can't force God.");
X#else TINKER
X	notify(player, "You can't force the Master Tinker.");
X#endif TINKER
X	return;
X    }
X#endif GOD_PRIV
X
X    /* force victim to do command */
X    writelog ("FORCE: success, player %s(%d), who '%s', what '%s'\n",
X	      db[player].name, player, what, command);
X
X    process_command(victim, command);
X}
X
Xvoid do_stats(dbref player, const char *name)
X{
X    dbref rooms;
X    dbref exits;
X    dbref things;
X    dbref players;
X    dbref total;
X    dbref i;
X    dbref owner;
X    char buf[BUFFER_LEN];
X
X    if(!Wizard(player)) {
X	sprintf(buf, "The universe contains %d objects.", db_top);
X	notify(player, buf);
X    } else {
X	owner = lookup_player(name);
X	total = rooms = exits = things = players = 0;
X	for(i = 0; i < db_top; i++) {
X	    if(owner == NOTHING || owner == db[i].owner) {
X		total++;
X		switch(Typeof(i)) {
X		  case TYPE_ROOM:
X		    rooms++;
X		    break;
X		  case TYPE_EXIT:
X		    exits++;
X		    break;
X		  case TYPE_THING:
X		    things++;
X		    break;
X		  case TYPE_PLAYER:
X		    players++;
X		    break;
X		  default:
X		    abort();
X		    break;
X		}
X	    }
X	}
X	sprintf(buf,
X		"%d objects = %d rooms, %d exits, %d things, %d players.",
X		total, rooms, exits, things, players);
X	notify(player, buf);
X#ifdef TEST_MALLOC
X	sprintf(buf, "Malloc count = %d.", malloc_count);
X	notify(player, buf);
X#endif /* TEST_MALLOC */
X    }
X}
X		
Xvoid do_bobble(dbref player, const char *name, const char *rname)
X{
X    dbref victim, recip, i;
X    char buf[BUFFER_LEN];
X    int newflags = 0;
X
X    if(!Wizard(player)) {
X#ifndef TINKER
X        writelog("TOAD: failed, priv %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "Only a Wizard can turn a person into a toad.");
X#else TINKER
X        writelog("BOBBLE: failed, priv %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "Only a Tinker can bobble a person.");
X#endif TINKER
X	return;
X    }
X
X    if (!name || !*name) {
X#ifndef TINKER
X        writelog("TOAD: failed, syntax %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("BOBBLE: failed, syntax %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X	notify(player, "You must specify a victim.");
X	return;
X    }
X    
X    init_match(player, name, TYPE_PLAYER);
X    match_neighbor();
X    match_absolute();
X    match_player();
X    if((victim = noisy_match_result()) == NOTHING) {
X#ifndef TINKER
X        writelog("TOAD: failed, victim %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("BOBBLE: failed, victim %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X	notify(player, "Please specify another victim.");
X	return;
X    }
X
X#ifdef RECYCLE
X    /* Default the recipient to RECYCLER */
X    if (!rname || !*rname || string_compare (rname, RECYCLER) == 0) {
X	recip = lookup_player(RECYCLER);
X	newflags = UNWANTED;		/* Can be gotten by other players */
X    } else {
X	recip = lookup_player(rname);
X    }
X#else
X    recip = lookup_player(rname);
X#endif
X
X    if(recip == NOTHING || recip == victim) {
X#ifndef TINKER
X        writelog("TOAD: failed, recip %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("BOBBLE: failed, recip %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X	notify(player, "Please specify another player to own the victim's effects.");
X	return;
X    }
X
X    if(Typeof(victim) != TYPE_PLAYER) {
X#ifndef TINKER
X        writelog("TOAD: failed, type %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "You can only turn players into toads!");
X#else TINKER
X        writelog("BOBBLE: failed, type %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "You can only bobble players!");
X#endif TINKER
X    } else if(Wizard(victim)) {
X#ifndef TINKER
X        writelog("TOAD: failed, wizard %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "You can't turn a Wizard into a toad.");
X#else TINKER
X        writelog("BOBBLE: failed, tinker %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "You can't bobble a Tinker.");
X#endif TINKER
X    } else if(db[victim].contents != NOTHING) {
X#ifndef TINKER
X        writelog("TOAD: failed, contents %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("BOBBLE: failed, contents %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X
X	notify(player, "What about what they are carrying?");
X    } else {
X#ifndef TINKER
X        writelog("TOAD: success %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("BOBBLE: success %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X
X	/* we are ok */
X	/* do it */
X	if(db[victim].password) {
X	    free((void *) db[victim].password);
X	    db[victim].password = 0;
X	}
X	db[victim].flags = TYPE_THING;
X
X	/* Give the sphere and all old belongings to recipient */
X	db[victim].owner = recip;
X	for (i=0; i<db_top; i++) {
X	    if (db[i].owner == victim) {
X		db[i].owner = recip;
X		db[i].flags |= newflags;
X	    }
X	}
X
X	db[victim].pennies = 1;	/* dont let him keep his immense wealth */
X
X	/* notify people */
X#ifndef TINKER
X	sprintf(buf, "You have been turned into a toad by %s.",
X		db[player].name);
X#else TINKER
X	sprintf(buf, "You have been encased in a stasis sphere by %s.",
X		db[player].name);
X#endif TINKER
X	notify(victim, buf);
X#ifndef TINKER
X	sprintf(buf, "You turned %s into a toad!", db[victim].name);
X#else TINKER
X	sprintf(buf, "You bobbled %s!", db[victim].name);
X#endif TINKER
X	notify(player, buf);
X
X	/* reset name */
X#ifdef PLAYER_LIST
X	delete_player(victim);
X#endif PLAYER_LIST	
X#ifndef TINKER
X	sprintf(buf, "a slimy toad named %s", db[victim].name);
X#else TINKER
X	sprintf(buf, "a silvery sphere containing %s", db[victim].name);
X#endif TINKER
X	free((void *) db[victim].name);
X	db[victim].name = alloc_string(buf);
X    }
X}
X
Xvoid do_unbobble(dbref player, const char *name, const char *newname)
X{
X    dbref victim;
X    char buf[BUFFER_LEN];
X
X    if(!Wizard(player)) {
X#ifndef TINKER
X        writelog("UNTOAD: failed, priv %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "Only a Wizard can turn a toad into a person.");
X#else TINKER
X        writelog("UNBOBBLE: failed, priv %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "Only a Tinker can unbobble a person.");
X#endif TINKER
X	return;
X    }
X
X    if (!name || !*name) {
X#ifndef TINKER
X        writelog("UNTOAD: failed, syntax %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("UNBOBBLE: failed, syntax %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X	notify(player, "You must specify a thing.");
X	return;
X    }
X    
X    if (!newname || !*newname) {
X#ifndef TINKER
X        writelog("UNTOAD: failed, syntax %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player,"You must specify a new name: @untoad <thing> = <name>");
X#else TINKER
X        writelog("UNBOBBLE: failed, syntax %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player,
X	       "You must specify a new name: @unbobble <thing> = <name>");
X#endif TINKER
X	return;
X    }
X    
X    init_match(player, name, TYPE_THING);
X    match_neighbor();
X    match_absolute();
X    match_player();
X    if((victim = noisy_match_result()) == NOTHING) {
X#ifndef TINKER
X        writelog("UNTOAD: failed, victim %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("UNBOBBLE: failed, victim %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X	notify(player, "Please specify another thing.");
X	return;
X    }
X
X    if(Typeof(victim) != TYPE_THING) {
X#ifndef TINKER
X        writelog("UNTOAD: failed, type %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "You can only turn players into toads!");
X#else TINKER
X        writelog("UNBOBBLE: failed, type %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "You can only bobble players!");
X#endif TINKER
X    } else if (!ok_player_name(newname)) {
X#ifndef TINKER
X        writelog("UNTOAD: failed, name %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("UNBOBBLE: failed, name %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X	notify(player, "You can't give a player that name!");
X    } else {
X#ifndef TINKER
X        writelog("UNTOAD: success %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#else TINKER
X        writelog("UNBOBBLE: success %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X#endif TINKER
X
X	/* we are ok */
X	/* do it */
X	db[victim].flags = TYPE_PLAYER;
X	db[victim].owner = victim;
X	db[victim].pennies = KILL_BONUS;
X
X	/* reset name */
X	free((void *) db[victim].name);
X	db[victim].name = alloc_string(newname);
X
X#ifndef TINKER
X	sprintf(buf, "You turned the toad back into %s!", db[victim].name);
X#else TINKER
X	sprintf(buf, "You unbobbled %s!", db[victim].name);
X#endif TINKER
X	notify(player, buf);
X
X	sprintf(buf, "Use @newpassword to give %s a password",
X		db[victim].name);
X	notify(player, buf);
X
X#ifdef PLAYER_LIST
X	add_player(victim);
X#endif PLAYER_LIST	
X    }
X}
X
Xvoid do_newpassword(dbref player, const char *name, const char *password)
X{
X    dbref victim;
X    char buf[BUFFER_LEN];
X
X    if(!Wizard(player)) {
X        writelog("PASSWORD: failed, priv %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "Your delusions of grandeur have been duly noted.");
X	return;
X    } else if((victim = lookup_player(name)) == NOTHING) {
X        writelog("PASSWORD: failed, victim %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "No such player.");
X    } else if(*password != '\0' && !ok_password(password)) {
X	/* Wiz can set null passwords, but not bad passwords */
X        writelog("PASSWORD: failed, password %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	notify(player, "Bad password");
X#ifdef GOD_PRIV	
X    } else if (God(victim) && !God(player)) {
X#ifndef TINKER
X        writelog("PASSWORD: failed, wizard %s(%d) who '%s'\n",
X#else TINKER
X        writelog("PASSWORD: failed, tinker %s(%d) who '%s'\n",
X#endif TINKER
X		 db[player].name, player, name);
X	notify(player, "You cannot change that player's password.");
X#endif GOD_PRIV	
X    } else {
X        writelog("PASSWORD: success %s(%d) who '%s'\n",
X		 db[player].name, player, name);
X	/* it's ok, do it */
X	if(db[victim].password) free((void *) db[victim].password);
X	db[victim].password = alloc_string(password);
X	notify(player, "Password changed.");
X	sprintf(buf, "Your password has been changed by %s.", db[player].name);
X	notify(victim, buf);
X    }
X}
X
Xvoid do_boot(dbref player, const char *name)
X{
X    dbref victim;
X    char buf[BUFFER_LEN];
X
X    if(!Wizard(player)) {
X	writelog ("BOOT: failed, priv player %s(%d), who '%s'\n",
X		  db[player].name, player, name);
X
X#ifndef TINKER
X	notify(player, "Only a Wizard can boot another player off!");
X#else TINKER
X	notify(player, "Only a Tinker can boot another player off!");
X#endif TINKER
X	return;
X    }
X
X    init_match(player, name, TYPE_PLAYER);
X    match_neighbor();
X    match_absolute();
X    match_player();
X    if((victim = noisy_match_result()) == NOTHING) return;
X
X#ifdef GOD_PRIV
X    if(God(victim)) {
X#ifndef TINKER
X	writelog ("BOOT: failed, wizard, player %s(%d), who '%s'\n",
X#else TINKER
X	writelog ("BOOT: failed, tinker, player %s(%d), who '%s'\n",
X#endif TINKER
X		  db[player].name, player, name);
X
X	notify(player, "You can't boot that player!");
X	return;
X    }
X#endif GOD_PRIV
X
X    if(Typeof(victim) != TYPE_PLAYER) {
X	writelog ("BOOT: failed, victim, player %s(%d), who '%s'\n",
X		  db[player].name, player, name);
X
X	notify(player, "You can only boot off other players!");
X    } else {
X	writelog ("BOOT: success, player %s(%d), who '%s'\n",
X		  db[player].name, player, name);
X
X	/* we are ok */
X	/* do it */
X	/* notify people */
X	sprintf(buf, "You have been booted off the game by %s.",
X		db[player].name);
X	notify(victim, buf);
X	sprintf(buf, "You booted %s off!", db[victim].name);
X	notify(player, buf);
X	boot_off(victim);
X	/* reset name */
X    }
X}
END_OF_FILE
if test 16849 -ne `wc -c <'wiz.c'`; then
    echo shar: \"'wiz.c'\" unpacked with wrong size!
fi
# end of 'wiz.c'
fi
echo shar: End of archive 5 \(of 10\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 10 archives.
    echo ">>> now type 'sh joinspl.sh'"
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0