calisto-20000323/
calisto-20000323/lib/
calisto-20000323/lib/etc/
calisto-20000323/lib/players/
calisto-20000323/lib/text/
calisto-20000323/log/
/*
 Calisto (c) 1998-2000 Peter Howkins, Matthew Howkins, Simon Howkins

 $Id: commands.c,v 1.32 2000/03/12 00:58:01 peter Exp $

 */
static char rcsid[] = "$Id: commands.c,v 1.32 2000/03/12 00:58:01 peter Exp $";

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "unistd.h"

#include "config.h"
#include "colours.h"
#include "commands.h"
#include "globals.h"
#include "help.h"
#include "library.h"
#include "log.h"
#include "msnprintf.h"
#include "playerdb.h"
#include "privs.h"
#include "structs.h"
#include "strplus.h"

typedef struct {
  const char *name;
  const char *shortcut;
  void (*function)(character *, char *);
  const char *privname;
} command;

void command_bug(character *, char *);
void command_cls(character *, char *);
void command_commands(character *, char *);
void command_dc(character *, char *);
void command_emote(character *, char *);
void command_finger(character *, char *);
void command_grant(character *, char *);
void command_group(character *, char *);
void command_idea(character *, char *);
void command_lsd(character *, char *);
void command_motd(character *, char *);
void command_ping(character *, char *);
void command_prompt(character *, char *);
void command_quit(character *, char *);
void command_recap(character *, char *);
void command_reload(character *, char *);
void command_remote(character *, char *);
void command_remove(character *, char *);
void command_save(character *, char *);
void command_say(character *, char *);
void command_set(character *, char *);
void command_shout(character *, char *);
void command_shutdown(character *, char *);
void command_stat(character *, char *);
void command_sumotd(character *, char *);
void command_tell(character *, char *);
void command_time(character *, char *);
void command_typo(character *, char *);
void command_users(character *, char *);
void command_version(character *, char *);
void command_who(character *, char *);
void command_whoami(character *, char *);

const command commands[] = {
  { "bug",     "",  command_bug,      "n_base" },
  { "bump",    "",  command_dc,       "s_bump" },
  { "clear",   "",  command_cls,      "n_base" },
  { "cls",     "",  command_cls,      "n_base" },
  { "commands","",  command_commands, "n_base" },
  { "dc",      "",  command_dc,       "s_bump" },
  { "emote",   ";:",command_emote,    "n_talk" },
  { "exit",    "",  command_quit,     "n_base" },
  { "finger",  "",  command_finger,   "n_base" },
  { "grant",   "",  command_grant,    "a_grant" },
  { "group",   "",  command_group,    "n_base" },
  { "help",    "",  command_help,     "n_base" }, /* Found in help.c */
  { "idea",    "",  command_idea,     "n_base" },
  { "lsd",     "",  command_lsd,      "s_trace" },
  { "motd",    "",  command_motd,     "n_base" },
  { "ping",    "",  command_ping,     "n_base" },
  { "prompt",  "",  command_prompt,   "n_base" },
  { "quit",    "",  command_quit,     "n_base" },
  { "recap",   "",  command_recap,    "n_base" },
  { "reload",  "",  command_reload,   "a_base" },
  { "remote",  ",", command_remote,   "n_talk" },
  { "remove",  "",  command_remove,   "a_grant" },
  { "save",    "",  command_save,     "n_save" },
  { "say",     "'", command_say,      "n_talk" },
  { "set",     "",  command_set,      "a_base" },
  { "shout",   "",  command_shout,    "n_talk" },
  { "shutdown","",  command_shutdown, "a_shutdown" },
  { "stat",    "",  command_stat,     "a_base" },
  { "sumotd",  "",  command_sumotd,   "s_base" },
  { "tell",    ".", command_tell,     "n_talk" },
  { "time",    "",  command_time,     "n_base" },
  { "typo",    "",  command_typo,     "n_base" },
  { "users",   "",  command_users,    "n_base" },
  { "version", "",  command_version,  "n_base" },
  { "who",     "",  command_who,      "n_base" },
  { "whoami",  "",  command_whoami,   "n_base" },
  { "x",       "",  command_finger,   "n_base" }
};
const unsigned commandn = sizeof commands / sizeof(command);

