TinyMAZE/
TinyMAZE/config/
TinyMAZE/doc/
TinyMAZE/run/msgs/
TinyMAZE/src/
TinyMAZE/src/db/
TinyMAZE/src/ident/
TinyMAZE/src/io/
TinyMAZE/src/prog/
TinyMAZE/src/softcode/
TinyMAZE/src/util/
#include <stdio.h>
#include <ctype.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#ifdef XENIX
#include <sys/signal.h>
#else
#include <signal.h>
#include <sys/wait.h>
#endif /* xenix */
#include "db.h"
#include "config.h"
#include "externs.h"
#include "commands.h"

/* Declarations */
char dumpfile[1024];
int epoch = 0;   /* Database suffix number */
int reserved;    /* To make sure there's an open file descriptor */
int depth = 0;   /* Excessive recursion prevention */
FILE *db_read_ptr;

#ifdef USE_DEV_URANDOM
int rand_fd = -1; /* For /dev/urandom access */
#endif /* USE_DEV_URANDOM */

OBJ *cmd_plyr = NULL;

static char for_bad[4096];
static OBJ *plyr;
static OBJ *cause_for_bad;

static void no_dbdump P((void));

struct command_struct command_set[] =
{
  {"+ansi",                 do_ansi,                      ARG1},
  {"+channel",              do_channel,                   ARG1|ARG2},
  {"+cmdav",                do_cmdav,                     NOARGS},
  {"+code",                 do_code,                      ARG1|ARG2},
  {"+com",                  do_com,                       ARG1|ARG2},
  {"+dirmail",              do_dirmail,                   PURE},
  {"+email",                do_email,                     ARG1|ARG2},
  {"+eventref",             do_eventref,                  ARG1|ARG2},
  {"+function",             do_function,                  ARG1|ARG2},
  {"+hostlockout",          do_hostlockout,               ARG1|ARG2},
  {"+laston",               do_laston,                    ARG1},
  {"+mail",                 do_mailcmd,                   ARG1|ARG2},
  {"+massmail",             do_massmail,                  ARG1},
  {"+mlist",                do_mlist,                     ARG1|ARG2},
  {"+motd",                 do_motd,                      ARG1|ARG2},
  {"+plugins",              do_plugins,                   NOARGS},
  {"+swlm",                 do_swlm,                      ARG1},
  {"+todo",                 do_todo,                      ARG1|ARG2},
  {"+whocolor",             do_whocolor,                  ARG1},
  {"@admins",               do_admin,                     NOARGS},
  {"@announce",             do_announce,                  ARG1|ARG2},
  {"@boot",                 do_boot,                      ARG1|ARG2},
  {"@botspot",              do_botspot,                   ARG1},
  {"@broadcast",            do_broadcast,                 ARG1|ARG2},
  {"@cemit",                do_cemit,                     ARG1|ARG2},
  {"@chownall",             do_chownall,                  ARG1|ARG2},
  {"@chown",                do_chown,                     ARG1|ARG2},
  {"@create",               do_create,                    ARG1},
  {"@class",                do_class,                     ARG1|ARG2},
  {"@config",               do_config,                    ARG1|ARG2},
  {"@connections",          do_listconnections,           NOARGS},
  {"@cpattr",               do_cpattr,                    ARG1|ARG2},
  {"@dbck",                 do_dbck,                      NOARGS},
  {"@dboot",                do_dboot,                     ARG1|ARG2},
  {"@describe",             do_describe,                  ARG1|ARG2},
  {"@destroy",              do_destroy,                   ARG1},
  {"@dig",                  do_dig,                       ARG1|ARG2},
  {"@disconnected",         do_disconnected,              ARG1},
  {"@dpage",                do_dpage,                     ARG1|ARG2},
  {"@dump",                 do_dump,                      NOARGS},
  {"@find",                 do_find,                      ARG1},
  {"@force",                do_force,                     ARG1|ARG2},
  {"@echo",                 do_echo,                      ARG1|ARG2},
  {"@edit",                 do_edit,                      ARG1|ARG2},
  {"@emit",                 do_emit,                      ARG1|ARG2},
  {"@empower",              do_empower,                   ARG1|ARG2},
  {"@getalias",             do_getalias,                  ARG1},
  {"@giveto",               do_giveto,                    ARG1|ARG2},
  {"@gethost",              do_gethost,                   ARG1},
  {"@grep",                 do_grep,                      ARG1|ARG2},
  {"@halt",                 do_halt,                      ARG1},
  {"@haltall",              do_haltall,                   NOARGS},
  {"@inactive",             do_inactive,                  NOARGS},
  {"@link",                 do_link,                      ARG1|ARG2},
  {"@name",                 do_name,                      ARG1|ARG2},
  {"@necho",                do_necho,                     PURE},
  {"@newpassword",          do_newpassword,               ARG1|ARG2},
  {"@nemit",                do_nemit,                     PURE},
  {"@noemit",               do_noemit,                    ARG1|PURE2},
  {"@noop",                 do_noop,                      NOARGS},
  {"@npemit",               do_npemit,                    ARG1|PURE2},
  {"@npage",                do_page,                      ARG1|PURE2},
  {"@nset",                 do_set,                       ARG1|PURE2},
  {"@nuke",                 do_nuke,                      ARG1|ARG2},
  {"@oemit",                do_oemit,                     ARG1|ARG2},
  {"@openexit",             do_openexit,                  ARG1|ARG2},
  {"@password",             do_password,                  ARG1|ARG2},
  {"@paste",                do_paste,                     ARG1|ARG2},
  {"@pastestats",           do_pastestats,                ARG1},
  {"@pbreak",               do_pbreak,                    NOARGS},
  {"@pcreate",              do_pcreate,                   ARG1|ARG2},
  {"@pemit",                do_pemit,                     ARG1|ARG2},
  {"@ps",                   do_ps,                        NOARGS},
  {"@reboot",               do_reboot,                    ARG1|ARG2},
  {"@remit",                do_remit,                     ARG1|ARG2},
  {"@search",               do_search,                    ARG1|ARG2},
  {"@shutdown",             do_shutdown,                  ARG1|ARG2},
  {"@stats",                do_stats,                     ARG1},
  {"@su",                   do_su,                        ARG1|ARG2},
  {"@wipeout",              do_wipeout,                   ARG1|ARG2},
  {"@wemit",                do_wemit,                     ARG1|ARG2},
  {"calias",                do_calias,                    ARG1|ARG2},
  {"commands",              do_commands,                  NOARGS},
  {"complain",              do_complain,                  ARG1|ARG2},
  {"cquota",                do_cquota,                    ARG1|ARG2},
  {"drop",                  do_drop,                      ARG1},
  {"enter",                 do_enter,                     ARG1},
  {"evaluate",              do_evaluate,                  ARG1},
  {"examine",               do_examine,                   ARG1},
  {"get",                   do_get,                       ARG1},
  {"give",                  do_give,                      ARG1|ARG2},
  {"gripe",                 do_gripe,                     ARG1|ARG2},
  {"hash",                  do_hash,                      NOARGS},
  {"help",                  do_help,                      ARG1|ARG2},
  {"info",                  do_info,                      ARG1},
  {"inventory",             do_inventory,                 ARG1},
  {"join",                  do_join,                      ARG1},
  {"kill",                  do_kill,                      ARG1},
  {"look",                  do_look_at,                   ARG1},
  {"leave",                 do_leave,                     NOARGS},
  {"money",                 do_money,                     ARG1},
  {"news",                  do_news,                      ARG1},
  {"page",                  do_page,                      ARG1|ARG2},
  {"pose",                  do_pose,                      ARG1|ARG2},
  {"poss",                  do_poss,                      ARG1|ARG2},
  {"powcount",              do_powcount,                  ARG1},
  {"powlist",               do_powlist,                   NOARGS},
  {"powers",                do_powers,                    ARG1},
  {"quota",                 do_quota,                     ARG1|ARG2},
  {"run",                   do_run,                       ARG1|ARG2},
  {"say",                   do_say,                       ARG1|ARG2},
  {"set",                   do_set,                       ARG1|ARG2},
  {"summon",                do_summon,                    ARG1},
  {"teleport",              do_teleport,                  ARG1|ARG2},
  {"think",                 do_think,                     ARG1},
  {"to",                    do_to,                        ARG1|ARG2},
  {"uptime",                do_uptime,                    NOARGS},
  {"version",               do_version,                   NOARGS},
  {"whereis",               do_whereis,                   ARG1},
  {"who",                   do_who,                       ARG1|ARG2},
  {"whois",                 do_whois,                     ARG1},
  { NULL }
};

