dbm/
misc/
old-docs/
/* utils.c */

#include "copyright.h"
#include "config.h"

#include <stdio.h>
#ifdef STRING_H
#include <string.h>
#else
#include <strings.h>
#endif				/* STRING_H */
#include <ctype.h>
#include <sys/time.h>
#ifdef STDDEF_H
#include <stddef.h>
#else				/* STDDEF_H */
#define size_t unsigned
#endif				/* STDDEF_H */
#ifdef MALLOC_H
#include <malloc.h>
#endif				/* MALLOC_H */
#if defined(ALLOCA_H) && !defined(NO_ALLOCA)
#include <alloca.h>
#endif

#include "teeny.h"
#include "rwho.h"

void            announce_connect();
void            announce_disconnect();

int             malloc_calls = 0, malloc_total = 0, malloc_free = 0;

/*
 * Some generic utility functions for TeenyMUD
 */

/*
 * Write a timestamp on an object. In minutes since Jan 1 1970
 */

void            stamp(obj)
{
  struct timeval  foo;

  (void) gettimeofday(&foo, (struct timezone *) 0);

  if (set_int_elt(obj, TIMESTAMP, (int) foo.tv_sec) == -1) {
    warning("timestamp", "failed write to object");
  }
}


/*
 * Manufactures a new player and returns the object number, one doesn't exist
 * already.
 * 
 */

int             create_player(p, code)
  char           *p;
  int             code;
{
  char           *name, *pwd;
  int             player;
  int             list, flags;

  if (parse_name_pwd(p, &name, &pwd) == -1)
    return (-1);

  if (!ok_player_name(name))
    return (-1);

  if (!pwd || !*pwd)
    return (-1);

  /* Create a player in object number 0 */

  player = create_obj(TYP_PLAYER);
  if (set_str_elt(player, NAME, name) == -1)
    goto createboom;
  if (set_str_elt(player, PASSWORD, crypt(pwd, CRYPT_KEY)) == -1)
    goto createboom;
  if (code == -1) {
    if (get_int_elt(STARTING_LOC, CONTENTS, &list) == -1)
      goto createboom;
    if (set_int_elt(player, LOC, STARTING_LOC) == -1)
      goto createboom;
    if (set_int_elt(STARTING_LOC, CONTENTS, player) == -1)
      goto createboom;
#ifdef AUTO_GUEST
    if (get_int_elt(player, FLAGS, &flags) == -1)
      goto createboom;
    if (set_int_elt(player, FLAGS, flags | GUEST) == -1)
      goto createboom;
#endif
  } else {
    if (get_int_elt(code, CONTENTS, &list) == -1)
      goto createboom;
    if (set_int_elt(player, LOC, code) == -1)
      goto createboom;
    if (set_int_elt(code, CONTENTS, player) == -1)
      goto createboom;
  }
  if (set_int_elt(player, NEXT, list) == -1)
    goto createboom;
  if (set_int_elt(player, HOME, STARTING_LOC) == -1)
    goto createboom;
  if (set_int_elt(player, OWNER, player) == -1)
    goto createboom;
#ifdef AUTO_BUILDER
  if (get_int_elt(player, FLAGS, &flags) == -1)
    goto createboom;
  if (set_int_elt(player, FLAGS, flags | BUILDER) == -1)
    goto createboom;
#endif
  if (set_int_elt(player, QUOTA, STARTING_QUOTA) == -1)
    goto createboom;
  if (code == -1) {
    int             loc;

    if (get_int_elt(player, LOC, &loc) == -1)
      goto createboom;

    if (!isdark(player) && !isdark(loc))
      do_pose(player, "has connected.");
    announce_connect(player);
  }
  return (player);

createboom:
  destroy_obj(player);
  return (-1);
}

/*
 * Connects a player, if it exists and the password matches. Returns -1 if no
 * dice.
 * 
 */

int             connect_player(p)
  char           *p;

