/
2.0.5/doc/
2.0.5/gnu/
2.0.5/sha/
/* interface.c */

#include "config.h"

/*
 *		       This file is part of TeenyMUD II.
 *		 Copyright(C) 1993, 1994, 1995 by Jason Downs.
 *                           All rights reserved.
 * 
 * TeenyMUD II is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * TeenyMUD II is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file 'COPYING'); if not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA.
 *
 */

/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca	__builtin_alloca
#else	/* not __GNUC__ */
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else	/* not HAVE_ALLOCA_H */
#ifdef _AIX
 #pragma alloca
#endif	/* not _AIX */
#endif	/* not HAVE_ALLOCA_H */
#endif 	/* not __GNUC__ */

#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif			/* HAVE_STRING_H */
#include <ctype.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif			/* HAVE_SYS_TIME_H */
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif			/* HAVE_STDLIB_H */

#include "conf.h"
#include "teeny.h"
#include "commands.h"
#include "fcache.h"
#include "conn.h"
#include "externs.h"

enum who_code { LIST_WHO, LIST_WHERE, LIST_SESSION };
enum str_code { PREFIX, SUFFIX };

static char poll_str[41];		/* the poll */

static void conn_updsite _ANSI_ARGS_((struct conn *));
static void set_output_str _ANSI_ARGS_((struct conn *, char *, enum str_code));
static void do_wholine _ANSI_ARGS_((struct conn *, struct conn *,
				    char *, enum who_code, int, int *, int *));
static void do_wholist _ANSI_ARGS_((struct conn *, char *, enum who_code));
static void do_stty _ANSI_ARGS_((struct conn *, char *));
static void log_create _ANSI_ARGS_((struct conn *));
static void log_badconnect _ANSI_ARGS_((struct conn *, char *));
static void log_badcreate _ANSI_ARGS_((struct conn *, char *));

void interface_init()
{
  time_t now;

  time(&now);

  mudstat.now = now;
  mudstat.lastdump = now;
  mudstat.startup = now;
  mudstat.lasttime = now;
  poll_str[0] = '\0';
}

void timers()
{
  register struct conn *cp;

  /* run the queue */
  queue_run(mudconf.queue_slice);

  /* timeout connections. */
  if (mudstat.now > mudstat.lasttime) {
    for(cp = connlist; cp != (struct conn *)NULL; cp = cp->next) {
      if((cp->player == -1) && mudconf.login_timeout) {
	if((cp->last - mudstat.now) > mudconf.login_timeout) {
	  conn_dump_file(cp, mudconf.timeout_file);
	  conn_logoff(cp);
	}
      }
      if((cp->player != -1) && mudconf.player_timeout
         && !isWIZARD(cp->player)) {
        if((cp->last - mudstat.now) > mudconf.player_timeout) {
	  conn_dump_file(cp, mudconf.timeout_file);
	  conn_logoff(cp);
	}
      }

      cp->cc = 0;
    }
  }

  /* dump the database. */
  if ((mudstat.now - mudstat.lastdump) > mudconf.dump_interval) {
    mudstat.lastdump = mudstat.now;
    dump_db();
  }

  /* ping rwho */
  if (mudconf.enable_rwho
      && ((mudstat.now - mudstat.lastrwho) > mudconf.rwho_interval)) {
    mudstat.lastrwho = mudstat.now;
    rwho_ping();
  }

  mudstat.lasttime = mudstat.now;
}

#define SKIP_WORD(x, y)		for(y = x; y[0] && !isspace(y[0]); y++); \
				for(; y[0] && isspace(y[0]); y++)

