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 <string.h>
#include "externs.h"
#include "db.h"

char *swlm;

#define W_EMAIL      0x1
#define W_DOING      0x2
#define W_HOST       0x4
#define W_PORT       0x8
#define W_DESCRIPTOR 0x10
#define W_THROUGHPUT 0x20
#define W_IDLE       0x40
#define W_ONFOR      0x80
#define W_CLASS      0x100
#define W_FLAGS      0x200
#define W_ALIAS      0x400
#define W_NAME       0x800

#define W_LASTBIT 0x800

#define NAME_LEN        9
#define ALIAS_LEN       5
#define CLASS_LEN       5
#define IDLE_LEN        4
#define ONFOR_LEN       7
#define DOING_LEN      30
#define FLAGS_LEN       5
#define DESCRIPTOR_LEN 10
#define THROUGHPUT_LEN 10
#define HOST_LEN       19
#define PORT_LEN        4
#define EMAIL_LEN      14

static unsigned long DEF_WHO_FLAGS =
  W_NAME|W_ALIAS|W_FLAGS|W_IDLE|W_ONFOR|W_DOING;

static unsigned long parse_flags(OBJ *player, char *list)
{
  char *l;
  unsigned long flags = 0;

  for(l = list;*l;l++)
  {
    switch(tolower(*l))
    {
      case 'n': flags |= W_NAME; break;
      case 'a': flags |= W_ALIAS; break;
      case 'c': flags |= W_CLASS; break;
      case 'i': flags |= W_IDLE; break;
      case 'o': flags |= W_ONFOR; break;
      case 'd': flags |= W_DOING; break;
      case 'f': flags |= W_FLAGS; break;
      case 'h': flags |= W_HOST; break;
      case 'x': flags |= W_DESCRIPTOR; break;
      case 't': flags |= W_THROUGHPUT; break;
      case 'p': flags |= W_PORT; break;
      case 'e': flags |= W_EMAIL; break;
      default:
        notify(player, tprintf("Unknown who flag: %c", *l));
        return(0);
    }
  }

  return(flags);
}

static char *get_field(OBJ *player, DDATA *d, unsigned long bit, int header)
{
  char buf[4096];

  *buf = '\0';

  switch(bit)
  {
    case W_NAME:
      if(header)
        strcpy(buf, my_ljust("NAME", NAME_LEN));
      else
        strcpy(buf, my_ljust(name(d->player), NAME_LEN));
      break;
    case W_ALIAS:
      if(header)
        strcpy(buf, my_ljust("ALIAS", ALIAS_LEN));
      else
        strcpy(buf, my_ljust(atr_get(d->player, "ALIAS"), ALIAS_LEN));
      break;
    case W_CLASS:
      if(header)
        strcpy(buf, my_ljust("CLASS", CLASS_LEN));
      else
        strcpy(buf,
          my_ljust(short_class_to_name(get_class(d->player)), CLASS_LEN));
      break;
    case W_FLAGS:
      if(header)
        strcpy(buf, my_ljust("FLAGS", FLAGS_LEN));
      else
      {
/* Make sure FLAGS_LEN is at least as big as the amount of flags */
        strcpy(buf, my_string(" ", FLAGS_LEN));  /* Init buf */
        if(get_class(d->player) > CLASS_CITIZEN)
          buf[0] = 'W';
        if(now-d->last_time > 300)
          buf[1] = 'i';
        if(*atr_get(d->player, "LHIDE"))
          buf[2] = 'h';
        if(d->player->flags & PLAYER_NEWBIE)
          buf[3] = 'n';
        if(d->player->flags & PLAYER_NO_WALLS)
          buf[4] = 'N';
      }
      break;
    case W_IDLE:
      if(header)
        strcpy(buf, my_rjust("IDLE", IDLE_LEN));
      else
        strcpy(buf, my_rjust(time_format(now-d->last_time, 1), IDLE_LEN));
      break;
    case W_ONFOR:
      if(header)
        strcpy(buf, my_rjust("ONFOR", ONFOR_LEN));
      else
        strcpy(buf, my_rjust(time_format(now-d->connected_at, 2), ONFOR_LEN));
      break;
    case W_DOING:
      if(header)
        strcpy(buf, my_ljust("DOING", DOING_LEN));
      else
        strcpy(buf, my_ljust(atr_get(d->player, "DOING"), DOING_LEN));
      break;
    case W_HOST:
      if(header)
        strcpy(buf, my_ljust("HOST", HOST_LEN));
      else
      {
        if(!controls(player, d->player, POW_HOST))
          strcpy(buf, "???");
        else
          strcpy(buf,
            my_ljust(tprintf("%s@%s", d->user, d->addr), HOST_LEN));
      }
      break;
    case W_DESCRIPTOR:
      if(header)
        strcpy(buf, my_ljust("DESCRIPTOR", DESCRIPTOR_LEN));
      else
        strcpy(buf, my_ljust(tprintf("%d", d->descriptor), DESCRIPTOR_LEN));
      break;
    case W_THROUGHPUT:
      if(header)
        strcpy(buf, my_ljust("THROUGHPUT", THROUGHPUT_LEN));
      else
        strcpy(buf, my_rjust(tprintf("%.1f", get_input(d)+get_output(d)),
          THROUGHPUT_LEN));
      break;
    case W_PORT:
      if(header)
        strcpy(buf, my_ljust("PORT", PORT_LEN));
      else
        strcpy(buf,
          my_ljust(tprintf("%d", ntohs(d->address.sin_port)), PORT_LEN));
      break;
    case W_EMAIL:
      if(header)
        strcpy(buf, my_ljust("EMAIL", EMAIL_LEN));
      else
        strcpy(buf, my_ljust(atr_get(d->player, "EMAIL"), EMAIL_LEN));
      break;
  }

  return(stack_string_alloc(buf, 0));
}