void *guest_command_set[] =
{
  do_laston, do_motd, do_todo, do_whocolor, do_admin, do_echo,
  do_emit, do_getalias, do_necho, do_nemit, do_paste, do_pbreak, do_stats,
  do_calias, do_commands, do_evaluate, do_examine, do_hash,
  do_help, do_info, do_look_at, do_news, do_page, do_pose, do_poss, 
  do_say, do_to, do_uptime, do_version, do_whois, do_who, do_ansi,
  do_plugins,
  NULL
};

/* Print out into error file */
void report()
{
  log_error("*** Reporting position ***");
  log_error("**************************");
}

/* Do absolutely nothing */
void do_noop()
{
}

void do_shutdown(OBJ *player, char *arg1, char *arg2)
{
  extern int exit_status;
  extern int shutdown_flag;
  extern struct timed_reboot_struct timed_reboot;
  char buf[4096] = "";

  log_sensitive(tprintf("Shutdown attempt by %s%s",
     unparse_object(player, player), buf));

  if(!power(player, POW_SHUTDOWN))
  {
    notify(player, perm_denied());
    return;
  }

  if(!string_compare(arg1, "cancel"))
  {
    if(!timed_reboot.when || timed_reboot.reboot)
      notify(player, "There is no server shutdown scheduled.");
    else
    {
      timed_reboot.when = 0;
      do_broadcast(root_obj, "Server shutdown cancelled.", NULL);
      notify(player, "Server shutdown cancelled.");
    }
    return;
  }

  if(strcmp(arg1, config.maze_name))
  {
    if(!*arg1)
      notify(player,
        "You must specify the name of the MAZE you wish to shutdown.");
    else
      notify(player,
        tprintf("This is %s, not %s.", config.maze_name, arg1));
    return;
  }

  if(*arg2)
  {
    if((timed_reboot.when = atoi(arg2)) < 1)
    {
      notify(player, "Countdown must be greater than 0.");
      timed_reboot.when = 0;
      return;
    }

    timed_reboot.when += now;
    sprintf(buf, " in %s", format_time(timed_reboot.when - now));
  }

  log_important(tprintf("SHUTDOWN: by %s%s",
    unparse_object(player, player), buf));

  if(now < timed_reboot.when)
    do_broadcast(root_obj,
      tprintf("There will be a server shutdown%s", buf), "");
  else
  {
    shutdown_flag = 1;
    exit_status = 0;
  }
}