VOID handle_input(cp, input)
    struct conn *cp;
    char *input;
{
  switch(input[0]) {
  case 'W':
  case 'w':	/* WHO or WHERE */
    if(!strncasecmp(input, "WHO", 3)) {
      if(cp->outputprefix != (char *)NULL)
	conn_put(cp, cp->outputprefix);
      do_wholist(cp, input + 3, LIST_WHO);
      if(cp->outputsuffix != (char *)NULL)
	conn_put(cp, cp->outputsuffix);
      return;
    } else if(!strncasecmp(input, "WHERE", 5)) {
      if(cp->outputprefix != (char *)NULL)
	conn_put(cp, cp->outputprefix);
      do_wholist(cp, input + 5, LIST_WHERE);
      if(cp->outputsuffix != (char *)NULL)
	conn_put(cp, cp->outputsuffix);
      return;
    }
    break;
  case 'S':
  case 's':	/* SESSION or STTY */
    if(!strncasecmp(input, "SESSION", 7)) {
      if(cp->outputprefix != (char *)NULL)
	conn_put(cp, cp->outputprefix);
      do_wholist(cp, input + 7, LIST_SESSION);
      if(cp->outputsuffix != (char *)NULL)
	conn_put(cp, cp->outputsuffix);
      return;
    } else if(!strncasecmp(input, "STTY", 4)) {
      if(cp->outputprefix != (char *)NULL)
        conn_put(cp, cp->outputprefix);
      do_stty(cp, input + 4);
      if(cp->outputsuffix != (char *)NULL)
        conn_put(cp, cp->outputsuffix);
      return;
    }
    break;
  case 'Q':
  case 'q':
    if(!strcasecmp(input, "QUIT")) {
      conn_dump_file(cp, mudconf.bye_file);
      conn_logoff(cp);
      return;
    }
    break;
  case 'O':	/* OUPUT*X */
    if(!strncmp(input, "OUTPUTPREFIX", 12)) {
      if(isROBOT(cp->player)) {
        set_output_str(cp, input + 12, PREFIX);
      } else {
        conn_put(cp, "Only robots may use OUTPUTPREFIX.");
      }
      return;
    } else if(!strncmp(input, "OUTPUTSUFFIX", 12)) {
      if(isROBOT(cp->player)) {
        set_output_str(cp, input + 12, SUFFIX);
      } else {
        conn_put(cp, "Only robots may use OUTPUTSUFFIX.");
      }
      return;
    }
    break;
  case 'P':	/* PUEBLO */
    if(!strncmp(input, "PUEBLOCLIENT", 12)) {
      if(mudconf.enable_pueblo) {
	cp->html_ext = HTML_PUEBLO;
	conn_put_raw(cp, "</xch_mudtext><img xch_mode=html>");
      } else {
	conn_put(cp, "Sorry, I don't *do* that.");
      }
      return;
    }
    break;
  }

  /* still here? */
  if(cp->outputprefix != (char *)NULL)
    conn_put(cp, cp->outputprefix);
  handle_cmd(cp->player, cp->player, input, 0, (char **)NULL);
  if(cp->outputsuffix != (char *)NULL)
    conn_put(cp, cp->outputsuffix);
}