static char *cur_time()
{
  char buf[4096];
  struct tm *tim = localtime(&now);
  char *suffix;
  int hour;

  suffix = (tim->tm_hour/12)?"pm":"am";
  hour = (tim->tm_hour%12)?tim->tm_hour%12:12;

  sprintf(buf, "%d:%02d:%02d%s",
    hour, tim->tm_min, tim->tm_sec, suffix);
  return(stack_string_alloc(buf, 0));
}

static int get_plist(DDATA ***plist, OBJ *player, char *arg)
{
  DDATA *d;
  OBJ *victim;
  int ctr = 0, done = 0;
  char *p, *q;

  for(d = descriptor_list;d;d = d->next)
    ctr++;
  *plist = (DDATA **)stack_alloc(sizeof(DDATA *)*ctr, 0, 0);
  ctr = 0;

  if(!*arg)
  {
    for(d = descriptor_list;d;d = d->next)
      (*plist)[ctr++] = d;
    return(ctr);
  }

  for(p = arg;p && *p;)
  {
    if((q = strchr(p, ' ')))
      *q = '\0';
    else
      done = 1;

    if(!(victim = match_player(NULL, p)))
    {
      notify(player, no_match(p));
      p = q;
      if(!done)
        p++;
      continue;
    }
    for(d = descriptor_list;d;d = d->next)
      if(d->player == victim)
        if(controls(player, victim, POW_WHO) ||
          could_doit(player, victim, "LHIDE"))
        {
          (*plist)[ctr++] = d;
        }
    p = q;
    if(!done)
      p++;
  }

  return(ctr);
}

