/ circle3.1 / src / comm.c
comm.c
   1  /* ************************************************************************
   2  *   File: comm.c                                        Part of CircleMUD *
   3  *  Usage: Communication, socket handling, main(), central game loop       *
   4  *                                                                         *
   5  *  All rights reserved.  See license.doc for complete information.        *
   6  *                                                                         *
   7  *  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
   8  *  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
   9  ************************************************************************ */
  10  
  11  #define __COMM_C__
  12  
  13  #include "conf.h"
  14  #include "sysdep.h"
  15  
  16  #if CIRCLE_GNU_LIBC_MEMORY_TRACK
  17  # include <mcheck.h>
  18  #endif
  19  
  20  #ifdef CIRCLE_MACINTOSH		/* Includes for the Macintosh */
  21  # define SIGPIPE 13
  22  # define SIGALRM 14
  23    /* GUSI headers */
  24  # include <sys/ioctl.h>
  25    /* Codewarrior dependant */
  26  # include <SIOUX.h>
  27  # include <console.h>
  28  #endif
  29  
  30  #ifdef CIRCLE_WINDOWS		/* Includes for Win32 */
  31  # ifdef __BORLANDC__
  32  #  include <dir.h>
  33  # else /* MSVC */
  34  #  include <direct.h>
  35  # endif
  36  # include <mmsystem.h>
  37  #endif /* CIRCLE_WINDOWS */
  38  
  39  #ifdef CIRCLE_AMIGA		/* Includes for the Amiga */
  40  # include <sys/ioctl.h>
  41  # include <clib/socket_protos.h>
  42  #endif /* CIRCLE_AMIGA */
  43  
  44  #ifdef CIRCLE_ACORN		/* Includes for the Acorn (RiscOS) */
  45  # include <socklib.h>
  46  # include <inetlib.h>
  47  # include <sys/ioctl.h>
  48  #endif
  49  
  50  /*
  51   * Note, most includes for all platforms are in sysdep.h.  The list of
  52   * files that is included is controlled by conf.h for that platform.
  53   */
  54  
  55  #include "structs.h"
  56  #include "utils.h"
  57  #include "comm.h"
  58  #include "interpreter.h"
  59  #include "handler.h"
  60  #include "db.h"
  61  #include "house.h"
  62  
  63  #ifdef HAVE_ARPA_TELNET_H
  64  #include <arpa/telnet.h>
  65  #else
  66  #include "telnet.h"
  67  #endif
  68  
  69  #ifndef INVALID_SOCKET
  70  #define INVALID_SOCKET (-1)
  71  #endif
  72  
  73  /* externs */
  74  extern struct ban_list_element *ban_list;
  75  extern int num_invalid;
  76  extern char *GREETINGS;
  77  extern const char *circlemud_version;
  78  extern int circle_restrict;
  79  extern int mini_mud;
  80  extern int no_rent_check;
  81  extern FILE *player_fl;
  82  extern ush_int DFLT_PORT;
  83  extern const char *DFLT_DIR;
  84  extern const char *DFLT_IP;
  85  extern const char *LOGNAME;
  86  extern int max_playing;
  87  extern int nameserver_is_slow;	/* see config.c */
  88  extern int auto_save;		/* see config.c */
  89  extern int autosave_time;	/* see config.c */
  90  extern int *cmd_sort_info;
  91  
  92  extern struct time_info_data time_info;		/* In db.c */
  93  extern char *help;
  94  
  95  /* local globals */
  96  struct descriptor_data *descriptor_list = NULL;		/* master desc list */
  97  struct txt_block *bufpool = 0;	/* pool of large output buffers */
  98  int buf_largecount = 0;		/* # of large buffers which exist */
  99  int buf_overflows = 0;		/* # of overflows of output */
 100  int buf_switches = 0;		/* # of switches from small to large buf */
 101  int circle_shutdown = 0;	/* clean shutdown */
 102  int circle_reboot = 0;		/* reboot the game after a shutdown */
 103  int no_specials = 0;		/* Suppress ass. of special routines */
 104  int max_players = 0;		/* max descriptors available */
 105  int tics = 0;			/* for extern checkpointing */
 106  int scheck = 0;			/* for syntax checking mode */
 107  struct timeval null_time;	/* zero-valued time structure */
 108  byte reread_wizlist;		/* signal: SIGUSR1 */
 109  byte emergency_unban;		/* signal: SIGUSR2 */
 110  FILE *logfile = NULL;		/* Where to send the log messages. */
 111  const char *text_overflow = "**OVERFLOW**\r\n";
 112  
 113  /* functions in this file */
 114  RETSIGTYPE reread_wizlists(int sig);
 115  RETSIGTYPE unrestrict_game(int sig);
 116  RETSIGTYPE reap(int sig);
 117  RETSIGTYPE checkpointing(int sig);
 118  RETSIGTYPE hupsig(int sig);
 119  ssize_t perform_socket_read(socket_t desc, char *read_point,size_t space_left);
 120  ssize_t perform_socket_write(socket_t desc, const char *txt,size_t length);
 121  void echo_off(struct descriptor_data *d);
 122  void echo_on(struct descriptor_data *d);
 123  void circle_sleep(struct timeval *timeout);
 124  int get_from_q(struct txt_q *queue, char *dest, int *aliased);
 125  void init_game(ush_int port);
 126  void signal_setup(void);
 127  void game_loop(socket_t mother_desc);
 128  socket_t init_socket(ush_int port);
 129  int new_descriptor(socket_t s);
 130  int get_max_players(void);
 131  int process_output(struct descriptor_data *t);
 132  int process_input(struct descriptor_data *t);
 133  void timediff(struct timeval *diff, struct timeval *a, struct timeval *b);
 134  void timeadd(struct timeval *sum, struct timeval *a, struct timeval *b);
 135  void flush_queues(struct descriptor_data *d);
 136  void nonblock(socket_t s);
 137  int perform_subst(struct descriptor_data *t, char *orig, char *subst);
 138  void record_usage(void);
 139  char *make_prompt(struct descriptor_data *point);
 140  void check_idle_passwords(void);
 141  void heartbeat(int pulse);
 142  struct in_addr *get_bind_addr(void);
 143  int parse_ip(const char *addr, struct in_addr *inaddr);
 144  int set_sendbuf(socket_t s);
 145  void setup_log(const char *filename, int fd);
 146  int open_logfile(const char *filename, FILE *stderr_fp);
 147  #if defined(POSIX)
 148  sigfunc *my_signal(int signo, sigfunc *func);
 149  #endif
 150  
 151  /* extern fcnts */
 152  void reboot_wizlists(void);
 153  void boot_world(void);
 154  void affect_update(void);	/* In magic.c */
 155  void mobile_activity(void);
 156  void perform_violence(void);
 157  void show_string(struct descriptor_data *d, char *input);
 158  int isbanned(char *hostname);
 159  void weather_and_time(int mode);
 160  int perform_alias(struct descriptor_data *d, char *orig, size_t maxlen);
 161  void clear_free_list(void);
 162  void free_messages(void);
 163  void Board_clear_all(void);
 164  void free_social_messages(void);
 165  void Free_Invalid_List(void);
 166  
 167  #ifdef __CXREF__
 168  #undef FD_ZERO
 169  #undef FD_SET
 170  #undef FD_ISSET
 171  #undef FD_CLR
 172  #define FD_ZERO(x)
 173  #define FD_SET(x, y) 0
 174  #define FD_ISSET(x, y) 0
 175  #define FD_CLR(x, y)
 176  #endif
 177  
 178  
 179  /***********************************************************************
 180  *  main game loop and related stuff                                    *
 181  ***********************************************************************/
 182  
 183  #if defined(CIRCLE_WINDOWS) || defined(CIRCLE_MACINTOSH)
 184  
 185  /*
 186   * Windows doesn't have gettimeofday, so we'll simulate it.
 187   * The Mac doesn't have gettimeofday either.
 188   * Borland C++ warns: "Undefined structure 'timezone'"
 189   */
 190  void gettimeofday(struct timeval *t, struct timezone *dummy)
 191  {
 192  #if defined(CIRCLE_WINDOWS)
 193    DWORD millisec = GetTickCount();
 194  #elif defined(CIRCLE_MACINTOSH)
 195    unsigned long int millisec;
 196    millisec = (int)((float)TickCount() * 1000.0 / 60.0);
 197  #endif
 198  
 199    t->tv_sec = (int) (millisec / 1000);
 200    t->tv_usec = (millisec % 1000) * 1000;
 201  }
 202  
 203  #endif	/* CIRCLE_WINDOWS || CIRCLE_MACINTOSH */
 204  
 205  
 206  int main(int argc, char **argv)
 207  {
 208    ush_int port;
 209    int pos = 1;
 210    const char *dir;
 211  
 212  #if CIRCLE_GNU_LIBC_MEMORY_TRACK
 213    mtrace();	/* This must come before any use of malloc(). */
 214  #endif
 215  
 216  #ifdef CIRCLE_MACINTOSH
 217    /*
 218     * ccommand() calls the command line/io redirection dialog box from
 219     * Codewarriors's SIOUX library
 220     */
 221    argc = ccommand(&argv);
 222    /* Initialize the GUSI library calls.  */
 223    GUSIDefaultSetup();
 224  #endif
 225  
 226    port = DFLT_PORT;
 227    dir = DFLT_DIR;
 228  
 229    while ((pos < argc) && (*(argv[pos]) == '-')) {
 230      switch (*(argv[pos] + 1)) {
 231      case 'o':
 232        if (*(argv[pos] + 2))
 233  	LOGNAME = argv[pos] + 2;
 234        else if (++pos < argc)
 235  	LOGNAME = argv[pos];
 236        else {
 237  	puts("SYSERR: File name to log to expected after option -o.");
 238  	exit(1);
 239        }
 240        break;
 241      case 'd':
 242        if (*(argv[pos] + 2))
 243  	dir = argv[pos] + 2;
 244        else if (++pos < argc)
 245  	dir = argv[pos];
 246        else {
 247  	puts("SYSERR: Directory arg expected after option -d.");
 248  	exit(1);
 249        }
 250        break;
 251      case 'm':
 252        mini_mud = 1;
 253        no_rent_check = 1;
 254        puts("Running in minimized mode & with no rent check.");
 255        break;
 256      case 'c':
 257        scheck = 1;
 258        puts("Syntax check mode enabled.");
 259        break;
 260      case 'q':
 261        no_rent_check = 1;
 262        puts("Quick boot mode -- rent check supressed.");
 263        break;
 264      case 'r':
 265        circle_restrict = 1;
 266        puts("Restricting game -- no new players allowed.");
 267        break;
 268      case 's':
 269        no_specials = 1;
 270        puts("Suppressing assignment of special routines.");
 271        break;
 272      case 'h':
 273        /* From: Anil Mahajan <amahajan@proxicom.com> */
 274        printf("Usage: %s [-c] [-m] [-q] [-r] [-s] [-d pathname] [port #]\n"
 275                "  -c             Enable syntax check mode.\n"
 276                "  -d <directory> Specify library directory (defaults to 'lib').\n"
 277                "  -h             Print this command line argument help.\n"
 278                "  -m             Start in mini-MUD mode.\n"
 279  	      "  -o <file>      Write log to <file> instead of stderr.\n"
 280                "  -q             Quick boot (doesn't scan rent for object limits)\n"
 281                "  -r             Restrict MUD -- no new players allowed.\n"
 282                "  -s             Suppress special procedure assignments.\n",
 283  		 argv[0]
 284        );
 285        exit(0);
 286      default:
 287        printf("SYSERR: Unknown option -%c in argument string.\n", *(argv[pos] + 1));
 288        break;
 289      }
 290      pos++;
 291    }
 292  
 293    if (pos < argc) {
 294      if (!isdigit(*argv[pos])) {
 295        printf("Usage: %s [-c] [-m] [-q] [-r] [-s] [-d pathname] [port #]\n", argv[0]);
 296        exit(1);
 297      } else if ((port = atoi(argv[pos])) <= 1024) {
 298        printf("SYSERR: Illegal port number %d.\n", port);
 299        exit(1);
 300      }
 301    }
 302  
 303    /* All arguments have been parsed, try to open log file. */
 304    setup_log(LOGNAME, STDERR_FILENO);
 305  
 306    /*
 307     * Moved here to distinguish command line options and to show up
 308     * in the log if stderr is redirected to a file.
 309     */
 310    log("%s", circlemud_version);
 311  
 312    if (chdir(dir) < 0) {
 313      perror("SYSERR: Fatal error changing to data directory");
 314      exit(1);
 315    }
 316    log("Using %s as data directory.", dir);
 317  
 318    if (scheck)
 319      boot_world();
 320    else {
 321      log("Running game on port %d.", port);
 322      init_game(port);
 323    }
 324  
 325    log("Clearing game world.");
 326    destroy_db();
 327  
 328    if (!scheck) {
 329      log("Clearing other memory.");
 330      free_player_index();	/* db.c */
 331      free_messages();		/* fight.c */
 332      clear_free_list();		/* mail.c */
 333      free_text_files();		/* db.c */
 334      Board_clear_all();		/* boards.c */
 335      free(cmd_sort_info);	/* act.informative.c */
 336      free_social_messages();	/* act.social.c */
 337      free_help();		/* db.c */
 338      Free_Invalid_List();	/* ban.c */
 339    }
 340  
 341    log("Done.");
 342    return (0);
 343  }
 344  
 345  
 346  
 347  /* Init sockets, run game, and cleanup sockets */
 348  void init_game(ush_int port)
 349  {
 350    socket_t mother_desc;
 351  
 352    /* We don't want to restart if we crash before we get up. */
 353    touch(KILLSCRIPT_FILE);
 354  
 355    circle_srandom(time(0));
 356  
 357    log("Finding player limit.");
 358    max_players = get_max_players();
 359  
 360    log("Opening mother connection.");
 361    mother_desc = init_socket(port);
 362  
 363    boot_db();
 364  
 365  #if defined(CIRCLE_UNIX) || defined(CIRCLE_MACINTOSH)
 366    log("Signal trapping.");
 367    signal_setup();
 368  #endif
 369  
 370    /* If we made it this far, we will be able to restart without problem. */
 371    remove(KILLSCRIPT_FILE);
 372  
 373    log("Entering game loop.");
 374  
 375    game_loop(mother_desc);
 376  
 377    Crash_save_all();
 378  
 379    log("Closing all sockets.");
 380    while (descriptor_list)
 381      close_socket(descriptor_list);
 382  
 383    CLOSE_SOCKET(mother_desc);
 384    fclose(player_fl);
 385  
 386    log("Saving current MUD time.");
 387    save_mud_time(&time_info);
 388  
 389    if (circle_reboot) {
 390      log("Rebooting.");
 391      exit(52);			/* what's so great about HHGTTG, anyhow? */
 392    }
 393    log("Normal termination of game.");
 394  }
 395  
 396  
 397  
 398  /*
 399   * init_socket sets up the mother descriptor - creates the socket, sets
 400   * its options up, binds it, and listens.
 401   */
 402  socket_t init_socket(ush_int port)
 403  {
 404    socket_t s;
 405    struct sockaddr_in sa;
 406    int opt;
 407  
 408  #ifdef CIRCLE_WINDOWS
 409    {
 410      WORD wVersionRequested;
 411      WSADATA wsaData;
 412  
 413      wVersionRequested = MAKEWORD(1, 1);
 414  
 415      if (WSAStartup(wVersionRequested, &wsaData) != 0) {
 416        log("SYSERR: WinSock not available!");
 417        exit(1);
 418      }
 419  
 420      /*
 421       * 4 = stdin, stdout, stderr, mother_desc.  Windows might
 422       * keep sockets and files separate, in which case this isn't
 423       * necessary, but we will err on the side of caution.
 424       */
 425      if ((wsaData.iMaxSockets - 4) < max_players) {
 426        max_players = wsaData.iMaxSockets - 4;
 427      }
 428      log("Max players set to %d", max_players);
 429  
 430      if ((s = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
 431        log("SYSERR: Error opening network connection: Winsock error #%d",
 432  	  WSAGetLastError());
 433        exit(1);
 434      }
 435    }
 436  #else
 437    /*
 438     * Should the first argument to socket() be AF_INET or PF_INET?  I don't
 439     * know, take your pick.  PF_INET seems to be more widely adopted, and
 440     * Comer (_Internetworking with TCP/IP_) even makes a point to say that
 441     * people erroneously use AF_INET with socket() when they should be using
 442     * PF_INET.  However, the man pages of some systems indicate that AF_INET
 443     * is correct; some such as ConvexOS even say that you can use either one.
 444     * All implementations I've seen define AF_INET and PF_INET to be the same
 445     * number anyway, so the point is (hopefully) moot.
 446     */
 447  
 448    if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
 449      perror("SYSERR: Error creating socket");
 450      exit(1);
 451    }
 452  #endif				/* CIRCLE_WINDOWS */
 453  
 454  #if defined(SO_REUSEADDR) && !defined(CIRCLE_MACINTOSH)
 455    opt = 1;
 456    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof(opt)) < 0){
 457      perror("SYSERR: setsockopt REUSEADDR");
 458      exit(1);
 459    }
 460  #endif
 461  
 462    set_sendbuf(s);
 463  
 464  /*
 465   * The GUSI sockets library is derived from BSD, so it defines
 466   * SO_LINGER, even though setsockopt() is unimplimented.
 467   *	(from Dean Takemori <dean@UHHEPH.PHYS.HAWAII.EDU>)
 468   */
 469  #if defined(SO_LINGER) && !defined(CIRCLE_MACINTOSH)
 470    {
 471      struct linger ld;
 472  
 473      ld.l_onoff = 0;
 474      ld.l_linger = 0;
 475      if (setsockopt(s, SOL_SOCKET, SO_LINGER, (char *) &ld, sizeof(ld)) < 0)
 476        perror("SYSERR: setsockopt SO_LINGER");	/* Not fatal I suppose. */
 477    }
 478  #endif
 479  
 480    /* Clear the structure */
 481    memset((char *)&sa, 0, sizeof(sa));
 482  
 483    sa.sin_family = AF_INET;
 484    sa.sin_port = htons(port);
 485    sa.sin_addr = *(get_bind_addr());
 486  
 487    if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
 488      perror("SYSERR: bind");
 489      CLOSE_SOCKET(s);
 490      exit(1);
 491    }
 492    nonblock(s);
 493    listen(s, 5);
 494    return (s);
 495  }
 496  
 497  
 498  int get_max_players(void)
 499  {
 500  #ifndef CIRCLE_UNIX
 501    return (max_playing);
 502  #else
 503  
 504    int max_descs = 0;
 505    const char *method;
 506  
 507  /*
 508   * First, we'll try using getrlimit/setrlimit.  This will probably work
 509   * on most systems.  HAS_RLIMIT is defined in sysdep.h.
 510   */
 511  #ifdef HAS_RLIMIT
 512    {
 513      struct rlimit limit;
 514  
 515      /* find the limit of file descs */
 516      method = "rlimit";
 517      if (getrlimit(RLIMIT_NOFILE, &limit) < 0) {
 518        perror("SYSERR: calling getrlimit");
 519        exit(1);
 520      }
 521  
 522      /* set the current to the maximum */
 523      limit.rlim_cur = limit.rlim_max;
 524      if (setrlimit(RLIMIT_NOFILE, &limit) < 0) {
 525        perror("SYSERR: calling setrlimit");
 526        exit(1);
 527      }
 528  #ifdef RLIM_INFINITY
 529      if (limit.rlim_max == RLIM_INFINITY)
 530        max_descs = max_playing + NUM_RESERVED_DESCS;
 531      else
 532        max_descs = MIN(max_playing + NUM_RESERVED_DESCS, limit.rlim_max);
 533  #else
 534      max_descs = MIN(max_playing + NUM_RESERVED_DESCS, limit.rlim_max);
 535  #endif
 536    }
 537  
 538  #elif defined (OPEN_MAX) || defined(FOPEN_MAX)
 539  #if !defined(OPEN_MAX)
 540  #define OPEN_MAX FOPEN_MAX
 541  #endif
 542    method = "OPEN_MAX";
 543    max_descs = OPEN_MAX;		/* Uh oh.. rlimit didn't work, but we have
 544  				 * OPEN_MAX */
 545  #elif defined (_SC_OPEN_MAX)
 546    /*
 547     * Okay, you don't have getrlimit() and you don't have OPEN_MAX.  Time to
 548     * try the POSIX sysconf() function.  (See Stevens' _Advanced Programming
 549     * in the UNIX Environment_).
 550     */
 551    method = "POSIX sysconf";
 552    errno = 0;
 553    if ((max_descs = sysconf(_SC_OPEN_MAX)) < 0) {
 554      if (errno == 0)
 555        max_descs = max_playing + NUM_RESERVED_DESCS;
 556      else {
 557        perror("SYSERR: Error calling sysconf");
 558        exit(1);
 559      }
 560    }
 561  #else
 562    /* if everything has failed, we'll just take a guess */
 563    method = "random guess";
 564    max_descs = max_playing + NUM_RESERVED_DESCS;
 565  #endif
 566  
 567    /* now calculate max _players_ based on max descs */
 568    max_descs = MIN(max_playing, max_descs - NUM_RESERVED_DESCS);
 569  
 570    if (max_descs <= 0) {
 571      log("SYSERR: Non-positive max player limit!  (Set at %d using %s).",
 572  	    max_descs, method);
 573      exit(1);
 574    }
 575    log("   Setting player limit to %d using %s.", max_descs, method);
 576    return (max_descs);
 577  #endif /* CIRCLE_UNIX */
 578  }
 579  
 580  
 581  
 582  /*
 583   * game_loop contains the main loop which drives the entire MUD.  It
 584   * cycles once every 0.10 seconds and is responsible for accepting new
 585   * new connections, polling existing connections for input, dequeueing
 586   * output and sending it out to players, and calling "heartbeat" functions
 587   * such as mobile_activity().
 588   */
 589  void game_loop(socket_t mother_desc)
 590  {
 591    fd_set input_set, output_set, exc_set, null_set;
 592    struct timeval last_time, opt_time, process_time, temp_time;
 593    struct timeval before_sleep, now, timeout;
 594    char comm[MAX_INPUT_LENGTH];
 595    struct descriptor_data *d, *next_d;
 596    int pulse = 0, missed_pulses, maxdesc, aliased;
 597  
 598    /* initialize various time values */
 599    null_time.tv_sec = 0;
 600    null_time.tv_usec = 0;
 601    opt_time.tv_usec = OPT_USEC;
 602    opt_time.tv_sec = 0;
 603    FD_ZERO(&null_set);
 604  
 605    gettimeofday(&last_time, (struct timezone *) 0);
 606  
 607    /* The Main Loop.  The Big Cheese.  The Top Dog.  The Head Honcho.  The.. */
 608    while (!circle_shutdown) {
 609  
 610      /* Sleep if we don't have any connections */
 611      if (descriptor_list == NULL) {
 612        log("No connections.  Going to sleep.");
 613        FD_ZERO(&input_set);
 614        FD_SET(mother_desc, &input_set);
 615        if (select(mother_desc + 1, &input_set, (fd_set *) 0, (fd_set *) 0, NULL) < 0) {
 616  	if (errno == EINTR)
 617  	  log("Waking up to process signal.");
 618  	else
 619  	  perror("SYSERR: Select coma");
 620        } else
 621  	log("New connection.  Waking up.");
 622        gettimeofday(&last_time, (struct timezone *) 0);
 623      }
 624      /* Set up the input, output, and exception sets for select(). */
 625      FD_ZERO(&input_set);
 626      FD_ZERO(&output_set);
 627      FD_ZERO(&exc_set);
 628      FD_SET(mother_desc, &input_set);
 629  
 630      maxdesc = mother_desc;
 631      for (d = descriptor_list; d; d = d->next) {
 632  #ifndef CIRCLE_WINDOWS
 633        if (d->descriptor > maxdesc)
 634  	maxdesc = d->descriptor;
 635  #endif
 636        FD_SET(d->descriptor, &input_set);
 637        FD_SET(d->descriptor, &output_set);
 638        FD_SET(d->descriptor, &exc_set);
 639      }
 640  
 641      /*
 642       * At this point, we have completed all input, output and heartbeat
 643       * activity from the previous iteration, so we have to put ourselves
 644       * to sleep until the next 0.1 second tick.  The first step is to
 645       * calculate how long we took processing the previous iteration.
 646       */
 647      
 648      gettimeofday(&before_sleep, (struct timezone *) 0); /* current time */
 649      timediff(&process_time, &before_sleep, &last_time);
 650  
 651      /*
 652       * If we were asleep for more than one pass, count missed pulses and sleep
 653       * until we're resynchronized with the next upcoming pulse.
 654       */
 655      if (process_time.tv_sec == 0 && process_time.tv_usec < OPT_USEC) {
 656        missed_pulses = 0;
 657      } else {
 658        missed_pulses = process_time.tv_sec * PASSES_PER_SEC;
 659        missed_pulses += process_time.tv_usec / OPT_USEC;
 660        process_time.tv_sec = 0;
 661        process_time.tv_usec = process_time.tv_usec % OPT_USEC;
 662      }
 663  
 664      /* Calculate the time we should wake up */
 665      timediff(&temp_time, &opt_time, &process_time);
 666      timeadd(&last_time, &before_sleep, &temp_time);
 667  
 668      /* Now keep sleeping until that time has come */
 669      gettimeofday(&now, (struct timezone *) 0);
 670      timediff(&timeout, &last_time, &now);
 671  
 672      /* Go to sleep */
 673      do {
 674        circle_sleep(&timeout);
 675        gettimeofday(&now, (struct timezone *) 0);
 676        timediff(&timeout, &last_time, &now);
 677      } while (timeout.tv_usec || timeout.tv_sec);
 678  
 679      /* Poll (without blocking) for new input, output, and exceptions */
 680      if (select(maxdesc + 1, &input_set, &output_set, &exc_set, &null_time) < 0) {
 681        perror("SYSERR: Select poll");
 682        return;
 683      }
 684      /* If there are new connections waiting, accept them. */
 685      if (FD_ISSET(mother_desc, &input_set))
 686        new_descriptor(mother_desc);
 687  
 688      /* Kick out the freaky folks in the exception set and marked for close */
 689      for (d = descriptor_list; d; d = next_d) {
 690        next_d = d->next;
 691        if (FD_ISSET(d->descriptor, &exc_set)) {
 692  	FD_CLR(d->descriptor, &input_set);
 693  	FD_CLR(d->descriptor, &output_set);
 694  	close_socket(d);
 695        }
 696      }
 697  
 698      /* Process descriptors with input pending */
 699      for (d = descriptor_list; d; d = next_d) {
 700        next_d = d->next;
 701        if (FD_ISSET(d->descriptor, &input_set))
 702  	if (process_input(d) < 0)
 703  	  close_socket(d);
 704      }
 705  
 706      /* Process commands we just read from process_input */
 707      for (d = descriptor_list; d; d = next_d) {
 708        next_d = d->next;
 709  
 710        /*
 711         * Not combined to retain --(d->wait) behavior. -gg 2/20/98
 712         * If no wait state, no subtraction.  If there is a wait
 713         * state then 1 is subtracted. Therefore we don't go less
 714         * than 0 ever and don't require an 'if' bracket. -gg 2/27/99
 715         */
 716        if (d->character) {
 717          GET_WAIT_STATE(d->character) -= (GET_WAIT_STATE(d->character) > 0);
 718  
 719          if (GET_WAIT_STATE(d->character))
 720            continue;
 721        }
 722  
 723        if (!get_from_q(&d->input, comm, &aliased))
 724          continue;
 725  
 726        if (d->character) {
 727  	/* Reset the idle timer & pull char back from void if necessary */
 728  	d->character->char_specials.timer = 0;
 729  	if (STATE(d) == CON_PLAYING && GET_WAS_IN(d->character) != NOWHERE) {
 730  	  if (IN_ROOM(d->character) != NOWHERE)
 731  	    char_from_room(d->character);
 732  	  char_to_room(d->character, GET_WAS_IN(d->character));
 733  	  GET_WAS_IN(d->character) = NOWHERE;
 734  	  act("$n has returned.", TRUE, d->character, 0, 0, TO_ROOM);
 735  	}
 736          GET_WAIT_STATE(d->character) = 1;
 737        }
 738        d->has_prompt = FALSE;
 739  
 740        if (d->str)		/* Writing boards, mail, etc. */
 741  	string_add(d, comm);
 742        else if (d->showstr_count) /* Reading something w/ pager */
 743  	show_string(d, comm);
 744        else if (STATE(d) != CON_PLAYING) /* In menus, etc. */
 745  	nanny(d, comm);
 746        else {			/* else: we're playing normally. */
 747  	if (aliased)		/* To prevent recursive aliases. */
 748  	  d->has_prompt = TRUE;	/* To get newline before next cmd output. */
 749  	else if (perform_alias(d, comm, sizeof(comm)))    /* Run it through aliasing system */
 750  	  get_from_q(&d->input, comm, &aliased);
 751  	command_interpreter(d->character, comm); /* Send it to interpreter */
 752        }
 753      }
 754  
 755      /* Send queued output out to the operating system (ultimately to user). */
 756      for (d = descriptor_list; d; d = next_d) {
 757        next_d = d->next;
 758        if (*(d->output) && FD_ISSET(d->descriptor, &output_set)) {
 759  	/* Output for this player is ready. */
 760  
 761          process_output(d);
 762          if (d->bufptr == 0)	/* All output sent. */
 763            d->has_prompt = TRUE;
 764        }
 765      }
 766  
 767      /* Print prompts for other descriptors who had no other output */
 768      for (d = descriptor_list; d; d = d->next) {
 769        if (!d->has_prompt && d->bufptr == 0) {
 770  	write_to_descriptor(d->descriptor, make_prompt(d));
 771  	d->has_prompt = TRUE;
 772        }
 773      }
 774  
 775      /* Kick out folks in the CON_CLOSE or CON_DISCONNECT state */
 776      for (d = descriptor_list; d; d = next_d) {
 777        next_d = d->next;
 778        if (STATE(d) == CON_CLOSE || STATE(d) == CON_DISCONNECT)
 779  	close_socket(d);
 780      }
 781  
 782      /*
 783       * Now, we execute as many pulses as necessary--just one if we haven't
 784       * missed any pulses, or make up for lost time if we missed a few
 785       * pulses by sleeping for too long.
 786       */
 787      missed_pulses++;
 788  
 789      if (missed_pulses <= 0) {
 790        log("SYSERR: **BAD** MISSED_PULSES NONPOSITIVE (%d), TIME GOING BACKWARDS!!", missed_pulses);
 791        missed_pulses = 1;
 792      }
 793  
 794      /* If we missed more than 30 seconds worth of pulses, just do 30 secs */
 795      if (missed_pulses > 30 RL_SEC) {
 796        log("SYSERR: Missed %d seconds worth of pulses.", missed_pulses / PASSES_PER_SEC);
 797        missed_pulses = 30 RL_SEC;
 798      }
 799  
 800      /* Now execute the heartbeat functions */
 801      while (missed_pulses--)
 802        heartbeat(++pulse);
 803  
 804      /* Check for any signals we may have received. */
 805      if (reread_wizlist) {
 806        reread_wizlist = FALSE;
 807        mudlog(CMP, LVL_IMMORT, TRUE, "Signal received - rereading wizlists.");
 808        reboot_wizlists();
 809      }
 810      if (emergency_unban) {
 811        emergency_unban = FALSE;
 812        mudlog(BRF, LVL_IMMORT, TRUE, "Received SIGUSR2 - completely unrestricting game (emergent)");
 813        ban_list = NULL;
 814        circle_restrict = 0;
 815        num_invalid = 0;
 816      }
 817  
 818      /* Roll pulse over after 10 hours */
 819      if (pulse >= (10 * 60 * 60 * PASSES_PER_SEC))
 820        pulse = 0;
 821  
 822  #ifdef CIRCLE_UNIX
 823      /* Update tics for deadlock protection (UNIX only) */
 824      tics++;
 825  #endif
 826    }
 827  }
 828  
 829  
 830  void heartbeat(int pulse)
 831  {
 832    static int mins_since_crashsave = 0;
 833  
 834    if (!(pulse % PULSE_ZONE))
 835      zone_update();
 836  
 837    if (!(pulse % PULSE_IDLEPWD))		/* 15 seconds */
 838      check_idle_passwords();
 839  
 840    if (!(pulse % PULSE_MOBILE))
 841      mobile_activity();
 842  
 843    if (!(pulse % PULSE_VIOLENCE))
 844      perform_violence();
 845  
 846    if (!(pulse % (SECS_PER_MUD_HOUR * PASSES_PER_SEC))) {
 847      weather_and_time(1);
 848      affect_update();
 849      point_update();
 850      fflush(player_fl);
 851    }
 852  
 853    if (auto_save && !(pulse % PULSE_AUTOSAVE)) {	/* 1 minute */
 854      if (++mins_since_crashsave >= autosave_time) {
 855        mins_since_crashsave = 0;
 856        Crash_save_all();
 857        House_save_all();
 858      }
 859    }
 860  
 861    if (!(pulse % PULSE_USAGE))
 862      record_usage();
 863  
 864    if (!(pulse % PULSE_TIMESAVE))
 865      save_mud_time(&time_info);
 866  
 867    /* Every pulse! Don't want them to stink the place up... */
 868    extract_pending_chars();
 869  }
 870  
 871  
 872  /* ******************************************************************
 873  *  general utility stuff (for local use)                            *
 874  ****************************************************************** */
 875  
 876  /*
 877   *  new code to calculate time differences, which works on systems
 878   *  for which tv_usec is unsigned (and thus comparisons for something
 879   *  being < 0 fail).  Based on code submitted by ss@sirocco.cup.hp.com.
 880   */
 881  
 882  /*
 883   * code to return the time difference between a and b (a-b).
 884   * always returns a nonnegative value (floors at 0).
 885   */
 886  void timediff(struct timeval *rslt, struct timeval *a, struct timeval *b)
 887  {
 888    if (a->tv_sec < b->tv_sec)
 889      *rslt = null_time;
 890    else if (a->tv_sec == b->tv_sec) {
 891      if (a->tv_usec < b->tv_usec)
 892        *rslt = null_time;
 893      else {
 894        rslt->tv_sec = 0;
 895        rslt->tv_usec = a->tv_usec - b->tv_usec;
 896      }
 897    } else {			/* a->tv_sec > b->tv_sec */
 898      rslt->tv_sec = a->tv_sec - b->tv_sec;
 899      if (a->tv_usec < b->tv_usec) {
 900        rslt->tv_usec = a->tv_usec + 1000000 - b->tv_usec;
 901        rslt->tv_sec--;
 902      } else
 903        rslt->tv_usec = a->tv_usec - b->tv_usec;
 904    }
 905  }
 906  
 907  /*
 908   * Add 2 time values.
 909   *
 910   * Patch sent by "d. hall" <dhall@OOI.NET> to fix 'static' usage.
 911   */
 912  void timeadd(struct timeval *rslt, struct timeval *a, struct timeval *b)
 913  {
 914    rslt->tv_sec = a->tv_sec + b->tv_sec;
 915    rslt->tv_usec = a->tv_usec + b->tv_usec;
 916  
 917    while (rslt->tv_usec >= 1000000) {
 918      rslt->tv_usec -= 1000000;
 919      rslt->tv_sec++;
 920    }
 921  }
 922  
 923  
 924  void record_usage(void)
 925  {
 926    int sockets_connected = 0, sockets_playing = 0;
 927    struct descriptor_data *d;
 928  
 929    for (d = descriptor_list; d; d = d->next) {
 930      sockets_connected++;
 931      if (STATE(d) == CON_PLAYING)
 932        sockets_playing++;
 933    }
 934  
 935    log("nusage: %-3d sockets connected, %-3d sockets playing",
 936  	  sockets_connected, sockets_playing);
 937  
 938  #ifdef RUSAGE	/* Not RUSAGE_SELF because it doesn't guarantee prototype. */
 939    {
 940      struct rusage ru;
 941  
 942      getrusage(RUSAGE_SELF, &ru);
 943      log("rusage: user time: %ld sec, system time: %ld sec, max res size: %ld",
 944  	    ru.ru_utime.tv_sec, ru.ru_stime.tv_sec, ru.ru_maxrss);
 945    }
 946  #endif
 947  
 948  }
 949  
 950  
 951  
 952  /*
 953   * Turn off echoing (specific to telnet client)
 954   */
 955  void echo_off(struct descriptor_data *d)
 956  {
 957    char off_string[] =
 958    {
 959      (char) IAC,
 960      (char) WILL,
 961      (char) TELOPT_ECHO,
 962      (char) 0,
 963    };
 964  
 965    write_to_output(d, "%s", off_string);
 966  }
 967  
 968  
 969  /*
 970   * Turn on echoing (specific to telnet client)
 971   */
 972  void echo_on(struct descriptor_data *d)
 973  {
 974    char on_string[] =
 975    {
 976      (char) IAC,
 977      (char) WONT,
 978      (char) TELOPT_ECHO,
 979      (char) 0
 980    };
 981  
 982    write_to_output(d, "%s", on_string);
 983  }
 984  
 985  
 986  char *make_prompt(struct descriptor_data *d)
 987  {
 988    static char prompt[MAX_PROMPT_LENGTH];
 989  
 990    /* Note, prompt is truncated at MAX_PROMPT_LENGTH chars (structs.h) */
 991  
 992    if (d->str)
 993      strcpy(prompt, "] ");	/* strcpy: OK (for 'MAX_PROMPT_LENGTH >= 3') */
 994    else if (d->showstr_count) {
 995      snprintf(prompt, sizeof(prompt),
 996  	    "\r\n[ Return to continue, (q)uit, (r)efresh, (b)ack, or page number (%d/%d) ]",
 997  	    d->showstr_page, d->showstr_count);
 998    } else if (STATE(d) == CON_PLAYING && !IS_NPC(d->character)) {
 999      int count;
1000      size_t len = 0;
1001  
1002      *prompt = '\0';
1003  
1004      if (GET_INVIS_LEV(d->character) && len < sizeof(prompt)) {
1005        count = snprintf(prompt + len, sizeof(prompt) - len, "i%d ", GET_INVIS_LEV(d->character));
1006        if (count >= 0)
1007          len += count;
1008      }
1009  
1010      if (PRF_FLAGGED(d->character, PRF_DISPHP) && len < sizeof(prompt)) {
1011        count = snprintf(prompt + len, sizeof(prompt) - len, "%dH ", GET_HIT(d->character));
1012        if (count >= 0)
1013          len += count;
1014      }
1015  
1016      if (PRF_FLAGGED(d->character, PRF_DISPMANA) && len < sizeof(prompt)) {
1017        count = snprintf(prompt + len, sizeof(prompt) - len, "%dM ", GET_MANA(d->character));
1018        if (count >= 0)
1019          len += count;
1020      }
1021  
1022      if (PRF_FLAGGED(d->character, PRF_DISPMOVE) && len < sizeof(prompt)) {
1023        count = snprintf(prompt + len, sizeof(prompt) - len, "%dV ", GET_MOVE(d->character));
1024        if (count >= 0)
1025          len += count;
1026      }
1027  
1028      if (len < sizeof(prompt))
1029        strncat(prompt, "> ", sizeof(prompt) - len - 1);	/* strncat: OK */
1030    } else if (STATE(d) == CON_PLAYING && IS_NPC(d->character))
1031      snprintf(prompt, sizeof(prompt), "%s> ", GET_NAME(d->character));
1032    else
1033      *prompt = '\0';
1034  
1035    return (prompt);
1036  }
1037  
1038  
1039  /*
1040   * NOTE: 'txt' must be at most MAX_INPUT_LENGTH big.
1041   */
1042  void write_to_q(const char *txt, struct txt_q *queue, int aliased)
1043  {
1044    struct txt_block *newt;
1045  
1046    CREATE(newt, struct txt_block, 1);
1047    newt->text = strdup(txt);
1048    newt->aliased = aliased;
1049  
1050    /* queue empty? */
1051    if (!queue->head) {
1052      newt->next = NULL;
1053      queue->head = queue->tail = newt;
1054    } else {
1055      queue->tail->next = newt;
1056      queue->tail = newt;
1057      newt->next = NULL;
1058    }
1059  }
1060  
1061  
1062  /*
1063   * NOTE: 'dest' must be at least MAX_INPUT_LENGTH big.
1064   */
1065  int get_from_q(struct txt_q *queue, char *dest, int *aliased)
1066  {
1067    struct txt_block *tmp;
1068  
1069    /* queue empty? */
1070    if (!queue->head)
1071      return (0);
1072  
1073    strcpy(dest, queue->head->text);	/* strcpy: OK (mutual MAX_INPUT_LENGTH) */
1074    *aliased = queue->head->aliased;
1075  
1076    tmp = queue->head;
1077    queue->head = queue->head->next;
1078    free(tmp->text);
1079    free(tmp);
1080  
1081    return (1);
1082  }
1083  
1084  
1085  /* Empty the queues before closing connection */
1086  void flush_queues(struct descriptor_data *d)
1087  {
1088    if (d->large_outbuf) {
1089      d->large_outbuf->next = bufpool;
1090      bufpool = d->large_outbuf;
1091    }
1092    while (d->input.head) {
1093      struct txt_block *tmp = d->input.head;
1094      d->input.head = d->input.head->next;
1095      free(tmp->text);
1096      free(tmp);
1097    }
1098  }
1099  
1100  
1101  /* Add a new string to a player's output queue. For outside use. */
1102  size_t write_to_output(struct descriptor_data *t, const char *txt, ...)
1103  {
1104    va_list args;
1105    size_t left;
1106  
1107    va_start(args, txt);
1108    left = vwrite_to_output(t, txt, args);
1109    va_end(args);
1110  
1111    return left;
1112  }
1113  
1114  
1115  /* Add a new string to a player's output queue. */
1116  size_t vwrite_to_output(struct descriptor_data *t, const char *format, va_list args)
1117  {
1118    static char txt[MAX_STRING_LENGTH];
1119    size_t wantsize;
1120    int size;
1121  
1122    /* if we're in the overflow state already, ignore this new output */
1123    if (t->bufspace == 0)
1124      return (0);
1125  
1126    wantsize = size = vsnprintf(txt, sizeof(txt), format, args);
1127    /* If exceeding the size of the buffer, truncate it for the overflow message */
1128    if (size < 0 || wantsize >= sizeof(txt)) {
1129      size = sizeof(txt) - 1;
1130      strcpy(txt + size - strlen(text_overflow), text_overflow);	/* strcpy: OK */
1131    }
1132  
1133    /*
1134     * If the text is too big to fit into even a large buffer, truncate
1135     * the new text to make it fit.  (This will switch to the overflow
1136     * state automatically because t->bufspace will end up 0.)
1137     */
1138    if (size + t->bufptr + 1 > LARGE_BUFSIZE) {
1139      size = LARGE_BUFSIZE - t->bufptr - 1;
1140      txt[size] = '\0';
1141      buf_overflows++;
1142    }
1143  
1144    /*
1145     * If we have enough space, just write to buffer and that's it! If the
1146     * text just barely fits, then it's switched to a large buffer instead.
1147     */
1148    if (t->bufspace > size) {
1149      strcpy(t->output + t->bufptr, txt);	/* strcpy: OK (size checked above) */
1150      t->bufspace -= size;
1151      t->bufptr += size;
1152      return (t->bufspace);
1153    }
1154  
1155    buf_switches++;
1156  
1157    /* if the pool has a buffer in it, grab it */
1158    if (bufpool != NULL) {
1159      t->large_outbuf = bufpool;
1160      bufpool = bufpool->next;
1161    } else {			/* else create a new one */
1162      CREATE(t->large_outbuf, struct txt_block, 1);
1163      CREATE(t->large_outbuf->text, char, LARGE_BUFSIZE);
1164      buf_largecount++;
1165    }
1166  
1167    strcpy(t->large_outbuf->text, t->output);	/* strcpy: OK (size checked previously) */
1168    t->output = t->large_outbuf->text;	/* make big buffer primary */
1169    strcat(t->output, txt);	/* strcat: OK (size checked) */
1170  
1171    /* set the pointer for the next write */
1172    t->bufptr = strlen(t->output);
1173  
1174    /* calculate how much space is left in the buffer */
1175    t->bufspace = LARGE_BUFSIZE - 1 - t->bufptr;
1176  
1177    return (t->bufspace);
1178  }
1179  
1180  
1181  
1182  /* ******************************************************************
1183  *  socket handling                                                  *
1184  ****************************************************************** */
1185  
1186  
1187  /*
1188   * get_bind_addr: Return a struct in_addr that should be used in our
1189   * call to bind().  If the user has specified a desired binding
1190   * address, we try to bind to it; otherwise, we bind to INADDR_ANY.
1191   * Note that inet_aton() is preferred over inet_addr() so we use it if
1192   * we can.  If neither is available, we always bind to INADDR_ANY.
1193   */
1194  
1195  struct in_addr *get_bind_addr()
1196  {
1197    static struct in_addr bind_addr;
1198  
1199    /* Clear the structure */
1200    memset((char *) &bind_addr, 0, sizeof(bind_addr));
1201  
1202    /* If DLFT_IP is unspecified, use INADDR_ANY */
1203    if (DFLT_IP == NULL) {
1204      bind_addr.s_addr = htonl(INADDR_ANY);
1205    } else {
1206      /* If the parsing fails, use INADDR_ANY */
1207      if (!parse_ip(DFLT_IP, &bind_addr)) {
1208        log("SYSERR: DFLT_IP of %s appears to be an invalid IP address",DFLT_IP);
1209        bind_addr.s_addr = htonl(INADDR_ANY);
1210      }
1211    }
1212  
1213    /* Put the address that we've finally decided on into the logs */
1214    if (bind_addr.s_addr == htonl(INADDR_ANY))
1215      log("Binding to all IP interfaces on this host.");
1216    else
1217      log("Binding only to IP address %s", inet_ntoa(bind_addr));
1218  
1219    return (&bind_addr);
1220  }
1221  
1222  #ifdef HAVE_INET_ATON
1223  
1224  /*
1225   * inet_aton's interface is the same as parse_ip's: 0 on failure, non-0 if
1226   * successful
1227   */
1228  int parse_ip(const char *addr, struct in_addr *inaddr)
1229  {
1230    return (inet_aton(addr, inaddr));
1231  }
1232  
1233  #elif HAVE_INET_ADDR
1234  
1235  /* inet_addr has a different interface, so we emulate inet_aton's */
1236  int parse_ip(const char *addr, struct in_addr *inaddr)
1237  {
1238    long ip;
1239  
1240    if ((ip = inet_addr(addr)) == -1) {
1241      return (0);
1242    } else {
1243      inaddr->s_addr = (unsigned long) ip;
1244      return (1);
1245    }
1246  }
1247  
1248  #else
1249  
1250  /* If you have neither function - sorry, you can't do specific binding. */
1251  int parse_ip(const char *addr, struct in_addr *inaddr)
1252  {
1253    log("SYSERR: warning: you're trying to set DFLT_IP but your system has no "
1254        "functions to parse IP addresses (how bizarre!)");
1255    return (0);
1256  }
1257  
1258  #endif /* INET_ATON and INET_ADDR */
1259  
1260  
1261  
1262  /* Sets the kernel's send buffer size for the descriptor */
1263  int set_sendbuf(socket_t s)
1264  {
1265  #if defined(SO_SNDBUF) && !defined(CIRCLE_MACINTOSH)
1266    int opt = MAX_SOCK_BUF;
1267  
1268    if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *) &opt, sizeof(opt)) < 0) {
1269      perror("SYSERR: setsockopt SNDBUF");
1270      return (-1);
1271    }
1272  
1273  #if 0
1274    if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *) &opt, sizeof(opt)) < 0) {
1275      perror("SYSERR: setsockopt RCVBUF");
1276      return (-1);
1277    }
1278  #endif
1279  
1280  #endif
1281  
1282    return (0);
1283  }
1284  
1285  int new_descriptor(socket_t s)
1286  {
1287    socket_t desc;
1288    int sockets_connected = 0;
1289    socklen_t i;
1290    static int last_desc = 0;	/* last descriptor number */
1291    struct descriptor_data *newd;
1292    struct sockaddr_in peer;
1293    struct hostent *from;
1294  
1295    /* accept the new connection */
1296    i = sizeof(peer);
1297    if ((desc = accept(s, (struct sockaddr *) &peer, &i)) == INVALID_SOCKET) {
1298      perror("SYSERR: accept");
1299      return (-1);
1300    }
1301    /* keep it from blocking */
1302    nonblock(desc);
1303  
1304    /* set the send buffer size */
1305    if (set_sendbuf(desc) < 0) {
1306      CLOSE_SOCKET(desc);
1307      return (0);
1308    }
1309  
1310    /* make sure we have room for it */
1311    for (newd = descriptor_list; newd; newd = newd->next)
1312      sockets_connected++;
1313  
1314    if (sockets_connected >= max_players) {
1315      write_to_descriptor(desc, "Sorry, CircleMUD is full right now... please try again later!\r\n");
1316      CLOSE_SOCKET(desc);
1317      return (0);
1318    }
1319    /* create a new descriptor */
1320    CREATE(newd, struct descriptor_data, 1);
1321  
1322    /* find the sitename */
1323    if (nameserver_is_slow || !(from = gethostbyaddr((char *) &peer.sin_addr,
1324  				      sizeof(peer.sin_addr), AF_INET))) {
1325  
1326      /* resolution failed */
1327      if (!nameserver_is_slow)
1328        perror("SYSERR: gethostbyaddr");
1329  
1330      /* find the numeric site address */
1331      strncpy(newd->host, (char *)inet_ntoa(peer.sin_addr), HOST_LENGTH);	/* strncpy: OK (n->host:HOST_LENGTH+1) */
1332      *(newd->host + HOST_LENGTH) = '\0';
1333    } else {
1334      strncpy(newd->host, from->h_name, HOST_LENGTH);	/* strncpy: OK (n->host:HOST_LENGTH+1) */
1335      *(newd->host + HOST_LENGTH) = '\0';
1336    }
1337  
1338    /* determine if the site is banned */
1339    if (isbanned(newd->host) == BAN_ALL) {
1340      CLOSE_SOCKET(desc);
1341      mudlog(CMP, LVL_GOD, TRUE, "Connection attempt denied from [%s]", newd->host);
1342      free(newd);
1343      return (0);
1344    }
1345  #if 0
1346    /*
1347     * Log new connections - probably unnecessary, but you may want it.
1348     * Note that your immortals may wonder if they see a connection from
1349     * your site, but you are wizinvis upon login.
1350     */
1351    mudlog(CMP, LVL_GOD, FALSE, "New connection from [%s]", newd->host);
1352  #endif
1353  
1354    /* initialize descriptor data */
1355    newd->descriptor = desc;
1356    newd->idle_tics = 0;
1357    newd->output = newd->small_outbuf;
1358    newd->bufspace = SMALL_BUFSIZE - 1;
1359    newd->login_time = time(0);
1360    *newd->output = '\0';
1361    newd->bufptr = 0;
1362    newd->has_prompt = 1;  /* prompt is part of greetings */
1363    STATE(newd) = CON_GET_NAME;
1364  
1365    /*
1366     * This isn't exactly optimal but allows us to make a design choice.
1367     * Do we embed the history in descriptor_data or keep it dynamically
1368     * allocated and allow a user defined history size?
1369     */
1370    CREATE(newd->history, char *, HISTORY_SIZE);
1371  
1372    if (++last_desc == 1000)
1373      last_desc = 1;
1374    newd->desc_num = last_desc;
1375  
1376    /* prepend to list */
1377    newd->next = descriptor_list;
1378    descriptor_list = newd;
1379  
1380    write_to_output(newd, "%s", GREETINGS);
1381  
1382    return (0);
1383  }
1384  
1385  
1386  /*
1387   * Send all of the output that we've accumulated for a player out to
1388   * the player's descriptor.
1389   *
1390   * 32 byte GARBAGE_SPACE in MAX_SOCK_BUF used for:
1391   *	 2 bytes: prepended \r\n
1392   *	14 bytes: overflow message
1393   *	 2 bytes: extra \r\n for non-comapct
1394   *      14 bytes: unused
1395   */
1396  int process_output(struct descriptor_data *t)
1397  {
1398    char i[MAX_SOCK_BUF], *osb = i + 2;
1399    int result;
1400  
1401    /* we may need this \r\n for later -- see below */
1402    strcpy(i, "\r\n");	/* strcpy: OK (for 'MAX_SOCK_BUF >= 3') */
1403  
1404    /* now, append the 'real' output */
1405    strcpy(osb, t->output);	/* strcpy: OK (t->output:LARGE_BUFSIZE < osb:MAX_SOCK_BUF-2) */
1406  
1407    /* if we're in the overflow state, notify the user */
1408    if (t->bufspace == 0)
1409      strcat(osb, "**OVERFLOW**\r\n");	/* strcpy: OK (osb:MAX_SOCK_BUF-2 reserves space) */
1410  
1411    /* add the extra CRLF if the person isn't in compact mode */
1412    if (STATE(t) == CON_PLAYING && t->character && !IS_NPC(t->character) && !PRF_FLAGGED(t->character, PRF_COMPACT))
1413      strcat(osb, "\r\n");	/* strcpy: OK (osb:MAX_SOCK_BUF-2 reserves space) */
1414  
1415    /* add a prompt */
1416    strcat(i, make_prompt(t));	/* strcpy: OK (i:MAX_SOCK_BUF reserves space) */
1417  
1418    /*
1419     * now, send the output.  If this is an 'interruption', use the prepended
1420     * CRLF, otherwise send the straight output sans CRLF.
1421     */
1422    if (t->has_prompt) {
1423      t->has_prompt = FALSE;
1424      result = write_to_descriptor(t->descriptor, i);
1425      if (result >= 2)
1426        result -= 2;
1427    } else
1428      result = write_to_descriptor(t->descriptor, osb);
1429  
1430    if (result < 0) {	/* Oops, fatal error. Bye! */
1431      close_socket(t);
1432      return (-1);
1433    } else if (result == 0)	/* Socket buffer full. Try later. */
1434      return (0);
1435  
1436    /* Handle snooping: prepend "% " and send to snooper. */
1437    if (t->snoop_by)
1438      write_to_output(t->snoop_by, "%% %*s%%%%", result, t->output);
1439  
1440    /* The common case: all saved output was handed off to the kernel buffer. */
1441    if (result >= t->bufptr) {
1442      /*
1443       * if we were using a large buffer, put the large buffer on the buffer pool
1444       * and switch back to the small one
1445       */
1446      if (t->large_outbuf) {
1447        t->large_outbuf->next = bufpool;
1448        bufpool = t->large_outbuf;
1449        t->large_outbuf = NULL;
1450        t->output = t->small_outbuf;
1451      }
1452      /* reset total bufspace back to that of a small buffer */
1453      t->bufspace = SMALL_BUFSIZE - 1;
1454      t->bufptr = 0;
1455      *(t->output) = '\0';
1456  
1457      /*
1458       * If the overflow message or prompt were partially written, try to save
1459       * them. There will be enough space for them if this is true.  'result'
1460       * is effectively unsigned here anyway.
1461       */
1462      if ((unsigned int)result < strlen(osb)) {
1463        size_t savetextlen = strlen(osb + result);
1464  
1465        strcat(t->output, osb + result);
1466        t->bufptr   -= savetextlen;
1467        t->bufspace += savetextlen;
1468      }
1469  
1470    } else {
1471      /* Not all data in buffer sent.  result < output buffersize. */
1472  
1473      strcpy(t->output, t->output + result);	/* strcpy: OK (overlap) */
1474      t->bufptr   -= result;
1475      t->bufspace += result;
1476    }
1477  
1478    return (result);
1479  }
1480  
1481  
1482  /*
1483   * perform_socket_write: takes a descriptor, a pointer to text, and a
1484   * text length, and tries once to send that text to the OS.  This is
1485   * where we stuff all the platform-dependent stuff that used to be
1486   * ugly #ifdef's in write_to_descriptor().
1487   *
1488   * This function must return:
1489   *
1490   * -1  If a fatal error was encountered in writing to the descriptor.
1491   *  0  If a transient failure was encountered (e.g. socket buffer full).
1492   * >0  To indicate the number of bytes successfully written, possibly
1493   *     fewer than the number the caller requested be written.
1494   *
1495   * Right now there are two versions of this function: one for Windows,
1496   * and one for all other platforms.
1497   */
1498  
1499  #if defined(CIRCLE_WINDOWS)
1500  
1501  ssize_t perform_socket_write(socket_t desc, const char *txt, size_t length)
1502  {
1503    ssize_t result;
1504  
1505    result = send(desc, txt, length, 0);
1506  
1507    if (result > 0) {
1508      /* Write was sucessful */
1509      return (result);
1510    }
1511  
1512    if (result == 0) {
1513      /* This should never happen! */
1514      log("SYSERR: Huh??  write() returned 0???  Please report this!");
1515      return (-1);
1516    }
1517  
1518    /* result < 0: An error was encountered. */
1519  
1520    /* Transient error? */
1521    if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINTR)
1522      return (0);
1523  
1524    /* Must be a fatal error. */
1525    return (-1);
1526  }
1527  
1528  #else
1529  
1530  #if defined(CIRCLE_ACORN)
1531  #define write	socketwrite
1532  #endif
1533  
1534  /* perform_socket_write for all Non-Windows platforms */
1535  ssize_t perform_socket_write(socket_t desc, const char *txt, size_t length)
1536  {
1537    ssize_t result;
1538  
1539    result = write(desc, txt, length);
1540  
1541    if (result > 0) {
1542      /* Write was successful. */
1543      return (result);
1544    }
1545  
1546    if (result == 0) {
1547      /* This should never happen! */
1548      log("SYSERR: Huh??  write() returned 0???  Please report this!");
1549      return (-1);
1550    }
1551  
1552    /*
1553     * result < 0, so an error was encountered - is it transient?
1554     * Unfortunately, different systems use different constants to
1555     * indicate this.
1556     */
1557  
1558  #ifdef EAGAIN		/* POSIX */
1559    if (errno == EAGAIN)
1560      return (0);
1561  #endif
1562  
1563  #ifdef EWOULDBLOCK	/* BSD */
1564    if (errno == EWOULDBLOCK)
1565      return (0);
1566  #endif
1567  
1568  #ifdef EDEADLK		/* Macintosh */
1569    if (errno == EDEADLK)
1570      return (0);
1571  #endif
1572  
1573    /* Looks like the error was fatal.  Too bad. */
1574    return (-1);
1575  }
1576  
1577  #endif /* CIRCLE_WINDOWS */
1578  
1579      
1580  /*
1581   * write_to_descriptor takes a descriptor, and text to write to the
1582   * descriptor.  It keeps calling the system-level write() until all
1583   * the text has been delivered to the OS, or until an error is
1584   * encountered.
1585   *
1586   * Returns:
1587   * >=0  If all is well and good.
1588   *  -1  If an error was encountered, so that the player should be cut off.
1589   */
1590  int write_to_descriptor(socket_t desc, const char *txt)
1591  {
1592    ssize_t bytes_written;
1593    size_t total = strlen(txt), write_total = 0;
1594  
1595    while (total > 0) {
1596      bytes_written = perform_socket_write(desc, txt, total);
1597  
1598      if (bytes_written < 0) {
1599        /* Fatal error.  Disconnect the player. */
1600        perror("SYSERR: Write to socket");
1601        return (-1);
1602      } else if (bytes_written == 0) {
1603        /* Temporary failure -- socket buffer full. */
1604        return (write_total);
1605      } else {
1606        txt += bytes_written;
1607        total -= bytes_written;
1608        write_total += bytes_written;
1609      }
1610    }
1611  
1612    return (write_total);
1613  }
1614  
1615  
1616  /*
1617   * Same information about perform_socket_write applies here. I like
1618   * standards, there are so many of them. -gg 6/30/98
1619   */
1620  ssize_t perform_socket_read(socket_t desc, char *read_point, size_t space_left)
1621  {
1622    ssize_t ret;
1623  
1624  #if defined(CIRCLE_ACORN)
1625    ret = recv(desc, read_point, space_left, MSG_DONTWAIT);
1626  #elif defined(CIRCLE_WINDOWS)
1627    ret = recv(desc, read_point, space_left, 0);
1628  #else
1629    ret = read(desc, read_point, space_left);
1630  #endif
1631  
1632    /* Read was successful. */
1633    if (ret > 0)
1634      return (ret);
1635  
1636    /* read() returned 0, meaning we got an EOF. */
1637    if (ret == 0) {
1638      log("WARNING: EOF on socket read (connection broken by peer)");
1639      return (-1);
1640    }
1641  
1642    /*
1643     * read returned a value < 0: there was an error
1644     */
1645  
1646  #if defined(CIRCLE_WINDOWS)	/* Windows */
1647    if (WSAGetLastError() == WSAEWOULDBLOCK || WSAGetLastError() == WSAEINTR)
1648      return (0);
1649  #else
1650  
1651  #ifdef EINTR		/* Interrupted system call - various platforms */
1652    if (errno == EINTR)
1653      return (0);
1654  #endif
1655  
1656  #ifdef EAGAIN		/* POSIX */
1657    if (errno == EAGAIN)
1658      return (0);
1659  #endif
1660  
1661  #ifdef EWOULDBLOCK	/* BSD */
1662    if (errno == EWOULDBLOCK)
1663      return (0);
1664  #endif /* EWOULDBLOCK */
1665  
1666  #ifdef EDEADLK		/* Macintosh */
1667    if (errno == EDEADLK)
1668      return (0);
1669  #endif
1670  
1671  #ifdef ECONNRESET
1672    if (errno == ECONNRESET)
1673      return (-1);
1674  #endif
1675  
1676  #endif /* CIRCLE_WINDOWS */
1677  
1678    /*
1679     * We don't know what happened, cut them off. This qualifies for
1680     * a SYSERR because we have no idea what happened at this point.
1681     */
1682    perror("SYSERR: perform_socket_read: about to lose connection");
1683    return (-1);
1684  }
1685  
1686  /*
1687   * ASSUMPTION: There will be no newlines in the raw input buffer when this
1688   * function is called.  We must maintain that before returning.
1689   *
1690   * Ever wonder why 'tmp' had '+8' on it?  The crusty old code could write
1691   * MAX_INPUT_LENGTH+1 bytes to 'tmp' if there was a '$' as the final
1692   * character in the input buffer.  This would also cause 'space_left' to
1693   * drop to -1, which wasn't very happy in an unsigned variable.  Argh.
1694   * So to fix the above, 'tmp' lost the '+8' since it doesn't need it
1695   * and the code has been changed to reserve space by accepting one less
1696   * character. (Do you really need 256 characters on a line?)
1697   * -gg 1/21/2000
1698   */
1699  int process_input(struct descriptor_data *t)
1700  {
1701    int buf_length, failed_subst;
1702    ssize_t bytes_read;
1703    size_t space_left;
1704    char *ptr, *read_point, *write_point, *nl_pos = NULL;
1705    char tmp[MAX_INPUT_LENGTH];
1706  
1707    /* first, find the point where we left off reading data */
1708    buf_length = strlen(t->inbuf);
1709    read_point = t->inbuf + buf_length;
1710    space_left = MAX_RAW_INPUT_LENGTH - buf_length - 1;
1711  
1712    do {
1713      if (space_left <= 0) {
1714        log("WARNING: process_input: about to close connection: input overflow");
1715        return (-1);
1716      }
1717  
1718      bytes_read = perform_socket_read(t->descriptor, read_point, space_left);
1719  
1720      if (bytes_read < 0)	/* Error, disconnect them. */
1721        return (-1);
1722      else if (bytes_read == 0)	/* Just blocking, no problems. */
1723        return (0);
1724  
1725      /* at this point, we know we got some data from the read */
1726  
1727      *(read_point + bytes_read) = '\0';	/* terminate the string */
1728  
1729      /* search for a newline in the data we just read */
1730      for (ptr = read_point; *ptr && !nl_pos; ptr++)
1731        if (ISNEWL(*ptr))
1732  	nl_pos = ptr;
1733  
1734      read_point += bytes_read;
1735      space_left -= bytes_read;
1736  
1737  /*
1738   * on some systems such as AIX, POSIX-standard nonblocking I/O is broken,
1739   * causing the MUD to hang when it encounters input not terminated by a
1740   * newline.  This was causing hangs at the Password: prompt, for example.
1741   * I attempt to compensate by always returning after the _first_ read, instead
1742   * of looping forever until a read returns -1.  This simulates non-blocking
1743   * I/O because the result is we never call read unless we know from select()
1744   * that data is ready (process_input is only called if select indicates that
1745   * this descriptor is in the read set).  JE 2/23/95.
1746   */
1747  #if !defined(POSIX_NONBLOCK_BROKEN)
1748    } while (nl_pos == NULL);
1749  #else
1750    } while (0);
1751  
1752    if (nl_pos == NULL)
1753      return (0);
1754  #endif /* POSIX_NONBLOCK_BROKEN */
1755  
1756    /*
1757     * okay, at this point we have at least one newline in the string; now we
1758     * can copy the formatted data to a new array for further processing.
1759     */
1760  
1761    read_point = t->inbuf;
1762  
1763    while (nl_pos != NULL) {
1764      write_point = tmp;
1765      space_left = MAX_INPUT_LENGTH - 1;
1766  
1767      /* The '> 1' reserves room for a '$ => $$' expansion. */
1768      for (ptr = read_point; (space_left > 1) && (ptr < nl_pos); ptr++) {
1769        if (*ptr == '\b' || *ptr == 127) { /* handle backspacing or delete key */
1770  	if (write_point > tmp) {
1771  	  if (*(--write_point) == '$') {
1772  	    write_point--;
1773  	    space_left += 2;
1774  	  } else
1775  	    space_left++;
1776  	}
1777        } else if (isascii(*ptr) && isprint(*ptr)) {
1778  	if ((*(write_point++) = *ptr) == '$') {		/* copy one character */
1779  	  *(write_point++) = '$';	/* if it's a $, double it */
1780  	  space_left -= 2;
1781  	} else
1782  	  space_left--;
1783        }
1784      }
1785  
1786      *write_point = '\0';
1787  
1788      if ((space_left <= 0) && (ptr < nl_pos)) {
1789        char buffer[MAX_INPUT_LENGTH + 64];
1790  
1791        snprintf(buffer, sizeof(buffer), "Line too long.  Truncated to:\r\n%s\r\n", tmp);
1792        if (write_to_descriptor(t->descriptor, buffer) < 0)
1793  	return (-1);
1794      }
1795      if (t->snoop_by)
1796        write_to_output(t->snoop_by, "%% %s\r\n", tmp);
1797      failed_subst = 0;
1798  
1799      if (*tmp == '!' && !(*(tmp + 1)))	/* Redo last command. */
1800        strcpy(tmp, t->last_input);	/* strcpy: OK (by mutual MAX_INPUT_LENGTH) */
1801      else if (*tmp == '!' && *(tmp + 1)) {
1802        char *commandln = (tmp + 1);
1803        int starting_pos = t->history_pos,
1804  	  cnt = (t->history_pos == 0 ? HISTORY_SIZE - 1 : t->history_pos - 1);
1805  
1806        skip_spaces(&commandln);
1807        for (; cnt != starting_pos; cnt--) {
1808  	if (t->history[cnt] && is_abbrev(commandln, t->history[cnt])) {
1809  	  strcpy(tmp, t->history[cnt]);	/* strcpy: OK (by mutual MAX_INPUT_LENGTH) */
1810  	  strcpy(t->last_input, tmp);	/* strcpy: OK (by mutual MAX_INPUT_LENGTH) */
1811            write_to_output(t, "%s\r\n", tmp);
1812  	  break;
1813  	}
1814          if (cnt == 0)	/* At top, loop to bottom. */
1815  	  cnt = HISTORY_SIZE;
1816        }
1817      } else if (*tmp == '^') {
1818        if (!(failed_subst = perform_subst(t, t->last_input, tmp)))
1819  	strcpy(t->last_input, tmp);	/* strcpy: OK (by mutual MAX_INPUT_LENGTH) */
1820      } else {
1821        strcpy(t->last_input, tmp);	/* strcpy: OK (by mutual MAX_INPUT_LENGTH) */
1822        if (t->history[t->history_pos])
1823  	free(t->history[t->history_pos]);	/* Clear the old line. */
1824        t->history[t->history_pos] = strdup(tmp);	/* Save the new. */
1825        if (++t->history_pos >= HISTORY_SIZE)	/* Wrap to top. */
1826  	t->history_pos = 0;
1827      }
1828  
1829      if (!failed_subst)
1830        write_to_q(tmp, &t->input, 0);
1831  
1832      /* find the end of this line */
1833      while (ISNEWL(*nl_pos))
1834        nl_pos++;
1835  
1836      /* see if there's another newline in the input buffer */
1837      read_point = ptr = nl_pos;
1838      for (nl_pos = NULL; *ptr && !nl_pos; ptr++)
1839        if (ISNEWL(*ptr))
1840  	nl_pos = ptr;
1841    }
1842  
1843    /* now move the rest of the buffer up to the beginning for the next pass */
1844    write_point = t->inbuf;
1845    while (*read_point)
1846      *(write_point++) = *(read_point++);
1847    *write_point = '\0';
1848  
1849    return (1);
1850  }
1851  
1852  
1853  
1854  /* perform substitution for the '^..^' csh-esque syntax orig is the
1855   * orig string, i.e. the one being modified.  subst contains the
1856   * substition string, i.e. "^telm^tell"
1857   */
1858  int perform_subst(struct descriptor_data *t, char *orig, char *subst)
1859  {
1860    char newsub[MAX_INPUT_LENGTH + 5];
1861  
1862    char *first, *second, *strpos;
1863  
1864    /*
1865     * first is the position of the beginning of the first string (the one
1866     * to be replaced
1867     */
1868    first = subst + 1;
1869  
1870    /* now find the second '^' */
1871    if (!(second = strchr(first, '^'))) {
1872      write_to_output(t, "Invalid substitution.\r\n");
1873      return (1);
1874    }
1875    /* terminate "first" at the position of the '^' and make 'second' point
1876     * to the beginning of the second string */
1877    *(second++) = '\0';
1878  
1879    /* now, see if the contents of the first string appear in the original */
1880    if (!(strpos = strstr(orig, first))) {
1881      write_to_output(t, "Invalid substitution.\r\n");
1882      return (1);
1883    }
1884    /* now, we construct the new string for output. */
1885  
1886    /* first, everything in the original, up to the string to be replaced */
1887    strncpy(newsub, orig, strpos - orig);	/* strncpy: OK (newsub:MAX_INPUT_LENGTH+5 > orig:MAX_INPUT_LENGTH) */
1888    newsub[strpos - orig] = '\0';
1889  
1890    /* now, the replacement string */
1891    strncat(newsub, second, MAX_INPUT_LENGTH - strlen(newsub) - 1);	/* strncpy: OK */
1892  
1893    /* now, if there's anything left in the original after the string to
1894     * replaced, copy that too. */
1895    if (((strpos - orig) + strlen(first)) < strlen(orig))
1896      strncat(newsub, strpos + strlen(first), MAX_INPUT_LENGTH - strlen(newsub) - 1);	/* strncpy: OK */
1897  
1898    /* terminate the string in case of an overflow from strncat */
1899    newsub[MAX_INPUT_LENGTH - 1] = '\0';
1900    strcpy(subst, newsub);	/* strcpy: OK (by mutual MAX_INPUT_LENGTH) */
1901  
1902    return (0);
1903  }
1904  
1905  
1906  
1907  void close_socket(struct descriptor_data *d)
1908  {
1909    struct descriptor_data *temp;
1910  
1911    REMOVE_FROM_LIST(d, descriptor_list, next);
1912    CLOSE_SOCKET(d->descriptor);
1913    flush_queues(d);
1914  
1915    /* Forget snooping */
1916    if (d->snooping)
1917      d->snooping->snoop_by = NULL;
1918  
1919    if (d->snoop_by) {
1920      write_to_output(d->snoop_by, "Your victim is no longer among us.\r\n");
1921      d->snoop_by->snooping = NULL;
1922    }
1923  
1924    if (d->character) {
1925      /* If we're switched, this resets the mobile taken. */
1926      d->character->desc = NULL;
1927  
1928      /* Plug memory leak, from Eric Green. */
1929      if (!IS_NPC(d->character) && PLR_FLAGGED(d->character, PLR_MAILING) && d->str) {
1930        if (*(d->str))
1931          free(*(d->str));
1932        free(d->str);
1933      }
1934  
1935      if (STATE(d) == CON_PLAYING || STATE(d) == CON_DISCONNECT) {
1936        struct char_data *link_challenged = d->original ? d->original : d->character;
1937  
1938        /* We are guaranteed to have a person. */
1939        act("$n has lost $s link.", TRUE, link_challenged, 0, 0, TO_ROOM);
1940        save_char(link_challenged);
1941        mudlog(NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(link_challenged)), TRUE, "Closing link to: %s.", GET_NAME(link_challenged));
1942      } else {
1943        mudlog(CMP, LVL_IMMORT, TRUE, "Losing player: %s.", GET_NAME(d->character) ? GET_NAME(d->character) : "<null>");
1944        free_char(d->character);
1945      }
1946    } else
1947      mudlog(CMP, LVL_IMMORT, TRUE, "Losing descriptor without char.");
1948  
1949    /* JE 2/22/95 -- part of my unending quest to make switch stable */
1950    if (d->original && d->original->desc)
1951      d->original->desc = NULL;
1952  
1953    /* Clear the command history. */
1954    if (d->history) {
1955      int cnt;
1956      for (cnt = 0; cnt < HISTORY_SIZE; cnt++)
1957        if (d->history[cnt])
1958  	free(d->history[cnt]);
1959      free(d->history);
1960    }
1961  
1962    if (d->showstr_head)
1963      free(d->showstr_head);
1964    if (d->showstr_count)
1965      free(d->showstr_vector);
1966  
1967    free(d);
1968  }
1969  
1970  
1971  
1972  void check_idle_passwords(void)
1973  {
1974    struct descriptor_data *d, *next_d;
1975  
1976    for (d = descriptor_list; d; d = next_d) {
1977      next_d = d->next;
1978      if (STATE(d) != CON_PASSWORD && STATE(d) != CON_GET_NAME)
1979        continue;
1980      if (!d->idle_tics) {
1981        d->idle_tics++;
1982        continue;
1983      } else {
1984        echo_on(d);
1985        write_to_output(d, "\r\nTimed out... goodbye.\r\n");
1986        STATE(d) = CON_CLOSE;
1987      }
1988    }
1989  }
1990  
1991  
1992  
1993  /*
1994   * I tried to universally convert Circle over to POSIX compliance, but
1995   * alas, some systems are still straggling behind and don't have all the
1996   * appropriate defines.  In particular, NeXT 2.x defines O_NDELAY but not
1997   * O_NONBLOCK.  Krusty old NeXT machines!  (Thanks to Michael Jones for
1998   * this and various other NeXT fixes.)
1999   */
2000  
2001  #if defined(CIRCLE_WINDOWS)
2002  
2003  void nonblock(socket_t s)
2004  {
2005    unsigned long val = 1;
2006    ioctlsocket(s, FIONBIO, &val);
2007  }
2008  
2009  #elif defined(CIRCLE_AMIGA)
2010  
2011  void nonblock(socket_t s)
2012  {
2013    long val = 1;
2014    IoctlSocket(s, FIONBIO, &val);
2015  }
2016  
2017  #elif defined(CIRCLE_ACORN)
2018  
2019  void nonblock(socket_t s)
2020  {
2021    int val = 1;
2022    socket_ioctl(s, FIONBIO, &val);
2023  }
2024  
2025  #elif defined(CIRCLE_VMS)
2026  
2027  void nonblock(socket_t s)
2028  {
2029    int val = 1;
2030  
2031    if (ioctl(s, FIONBIO, &val) < 0) {
2032      perror("SYSERR: Fatal error executing nonblock (comm.c)");
2033      exit(1);
2034    }
2035  }
2036  
2037  #elif defined(CIRCLE_UNIX) || defined(CIRCLE_OS2) || defined(CIRCLE_MACINTOSH)
2038  
2039  #ifndef O_NONBLOCK
2040  #define O_NONBLOCK O_NDELAY
2041  #endif
2042  
2043  void nonblock(socket_t s)
2044  {
2045    int flags;
2046  
2047    flags = fcntl(s, F_GETFL, 0);
2048    flags |= O_NONBLOCK;
2049    if (fcntl(s, F_SETFL, flags) < 0) {
2050      perror("SYSERR: Fatal error executing nonblock (comm.c)");
2051      exit(1);
2052    }
2053  }
2054  
2055  #endif  /* CIRCLE_UNIX || CIRCLE_OS2 || CIRCLE_MACINTOSH */
2056  
2057  
2058  /* ******************************************************************
2059  *  signal-handling functions (formerly signals.c).  UNIX only.      *
2060  ****************************************************************** */
2061  
2062  #if defined(CIRCLE_UNIX) || defined(CIRCLE_MACINTOSH)
2063  
2064  RETSIGTYPE reread_wizlists(int sig)
2065  {
2066    reread_wizlist = TRUE;
2067  }
2068  
2069  
2070  RETSIGTYPE unrestrict_game(int sig)
2071  {
2072    emergency_unban = TRUE;
2073  }
2074  
2075  #ifdef CIRCLE_UNIX
2076  
2077  /* clean up our zombie kids to avoid defunct processes */
2078  RETSIGTYPE reap(int sig)
2079  {
2080    while (waitpid(-1, NULL, WNOHANG) > 0);
2081  
2082    my_signal(SIGCHLD, reap);
2083  }
2084  
2085  /* Dying anyway... */
2086  RETSIGTYPE checkpointing(int sig)
2087  {
2088    if (!tics) {
2089      log("SYSERR: CHECKPOINT shutdown: tics not updated. (Infinite loop suspected)");
2090      abort();
2091    } else
2092      tics = 0;
2093  }
2094  
2095  
2096  /* Dying anyway... */
2097  RETSIGTYPE hupsig(int sig)
2098  {
2099    log("SYSERR: Received SIGHUP, SIGINT, or SIGTERM.  Shutting down...");
2100    exit(1);			/* perhaps something more elegant should
2101  				 * substituted */
2102  }
2103  
2104  #endif	/* CIRCLE_UNIX */
2105  
2106  /*
2107   * This is an implementation of signal() using sigaction() for portability.
2108   * (sigaction() is POSIX; signal() is not.)  Taken from Stevens' _Advanced
2109   * Programming in the UNIX Environment_.  We are specifying that all system
2110   * calls _not_ be automatically restarted for uniformity, because BSD systems
2111   * do not restart select(), even if SA_RESTART is used.
2112   *
2113   * Note that NeXT 2.x is not POSIX and does not have sigaction; therefore,
2114   * I just define it to be the old signal.  If your system doesn't have
2115   * sigaction either, you can use the same fix.
2116   *
2117   * SunOS Release 4.0.2 (sun386) needs this too, according to Tim Aldric.
2118   */
2119  
2120  #ifndef POSIX
2121  #define my_signal(signo, func) signal(signo, func)
2122  #else
2123  sigfunc *my_signal(int signo, sigfunc *func)
2124  {
2125    struct sigaction sact, oact;
2126  
2127    sact.sa_handler = func;
2128    sigemptyset(&sact.sa_mask);
2129    sact.sa_flags = 0;
2130  #ifdef SA_INTERRUPT
2131    sact.sa_flags |= SA_INTERRUPT;	/* SunOS */
2132  #endif
2133  
2134    if (sigaction(signo, &sact, &oact) < 0)
2135      return (SIG_ERR);
2136  
2137    return (oact.sa_handler);
2138  }
2139  #endif				/* POSIX */
2140  
2141  
2142  void signal_setup(void)
2143  {
2144  #ifndef CIRCLE_MACINTOSH
2145    struct itimerval itime;
2146    struct timeval interval;
2147  
2148    /* user signal 1: reread wizlists.  Used by autowiz system. */
2149    my_signal(SIGUSR1, reread_wizlists);
2150  
2151    /*
2152     * user signal 2: unrestrict game.  Used for emergencies if you lock
2153     * yourself out of the MUD somehow.  (Duh...)
2154     */
2155    my_signal(SIGUSR2, unrestrict_game);
2156  
2157    /*
2158     * set up the deadlock-protection so that the MUD aborts itself if it gets
2159     * caught in an infinite loop for more than 3 minutes.
2160     */
2161    interval.tv_sec = 180;
2162    interval.tv_usec = 0;
2163    itime.it_interval = interval;
2164    itime.it_value = interval;
2165    setitimer(ITIMER_VIRTUAL, &itime, NULL);
2166    my_signal(SIGVTALRM, checkpointing);
2167  
2168    /* just to be on the safe side: */
2169    my_signal(SIGHUP, hupsig);
2170    my_signal(SIGCHLD, reap);
2171  #endif /* CIRCLE_MACINTOSH */
2172    my_signal(SIGINT, hupsig);
2173    my_signal(SIGTERM, hupsig);
2174    my_signal(SIGPIPE, SIG_IGN);
2175    my_signal(SIGALRM, SIG_IGN);
2176  }
2177  
2178  #endif	/* CIRCLE_UNIX || CIRCLE_MACINTOSH */
2179  
2180  /* ****************************************************************
2181  *       Public routines for system-to-player-communication        *
2182  **************************************************************** */
2183  
2184  size_t send_to_char(struct char_data *ch, const char *messg, ...)
2185  {
2186    if (ch->desc && messg && *messg) {
2187      size_t left;
2188      va_list args;
2189  
2190      va_start(args, messg);
2191      left = vwrite_to_output(ch->desc, messg, args);
2192      va_end(args);
2193      return left;
2194    }
2195    return 0;
2196  }
2197  
2198  
2199  void send_to_all(const char *messg, ...)
2200  {
2201    struct descriptor_data *i;
2202    va_list args;
2203  
2204    if (messg == NULL)
2205      return;
2206  
2207    for (i = descriptor_list; i; i = i->next) {
2208      if (STATE(i) != CON_PLAYING)
2209        continue;
2210  
2211      va_start(args, messg);
2212      vwrite_to_output(i, messg, args);
2213      va_end(args);
2214    }
2215  }
2216  
2217  
2218  void send_to_outdoor(const char *messg, ...)
2219  {
2220    struct descriptor_data *i;
2221  
2222    if (!messg || !*messg)
2223      return;
2224  
2225    for (i = descriptor_list; i; i = i->next) {
2226      va_list args;
2227  
2228      if (STATE(i) != CON_PLAYING || i->character == NULL)
2229        continue;
2230      if (!AWAKE(i->character) || !OUTSIDE(i->character))
2231        continue;
2232  
2233      va_start(args, messg);
2234      vwrite_to_output(i, messg, args);
2235      va_end(args);
2236    }
2237  }
2238  
2239  
2240  
2241  void send_to_room(room_rnum room, const char *messg, ...)
2242  {
2243    struct char_data *i;
2244    va_list args;
2245  
2246    if (messg == NULL)
2247      return;
2248  
2249    for (i = world[room].people; i; i = i->next_in_room) {
2250      if (!i->desc)
2251        continue;
2252  
2253      va_start(args, messg);
2254      vwrite_to_output(i->desc, messg, args);
2255      va_end(args);
2256    }
2257  }
2258  
2259  
2260  
2261  const char *ACTNULL = "<NULL>";
2262  
2263  #define CHECK_NULL(pointer, expression) \
2264    if ((pointer) == NULL) i = ACTNULL; else i = (expression);
2265  
2266  
2267  /* higher-level communication: the act() function */
2268  void perform_act(const char *orig, struct char_data *ch, struct obj_data *obj,
2269  		const void *vict_obj, const struct char_data *to)
2270  {
2271    const char *i = NULL;
2272    char lbuf[MAX_STRING_LENGTH], *buf, *j;
2273    bool uppercasenext = FALSE;
2274  
2275    buf = lbuf;
2276  
2277    for (;;) {
2278      if (*orig == '$') {
2279        switch (*(++orig)) {
2280        case 'n':
2281  	i = PERS(ch, to);
2282  	break;
2283        case 'N':
2284  	CHECK_NULL(vict_obj, PERS((const struct char_data *) vict_obj, to));
2285  	break;
2286        case 'm':
2287  	i = HMHR(ch);
2288  	break;
2289        case 'M':
2290  	CHECK_NULL(vict_obj, HMHR((const struct char_data *) vict_obj));
2291  	break;
2292        case 's':
2293  	i = HSHR(ch);
2294  	break;
2295        case 'S':
2296  	CHECK_NULL(vict_obj, HSHR((const struct char_data *) vict_obj));
2297  	break;
2298        case 'e':
2299  	i = HSSH(ch);
2300  	break;
2301        case 'E':
2302  	CHECK_NULL(vict_obj, HSSH((const struct char_data *) vict_obj));
2303  	break;
2304        case 'o':
2305  	CHECK_NULL(obj, OBJN(obj, to));
2306  	break;
2307        case 'O':
2308  	CHECK_NULL(vict_obj, OBJN((const struct obj_data *) vict_obj, to));
2309  	break;
2310        case 'p':
2311  	CHECK_NULL(obj, OBJS(obj, to));
2312  	break;
2313        case 'P':
2314  	CHECK_NULL(vict_obj, OBJS((const struct obj_data *) vict_obj, to));
2315  	break;
2316        case 'a':
2317  	CHECK_NULL(obj, SANA(obj));
2318  	break;
2319        case 'A':
2320  	CHECK_NULL(vict_obj, SANA((const struct obj_data *) vict_obj));
2321  	break;
2322        case 'T':
2323  	CHECK_NULL(vict_obj, (const char *) vict_obj);
2324  	break;
2325        case 'F':
2326  	CHECK_NULL(vict_obj, fname((const char *) vict_obj));
2327  	break;
2328        /* uppercase previous word */
2329        case 'u':
2330          for (j=buf; j > lbuf && !isspace((int) *(j-1)); j--);
2331          if (j != buf)
2332            *j = UPPER(*j);
2333          i = "";
2334          break;
2335        /* uppercase next word */
2336        case 'U':
2337          uppercasenext = TRUE;
2338          i = "";
2339          break;
2340        case '$':
2341  	i = "$";
2342  	break;
2343        default:
2344  	log("SYSERR: Illegal $-code to act(): %c", *orig);
2345  	log("SYSERR: %s", orig);
2346  	i = "";
2347  	break;
2348        }
2349        while ((*buf = *(i++)))
2350          {
2351          if (uppercasenext && !isspace((int) *buf))
2352            {
2353            *buf = UPPER(*buf);
2354            uppercasenext = FALSE;
2355            }
2356  	buf++;
2357          }
2358        orig++;
2359      } else if (!(*(buf++) = *(orig++))) {
2360        break;
2361      } else if (uppercasenext && !isspace((int) *(buf-1))) {
2362        *(buf-1) = UPPER(*(buf-1));
2363        uppercasenext = FALSE;
2364      }
2365    }
2366  
2367    *(--buf) = '\r';
2368    *(++buf) = '\n';
2369    *(++buf) = '\0';
2370  
2371    write_to_output(to->desc, "%s", CAP(lbuf));
2372  }
2373  
2374  
2375  #define SENDOK(ch)	((ch)->desc && (to_sleeping || AWAKE(ch)) && \
2376  			(IS_NPC(ch) || !PLR_FLAGGED((ch), PLR_WRITING)))
2377  
2378  void act(const char *str, int hide_invisible, struct char_data *ch,
2379  	 struct obj_data *obj, const void *vict_obj, int type)
2380  {
2381    const struct char_data *to;
2382    int to_sleeping;
2383  
2384    if (!str || !*str)
2385      return;
2386  
2387    /*
2388     * Warning: the following TO_SLEEP code is a hack.
2389     * 
2390     * I wanted to be able to tell act to deliver a message regardless of sleep
2391     * without adding an additional argument.  TO_SLEEP is 128 (a single bit
2392     * high up).  It's ONLY legal to combine TO_SLEEP with one other TO_x
2393     * command.  It's not legal to combine TO_x's with each other otherwise.
2394     * TO_SLEEP only works because its value "happens to be" a single bit;
2395     * do not change it to something else.  In short, it is a hack.
2396     */
2397  
2398    /* check if TO_SLEEP is there, and remove it if it is. */
2399    if ((to_sleeping = (type & TO_SLEEP)))
2400      type &= ~TO_SLEEP;
2401  
2402    if (type == TO_CHAR) {
2403      if (ch && SENDOK(ch))
2404        perform_act(str, ch, obj, vict_obj, ch);
2405      return;
2406    }
2407  
2408    if (type == TO_VICT) {
2409      if ((to = (const struct char_data *) vict_obj) != NULL && SENDOK(to))
2410        perform_act(str, ch, obj, vict_obj, to);
2411      return;
2412    }
2413    /* ASSUMPTION: at this point we know type must be TO_NOTVICT or TO_ROOM */
2414  
2415    if (ch && IN_ROOM(ch) != NOWHERE)
2416      to = world[IN_ROOM(ch)].people;
2417    else if (obj && IN_ROOM(obj) != NOWHERE)
2418      to = world[IN_ROOM(obj)].people;
2419    else {
2420      log("SYSERR: no valid target to act()!");
2421      return;
2422    }
2423  
2424    for (; to; to = to->next_in_room) {
2425      if (!SENDOK(to) || (to == ch))
2426        continue;
2427      if (hide_invisible && ch && !CAN_SEE(to, ch))
2428        continue;
2429      if (type != TO_ROOM && to == vict_obj)
2430        continue;
2431      perform_act(str, ch, obj, vict_obj, to);
2432    }
2433  }
2434  
2435  
2436  /* Prefer the file over the descriptor. */
2437  void setup_log(const char *filename, int fd)
2438  {
2439    FILE *s_fp;
2440  
2441  #if defined(__MWERKS__) || defined(__GNUC__)
2442    s_fp = stderr;
2443  #else
2444    if ((s_fp = fdopen(STDERR_FILENO, "w")) == NULL) {
2445      puts("SYSERR: Error opening stderr, trying stdout.");
2446  
2447      if ((s_fp = fdopen(STDOUT_FILENO, "w")) == NULL) {
2448        puts("SYSERR: Error opening stdout, trying a file.");
2449  
2450        /* If we don't have a file, try a default. */
2451        if (filename == NULL || *filename == '\0')
2452          filename = "log/syslog";
2453      }
2454    }
2455  #endif
2456  
2457    if (filename == NULL || *filename == '\0') {
2458      /* No filename, set us up with the descriptor we just opened. */
2459      logfile = s_fp;
2460      puts("Using file descriptor for logging.");
2461      return;
2462    }
2463  
2464    /* We honor the default filename first. */
2465    if (open_logfile(filename, s_fp))
2466      return;
2467  
2468    /* Well, that failed but we want it logged to a file so try a default. */
2469    if (open_logfile("log/syslog", s_fp))
2470      return;
2471  
2472    /* Ok, one last shot at a file. */
2473    if (open_logfile("syslog", s_fp))
2474      return;
2475  
2476    /* Erp, that didn't work either, just die. */
2477    puts("SYSERR: Couldn't open anything to log to, giving up.");
2478    exit(1);
2479  }
2480  
2481  int open_logfile(const char *filename, FILE *stderr_fp)
2482  {
2483    if (stderr_fp)	/* freopen() the descriptor. */
2484      logfile = freopen(filename, "w", stderr_fp);
2485    else
2486      logfile = fopen(filename, "w");
2487  
2488    if (logfile) {
2489      printf("Using log file '%s'%s.\n",
2490  		filename, stderr_fp ? " with redirection" : "");
2491      return (TRUE);
2492    }
2493  
2494    printf("SYSERR: Error opening file '%s': %s\n", filename, strerror(errno));
2495    return (FALSE);
2496  }
2497  
2498  /*
2499   * This may not be pretty but it keeps game_loop() neater than if it was inline.
2500   */
2501  #if defined(CIRCLE_WINDOWS)
2502  
2503  void circle_sleep(struct timeval *timeout)
2504  {
2505    Sleep(timeout->tv_sec * 1000 + timeout->tv_usec / 1000);
2506  }
2507  
2508  #else
2509  
2510  void circle_sleep(struct timeval *timeout)
2511  {
2512    if (select(0, (fd_set *) 0, (fd_set *) 0, (fd_set *) 0, timeout) < 0) {
2513      if (errno != EINTR) {
2514        perror("SYSERR: Select sleep");
2515        exit(1);
2516      }
2517    }
2518  }
2519  
2520  #endif /* CIRCLE_WINDOWS */