VOID handle_login(cp, input)
    struct conn *cp;
    char *input;
{
  char *ptr, *name, *pwd, *mesg;
  int player;

  switch(input[0]) {
  case 'W':
  case 'w':	/* WHO or WHERE */
    if(!strncasecmp(input, "WHO", 3)) {
      if(cp->outputprefix != (char *)NULL)
	conn_put(cp, cp->outputprefix);
      do_wholist(cp, input + 3, LIST_WHO);
      if(cp->outputsuffix != (char *)NULL)
	conn_put(cp, cp->outputsuffix);
    } else if(!strncasecmp(input, "WHERE", 5)) {
      if(cp->outputprefix != (char *)NULL)
	conn_put(cp, cp->outputprefix);
      do_wholist(cp, input + 5, LIST_WHERE);
      if(cp->outputsuffix != (char *)NULL)
	conn_put(cp, cp->outputsuffix);
    }
    return;
  case 'S':
  case 's':	/* SESSION or STTY */
    if(!strncasecmp(input, "SESSION", 7)) {
      if(cp->outputprefix != (char *)NULL)
	conn_put(cp, cp->outputprefix);
      do_wholist(cp, input + 7, LIST_SESSION);
      if(cp->outputsuffix != (char *)NULL)
	conn_put(cp, cp->outputsuffix);
    } else if(!strncasecmp(input, "STTY", 4)) {
      if(cp->outputprefix != (char *)NULL)
        conn_put(cp, cp->outputprefix);
      do_stty(cp, input + 4);
      if(cp->outputsuffix != (char *)NULL)
        conn_put(cp, cp->outputsuffix);
    }
    return;
  case 'Q':
  case 'q':	/* QUIT */
    if(!strcasecmp(input, "QUIT"))
      conn_logoff(cp);
    return;
  case 'O':	/* OUTPUT*X */
    if(!strncmp(input, "OUTPUTPREFIX", 12))
      set_output_str(cp, input + 12, PREFIX);
    else if(!strncmp(input, "OUTPUTSUFFIX", 12))
      set_output_str(cp, input + 12, SUFFIX);
    return;
  case 'P':     /* PUEBLO */
    if(!strncmp(input, "PUEBLOCLIENT", 12)) {
      if(mudconf.enable_pueblo) {
	cp->html_ext = HTML_PUEBLO;
	conn_put_raw(cp, "</xch_mudtext><img xch_mode=html>");
      } else {
	conn_put(cp, "Sorry, I don't *do* that.");
      }
      return;
    }
    break;
  }

  /* still here? */
  if(!strncasecmp(input, "co", 2)) {
    /* login attempt */
    SKIP_WORD(input, ptr);

    if(parse_name_pwd(ptr, &name, &pwd) != 0)
      conn_put(cp, "Error parsing connection sequence.");
    else {
      player = connect_player(name, pwd);
      if(player == -1) {
	conn_dump_file(cp, mudconf.badconn_file);
	log_badconnect(cp, name);
      } else {
	char *hatr;
	int haflgs;

	if((mudstat.logins != LOGINS_DISABLED) || isWIZARD(player)) {
          announce_connect(player, cp->user, cp->host);	/* first */
	  animate(player);
	  cp->player = player;
	  cp->handler = handle_input;
	  log_connect(cp);
	  if(mudconf.enable_rwho)
	    rwho_login(player);

	  if(!isGUEST(player)) {
	    if(attr_get(player, SITE, &hatr, &haflgs) != -1) {
	      if((hatr == (char *)NULL) || (hatr[0] == '\0'))
	        conn_dump_file(cp, mudconf.newp_file);
	    } else
	      logfile(LOG_ERROR,
		      "handle_login: couldn't get host on player #%d\n",
		      player);
	    conn_dump_file(cp, mudconf.motd_file);
	    if(mudstat.exmotd != (char *)NULL)
	      conn_put(cp, mudstat.exmotd);
	    if(isWIZARD(player)) {
	      conn_dump_file(cp, mudconf.wizn_file);
	      if(mudstat.exwiz != (char *)NULL)
	        conn_put(cp, mudstat.exwiz);
	    }
	  } else
	    conn_dump_file(cp, mudconf.guest_file);
	  check_last(player);
	  check_news(player);
	  if(mudconf.enable_money)
	    check_paycheck(player);

	  conn_updsite(cp);
	  stamp(player, STAMP_LOGIN);
	  if(!isROBOT(player)
	     && ((cp->outputprefix != (char *)NULL)
	 	  || (cp->outputsuffix != (char *)NULL))) {
	    conn_put(cp,
		     "Your OUTPUTREFIX and OUTPUTSUFFIX strings have been cleared.");
	    if(cp->outputprefix != (char *)NULL) {
	      ty_free((VOID *)cp->outputprefix);
	      cp->outputprefix = (char *)NULL;
	    }
	    if(cp->outputsuffix != (char *)NULL) {
	      ty_free((VOID *)cp->outputsuffix);
	      cp->outputsuffix = (char *)NULL;
	    }
	  }
	  stty_restore(cp);
	  look_location(player, player, 0);
	} else
	  conn_put(cp, "Sorry, logins are disabled.");
      }
    }
  } else if(!strncasecmp(input, "cr", 2)) {
    /* creation attempt */
    SKIP_WORD(input, ptr);

    if(mudstat.logins != LOGINS_DISABLED) {
      if(!mudconf.registration) {
        if(check_host(cp->host, LOCK_REGISTER, &mesg)) {
	  if(mesg && *mesg) {
	    conn_put(cp, mesg);
	  } else {
	    conn_dump_file(cp, mudconf.register_file);
	  }
	  return;
        }
        if(parse_name_pwd(ptr, &name, &pwd) != 0)
	  conn_put(cp, "Error parsing creation sequence.");
        else {
	  player = create_player(name, pwd, -1);
	  if(player == -1) {
	    conn_dump_file(cp, mudconf.badcrt_file);
	    log_badcreate(cp, name);
	  } else {
	    announce_connect(player, cp->user, cp->host);	/* first */
	    animate(player);
	    cp->player = player;
	    cp->handler = handle_input;
	    log_create(cp);
	    if(mudconf.enable_rwho)
	      rwho_login(player);

	    conn_dump_file(cp, mudconf.newp_file);
	    conn_dump_file(cp, mudconf.motd_file);
	    if(mudstat.exmotd != (char *)NULL)
	      conn_put(cp, mudstat.exmotd);
	    check_news(player);
	    conn_updsite(cp);
	    stamp(player, STAMP_LOGIN);
	    if(!isROBOT(player)
	       && ((cp->outputprefix != (char *)NULL)
		   || (cp->outputsuffix != (char *)NULL))) {
	      conn_put(cp,
		       "Your OUTPUTPREFIX and OUTPUTSUFFIX strings have been cleared.");
	      if(cp->outputprefix != (char *)NULL) {
	        ty_free((VOID *)cp->outputprefix);
	        cp->outputprefix = (char *)NULL;
	      }
	      if(cp->outputsuffix != (char *)NULL) {
	        ty_free((VOID *)cp->outputsuffix);
	        cp->outputsuffix = (char *)NULL;
	      }
	    }
	    stty_restore(cp);
	    look_location(player, player, 0);
	  }
        }
      } else
        conn_dump_file(cp, mudconf.register_file);
    } else
      conn_put(cp, "Sorry, logins are disabled.");
  } else
    conn_greet(cp);
}