void do_reboot(OBJ *player, char *arg1, char *arg2)
{
  extern int exit_status;
  extern int shutdown_flag;
  extern int quiet_reboot;
  extern struct timed_reboot_struct timed_reboot;
  char buf[4096] = "";

  quiet_reboot = 0;

  log_sensitive(tprintf("Reboot attempt by %s",
    unparse_object(player, player)));

  if(!power(player, POW_SHUTDOWN))
  {
    notify(player, perm_denied());
    return;
  }

  if(*arg2)
  {
    if((timed_reboot.when = atoi(arg2)) < 1)
    {
      notify(player, "Countdown value must be greater than 0.");
      timed_reboot.when = 0;
      if(*timed_reboot.arg);
        stack_free(timed_reboot.arg);
      timed_reboot.arg = "";
      return;
    }

    timed_reboot.when += now;
    timed_reboot.reboot = 1;
    SET(timed_reboot.arg, arg1);
    sprintf(buf, " in %s", format_time(timed_reboot.when - now));
  }

  if(!string_compare(arg1, "crash"))
  {
    log_important(tprintf("CRASH: by %s%s",
      unparse_object(player, player), buf));
    if(timed_reboot.when)
    {
      do_broadcast(root_obj,
        tprintf("There will be a server crash%s", buf), "");
      return;
    }
    kill(getpid(), SIGSEGV);
    return;    /* Shouldn't ever get here */
  }

  if(!string_compare(arg1, "cancel"))
  {
    if(!timed_reboot.when || !timed_reboot.reboot)
      notify(player, "There is no reboot scheduled.");
    else
    {
      timed_reboot.when = 0;
      timed_reboot.reboot = 0;
      if(*timed_reboot.arg)
        stack_free(timed_reboot.arg);
      timed_reboot.arg = "";
      do_broadcast(root_obj, "Server reboot cancelled.", "");
      notify(player, "Server reboot cancelled.");
    }
    return;
  }

  if(!string_compare(arg1, "quiet") && now >= timed_reboot.when)
    quiet_reboot = 1;

  log_important(tprintf("REBOOT: by %s%s",
    unparse_object(player, player), buf));
  if(now < timed_reboot.when)
  {
    do_broadcast(root_obj,
      tprintf("There will be a server reboot%s", buf), "");
    return;
  }
  else
  {
    shutdown_flag = 1;
    exit_status = 1;
  }
}