void command_version(character *c, char *r)
{
  descriptor *des = getdes(c);

  bar2(des, "Version", NULL, NULL);
  send_to_char(c, "^PCalisto^n %u.%02u (c) 1998-2000 ^YFlibble^n, ^YThe_Pope^n and ^YWilfred^n\n", version/100, version%100);
  send_to_char(c, "  ^G+^n Colour Code ^G-^n ^YEkto^n (ekto@ekto.org)\n");
  send_to_char(c, "  ^G+^n snprintf    ^G-^n based on code by ^YAlain Magloire^n (alainm@rcsm.ee.mcgill.ca)\n");
  bar2(des, NULL, NULL, NULL);
}

void command_set(character *c, char *r)
{
  char *variable;
  char *value;
  bool quoted = FALSE;

  if (STREQ(r, "")) {
    send_to_char(c, "use_net_lookups: %d\n", use_net_lookups);
    send_to_char(c, "idle_boot_time:  %u minutes\n", idle_boot_time);
    send_to_char(c, "max_connections: %u\n", max_connections);
    return;
  }

  /* Break input into variable and value */
  strmunch(r, &variable, &r);
  if (*r == '\"') {
    quoted = TRUE;
    r++;
  }
  value = r;
  if (quoted) {
    while (*r && *r != '\"')
      r++;
  } else {
    while (*r && !isspace(*r))
      r++;
  }
  *r = '\0';
/*  send_to_char(c, "variable = \'%s\'\n", variable);
  send_to_char(c, "value    = \'%s\'\n", value);*/

  /* Check if value specified OK */
  if (STREQ(value, "")) {
    help_usage(c, "set");
    return;
  }

  /* Handle known variables, and complain about unknown ones */
  if (STRIEQ(variable, "use_net_lookups")) {
    use_net_lookups = atoi(value);
    if (use_net_lookups)
      use_net_lookups = TRUE;
  } else if (STRIEQ(variable, "idle_boot_time")) {
    idle_boot_time = (unsigned) atoi(value);
  } else if (STRIEQ(variable, "max_connections")) {
    max_connections = (unsigned) atoi(value);
  } else {
    send_to_char(c, "Unknown variable '%s'\n"
                 "Use the set command without parameters to list variables.\n",
                 variable);
  }
}

void command_recap(character *c, char *r)
{
  if(STREQ(r, "")) {
    help_usage(c, "recap");
    return; 
  }
  if(STRIEQ(r, c->name)) {
    STRNCOPY(c->name, r, sizeof(c->name));
    send_to_char(c, "Name recapitalised\n");
  } else {
    send_to_char(c, "Input must be the same as your name\n");
  }
}

void command_save(character *c, char *r)
{
  int error = save_player(c, c->name);
  if(error) {
    send_to_char(c, "Error saving your character\n");
  } else {
    send_to_char(c, "Successfully saved your character\n");
  }
}

void command_sumotd(character *c, char *r)
{
  descriptor *des = getdes(c);

  bar2(des, "Super-user Message Of The Day", NULL, NULL);
  send_file_to_descriptor("lib/etc/sumotd", des);
  bar2(des, NULL, NULL, NULL);
}

void command_cls(character *c, char *r)
{
  descriptor *des = getdes(c);
  int i;

  for (i = 0; i < des->term_height; i++) {
    send_to_char(c, "\n");
  }
/*  send_to_char(c, "\x1b[0;0H"); */
  send_to_char(c, "\x1b[%dA", des->term_height);
}

void command_reload(character *c, char *r)
{
  if (STRIEQ(r, "help")) {
    help_reload(c);
  } else if (STRIEQ(r, "all")) {
    help_reload(c);
  } else {
    send_to_char(c, "Unrecognised reload option %s\n", r);
  }
}