static void conn_updsite(cp)
    struct conn *cp;
{
  if(cp->player == -1)
    return;

  if(cp->user != (char *)NULL) {
    char *buff = (char *)alloca(strlen(cp->user) + strlen(cp->host) + 2);

    if(buff == (char *)NULL) {
      panic("conn_updsite: stack allocation failed.\n");
    }
    strcpy(buff, cp->user);
    strcat(buff, "@");
    strcat(buff, cp->host);

    if(attr_add(cp->player, SITE, buff, SITE_FLGS) == -1)
      logfile(LOG_ERROR,
              "conn_updsite: couldn't set host on player #%d\n", cp->player);
  } else if((cp->host != (char *)NULL) && (cp->host[0] != '\0')) {
    if(attr_add(cp->player, SITE, cp->host, SITE_FLGS) == -1)
      logfile(LOG_ERROR,
              "conn_updsite: couldn't set host on player #%d\n", cp->player);
  }
}

#if defined(__STDC__)
static void set_output_str(struct conn *cp, char *string, enum str_code code)
#else
static void set_output_str(cp, string, code)
    struct conn *cp;
    char *string;
    enum str_code code;
#endif
{
  while (string[0] && isspace(string[0]))
    string++;

  switch(code) {
  case PREFIX:
    if (!string || !*string) {
      ty_free((VOID *)cp->outputprefix);
      cp->outputprefix = (char *)NULL;
    } else {
      ty_free((VOID *)cp->outputprefix);
      cp->outputprefix = (char *)ty_strdup(string,
      					"set_output_str.outputprefix");
    }
    break;
  case SUFFIX:
    if (!string || !*string) {
      ty_free((VOID *)cp->outputsuffix);
      cp->outputsuffix = (char *)NULL;
    } else {
      ty_free((VOID *)cp->outputsuffix);
      cp->outputsuffix = (char *)ty_strdup(string,
      					"set_output_str.outputprefix");
    }
    break;
  }
}

void conn_greet(cp)
    struct conn *cp;
{
  if (cp->player == -1) {
    if (mudconf.enable_pueblo)
      conn_put(cp, "This world is Pueblo 1.0 Enhanced.");
    conn_dump_file(cp, mudconf.greet_file);
  }
}

int conn_dump_file(cp, filename)
    struct conn *cp;
    char *filename;
{
  FCACHE *fc;
  off_t size;

  /* problem: fcache'd files of zero lenght return NULL. */
  fc = fcache_open(filename, &size);
  if ((fc == (FCACHE *)NULL) && (size == -1)) {
    char buff[256];

    snprintf(buff, sizeof(buff), "I'm sorry, %s seems to be broken.",
	     filename);
    conn_put(cp, buff);
    return(-1);
  }

  while(fc != (FCACHE *)NULL) {
    conn_put(cp, fcache_read(fc));

    fc = fcache_next(fc);
  }
  return(1);
}

/* Display the WHO list to a connection. */
INLINE static char *convtime1(wtime)
    time_t wtime;
{
  register time_t g, h, i, j;
  static char ret[40];

  g = wtime;
  h = g / 86400;
  g %= 86400;
  i = g / 3600;
  j = g / 60 % 60;

  if (h)
    snprintf(ret, sizeof(ret), "%ldd %02ld:%02ld", h, i, j);
  else
    snprintf(ret, sizeof(ret), "%02ld:%02ld", i, j);
  return (ret);
}

INLINE static char *convtime2(idtime)
    time_t idtime;
{
  register time_t k;
  register char idletype;
  static char ret[40];

  k = idtime;
  idletype = 's';
  if (k > 59) {
    idletype = 'm';
    k /= 60;
    if (k > 59) {
      idletype = 'h';
      k /= 60;
      if (k > 23) {
	idletype = 'd';
	k /= 24;
      }
    }
  }
  snprintf(ret, sizeof(ret), "%2ld%c", k, idletype);
  return (ret);
}

#if defined(__STDC__)
static void do_wholine(register struct conn *cp, register struct conn *who,
		       char *arg, enum who_code code, int wizard, int *total,
		       int *utotal)
#else
static void do_wholine(cp, who, arg, code, wizard, total, utotal)
    register struct conn *cp, *who;
    char *arg;
    enum who_code code;
    int wizard, *total, *utotal;