static void dump_database_internal()
{
  char tmpfile[2048];
  FILE *f;
  
  sprintf(tmpfile, "%s.#%d#", dumpfile, epoch-3);
  unlink(tprintf("%s.#%d#", dumpfile, epoch-3));
  sprintf(tmpfile, "%s.#%d#", dumpfile, epoch);

  if((f = fopen(tmpfile, "w")) != NULL)
  {
    db_write(f);
    fclose(f);
    unlink(dumpfile);
    if(link(tmpfile, dumpfile) < 0 )
    {
      perror(tmpfile);
      no_dbdump();
    }
    sync();
  }
  else
  {
    no_dbdump();
    perror(tmpfile);
  }
}

void panic(char *message)
{
  char panicommand_loge[2048];
  FILE *f;
  int i;

  log_error(tprintf("PANIC!!! %s", message));
  
  report();

/* Turn off signals */
  for(i = 0;i < NSIG;i++)
    signal(i, SIG_IGN);
  
/* Shut down interface */
  emergency_shutdown();
  
/* Dump panic file */
  sprintf(panicommand_loge, "%s.PANIC", dumpfile);
  if((f = fopen(panicommand_loge, "w")) == NULL)
  {
    perror("CANNOT OPEN PANIC FILE, YOU LOSE");
    exit_nicely(136);
  }
  else
  {
    log_io(tprintf("DUMPING: %s", panicommand_loge));
    db_write(f);
    fclose(f);
    log_io(tprintf("DUMPING: %s (done)", panicommand_loge));
    exit_nicely(136);
  }
}

void dump_database()
{
  epoch++;
  
  log_io(tprintf("DUMPING: %s.#%d#", dumpfile, epoch));
  dump_database_internal();
  log_io(tprintf("DUMPING: %s.#%d# (done)", dumpfile, epoch));
}

void fork_and_dump()
{
  char buf[4096] = "";
  
/* First time through only, setup dump message */
  if(*buf == '\0')
#ifdef USE_VFORK
    sprintf(buf, "%s Database saved. Sorry for the lag.", maze_name);
#endif
  
  epoch++;
  
  log_io(tprintf("CHECKPOINTING: %s.#%d#", dumpfile, epoch));
  close(reserved);
  dump_database_internal();
  reserved = open(NullFile, O_RDWR, 0);
}

static void no_dbdump()
{
  do_broadcast(root_obj,
    "Database save failed. Please take appropriate precautions.", "");
}

int init_game(char *db_file)
{
  FILE *f = db_read_ptr;
  depth = 0;
  
  if((f = fopen(db_file, "r")) == NULL)
    return(-1);
  
  log_important(tprintf("LOADING: %s", db_file));
  
  fflush(stdout);
  db_set_read(f);
  log_important(tprintf("LOADING: %s (done)", db_file));
  
/* Initialize random number generator */
#ifndef USE_DEV_URANDOM
  srandom((unsigned int)time(NULL)-getpid());
#else
  if((rand_fd = open("/dev/urandom", O_RDONLY)) == -1)
    log_error("Unable to open \"/dev/urandom\" for reading!");
#endif /* USE_DEV_URANDOM */

/* Set up dumper */
  strcpy(dumpfile, db_file);
  init_timer();
  
  return(0);
}