#define COMMAND_STAT_OPTIONS "net mem"
static void command_stat_usage(character *c)
{
  send_to_char(c, "Usage: stat <option> [<option>...]\n");
  send_to_char(c, "where <option> is one of `%s all`\n",
               COMMAND_STAT_OPTIONS);
}

void command_stat(character *c, char *r)
{
  if (*r) {
    while (*r) {
      char *sub;

      strmunch(r, &sub, &r);
      if (STRIEQ(sub, "mem")) {
        pool_stat_t ps = pool_stat(descriptor_pool);

        send_to_char(c, "^H[Memory - Descriptors]^n\n");
        send_to_char(c, "   Block Size : %u\n", ps.block_size);
        send_to_char(c, "        Usage : %u\n", ps.usage);
        send_to_char(c, "     Capacity : %u (%.1fk)\n", ps.capacity,
                     (double) (ps.block_size * ps.capacity) / 1024.0);
        send_to_char(c, "         Free : %u\n", ps.capacity - ps.usage);
        send_to_char(c, "  Connections : %u/%u\n", ps.usage,
                     max_connections);
      } else if (STRIEQ(sub, "net")) {
        FILE *f;
        const char *hostname = getenv("HOSTNAME");
        const char *machtype = getenv("MACHTYPE");

        send_to_char(c, "^H[Network and Machine]^n\n");
        send_to_char(c, "    PID : %u\n", (unsigned) getpid());
        send_to_char(c, "   PPID : %u\n", (unsigned) getppid());
        send_to_char(c, "   HOST : %s\n", hostname ? hostname : "** Unknown **");
        send_to_char(c, "   TYPE : %s\n", machtype ? machtype : "** Unknown **");
        /* Display load average of server, if available */
        f = fopen("/proc/loadavg", "r");
        if (f) {
          char buffer[256];
          float load1, load5, load15;

          if (fgets(buffer, sizeof(buffer), f)) {
            if (sscanf(buffer, "%f %f %f", &load1, &load5, &load15) == 3) {
              send_to_char(c, "LoadAvg : %.2f %.2f %.2f\n",
                           load1, load5, load15);
            }
          }
          fclose(f);
        }
      } else if (STRIEQ(sub, "all")) {
        char all[] = COMMAND_STAT_OPTIONS;

        command_stat(c, all);
      } else {
        send_to_char(c, "Unknown stat option `%s`\n", sub);
        command_stat_usage(c);
      }
    }
  } else {
    command_stat_usage(c);
  }
#undef COMMAND_STAT_OPTIONS
}

void command_finger(character *c, char *r)
{
  /* formats 
     finger       - does a finger on the character that called func
     finger bob   - does a finger on bob
     check for
       r = ""
       r logged in 
       r not logged in and exists
       r not logged in and doesn't exist
  */
  time_t now;
  descriptor *des = getdes(c);
  descriptor *victdes;
  character *victim;
  character target;
  char buffer[OUTPUT_BUFFER];
  bool loggedin = FALSE;

  if(STREQ(r, "")) {
    victim = c;
    loggedin = TRUE;
  } else {
    if((victim = character_from_name(r)) != NULL) {
      /* victim is logged on and found */
      loggedin = TRUE;
    } else {
      /* check to see is r is in the players directory, if so load
         else return */
      int failed;
      failed = load_player(&target, r);
      if (failed) {
        send_to_char(c, "Player %s, not found\n", r);
        return;
      } else {
        victim = &target;
        loggedin = FALSE;
      }
    }
  }

  now = time(NULL);
  victdes = getdes(victim);
  if (loggedin) {
    seconds_to_string(victim->prevtime + difftime(now, victim->logintime),
                    buffer, sizeof(buffer));
  } else {
    seconds_to_string(victim->prevtime, buffer, sizeof(buffer));
  }
  bar2(des, "Finger", NULL, NULL);
  send_to_char(c, "      Name: %s\n", victim->name);
  send_to_char(c, "Total Time: %s\n", buffer);
  /* Display privileges */
  if (victim == c || haspriv(c, "s_base")) {
    send_to_char(c, "     Privs:");
    privs_list_player(c, victim);
    send_to_char(c, "^n\n");
  }
  if (loggedin) {
    send_to_char(c, "     Group: %s\n", victim->group);
    send_to_char(c, "  Termtype: %s (%ux%u)\n", victdes->termtype,
                 victdes->term_width, victdes->term_height);
    if (haspriv(c, "s_trace")) {
      send_to_char(c, "      Host: %s\n", victdes->hostname);
    }
  }
  bar2(des, NULL, NULL, NULL);
}

