untermud/DOC/
untermud/DOC/U/
untermud/DOC/U/U-examples/
untermud/DOC/internals/
untermud/DOC/wizard/
untermud/MISC/
untermud/MISC/dbchk/
untermud/RWHO/
untermud/RWHO/rwhod/
/*
    Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

/* configure all options BEFORE including system stuff. */
#include    "config.h"
#include    "mud.h"
#include    "sym.h"
#include    "sbuf.h"
#include    "vars.h"
#include    "RWHO/rwho.h"

/* GLOBAL !*/
int cron_quantum = 3600;        /* one hour */

static int mud_running = 1;
static char *mud_myname = (char *) 0;


time_t cronlast;
time_t currtime;



static int usage (void)
{
  fprintf (stderr, "usage: mud -c configfile -s startupfile\n");
  return (1);
}




/* choke down a file full of commands */
static int boot_file (char *path)
{
  FILE *bfp;
  char ibuf[BUFSIZ];

  if ((bfp = fopen (path, "rb")) == (FILE *) 0) {
    log_printf ("can't open ", path, ": ", (char *) -1, "\n", (char *) 0);
    return (1);
  }

  while (fgets (ibuf, sizeof (ibuf), bfp) != (char *) 0)
    if (ibuf[0] != '#' && ibuf[0] != '\n')
      (void) run_boot (ibuf);
  fclose (bfp);
  return (0);
}




/* initiate shutdown (used in signal handlers) */
static void shutdown_mud (void)
{
  log_printf ("mud is down.\n", (char *) 0);
  mud_running = 0;
}




/* as simple as possible */
int main (int ac, char **av)
{
  int x;
  char *config = (char *) 0;
  char *startup = (char *) 0;

  for (x = 1; x < ac; x++) {
    if (av[x][0] == '-') {
      switch (av[x][1]) {
      case 'c':
        config = av[++x];
        break;

      case 's':
        startup = av[++x];
        break;
      default:
        return (usage ());
      }
    } else {
      return (usage ());
    }
  }



  /* if there is a configuration file, run it */
  if (config != (char *) 0 && boot_file (config))
    fatal ("configure failed.\n", (char *) 0);


  syminit ();

  WIN32STARTUP
  if (io_init ()) {
    fatal ("network init failed\n", (char *) 0);
    return (1);
  }

  if (cache_init ()) {
    fatal ("cache init failed\n", (char *) 0);
    return (1);
  }


  if (DB_INIT ()) {
    fatal ("database init failed\n", (char *) 0);
    return (1);
  }


  /* all I/O layers are initialized, now run startup file if one */
  if (startup != (char *) 0 && boot_file (startup))
    fatal ("startup failed.\n", (char *) 0);


  /* MUD name must be set */
  if (mud_myname == (char *) 0)
    fatal ("mud server name is unset\n", (char *) 0);

#ifdef  DAEMON
  (void) signal (SIGINT, shutdown_mud);
  (void) signal (SIGTERM, shutdown_mud);
  (void) signal (SIGQUIT, shutdown_mud);
#endif

  while (mud_running) {
    if (io_loop () != 0)
      break;

    /* flush I/O buffers */
    io_sync ();

    /* reset cache pointers */
    cache_reset ();


    /* maintenance/cron routines ? */
    (void) time (&currtime);
    if (currtime - cronlast > cron_quantum) {
      cron_run (currtime);
      cronlast = currtime;
    }

    /* free any temporarily allocated memory */
    tmp_sync ();
  }

  /* orderly shutdown */
  (void) cache_sync ();
  DB_CLOSE ();

#ifdef  USE_RWHO
  rwhocli_shutdown ();
#endif
  return (0);
}




/* return our protected name */
char *mud_getname (void)
{
  return (mud_myname);
}