struct command_struct *match_command(DDATA *d, OBJ *player, char *command)
{
  CS *c, **cmatched;
  char clower[4096];
  char *p, *q;
  int ctr = 0;
  char *b, buf[4096];
  int i;

/* Make clower equal to command but all lowercase for faster matching */
  for(p = command, q = clower;*p;)
    *q++ = tolower(*p++);
  *q = '\0';

/* Check for special case shortcut commands */
  if(!strcmp(clower, "l"))
    strcpy(clower, "look");
  else if(!strcmp(clower, "p"))
    strcpy(clower, "page");
  else if(!strcmp(clower, "f"))
    strcpy(clower, "fight");
  else if(!strcmp(clower, "c"))
    strcpy(clower, "cast");

/* Check for hashed commands first (Optional). */
  if(d)
    if((c = match_hash(d, clower)))
      return(c);

  if(player)
    if((c = match_comm_alias(player, clower)))
      return(c);

  for(c = command_set;c->name;c++)
  {
    if(!string_prefix(c->name, clower))
      continue;

/* If they're a guest, their commands are restricted */
    if(Guest(player))
    {
      for(i = 0;guest_command_set[i];++i)
        if(guest_command_set[i] == c->func)
          break;
      if(!guest_command_set[i])
        continue;   /* Just pretend it didn't match it */
    }

/* Check if it's the whole command name */
      if(strlen(c->name) == strlen(clower))
        return(c);

/* Check for ambiguous matches */
    if(!ctr)
      cmatched = (CS **)stack_alloc(sizeof(CS *), 0, 0);
    else
      cmatched = (CS **)stack_realloc_tmp(cmatched, sizeof(CS *)*(ctr+1));
    cmatched[ctr++] = c;
  }

/* See if any plugin commands match */
  plugin_command_match(clower, &cmatched, &ctr);

  if(!ctr)
    return(NULL);
  else if(ctr == 1)
    return(*cmatched);

  if(!player)
    return((CS *)-1);

  for(i = 0, b = buf;i < ctr;++i, b += strlen(b))
    if(!i)
      strcpy(b, cmatched[i]->name);
    else
      sprintf(b, ", %s", cmatched[i]->name);

  if(player)
    notify(player, tprintf("Ambiguous command (%s).", buf));
  return((CS *)-1);
}

static int chk_single_char_cmds(OBJ *player, char *command)
{
  if(*command == SAY_TOKEN)
  {
    do_say(player, command+1, "");
    return(1);
  }
  if(*command == POSE_TOKEN)
  {
    do_pose(player, command+1, "");
    return(1);
  }
  if(*command == POSS_TOKEN)
  {
    do_poss(player, command+1, "");
    return(1);
  }
  if(*command == COM_TOKEN)
  {
    do_com(player, "", command+1);
    return(1);
  }
  if(*command == TO_TOKEN)
  {
    do_to(player, command+1, "");
    return(1);
  }
  if(*command == THINK_TOKEN)
  {
    do_think(player, command+1);
    return(1);
  }

  return(0);
}

void parse_arguments(char *command, char **arg1, char **arg2)
{
  char *p;

  *arg2 = "";

/* Move over command word and find arg1 */
  for(*arg1 = command;**arg1 && !isspace(**arg1);(*arg1)++);

  if(!**arg1)
    return;

/* Truncate command */
  **arg1 = '\0';
  (*arg1)++;

/* Skip spaces */
  while(isspace(**arg1))
    (*arg1)++;

/* An '=' ends arg1 */
  for(*arg2 = *arg1;**arg2;(*arg2)++)
    if(**arg2 == '=')
      break;

  if(!**arg2)
    return;

/* Terminate arg1 and move arg2 past '=' */
  **arg2 = '\0';
  (*arg2)++;

/* Move over spaces */
  while(isspace(**arg2))
    (*arg2)++;

/* Remove trailing spaces */
  for(p = (*arg1)+strlen(*arg1)-1;p >= *arg1;p--)
  {
    if(!isspace(*p))
      break;
    *p = '\0';
  }

  for(p = (*arg2)+strlen(*arg2)-1;p >= *arg2;p--)
  {
    if(!isspace(*p))
      break;
    *p = '\0';
  }
}