void command_group(character *c, char *r)
{
  char groupname[MAX_GROUP_NAME_LENGTH+1];

  stripCodes(groupname, r);

  if(STREQ(r, "")) {
    STRNCOPY(groupname, "Public", sizeof(groupname));
  }
  if (strlen(r) > MAX_GROUP_NAME_LENGTH) {
    send_to_char(c, "Group name too long (max %d)\n", MAX_GROUP_NAME_LENGTH);
    return;
  }

  strlower(groupname);
  groupname[0] = toupper(groupname[0]);

  if (!STREQ(groupname, c->group)) {
    /* Announce departure of character from old group */
    send_to_room_except(c->group, c, "\n+++ %s joins group %s\n",
                        c->name, groupname);
    STRNCOPY(c->group, groupname, sizeof(c->group));
    /* annouce arrival in new group */
    send_to_char(c, "+++ You have joined group ^y%s^n\n", c->group);
    send_to_room_except(c->group, c, "\n+++ %s joins this group\n", c->name);
  } else {
    send_to_char(c, "You are already in group ^y%s^n\n", c->group);
  }
}

void command_dc(character *c, char *r)
{
  descriptor *des = NULL;
  character *ch;

  if (STREQ(r, "")) {
    help_usage(c, "bump/dc");
    return;
  }

  ch = character_from_name(r);
  if (ch) {
    /* found character, drop em */
    des = getdes(ch);
  } else {
    /* char name not found - assume a number */
    if (!strisdigit(r)) {
      /* Not a number - report bad character name */
      send_to_char(c, "Character %s not known\n", r);
      return;
    } else {
      int sfd = atoi(r);
      listnode *dNode = AllConns.head.next;

      while (LIST_NODE_IS_REAL(dNode)) {
        descriptor *des2 = LIST_GET_DATA(dNode, descriptor *, descriptorlink);
        if (sfd == des2->sfd) {
          des = des2;
          break;
        }
        dNode = dNode->next;
      }
      if (!des) { 
        send_to_char(c, "SFD %d not found\n", sfd);
        return;
      }
    }
  }

  /* Before we drop, check we are not dropping ourselves */
  if (des == getdes(c)) {
    send_to_char(c, "Haven't you heard of the quit command?\n");
    return;
  }
  des->state = STATE_CLOSING;
  if (des->player.loggedin) {
    send_to_all_except(&des->player, "\n+++ ^r%s^n has logged out\n",
                       des->player.name);
  }
}

void command_time(character *c, char *r)
{
  time_t now;
  struct tm nowtm;
  char buff[OUTPUT_BUFFER];
  unsigned long howlong;

  now = time(NULL);
  nowtm = *localtime(&now);
  strftime(buff, sizeof(buff), "%a %b %d %H:%M:%S %Y", &nowtm);
  send_to_char(c, "^WCurrent  : %s\n^n", buff);

  nowtm = *localtime(&starttime);
  strftime(buff, sizeof(buff), "%a %b %d %H:%M:%S %Y", &nowtm);
  send_to_char(c, "Up Since : %s\n", buff);

  howlong = (unsigned long) difftime(now, starttime);
  seconds_to_string(howlong, buff, sizeof(buff));
  send_to_char(c, "Up Time  : %s\n", buff);
}