#endif
{
  char *whonm;
  char line[256], namebuf[40], locbuf[60];
  int loc;

  if (wizard || ((who->player != -1) && (!isDARK(who->player)))) {
    if(who->player != -1) {
      (*total)++;

      if (get_str_elt(who->player, NAME, &whonm) != -1)
	strcpy(namebuf, whonm);
      else
	strcpy(namebuf, "???");
      if ((arg != (char *)NULL) && (arg[0] != '\0')
	  && !stringprefix(namebuf, arg))
	return;
      if (wizard) {
	snprintf(&namebuf[strlen(namebuf)], sizeof(namebuf) - strlen(namebuf),
		 "(#%d%s%s%s%s%s)", who->player,
		 (isWIZARD(who->player) ? "W" : ""),
		 (isDARK(who->player) ? "D" : ""),
		 (isHIDDEN(who->player) ? "h" : ""),
		 (isGUEST(who->player) ? "g" : ""),
		 ((who->html_ext == HTML_PUEBLO) ? "P" : ""));
      }
    } else {
      (*utotal)++;

      if ((arg != (char *)NULL) && (arg[0] != '\0'))	/* They don't match. */
	return;

      strcpy(namebuf, "***");
    }

    switch (code) {
    case LIST_WHO:
      snprintf(line, sizeof(line), "%-19s%9s%7s %s", namebuf,
	      convtime1(mudstat.now - who->connect),
	      convtime2(mudstat.now - who->last),
	      (who->doing != (char *)NULL) ? who->doing : "");
      break;
    case LIST_WHERE:
      if ((who->player == -1) ||
	  (get_int_elt(who->player, LOC, &loc) == -1) || !exists_object(loc))
	loc = -1;
      if (!wizard) {
	if (!isHIDDEN(who->player) && (loc != -1) && !isHIDDEN(loc) &&
	    (get_str_elt(loc, NAME, &whonm) != -1)) {
	  ty_strncpy(locbuf, whonm, 50);
	} else
	  strcpy(locbuf, "???");
	if ((strlen(locbuf) < 45) && exists_object(loc) && (isJUMP_OK(loc) ||
	    ((cp->player != -1) && controls(cp->player, cp->player, loc)))) {
	  snprintf(&locbuf[strlen(locbuf)], sizeof(locbuf) - strlen(locbuf),
		   "(#%d)", loc);
	}
	snprintf(line, sizeof(line), "%-20s%s", namebuf, locbuf);
      } else {
	if (loc == -1) {
	  strcpy(locbuf, "???");
	} else {
	  snprintf(locbuf, sizeof(locbuf), "(#%d)", loc);
	}

	if (who->user != (char *)NULL) {
	  snprintf(line, sizeof(line), "%-20s%8s  %-3d %-5d %s@%s", namebuf,
	  	  locbuf, who->fd, who->port, who->user, who->host);
	} else {
	  snprintf(line, sizeof(line), "%-20s%8s  %-3d %-5d %s", namebuf,
		   locbuf, who->fd, who->port, who->host);
	}
      }
      break;
    case LIST_SESSION:
      snprintf(line, sizeof(line), "%-20s %-10d %-15d %-15d", namebuf,
	      who->bcc, who->ibyte, who->obyte);
      break;
    }
    conn_put(cp, line);
  }
}

#if defined(__STDC__)
static void do_wholist(struct conn *cp, char *arg, enum who_code code)
#else
static void do_wholist(cp, arg, code)
    struct conn *cp;
    char *arg;
    enum who_code code;
#endif
{
  register struct conn *who;
  int total = 0, utotal = 0;
  int wizard = 0;
  int reverse = 0;
  char line[128];

  while (isspace(arg[0]))
    arg++;

  if (mudconf.wizwhoall || ((cp->player != -1) && isWIZARD(cp->player)))
    wizard = 1;
  if((cp->player != -1) && isREVERSED_WHO(cp->player))
    reverse = 1;

  if(!wizard && (code == LIST_SESSION))
    code = LIST_WHO;

  switch(code) {
  case LIST_WHO:
    snprintf(line, sizeof(line),
    	     "Player Name           On For   Idle %s", 
	     (poll_str[0] ? poll_str : "Doing"));
    break;
  case LIST_WHERE:
    strcpy(line, "Player Name         Location");
    if(wizard)
      strcat(line, "  Fd  Port  User/Site");
    break;
  case LIST_SESSION:
    strcpy(line,
    	"Player Name          Blown      Input Count     Output Count");
    break;
  }
  conn_put(cp, line);

  /* dump the list. */
  if(reverse) {
    who = connlist->prev;
    do {
      do_wholine(cp, who, arg, code, wizard, &total, &utotal);

      who = who->prev;
    } while(who != connlist->prev);
  } else {
    for(who = connlist; who != (struct conn *)NULL; who = who->next)
      do_wholine(cp, who, arg, code, wizard, &total, &utotal);
  }

  if (utotal) {
    snprintf(line, sizeof(line),
	     "There are %d connections to the twilight zone.", utotal);
    conn_put(cp, line);
  }
  if (total) {
    snprintf(line, sizeof(line), "%d user%s %s connected.  %sUptime: %s", total,
	     ((total == 1) ? "" : "s"), ((total == 1) ? "is" : "are"),
	     ((mudstat.logins == LOGINS_DISABLED) ? "Logins disabled.  " : ""),
	     convtime1(mudstat.now - mudstat.startup));
  } else {
    snprintf(line, sizeof(line), "No users are connected. %sUptime: %s",
    	     ((mudstat.logins == LOGINS_DISABLED) ? "Logins disabled.  " : ""),
	     convtime1(mudstat.now - mudstat.startup));
  }
  conn_put(cp, line);
}