void process_command(DDATA *d, OBJ *player, char *commandstr, OBJ *cause)
{
  char *arg1, *arg2;
  char *p;
  char commandbuf[4096];
  char *command;
  char arg[4096];               /* arg1 and arg2 unseparated */
  char pure[4096];              /* totally unparsed command */
  char pure2[4096];
  char *temp;
  int slave = IS(player, TYPE_PLAYER, PLAYER_SLAVE);
  int is_direct = 0;
  struct command_struct *c;
  
  strcpy(commandbuf, commandstr);
  command = commandbuf;

  if(!command || !*command)
    return;

  cmd_plyr = player;
  strcpy(for_bad, command);
  plyr = player;
  cause_for_bad = cause;

  inc_cmdav();

  if(is_root(player))
  {
    if(!cause)
    {
      is_direct = 1;
      log_is_root(tprintf("(direct) %s", command));
    }
    else
      log_is_root(tprintf("(cause %d) %s", cause->dbref, command));

    cause = player;
  }
  else
  {
    if(!cause)
    {
      log_command(tprintf("%s in %s directly executes: %s",
        unparse_object(player, player),
        unparse_object(player->location, player->location), command));
      is_direct = 1;
      cause = player;
    }
    else
    {
      log_command(tprintf("Caused by %s, %s in %s executes:%s",
        unparse_object(cause, cause), unparse_object(player, player),
        unparse_object(player->location, player->location), command));
    }
  }

  if(IS(player, TYPE_PLAYER, PLAYER_SUSPECT) && cause == player)
    log_suspect(tprintf("%s in %s(#%d): %s",
      name(player), player->location->name,
      player->location->dbref, command));

  if(Guest(player))
    log_guest(tprintf("%s in %s(#%d): %s", name(player),
      player->location->name, player->location->dbref, command));

/* Skip leading spaces */
  for(temp = command;isspace(*temp);temp++);

/* Skip firsts word */
  while(*temp && !isspace(*temp))
    temp++;

/* Skip leading space */
  if(*temp)
    temp++;

/* pure is everything after the command */
  strcpy(pure, temp);

  while(*temp && (*temp != '='))
    temp++;

/* Skip the '=' */
  if(*temp)
    temp++;

/* pure2 is everything after the first '=' */
  strcpy(pure2, temp);

/* Access the player */
  if(is_root(player) && !is_root(cause))
  {
    cmd_plyr = NULL;
    return;
  }
   
  if(slave)
  {
    notify(player, "You can't do anything while enslaved.");
    cmd_plyr = NULL;
    return;
  }

/* An object with PUPPET and DARK flag is in debug mode */
  if(player->flags & (PUPPET|DARK))
  {
    char buf[4096];

    sprintf(buf, "%s>> %s", name(player), command);
    raw_notify(player->owner, buf, 1);
  }

/* Eat leading whitespace */
  while(*command && isspace(*command))
    command++;

/* Eliminate double spaces */
  for(p = command;*p;)
  {
    if(isspace(*p) && isspace(*(p+1)))
      strcpy(p, p+1);
    else
      p++;
  }

/* arg is everything after command, but semi-parsed */
  if(!(p = strchr(command, ' ')))
    *arg = '\0';
  else
    strcpy(arg, p+1);

/* Important home checking comes first! */
  if(!string_compare(command, "home"))
  {
    do_move(player, command);
    cmd_plyr = NULL;
    return;
  }

/* See if 'command' is an exact match for an exit */
  if(can_move(player, command))
  {
    do_move(player, command);
    cmd_plyr = NULL;
    return;
  }

  if(chk_single_char_cmds(player, command))
  {
    cmd_plyr = NULL;
    return;
  }

  parse_arguments(command, &arg1, &arg2);

/* Check for comsystem aliases */
  if(find_channel(player, command))
    if(is_on_channel(player, find_channel(player, command), 0))
    {
      do_com(player, command, arg);
      cmd_plyr = NULL;
      return;
    }

/* Time to do command matching */
  if((c = match_command(d, player, command)))
  {
    if(c == (CS *)-1) /* Ambiguous command */
    {
      cmd_plyr = NULL;
      return;         /* match_command() handles the messages for us */
    }

    if(!strcmp(arg1, "/?"))
    {
      do_help(player, c->name, "");
      cmd_plyr = NULL;
      return;
    }

    add_hash(d, c);

/* Special commands need special attention */
    if(c->func == do_hash)
    {
      c->func(d, player);
      cmd_plyr = NULL;
      return;
    }
    if(c->func == do_paste)
    {
      c->func(d, arg1, arg2);
      cmd_plyr = NULL;
      return;
    }
    if(c->func == do_openexit)
    {
      c->func(player, arg1, arg2, NULL);
      cmd_plyr = NULL;
      return;
    }

    if(c->flags & ARG2 || c->flags & PURE2)
    {
      if(c->flags & ARG1)
        c->func(player, arg1, (c->flags & ARG2)?arg2:pure2);
      else
        c->func(player, pure, (c->flags & ARG2)?arg2:pure2);
    }
    else
    {
      if(c->flags & ARG1)
        c->func(player, arg1);
      else if(c->flags & PURE)
        c->func(player, pure);
      else
        c->func(player);
    }

    cmd_plyr = NULL;
    return;
  }

/* Only get here if the command didn't match anything */

/* Check for softcode commands */
  if(check_softcode_match(player, commandstr))
  {
    cmd_plyr = NULL;
    return;
  }

  if(!slave && test_set(player, command, arg1, arg2))
  {
    cmd_plyr = NULL;
    return;
  }

  if(bad_direction(command))
    notify(player, "You can't go that way.");
  else
  {
    notify(player, bad_cmd_mesg());
    if(player->flags & PLAYER_NEWBIE)
      notify(player, "(Type 'help' to get help on most commands.)");
/* Only log the bad commands that start with @ or + */
    if(command[0] == '@' || command[0] == '+')
      log_huh(tprintf("%s tried: %s",
        unparse_object(player, player), for_bad));
  }

  cmd_plyr = NULL;
}