void command_ping(character *c, char *r) 
{
  character *target;

  if (STREQ(r, "")) {
    help_usage(c, "ping");
  } else {  
    target = character_from_name(r);
    if (target == NULL) {
      send_to_char(c, "%s not found\n", r);
    } else {
      send_to_char(target, "\a^YPING\n^n%s is trying to contact you\n",
                   c->name);
    }
  }
}

void command_remove(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "remove");
    return;
  }
  {
    character *target;
    char *privname = r;
   
    strmunch(r, &r, &privname);
    /* r should now be player name, privname should be the priv */
    /* try to find player, if not found bail out of function */
    target = character_from_name(r);
    if (!target) {
      send_to_char(c, "Player %s not found\n", r);
      help_usage(c, "remove");
      return;
    }
    /* check if removing privs from oneself */
    if (c == target) {
      send_to_char(c, "You may not remove your own privs\n");
      return;
    }
    /* if privname is blank print out usage and bail out */
    if (STREQ(privname, "")) {
      send_to_char(c, "Unknown priv\n");
      help_usage(c, "remove");
      return;
    }
    /* search through the priv list and try to find the priv */
    if (privname_exists(privname)) {
      send_to_char(c, "You have removed from %s the %s priv.\n",
                   target->name, privname);
      send_to_char(target, "You have lost the %s priv\n",
                   privname);
      clearpriv(target, privname);
    } else {
      send_to_char(c, "Priv %s not found\n", privname);
      help_usage(c, "remove");
    }
  }
}

static void command_grant_usage(character *c)
{
  help_usage(c, "grant");
  send_to_char(c, "Available privs:\n");
  privs_list_all(c);
  send_to_char(c, "\n");
}

void command_grant(character *c, char *r) 
{
  if (STREQ(r, "")) {
    command_grant_usage(c);
    return;
  }
  {
    character *target;
    char *privname = r;
   
    strmunch(r, &r, &privname);
    /* r should now be player name, privname should be the priv */
    /* if privname is blank print out usage and bail out */
    if (STREQ(privname, "")) {
      command_grant_usage(c);
      return;
    }
    /* try to find player, if not found bail out of function */
    target = character_from_name(r);
    if (!target) {
      send_to_char(c, "Player %s not found\n", r);
      command_grant_usage(c);
      return;
    }
    /* search through the priv list and try to find the priv */
    if (privname_exists(privname)) {
      send_to_char(c, "You have granted %s the %s priv.\n",
                   target->name, privname);
      send_to_char(target, "You have been granted the %s priv\n",
                   privname);
      setpriv(target, privname);
    } else {
      send_to_char(c, "Priv %s not found\n", privname);
      command_grant_usage(c);
    }
  }
}

void command_lsd(character *c, char *r)
{
  listnode *dNode = AllConns.head.next;
  descriptor *des2;
  unsigned long howlong;
  time_t now;
  
  des2 = getdes(c);

  bar2(des2, "Sockets connected and states", NULL, NULL);
  send_to_char(c, "^YSFD State    (name)        (login)  Idle    Host^n\n\n");
  while (LIST_NODE_IS_REAL(dNode)) {
    descriptor *des = LIST_GET_DATA(dNode, descriptor *, descriptorlink);
    character *c2 = &des->player;
    char *state = "";

    send_to_char(c, "%.3d ", des->sfd);
    switch (des->state) {
      case STATE_LOGIN:    state = "LOGIN";    break;
      case STATE_NEW1:     state = "NEW1";     break;
      case STATE_NEW2:     state = "NEW2";     break;
      case STATE_NEW3:     state = "NEW3";     break;
      case STATE_PASSWORD: state = "PASSWORD"; break;
      case STATE_PLAY:     state = "PLAY";     break;
      case STATE_CLOSING:  state = "CLOSING";  break;
    }
    send_to_char(c, "%-9s", state);
    now = time(NULL);
    if (des->state == STATE_PLAY) {
      send_to_char(c, "%-13s", c2->name);
      /* login Time */
      howlong = (unsigned long) difftime(now, c2->logintime);
      send_to_char(c, " %02lu:", howlong / 3600);
      howlong %= 3600;
      send_to_char(c, "%02lu:", howlong / 60);
      howlong %= 60;
      send_to_char(c, "%02lu", howlong);
    } else {
      send_to_char(c, "                      ");
    }
    /* Idle Time */
    howlong = (unsigned long) difftime(now, des->idletime);
    send_to_char(c, " %02lu:", howlong / 60);
    howlong %= 60;
    send_to_char(c, "%02lu   %s\n", howlong, des->hostname);
    dNode = dNode->next;
  }
  bar2(des2, NULL, NULL, NULL);
}