/* Return a 'list' of the connected object numbers. */
void who_strlist(buffer, bufsiz)
    char *buffer;
    int bufsiz;
{
  struct conn *who;
  char sbuf[32];

  buffer[0] = '\0';
  for(who = connlist; who != (struct conn *)NULL; who = who->next) {
    if((who->player != -1)
       && ((!isDARK(who->player) && !isHIDDEN(who->player))
           || mudconf.wizwhoall)) {
      snprintf(sbuf, sizeof(sbuf), "#%d", who->player);
      slist_add(sbuf, buffer, bufsiz);
    }
  }
}

/* Count how many people are logged in from the host, or all. */
int count_logins(host)
    char *host;
{
  register int count = 0;
  register struct conn *who;

  for(who = connlist; who != (struct conn *)NULL; who = who->next) {
    if((host == (char *)NULL) || quick_wild(who->host, host))
      count++;
  }
  return(count);
}

/* IMPORTANT: These all must be in the same order! */
const char *const stty_nlmodekey[] = {"crnl", "cr", "nl", "nlcr"};
const int stty_nlmodeval[] = {CONN_CRNL, CONN_CR, CONN_NL, CONN_NLCR};
const char *const stty_nlmodes[] = {"\r\n", "\r", "\n", "\n\r"};
const char *const stty_nltab[] = {"CONN_CRNL", "CONN_CR", "CONN_NL",
				  "CONN_NLCR" };

static void do_stty(cp, input)
    struct conn *cp;
    char *input;
{
  int i;
  char *ptr;
  char buf[BUFFSIZ];

  while((*input != '\0') && isspace(*input))
    input++;

  switch(*input) {
  case 'N':
  case 'n':
    if(!strncasecmp(input, "nlmode", 6)) {
      while((*input != '\0') && !isspace(*input))
        input++;
      while((*input != '\0') && isspace(*input))
        input++;
      if(*input == '\0')
        break;

      for(i = 0; i < 4; i++) {
        if(!strcasecmp(input, stty_nlmodekey[i])) {
	  cp->lcrnl = stty_nlmodeval[i];
	  conn_put(cp, "Newline mode changed.");
	  return;
	}
      }
    }
    break;
  case 'W':
  case 'w':
    if(!strncasecmp(input, "wrap", 4)) {
      while((*input != '\0') && !isspace(*input))
        input++;
      while((*input != '\0') && isspace(*input))
        input++;
      if(*input == '\0')
        break;

      i = (int)strtol(input, &ptr, 10);
      if(ptr == input)
        break;
      if(i < 0)
        i = 0;
      cp->lwrap = i;
      conn_put(cp, ((i == 0) ? "Line wrap disabled." : "Line wrap enabled."));
      return;
    }
    break;
  case 'H':
  case 'h':
    if(!strncasecmp(input, "html", 4)) {
      while((*input != '\0') && !isspace(*input))
	input++;
      while((*input != '\0') && isspace(*input))
	input++;
      if(*input == '\0')
	break;

      if(!strcasecmp(input, "none")) {
	cp->html_ext = HTML_NONE;
	conn_put(cp, "Html mode disabled.");
      } else if(!strcasecmp(input, "pueblo")) {
	if(mudconf.enable_pueblo) {
	  cp->html_ext = HTML_PUEBLO;
	  conn_put(cp, "Html mode enabled for Pueblo.");
	  conn_put_raw(cp, "</xch_mudtext><img xch_mode=html>");
	} else
	  conn_put(cp, "I don't *do* that!");
      } 
      return;
    }
    break;
  }

  conn_put(cp, "Current stty settings:");
  if(cp->lwrap)
    snprintf(buf, sizeof(buf), "Line wrap: %d  Newline mode: ", cp->lwrap);
  else
    strcpy(buf, "Line wrap: *DISABLED*  Newline mode: ");
  strcat(buf, stty_nlmodekey[cp->lcrnl]);
  conn_put(cp, buf);

  switch (cp->html_ext) {
  case HTML_NONE:
    conn_put(cp, "Html mode: *DISABLED*");
    break;
  case HTML_PUEBLO:
    conn_put(cp, "Html mode: Pueblo");
    break;
  }
}