{
  char           *name, *pwd;
  char           *realpwd;
  int             player;

  if (parse_name_pwd(p, &name, &pwd) == -1)
    return (-1);

  player = match_player(name);
  if (player == -1) {
    return (-1);
  }
  /* Check the password */

  if (get_str_elt(player, PASSWORD, &realpwd) == -1) {
    warning("connect_player", "could not reference pword");
    return (-1);
  }
  if (((!realpwd || !*realpwd) && !pwd) ||
      (pwd && *pwd && (strcmp(realpwd, crypt(pwd, CRYPT_KEY)) == 0))) {
    return (player);
  }
  return (-1);

}

void            connect_player2(player)
  int             player;
{
  int             loc;

  if (get_int_elt(player, LOC, &loc) != -1) {
    if (!isdark(player) && !isdark(loc))
      do_pose(player, "has connected.");
  }
  announce_connect(player);
}

void            disconnect_player(player)
  int             player;
{
  int             loc;

  if (get_int_elt(player, LOC, &loc) == -1) {
    warning("disconnect_player", "could not ref player loc");
    return;
  }
  if (!isdark(player) && !isdark(loc))
    do_pose(player, "has disconnected.");
  announce_disconnect(player);

  if (isguest(player)) {
    /* send "GUEST" players to their home */
    send_home(player, loc);

    if (isroom(loc))
      flush_room(loc);
  }
#ifdef SUPPORT_RWHO
  if (rwho_enabled)
    rwho_logout(player);
#endif
}

/*
 * Hack name/pwd pair up. Hopefully modified to support multi-word names.
 */

int             parse_name_pwd(p, name, pwd)
  char           *p;
  char          **name, **pwd;

{
  register char  *q;
  char            ch;
  while (isspace(*p) && *p)
    p++;
  if (*p == '\0')
    return (-1);

  if (*p != '\"') {		/* the name isn't quoted, fuck */
    /* assume the first word is name, all other is pword */
    *name = p;
    while (!isspace(*p) && *p)
      p++;
    if (*p == '\0')
      return (-1);
    *p++ = '\0';

    while (isspace(*p) && *p)
      p++;
    if (*p == '\0')
      *pwd = (char *) 0;
    else
      *pwd = p;			/* Assume no trailing whitespace. */
    return (0);
  } else {			/* quoted name! YAY! */
    while (*p && *p == '\"')
      p++;
    while (*p && isspace(*p))
      p++;
    if (*p == 0)
      return (-1);
    for (*name = p; *p && *p != '\"'; p++);
    if (*p == 0)
      return (-1);
    /* found the other quote! */
    *p++ = 0;			/* terminate the name */
    while (*p && isspace(*p))
      p++;
    if (*p == 0)
      *pwd = (char *) 0;
    else
      *pwd = p;
    return (0);
  }
}

/*
 * Reliable memory allocation.
 */

char           *
                ty_malloc(n, util)
  int             n;
  char           *util;		/* Identifies the calling routine */

{
  char           *p;
  extern char    *malloc();

  if ((p = (char *) malloc((size_t) n)) == NULL) {
    fatal(util, "memory allocation failed");
  }
  malloc_calls++;
  malloc_total += n;
  return (p);
}

/*
 * Reliable free(), which does NULL OK.
 */

void            ty_free(p)
  char           *p;
{
  if (p == NULL) {
    return;			/* Ok */
  }
  malloc_free++;
  free(p);
}

void            parse_type(str, ret)
  char           *str;
  int            *ret;
{
  if (stringprefix(str, "player")) {
    *ret = TYP_PLAYER;
  } else if (stringprefix(str, "room")) {
    *ret = TYP_ROOM;
  } else if (stringprefix(str, "thing") || stringprefix(str, "object")) {
    *ret = TYP_THING;
  } else if (stringprefix(str, "exit")) {
    *ret = TYP_EXIT;
  }				/* else leave ret alone */
}