void do_who(OBJ *player, char *arg1, char *arg2)
{
  unsigned long flags;
  DDATA *d;
  char buf[4096], output[4096];
  unsigned long bit;
  int total_users = 0, total_hidden = 0, total_active = 0;
  double average_onfor = 0, average_idle = 0;
  char *header_color;
  unsigned int num_shown = 0;
  DDATA **plist;
  int i, num_in_list;

  if(!*(header_color = atr_get(player, "WHOCOLOR")))
    header_color = "n";

  if(!*arg1)
    flags = DEF_WHO_FLAGS;
  else
    flags = parse_flags(player, arg1);

  if(!flags)
    return;

  if(!(num_in_list = get_plist(&plist, player, arg2)))
  {
    notify(player, "Nothing to show.");
    return;
  }

  *output = '\0';

  notify(player, tprintf("|+W|%s", my_string("-", 78)));
  do_swlm(player, "");
  notify(player, tprintf("|+W|%s", my_string("-", 78)));

  for(bit = W_LASTBIT;bit > 0;bit >>= 1)
  {
    if(!(flags & bit))
      continue;

    sprintf(output+strlen(output), "%s ", get_field(player, NULL, bit, 1));
  }

  notify(player, tprintf("|%s|%s", header_color, output));

  for(i = 0, d = plist[0];i < num_in_list;d = plist[++i])
  {
    if(!check_state(d, STATE_CONNECTED))
      continue;

    total_users++;

    if(!could_doit(player, d->player, "LHIDE"))
    {
      total_hidden++;

      if(!controls(player, d->player, POW_WHO))
        continue;
    }

    num_shown++;

    if(now-d->last_time < 300)
      total_active++;

    average_onfor += (double)(now-d->connected_at);
    average_idle += (double)(now-d->last_time);

    *output = '\0';

    for(bit = W_LASTBIT;bit > 0;bit >>= 1)
    {
      if(!(flags & bit))
        continue;

      strcpy(buf, get_field(player, d, bit, 0));
      strcat(buf, " ");

      strcat(output, buf);
    }

    notify(player, output);
  }

  notify(player, tprintf("|+W|%s", my_string("-", 78)));

  sprintf(buf, "|%s|Total Users: |+W|%d", header_color, total_users);
  sprintf(buf+strlen(buf), "|%s|   Hidden Users: |+W|%d",
    header_color, total_hidden);
  sprintf(buf+strlen(buf), "|%s|   Active Users: |+W|%d",
    header_color, total_active);
  notify(player, buf);

  if(num_shown)
  {
    average_onfor /= num_shown;
    average_idle /= num_shown;
  }

  sprintf(buf, "|%s|Average Onfor: |+W|%s",
    header_color, time_format(average_onfor, 3));
  sprintf(buf+strlen(buf), "|%s|   Average Idle: |+W|%s",
    header_color, time_format(average_idle, 2));
  sprintf(buf+strlen(buf), "|%s|   Current Time: |+W|%s",
    header_color, cur_time());
  notify(player, buf);

  notify(player, tprintf("|+W|%s", my_string("-", 78)));
}

void do_whocolor(OBJ *player, char *arg)
{
  char clr[1024];
  char *c = atr_get(player, "WHOCOLOR");

  if(!my_is_color(c))
    sprintf(clr, "|n|n");
  else
    sprintf(clr, "|%s|%s", c, c);

  if(!*arg)
  {
    notify(player, tprintf("Who list header color: %s", clr));
    return;
  }

  if(!my_is_color(arg))
  {
    notify(player, tprintf("%s is not a valid color.", arg));
    return;
  }

  atr_add(player, "WHOCOLOR", arg);
  notify(player, tprintf("Who list color set to |%s|%s.", arg, arg));
}

void do_swlm(OBJ *player, char *arg)
{
  const char *default_msg = "|C|This is the Stupid Who List Message. To change me type '+swlm <msg>'.";
  char buf[4096];
  char *clr;

  if(!*(clr = atr_get(player, "WHOCOLOR")))
    clr = "n";

  if(!*arg)
  {
    notify(player, tprintf("|%s|SWLM|+W|: |n|%s", clr, swlm));
    return;
  }

  if(!strcmp(arg, "default"))
  {
    strcpy(buf, default_msg);
    log_important(tprintf("%s set the SWLM to the default message",
      unparse_object(player, player)));
  }
  else
  {
    if(strlen(arg) > 800)
      *(arg+800) = '\0';

    sprintf(buf, "|C|%s |+W|--%s", arg, name(player));
    log_important(tprintf("%s changed the SWLM to: %s",
      unparse_object(player, player), arg));
  }

  if(!swlm)
    swlm = stack_string_alloc(buf, 1);
  else
    swlm = stack_string_realloc(swlm, buf);

  notify(player, "SWLM set.");
}