void log_disconnect(cp)
    struct conn *cp;
{
  char *name;

  if (cp->player != -1) {
    if (get_str_elt(cp->player, NAME, &name) != -1) {
      logfile(LOG_STATUS, "DISCONNECT: %s(#%d) on fd %d.\n", name, cp->player,
	      cp->fd);
    } else
      logfile(LOG_STATUS, "DISCONNECT: ???(#%d) on fd %d.\n", cp->player,
	      cp->fd);
  } else
    logfile(LOG_STATUS, "DISCONNECT: fd %d never connected.\n", cp->fd);
}

void log_connect(cp)
    struct conn *cp;
{
  char *name;

  if (cp->player != -1) {
    if (get_str_elt(cp->player, NAME, &name) != -1) {
      logfile(LOG_STATUS, "CONNECTED: %s(#%d) on fd %d.\n", name, cp->player,
	      cp->fd);
    } else
      logfile(LOG_STATUS, "CONNECTED: ???(#%d) on fd %d.\n", cp->player,
	      cp->fd);
  } else {
    if(cp->user != (char *)NULL) {
      logfile(LOG_STATUS,
	      "CONNECTION: fd %d connected from [%s@%s], remort port %d.\n",
      	      cp->fd, cp->user, cp->host, cp->port);
    } else { 
      logfile(LOG_STATUS,
	      "CONNECTION: fd %d connected from [%s], remote port %d.\n",
	      cp->fd, cp->host, cp->port);
    }
  }
}

static void log_create(cp)
    struct conn *cp;
{
  char *name;

  if (get_str_elt(cp->player, NAME, &name) != -1) {
    logfile(LOG_STATUS, "CREATED: %s(#%d) on fd %d.\n", name, cp->player,
	    cp->fd);
  } else
    logfile(LOG_STATUS, "CREATED: ???(#%d) on fd %d.\n", cp->player, cp->fd);
}

static void log_badconnect(cp, s)
    struct conn *cp;
    char *s;
{
  logfile(LOG_STATUS, "FAILED CONNECT: fd %d failed connection to \"%s\".\n",
          cp->fd, s);
}

static void log_badcreate(cp, s)
    struct conn *cp;
    char *s;
{
  logfile(LOG_STATUS, "FAILED CREATE: fd %d failed to create player \"%s\".\n",
          cp->fd, s);
}

int numconnected(player)
    int player;
{
  register struct conn *cp;
  register int ret = 0;

  for (cp = connlist; cp != (struct conn *) NULL; cp = cp->next) {
    if ((cp->player != -1) && (cp->player == player))
      ret++;
  }
  return (ret);
}

int fd_conn(player)
    int player;
{
  register struct conn *cp;

  for (cp = connlist; cp != (struct conn *) NULL; cp = cp->next) {
    if ((cp->player != -1) && (cp->player == player))
      return (cp->fd);
  }
  return (-1);
}

/*
 * Determine if a player can do HTML.
 *
 * Since HTML status is per-connection, but the player state has no
 * notion of connections, we fudge things.
 */
int has_html(player)
    int player;
{
  register struct conn *cp;

  for (cp = connlist; cp != (struct conn *)NULL; cp = cp->next) {
    if ((cp->player != -1) && (cp->html_ext != HTML_NONE))
      return (cp->html_ext);
  }
  return (HTML_NONE);
}

int match_active_player(arg)
    char *arg;
{
  register struct conn *cp;
  int number = 0;
  int player = -1;
  int aflags;
  char *name, *alias;

  for (cp = connlist; cp != (struct conn *) NULL; cp = cp->next) {
    if(cp->player == -1)
      continue;

    if (get_str_elt(cp->player, NAME, &name) == -1) {
      logfile(LOG_ERROR, "match_active_player: bad player name reference #%d\n",
	      cp->player);
      return (-1);
    }
    if (attr_get(cp->player, ALIAS, &alias, &aflags) == -1) {
      logfile(LOG_ERROR, "match_active_player: bad player alias ref #%d\n",
	      cp->player);
      return(-1);
    }

    if (arg[0] && stringprefix(name, arg)) {
      if (strlen(arg) == strlen(name))
	return (cp->player);
      number++;
      if (number == 1) {
	player = cp->player;
      } else {
	if (cp->player != player)
	  return (-2);
	else
	  number = 1;
      }
    }
    if (arg[0] && (alias != (char *)NULL) && alias[0]
	&& stringprefix(alias, arg)) {
      if (strlen(arg) == strlen(name))
	return (cp->player);
      number++;
      if (number == 1) {
	player = cp->player;
      } else {
	if (cp->player != player)
	  return (-2);
	else
	  number = 1;
      }
    }
  }
  if (number)
    return (player);
  else
    return (-1);
}