void command_bug(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "bug");
  } else {
    log(bug, "%s - %s", c->name, r);
    send_to_char(c, "Thank you, the bug has been recorded\n");
  }
}

void command_idea(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "idea");
  } else {
    log(idea, "%s - %s", c->name, r);
    send_to_char(c, "Thank you, your idea has been recorded\n");
  }
}

void command_typo(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "typo");
  } else {
    log(typo, "%s - %s", c->name, r);
    send_to_char(c, "Thank you, the typo has been recorded\n");
  }
}

void command_shutdown(character *c, char *r)
{
  sdown = TRUE;
}

void command_motd(character *c, char *r)
{
  descriptor *des = getdes(c);

  bar2(des, "Message Of The Day", NULL, NULL);
  send_file_to_descriptor("lib/etc/motd", des);
  bar2(des, NULL, NULL, NULL);
}

void command_prompt(character *c, char *r)
{
  if(strlen(r) > MAX_PROMPT_LENGTH-2) {
    send_to_char(c, "Prompt too long (max %d)\n", MAX_PROMPT_LENGTH-2);
  } else {
    STRNCOPY(c->prompt, r, sizeof(c->prompt));
  } 
}

void command_commands(character *c, char *r)
{
  descriptor *des = getdes(c);
  int i;

  bar2(des, "List of commands", NULL, NULL);
  for(i = 0;i < commandn;i++) {
    if(haspriv(c, commands[i].privname))
      send_to_char(c, "%s%s^n ", privcol(commands[i].privname),
                   commands[i].name);
  }
  send_to_char(c, "\n");
  bar2(des, NULL, NULL, NULL);
}

void command_users(character *c, char *r)
{
  listnode *pNode = AllPlayers.head.next;

  while (LIST_NODE_IS_REAL(pNode)) {
    character *pChar = LIST_GET_DATA(pNode,character *, characterlink);
    send_to_char(c, "%s ", pChar->name);
    pNode = pNode->next;
  }
  send_to_char(c, "\n");
}

void command_who(character *c, char *r)
{
  descriptor *des = getdes(c);

  listnode *pNode = AllPlayers.head.next;
  int howmany = 0;
  time_t now;
  unsigned long howlong;

  now = time(NULL);
  bar2(des, "Who is logged on?", NULL, NULL);
  send_to_char(c, "^Y%-*s Login    Idle    %-*s ",
               MAX_NAME_LENGTH, "Name", MAX_GROUP_NAME_LENGTH, "Group");
  if(haspriv(c, "s_trace")) {
    send_to_char(c, "Host");
  }
  send_to_char(c, "^n\n");
  while (LIST_NODE_IS_REAL(pNode)) {
    character *pChar = LIST_GET_DATA(pNode, character *, characterlink);
    descriptor *des = LIST_GET_DATA(pChar, descriptor *, player);

    /* Display name */
    send_to_char(c, "%-*s", MAX_NAME_LENGTH, pChar->name);
    /* Calculate how long they have been logged in */
    howlong = (unsigned long) difftime(now, pChar->logintime);
    send_to_char(c, " %02lu:", howlong / 3600);
    howlong %= 3600;
    send_to_char(c, "%02lu:", howlong / 60);
    howlong %= 60;
    send_to_char(c, "%02lu", howlong);
    /* Calculate how long they have been idle for */
    howlong = (unsigned long) difftime(now, des->idletime);
    send_to_char(c, " %02lu:", howlong / 60);
    howlong %= 60;
    send_to_char(c, "%02lu   ", howlong);
    send_to_char(c, "%-*s ", MAX_GROUP_NAME_LENGTH, pChar->group);
    if(haspriv(c, "s_trace")) {
      send_to_char(c, "%s", des->hostname);
    }
    send_to_char(c, "\n");
    pNode = pNode->next;
    howmany++;
  }
  send_to_char(c, "Total: %d user%s\n", howmany, howmany != 1 ? "s" : "");
  bar2(des, NULL, NULL, NULL);
}