/* ARGSUSED */
int cmd__mudconfig (int ac, char *av[], char *who, char *aswho)
{
  if (!strcmp (av[1], "shutdown")) {
    log_printf ("shutdown by ", who, "\n", (char *) 0);
    shutdown_mud ();
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "log")) {
    if (ac != 3)
      return (UERR_ARGCNT);
    if (logf_open (av[2]))
      return (UERR_FATAL);
    log_printf ("log is now ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "chdir")) {
    if (ac != 3) {
      log_printf ("chdir: must provide directory.\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (chdir (av[2])) {
      log_printf ("cannot cd to ", av[2], " ", (char *) -1, "\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("working directory is now ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "name")) {
    if (ac != 3 || av[2][0] == '\0') {
      log_printf ("must provide mud name.\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (mud_myname != (char *) 0) {
      log_printf ("mud name is already set!\n", (char *) 0);
      return (UERR_FATAL);
    }
    mud_myname = (char *) malloc ((unsigned) strlen (av[2]) + 1);
    if (mud_myname == (char *) 0)
      fatal ("cannot allocate mud name buffer!\n", (char *) 0);
    (void) strcpy (mud_myname, av[2]);
    log_printf ("mud name is ", mud_myname, "\n", (char *) 0);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "newusers")) {
    if (ac != 3 || av[2][0] == '\0') {
      log_printf ("can only turn on or off newusers!\n", (char *) 0);
    } else if (!strcmp (av[2], "on")) {
      log_printf ("new user logons enabled.\n", (char *) 0);
      newusers = 1;
    } else if (!strcmp (av[2], "off")) {
      log_printf ("new user logons disabled.\n", (char *) 0);
      newusers = 0;
    } else {
      log_printf ("can only turn on or off newusers!\n", (char *) 0);
    }
    return (UERR_NONE);
  }
#ifdef  DAEMON
  /* daemonize ourself */
  if (!strcmp (av[1], "daemonize")) {
    (void) signal (SIGHUP, SIG_IGN);
    (void) signal (SIGCHLD, SIG_IGN);
    (void) signal (SIGALRM, SIG_IGN);
    if (fork ())
      exit (0);
#ifdef  SETSID
    (void) setsid ();
#endif
    log_printf ("daemonized.\n", (char *) 0);
    return (UERR_NONE);
  }
#endif

  /* define a known remote MUD */
  if (!strcmp (av[1], "defmud")) {
    char *timp = (char *) 0;

    if (ac < 9 || ac > 10) {
      log_printf
        ("usage: defmud name host symbolichost remotepassword localpassword port playerport [timeout]\n",
        (char *) 0);
      return (UERR_ARGCNT);
    }
    if (ac == 10)
      timp = av[9];
    if (xmit_def_mudent (av[2], av[3], av[4], av[5], av[6], av[7], av[8],
        timp)) {
      log_printf ("mud entry ", av[2], " NOT defined\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("added mud entry ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "defknownmud")) {
    if (ac != 3) {
      log_printf ("usage: defknownmud name\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (xmit_def_knownmud (av[2])) {
      log_printf ("known-mud entry ", av[2], " NOT defined\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("added known mud ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }

  /* list all global macros */
  if (!strcmp (av[1], "listmac")) {
    if (ac == 2)
      symlist (who, (char *) 0);
    else {
      int junk;
      for (junk = 2; junk < ac; junk++)
        symlist (who, av[junk]);
    }
    return (UERR_NONE);
  }

  /* define a global macro */
  if (!strcmp (av[1], "defmac")) {
    if (ac != 4) {
      log_printf ("usage: defmac name macro\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (symdef (av[2], av[3], SFLG_CMD)) {
      log_printf ("macro defn failed\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("defn macro ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "defUmac")) {
    if (ac != 4) {
      log_printf ("usage: defmac name macro\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (symdef (av[2], av[3], SFLG_UCMD)) {
      log_printf ("macro defn failed\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("defn U-code ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }

  /* mark a macro as priv'd */
  if (!strcmp (av[1], "privmac")) {
    if (ac != 4) {
      log_printf ("usage: privmac macroname owner\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (sympriv (av[2], av[3])) {
      log_printf ("macro setpriv failed\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("setpriv macro ", av[2], " as ", av[3], "\n", (char *) 0);
    return (UERR_NONE);
  }


  /* UNdefine a global macro */
  if (!strcmp (av[1], "undefmac")) {
    if (ac != 3) {
      log_printf ("usage: undefmac name\n", (char *) 0);
      return (UERR_ARGCNT);
    }
    if (symundef (av[2])) {
      log_printf ("macro undefined: ", av[2], "\n", (char *) 0);
      return (UERR_FATAL);
    }
    log_printf ("undefn macro ", av[2], "\n", (char *) 0);
    return (UERR_NONE);
  }
#ifdef  USE_RWHO
  if (!strcmp (av[1], "rwhoserver")) {
    char *info;

    if (ac < 4) {
      log_printf ("usage: rwhoserver hostname password\n", (char *) 0);
      return (UERR_ARGCNT);
    }

    info = ac > 4 ? av[4] : version;

    if (mud_myname == (char *) 0) {
      log_printf ("must set MUD name first\n", (char *) 0);
      return (UERR_FATAL);
    }
    if (rwhocli_setup (av[2], av[3], mud_myname, info)) {
      log_printf ("could not establish RWHO server\n", (char *) 0);
      return (UERR_FATAL);
    }
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "rwhodown")) {
    rwhocli_shutdown ();
    log_printf ("rwho service shut down\n", (char *) 0);
    return (UERR_NONE);
  }

  if (!strcmp (av[1], "rwhoupdate")) {
    update_rwho ();
    return (UERR_NONE);
  }
#endif

  /* backup */
  if (!strcmp (av[1], "backup")) {
    int sequence;
    int modulus = 0;
    char nxbuf[MAXOID];
    char filename[MAXPATHLEN];

    if (ac != 3 && ac != 4) {
      log_printf ("usage: backup <filename> [modulus]\n", (char *) 0);
      return (UERR_ARGCNT);
    }

    /* check for modulus */
    if (ac == 4)
      modulus = atoi (av[3]);

    /* get the backup sequence number */
    if (ut_getnum (system_object, var_bsequence, &sequence))
      sequence = 0;

    sequence++;

    if (modulus > 0)
      sequence %= modulus;

    /* assume this works */
    (void) ut_setnum (who, system_object, var_bsequence, sequence);
    (void) itoa (sequence, nxbuf, 10);

    if (cache_sync ()) {
      log_printf ("couldn't sync cache for backup #",
        nxbuf, "\n", (char *) 0);
      return (UERR_FATAL);
    }
    snprintf (filename, sizeof (filename), "%s.%s", av[2], nxbuf);

    if (DB_BACKUP (filename)) {
      log_printf ("couldn't write backup file ", filename, "\n", (char *) 0);
      return (UERR_FATAL);
    }

    log_printf ("wrote backup file ", filename, "\n", (char *) 0);
    return (UERR_NONE);
  }



  if (!strcmp (av[1], "help")) {
    say (who, av[0], " shutdown\n", (char *) 0);
    say (who, av[0], " log file-name\n", (char *) 0);
    say (who, av[0], " chdir directory-name\n", (char *) 0);
    say (who, av[0], " name mud-name\n", (char *) 0);
#ifdef  DAEMON
    say (who, av[0], " daemonize\n", (char *) 0);
#endif
    say (who, av[0], " newusers [on|off]\n", (char *) 0);
    say (who, av[0],
      " defmud MUDname hostIP-addr hostname remotepassword localpassword serverport playerport [timeout]\n",
      (char *) 0);
    say (who, av[0], " defknownmud MUDname\n", (char *) 0);
    say (who, av[0], " defmac mac-name macro\n", (char *) 0);
    say (who, av[0], " defUmac mac-name U-code\n", (char *) 0);
    say (who, av[0], " undefmac mac-name\n", (char *) 0);
    say (who, av[0], " privmac mac-name object-id\n", (char *) 0);
#ifdef  USE_RWHO
    say (who, av[0], " rwhoserver hostname password [comment]\n", (char *) 0);
    say (who, av[0], " rwhodown\n", (char *) 0);
#endif
    say (who, av[0], " backup file-name [modulus]\n", (char *) 0);
    return (UERR_NONE);
  }

  log_printf ("_mudconfig: I don't understand ", av[1], "\n", (char *) 0);
  return (UERR_NONE);
}