VOID do_doing(player, cause, switches, argone, argtwo)
    int player, cause, switches;
    char *argone, *argtwo;
{
  struct conn *cp;
  register char *ptr;
  int person;

  if ((argtwo != (char *)NULL) && argtwo[0]) {
    person = resolve_player(player, cause, argone,
    			    (!(switches & CMD_QUIET) ? RSLV_NOISY : 0));
    if(person == -1)
      return;
    if (!controls(player, cause, person)) {
      if(!(switches & CMD_QUIET))
        notify_player(player, cause, player, "You can't do that.", NOT_QUIET);
      return;
    }
  } else {
    person = player;
    argtwo = argone;
  }
  if (!isALIVE(person)) {	/* @force won't crash me */
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "That person is not connected.",
      		    NOT_QUIET);
    return;
  }

  if (argtwo && *argtwo && (strlen(argtwo) > (sizeof(poll_str)-1)))
    argtwo[sizeof(poll_str)] = '\0';

  for (cp = connlist; cp != (struct conn *) NULL; cp = cp->next) {
    if ((cp->player == -1) || (cp->player != person))
      continue;
    if (cp->doing != (char *)NULL) {
      ty_free((VOID *)cp->doing);
      cp->doing = (char *) NULL;
    }
    if (argtwo && *argtwo)
      cp->doing = (char *) ty_strdup(argtwo, "do_doing.doing");
    if (cp->doing != (char *)NULL) {
      for(ptr = cp->doing; *ptr != '\0'; ptr++) {
        if(!isprint(*ptr))
	  *ptr = ' ';
      }
    }
  }

  if(!(switches & CMD_QUIET))
    notify_player(player, cause, player,
  		  ((person == player) ? "Set.  Have fun doing it." : "Set."),
		  NOT_QUIET);
}

VOID do_poll(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  if ((argone == (char *)NULL) || (argone[0] == '\0'))
    argone = "Doing";

  if (strlen(argone) > (sizeof(poll_str)-1))
    argone[sizeof(poll_str)-1] = '\0';
  strcpy(poll_str, argone);

  if(!(switches & CMD_QUIET))
    notify_player(player, cause, player, "Poll set.", NOT_QUIET);
}

void stty_restore(cp)
    struct conn *cp;
{
  int aflags;
  char *stty, *ptr;

  if((cp->player != -1) && exists_object(cp->player) && isPLAYER(cp->player)) {
    if(attr_get(cp->player, STTY, &stty, &aflags) != -1) {
      if(stty && *stty) {
        cp->lwrap = (short)strtol(stty, &ptr, 10);
	if(*ptr != ':') {
	  cp->lwrap = 0;
	  return;
	} else {
	  register int idx;

	  ptr++;
	  for(idx = 0; idx < 4; idx++) {
	    if(strncmp(stty_nltab[idx], ptr, strlen(stty_nltab[idx])) == 0) {
	      cp->lcrnl = idx;
	      break;
	    }
	  }
	}
	conn_put(cp, "Stty settings restored.");
      }
    }
  }
}

VOID do_savestty(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  struct conn *cp;
  char buf[40];
  int person;

  if((argone != (char *)NULL) && argone[0]) {
    person = resolve_player(player, cause, argone,
    			    (!(switches & CMD_QUIET) ? RSLV_NOISY : 0));
    if(person == -1)
      return;
  } else
    person = player;

  if (!controls(player, cause, person)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "You can't do that.", NOT_QUIET);
    return;
  }

  if (switches & SAVESTTY_RESTORE) {
    for (cp = connlist; cp != (struct conn *) NULL; cp = cp->next) {
      if ((cp->player == -1) || (cp->player != person))
        continue;

      stty_restore(cp);
    }
    return;
  } else if (!(switches & SAVESTTY_CLEAR)) {
    if (!isALIVE(person)) {       /* @force won't crash me */
      if(!(switches & CMD_QUIET))
        notify_player(player, cause, player, "That person is not connected.",
		      NOT_QUIET);
      return;
    }

    for (cp = connlist; cp != (struct conn *) NULL; cp = cp->next) {
      if ((cp->player == -1) || (cp->player != person))
        continue;

      snprintf(buf, sizeof(buf), "%d:%s", cp->lwrap, stty_nltab[cp->lcrnl]);
      if(attr_add(player, STTY, buf, STTY_FLGS) == -1) {
        notify_bad(player);
        return;
      }
      break;
    }

    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Stty settings saved.", NOT_QUIET);
  } else {
    if(attr_delete(player, STTY) == -1) {
      notify_bad(player);
      return;
    }

    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Saved stty settings cleared.",
      		    NOT_QUIET);
  }
}