void command_tell(character *c, char *sRemainder)
{
  char *sMessage = sRemainder;
  char *sTerm;

  while (*sMessage && !isspace(*sMessage))
    sMessage++;
  sTerm = sMessage;
  while (*sMessage && isspace(*sMessage))
    sMessage++;
  *sTerm = 0;

  {
    character *pDest = character_from_name(sRemainder);

    if (!pDest) {
      send_to_char(c, "Character '%s' could not be found or is ambiguous.\n", sRemainder);
      return;
    }

    if (pDest == c) {
      send_to_char(c, "Talking to yourself again?\n");
      return;
    }

    if(STREQ(sMessage, "")) {
      send_to_char(c, "Tell %s, what ?\n", pDest->name);
      return;
    }
    
    send_to_char(pDest, "^W> %s tells you '%s^W'^n\n", c->name, sMessage);
    send_to_char(c, "You tell %s '%s^n'\n", pDest->name, sMessage);
  }
}

void command_remote(character *c, char *sRemainder)
{
  char *sMessage = sRemainder;
  char *sTerm;

  while (*sMessage && !isspace(*sMessage))
    sMessage++;
  sTerm = sMessage;
  while (*sMessage && isspace(*sMessage))
    sMessage++;
  *sTerm = 0;

  {
    character *pDest = character_from_name(sRemainder);

    if (!pDest) {
      send_to_char(c, "Character '%s' could not be found or is ambiguous.\n", sRemainder);
      return;
    }

    if (pDest == c) {
      send_to_char(c, "Thats you, you fool\n");
      return;
    }

    if(STREQ(sMessage, "")) {
      send_to_char(c, "Emote to %s, what ?\n", pDest->name);
      return;
    }
    
    send_to_char(pDest, "^W> %s %s^W, at you^n\n", c->name, sMessage);
    send_to_char(c, "You emote '%s %s^n' to %s^n\n", c->name, sMessage,
                 pDest->name);
  }
}

void command_say(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "say");
    return;
  }
  send_to_room_except(c->group, c, "%s says \'%s^n\'\n", c->name, r);
  send_to_char(c, "You say \'%s^n\'\n", r);
}

void command_emote(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "emote");
    return;
  }
  send_to_room_except(c->group, c, "%s %s\n", c->name, r);
  send_to_char(c, "You emote \'%s %s\'\n", c->name, r);
}

void command_shout(character *c, char *r)
{
  if (STREQ(r, "")) {
    help_usage(c, "shout");
    return;
  }
  send_to_all_except(c, "%s shouts \'%s^n\'\n", c->name, r);
  send_to_char(c, "You shout \'%s^n\'\n", r);
}

void command_quit(character *c, char *r)
{
  descriptor *des = getdes(c); 

  des->state = STATE_CLOSING;
  send_to_all_except(c, "\n+++ ^r%s^n has logged out\n", c->name);
  send_to_char(c, "\n+++ You have logged out\n");
  if (send_file_to_descriptor("lib/etc/logout", des) !=0)
    send_to_descriptor(des, "Goodbye!\n");

  des->safe = FALSE;
}

void command_whoami(character *c, char *r)
{
  send_to_char(c, "You are ^r%s^n\n", c->name);
}