/* an idea from TinyMUD that has been a long time in coming.. */

int             ok_name(name)
  char           *name;
{
  return (name && *name
	  && *name != '*'
	  && *name != '#'
	  && *name != '!'
	  && !index(name, '=')
	  && !index(name, '&')
	  && !index(name, '|')
#ifdef ILLEGAL_NAMES
	  && strcasecmp(name, "A")
	  && strcasecmp(name, "An")
	  && strcasecmp(name, "The")
	  && strcasecmp(name, "You")
	  && strcasecmp(name, "Your")
	  && strcasecmp(name, "Going")
	  && strcasecmp(name, "Huh?")
	  && strcasecmp(name, "[")
#endif				/* ILLEGAL_NAMES */
	  && strcasecmp(name, "me")
	  && strcasecmp(name, "home")
	  && strcasecmp(name, "here"));
}

int             ok_player_name(name)
  char           *name;
{
  if (!ok_name(name) || (strlen(name) > 16) || (match_player(name) != -1)
  /* || index(name, '=') || index(name, '&') || index(name, '|') */
      || isspace(name[0]) || isspace(name[strlen(name) - 1]))
    return (0);
  else
    return (1);
}

int             ok_exit_name(name)
  char           *name;
{
  char           *p, *q, *buf;

  if (!ok_name(name))
    return (0);

#ifdef NO_ALLOCA
  buf = (char *) ty_malloc(strlen(name) + 1, "ok_exit_name");
#else
  buf = (char *) alloca(strlen(name) + 1);
#endif
  (void) strcpy(buf, name);

  /* we have to check each sub string... */
  q = buf;
  while (q && *q) {
    for (p = q; *p && *p != ';'; p++);
    if (*p)
      *p++ = 0;
    if (!ok_name(q)) {
#ifdef NO_ALLOCA
      ty_free((char *) buf);
#endif
      return (0);
    }
    q = p;
  }

#ifdef NO_ALLOCA
  ty_free((char *) buf);
#endif
  return (1);
}

void            fix_newline(buff)
  char           *buff;
{
  register int    i;

  i = strlen(buff);
  if (buff[i - 1] == '\n') {
    buff[i - 1] = '\r';
    buff[i] = '\n';
    buff[i + 1] = '\0';
  }
}

int             domaincmp(x, y, i)
  char           *x;
  char           *y;
  int             i;
{
  register char  *p;

  while (i) {
    for (p = x; *p && *p != '.'; p++);
    p++;
    i--;
  }
  return (strcasecmp(p, y));
}

void            announce_connect(player)
  int             player;
{
  char           *name;
  char            buf[80];

  if (get_str_elt(player, NAME, &name) != -1) {
    (void) sprintf(buf, "* %s has connected. *\r\n", name);
    notify_wizz(buf);
  }
}
void            announce_disconnect(player)
  int             player;
{
  char           *name;
  char            buf[80];

  if (get_str_elt(player, NAME, &name) != -1) {
    (void) sprintf(buf, "* %s has disconnected. *\r\n", name);
    notify_wizz(buf);
  }
}

void            check_last(player)
  int             player;
{
  char           *host, *time;
  int             last;
  extern char    *ctime();
  extern char     cmdwork[];

  if (get_int_elt(player, TIMESTAMP, &last) == -1 ||
      get_str_elt(player, SITE, &host) == -1)
    return;
  if (last == 0)
    return;

  time = ctime(&((long) last));
  time[strlen(time) - 1] = 0;

  (void) sprintf(cmdwork, "Last connection: %s from %s\r\n", time,
		 (host == NULL) ? "???" : host);
  notify_player(player, cmdwork);
}

char           *getname(obj)
  int             obj;
{
  char           *nm;

  if (!exists_object(obj))
    return (char *) NULL;
  if (get_str_elt(obj, NAME, &nm) == -1)
    return (char *) NULL;
  return nm;
}