void exit_nicely(int i)
{
  exit(i);
}

int num_bad_cmd_msgs = 8;
char *bad_cmd_msgs[] =
{
  "WTF?! Was that a command?",
  "I don't understand that command.",
  "That's not a command! It's a...a...it's something different!",
  "What I wouldn't give for someone who knew what a command was!",
  "Are you trying to give me a command?",
  "Yo no lo comprendo esa instruccion.",
  "Back the FUCK off! Give me a real command or DIE!",
  "Bad Command...Bad, bad command! sit! Stay! sstttaaayyyy!"
};

char *bad_cmd_mesg()
{
  char buffer[4096];

  sprintf(buffer, "|+B|%s", bad_cmd_msgs[my_rand()%num_bad_cmd_msgs]);
  return(stack_string_alloc(buffer, 0));
}

static int num_guest_fail = 1;
static char *guest_msgs[] =
{
  "Sorry, guests may not do that."
};

char *guest_fail(OBJ *player, OBJ *cause, char *command)
{
  if(!cause)
    log_denied(tprintf("(GUEST) %s tried: %s",
      unparse_object(plyr, plyr), command));
  else
    log_denied(tprintf("(GUEST) %s (cause: %s <#%d>) tried: %s",
      unparse_object(plyr, plyr), name(cause), cause->dbref, command));

  return(guest_msgs[my_rand()%num_guest_fail]);
}

int num_perm_denied = 17;
char *perm_messages[] =
{
  "Permission denied.",
  "Try that again and DIE, asswipe.",
  "What the hell do you think you're doing?",
  "You're not allowed to do that!",
  "HAH! You wish!",
  "Umm...I don't think so.",
  "Bad user! No biscuit!",
  "You bad! No soup for you!",
  "Go away you nasty, evil hacker!",
  "You can't do that!",
  "Permission denied! Nah, nah, nah, nah, nah!",
  "Do that again and you're WALKING to grandma's!",
  "Dave. What are you doing, Dave? That hurts, Dave.",
  "Can we say 'NO'?",
  "Bad command! Bad, BAD command. Sit. Stay. Staaaaaaay.",
  "PERMISSION DENIED!!!!! Stay where you are. Police will arrive shortly.",
  "Permission denied. You will be @nuked in 5 seconds..."
};

char *perm_denied()
{
  char buffer[4096];
  sprintf(buffer, "|+R|%s", perm_messages[my_rand()%num_perm_denied]);

  if(!cause_for_bad)
    log_denied(tprintf("%s tried: %s",
      unparse_object(plyr, plyr), for_bad));
  else
    log_denied(tprintf("%s (cause: %s <#%d>) tried: %s",
      unparse_object(plyr, plyr),
      cause_for_bad->name, cause_for_bad->dbref, for_bad));

  return(stack_string_alloc(buffer, 0));
}