bool command_shortcut_run(descriptor *des, char *s)
{
  character *p = &des->player;
  int c;

  s = strip_leading_white_space(s);
  if (strlen(s) != 0) {
    for (c = 0; c < commandn; c++) {
      if (strchr(commands[c].shortcut, s[0]) &&
          haspriv(p, commands[c].privname))
      {
        void (*function)(character *, char *);

        function = commands[c].function;
        s++; /* to get past the shortcut character */
        s = strip_leading_white_space(s);
        function(p, s);
        return TRUE;
      }
    }
  }

  return FALSE;
}

void command_parse_n_run(descriptor *des, const char *first,
                         char *remainder)
{
  unsigned int count = 0;
  unsigned int index = 0;
  unsigned int c;
  character *p = &des->player;

  if (STREQ(first, ""))
    return;

  for (c = 0; c < commandn; c++) {
    if (STREQ(first, commands[c].name) &&
        haspriv(p, commands[c].privname))
    {
      /* Matches exactly */
      void (*function)(character *, char *);

      function = commands[c].function;
      function(p, remainder);
      return;
    } else if (STRNEQ(first, commands[c].name, strlen(first))
               && haspriv(p, commands[c].privname)) {
      /* Part matches */
      index = c;
      count ++;
    }
  }
  switch (count) {
    case 0:
      send_to_char(p, "Command \'%s\' not known, try help\n", first);
      break;
    case 1:
      /* Matches one command without ambiguity */
      {
        void (*function)(character *, char *);

        function = commands[index].function;
        function(p, remainder);
        return;
        break;
      }
    default:
      /* Part matches more than one command */
      send_to_char(p, "Command \'%s\' ambiguous, try help\n", first);
      break;
   }
}

void command_do(descriptor *des, const char *buffer)
{
  char line[MAX_RAW_INPUT_BUFFER];
  char *first, *remainder;
  char *temp;
  bool carryon = TRUE;

  STRNCOPY(line, buffer, sizeof(line));
  first = line;

  while (carryon == TRUE) {
    /* strip leading white space in command */
    first = strip_leading_white_space(first);
    /* search for a ; in the input */
    temp = strchr(first+1, ';');
    if (temp != NULL) {
      /* found a ; */
      *temp = '\0';
      temp++;
      if (*temp == '\0') {
        /* is temp a 0 length string ? */
        carryon = FALSE;
      } else {
        carryon = TRUE;
      }
    } else {
      carryon = FALSE;
    }

    strip_trailing_white_space(first);  
    if (command_shortcut_run(des, first) == FALSE) {
      strmunch(first, &first, &remainder);
      strlower(first);
      command_parse_n_run(des, first, remainder);
    }

    if (carryon == TRUE) {
      first = temp;
    }
  }

  /* Do a prompt */
  send_to_char(&des->player, "%s^n", &des->player.prompt);
}

descriptor* getdes(character *c) {
  return LIST_GET_DATA(c, descriptor *, player);
}

void seconds_to_string(unsigned long seconds, char *buffer, size_t size)
{
  unsigned long t;
  int len;

  t = seconds / (60 * 60 * 24);
  if (t > 0) {
    len = msnprintf(buffer, size, "%lu day%s, ", t, t != 1 ? "s" : "");
    buffer += len;
    size -= len;
  }
  seconds %= (60 * 60 * 24);
  t = seconds / (60 * 60);
  if (t > 0) {
    len = msnprintf(buffer, size, "%lu hr%s, ", t, t != 1 ? "s" : "");
    buffer += len;
    size -= len;
  }
  seconds %= (60 * 60);
  t = seconds / 60;
  if (t > 0) {
    len = msnprintf(buffer, size, "%lu min%s, ", t, t != 1 ? "s" : "");
    buffer += len;
    size -= len;
  }
  seconds %= 60;
  msnprintf(buffer, size, "%lu sec%s", seconds, seconds != 1 ? "s": "");
}