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

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

#include <stdio.h>
#include <ctype.h>

#include "teeny.h"
#include "db.h"
#include "case.h"

/*
 * This is the only file in the mud directory that knows about the index. Use
 * EXTREME caution when modifing the routines in this file.
 */

extern struct dsc **main_index;
extern int      total_objects;
extern int      actual_objects;

static void     find_object();

int             controls(player, obj)
  int             player;
  int             obj;
{
  if (obj == -3)
    return 1;			/* everyone controls HOME */

  if (player < 0 || player > total_objects || main_index[player] == NULL) {
    warning("controls", "called with nonexistant player");
    return 0;
  }
  if (obj < 0 || obj > total_objects || main_index[obj] == NULL) {
    warning("controls", "called with nonexistant object");
    return 0;
  }
  if (GodP(main_index[player]) || WizP(main_index[player]))
    return 1;

  if (ExitP(main_index[obj]) && exists_object(DSC_DESTINATION(main_index[obj])))
    if (DSC_OWNER(main_index[DSC_DESTINATION(main_index[obj])]) == player)
      return 1;

  if (DSC_OWNER(main_index[obj]) == player)
    return 1;

  return 0;
}

static void     find_object(player, name, type)
  int             player;
  char           *name;
  int             type;
{
  register int    i;
  register char  *str;
  extern char     cmdwork[];

  for (i = 0; i < total_objects; i++) {
    if (main_index[i] == NULL)
      continue;

    if (((type != -1) && ((DSC_FLAGS(main_index[i]) & TYPE_MASK) != type))
	|| (type == -1 && isexit(i)))
      continue;

    if (!controls(player, i))
      continue;
    str = DSC_NAME(main_index[i]);
    if (str == NULL) {
      log_error("find_object: obj (#%d) has NULL name.\n", i);
      continue;
    }
    if ((name == (char *) 0) || strstr_CI(str, name)) {
      (void) strcpy(cmdwork, stuff_name(player, i));
      (void) strcat(cmdwork, "\r\n");
      notify_player(player, cmdwork);
    }
  }
  notify_player(player, "***End of list***\r\n");
}
voidfunc        do_owned(player, argone, argtwo)
  int             player;
  char           *argone;
  char           *argtwo;
{
  int             matchfor, i, type;
  extern char     cmdwork[];

  if (!iswiz(player)) {
    notify_player(player, "Only a Wizard may look at the owners list.\r\n");
    return;
  }
  if (!argone || !*argone) {
    notify_player(player, "I need a player name.\r\n");
    return;
  }
  if ((matchfor = resolve_player(player, argone, 1)) == -1) {
    notify_player(player, "I can't find that person.\r\n");
    return;
  }
  type = -1;
  if (argtwo && *argtwo) {
    parse_type(argtwo, &type);
    if (type == -1) {
      notify_player(player, "@owned <player> [=<type>] where type is {e,p,r,t}\r\n");
      return;
    }
  }
  for (i = 0; i < total_objects; i++) {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) != matchfor)
      continue;
    /* they own this object */
    if (type != -1) {
      if ((DSC_FLAGS(main_index[i]) & TYPE_MASK) != type)
	continue;
    }
    (void) strcpy(cmdwork, stuff_name(player, i));
    (void) strcat(cmdwork, "\r\n");
    notify_player(player, cmdwork);
  }
  notify_player(player, "***End of list***\r\n");
}
voidfunc        do_entrances(player, arg)
  int             player;
  char           *arg;
{
  register int    i;
  int             search_for;
  extern char     cmdwork[];

  if (!arg || !*arg) {
    if (get_int_elt(player, LOC, &search_for) == -1) {
      notify_bad(player);
      return;
    }
  } else {
    if ((search_for = resolve_object(player, arg, 0)) == -1
	|| search_for == -2 || search_for == -3) {
      notify_player(player, "No such thing.\r\n");
      return;
    }
    if (ExitP(main_index[search_for])) {
      notify_player(player, "That won't have anything linked to it.\r\n");
      return;
    }
  }

  if (!controls(player, search_for)) {
    notify_player(player, "Permission denied.\r\n");
    return;
  }
  for (i = 0; i < total_objects; i++) {
    if (main_index[i] == NULL || !ExitP(main_index[i]))
      continue;
    if (DSC_DESTINATION(main_index[i]) != search_for)
      continue;
    (void) strcpy(cmdwork, stuff_name(player, i));
    (void) strcat(cmdwork, "\r\n");
    notify_player(player, cmdwork);
  }
  notify_player(player, "***End of list***\r\n");
}

int             chownall(oldowner, newowner)
  register int    oldowner;
  register int    newowner;
{
  int             i, count = 0;

  if (!exists_object(oldowner) || !exists_object(newowner)) {
    warning("chownall", "called with nonexistant object as an argument");
    return 0;
  }
  for (i = 0; i < total_objects; i++) {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) == oldowner) {
      DSC_OWNER(main_index[i]) = newowner;
      count++;
    }
  }
  return count;
}
voidfunc        do_find(player, argone, argtwo)
  int             player;
  char           *argone;
  char           *argtwo;
{
  int             type;

  if (!argone || !*argone)
    argone = (char *) 0;

  type = -1;
  if (argtwo && *argtwo) {
    parse_type(argtwo, &type);
    if (type == -1) {
      notify_player(player, "@find <string> [=<type>] where type is {e,p,r,t}\r\n");
      return;
    }
  }
  find_object(player, argone, type);
}

#define COUNT_OBJ(x)    \
(((matchfor != -2)&&(DSC_OWNER(main_index[x])==matchfor)) || matchfor == -2)
#define STATS_FRMT      \
"%d object%s = %d room%s, %d exit%s, %d thing%s, %d player%s (%d garbage).\r\n"
voidfunc        do_stats(player, arg)
  int             player;
  char           *arg;
{
  extern char     cmdwork[];
  int             matchfor;

  if (!arg || !*arg) {
    matchfor = -2;
  } else {
    if ((matchfor = resolve_player(player, arg, iswiz(player))) == -1) {
      notify_player(player, "I can't find that person.\r\n");
      return;
    }
    if ((matchfor != player) && !iswiz(player)) {
      notify_player(player, "You can't stat other players!\r\n");
      return;
    }
    /* matchfor should now contain a valid player number */
  }

  if (!iswiz(player) && matchfor == -2) {
    sprintf(cmdwork, "The universe contains %d objects.\r\n", actual_objects);
    notify_player(player, cmdwork);
  } else {
    register int    i;
    register int    exits = 0;
    register int    rooms = 0;
    register int    players = 0;
    register int    things = 0;
    register int    total = 0;

    for (i = 0; i < total_objects; i++) {
      if (main_index[i] == NULL)
	continue;
      if (ExitP(main_index[i])) {
	if (COUNT_OBJ(i)) {
	  total++;
	  exits++;
	}
	continue;
      }
      if (RoomP(main_index[i])) {
	if (COUNT_OBJ(i)) {
	  rooms++;
	  total++;
	}
	continue;
      }
      if (PlayerP(main_index[i])) {
	if (COUNT_OBJ(i)) {
	  total++;
	  players++;
	}
	continue;
      }
      if (ThingP(main_index[i])) {
	if (COUNT_OBJ(i)) {
	  total++;
	  things++;
	}
	continue;
      }
    }

    sprintf(cmdwork, STATS_FRMT,
      total, (total == 1) ? "" : "s", rooms, (rooms == 1) ? "" : "s", exits,
	 (exits == 1) ? "" : "s", things, (things == 1) ? "" : "s", players,
	    (players == 1) ? "" : "s",
	    (matchfor == -2) ? total_objects - actual_objects : 0);
    notify_player(player, cmdwork);

    if (iswiz(player) && matchfor == -2) {
      extern int      cache_usage, cache_size, cache_hits, cache_misses;
      extern int      cache_errors, malloc_calls, malloc_total, malloc_free;

      sprintf(cmdwork, "Cache stats: %d bytes in use of %d max. %d cache hits with %d misses. %d database errors.\r\n", cache_usage, cache_size,
	      cache_hits, cache_misses, cache_errors);
      notify_player(player, cmdwork);
      sprintf(cmdwork, "Malloc stats: %d requests for %d total bytes. %d requests freed.\r\n", malloc_calls, malloc_total, malloc_free);
      notify_player(player, cmdwork);
    }
  }
}

#undef COUNT_OBJ
#undef STATS_FRMT

/* fix up destinations/homes/dropto's that point at non existant objects */
void            zap_destinations(oldobj)
  int             oldobj;
{
  register int    i;

  for (i = 0; i < total_objects; i++) {
    if ((main_index[i] == NULL) || (DSC_HOME(main_index[i]) != oldobj))
      continue;
    switch (DSC_FLAGS(main_index[i]) & TYPE_MASK) {
    case TYP_PLAYER:
      DSC_HOME(main_index[i]) = STARTING_LOC;
      break;
    case TYP_THING:
      DSC_HOME(main_index[i]) =	/* link to owners home */
	DSC_HOME(main_index[DSC_OWNER(main_index[i])]);
      break;
    case TYP_ROOM:
      DSC_DROPTO(main_index[i]) = -1;	/* unlink */
      break;
    case TYP_EXIT:
      DSC_DESTINATION(main_index[i]) = -1;	/* unlink */
      break;
    default:			/* fuckit */
      fprintf(stderr, "warning: object #%d is unknown type.\n", i);
    }
  }
}

int             recycleobj(obj)
  int             obj;
{
  int             loc;
  int             list, next;
  int             total = 0;

  if (!exists_object(obj))
    return 0;

  if (PlayerP(main_index[obj]))
    return 0;

  if (get_int_elt(obj, LOC, &loc) == -1)
    goto recbomb;
  if (RoomP(main_index[obj])) {
    list_drop(obj, loc, ROOMS_LIST);
    if (get_int_elt(obj, ROOMS, &list) == -1)
      goto recbomb;
    while (list != -1) {
      next = DSC_NEXT(main_index[list]);
      list_add(list, ROOT_PARENT, ROOMS_LIST);
      if (set_int_elt(list, LOC, ROOT_PARENT) == -1)
	goto recbomb;
      list = next;
    }

    /* Nuke the exits. Ownership? Who cares. */

    if (get_int_elt(obj, EXITS, &list) == -1)
      goto recbomb;
    while (list != -1) {
      next = DSC_NEXT(main_index[list]);
      destroy_obj(list);
      total++;
      list = next;
    }

    /* Try to send everything here home. Nuke what's left */
    /* I.E. Anything homed here will get nuked. BOOM!     */

    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto recbomb;
    while (list != -1) {
      next = DSC_NEXT(main_index[list]);

      /* If this is a player homed here, set home to zero */

      if (PlayerP(main_index[list])) {
	if (DSC_HOME(main_index[list]) == obj) {
	  DSC_HOME(main_index[list]) = STARTING_LOC;
	}
      }
      if (PlayerP(main_index[list])) {
	register char  *name;

	name = DSC_NAME(main_index[list]);

	notify_player(list, "You feel a wrenching sensation...\r\n");
	send_home(list, obj);
	notify_oall(list, name);
	notify_oall(list, " has arrived.\r\n");

	do_look(list, (char *) NULL);
      } else {
	send_home(list, obj);
      }
      list = next;
    }
    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto recbomb;
    while (list != -1) {
      next = DSC_NEXT(main_index[list]);
      destroy_obj(list);
      total++;
      list = next;
    }

    /* nuke the room itself. */

    destroy_obj(obj);
    total++;

    /* Skip over the DB checking all exits, and unlinking the */
    /* ones that come here.                                   */

    zap_destinations(obj);
  } else if (ExitP(main_index[obj])) {
    list_drop(obj, loc, 0);
    destroy_obj(obj);
    total++;
  } else if (ThingP(main_index[obj])) {
    list_drop(obj, loc, 1);
    zap_destinations(obj);
    if (get_int_elt(obj, CONTENTS, &list) == -1)
      goto recbomb;
    while (list != -1) {
      /* send objects home */
      next = DSC_NEXT(main_index[list]);
      send_home(list, obj);
      list = next;
    }
    if (get_int_elt(obj, EXITS, &list) == -1)
      goto recbomb;
    while (list != -1) {
      /* nuke exits */
      next = DSC_NEXT(main_index[list]);
      destroy_obj(list);
      total++;
      list = next;
    }
    destroy_obj(obj);
    total++;
  } else {
    warning("recycleobj", "unknown object type");
    goto recbomb;
  }
  return total;

recbomb:

  return -1;
}

/* recycle everything owned by obj, *except* obj */
int             purgepossessions(obj)
  int             obj;
{
  register int    i;
  int             ret, total = 0;

  if (!exists_object(obj)) {
    warning("purgepossessions", "called with nonexistant object");
    return 0;
  }
  for (i = 0; i < total_objects; i++) {
    if (main_index[i] == NULL)
      continue;
    if ((i == obj) || (DSC_OWNER(main_index[i]) != obj))
      continue;
    /* nuke this, what ever it is */
    ret = recycleobj(i);
    if (ret > 0)
      total += ret;
  }
  return total;
}

/*
 * Matches a player. This is kind of expensive CPU wise.
 */
int             match_player(name)
  register char  *name;
{
  register int    i;
  register char  *player;

  for (i = 0; i < total_objects; i++) {
    if (main_index[i] == NULL || !PlayerP(main_index[i]))
      continue;
    player = DSC_NAME(main_index[i]);
    if (!player || !*player) {
      warning("match_player", "player with null name found");
      continue;
    }
    if (!strcasecmp(name, player))
      return (i);
  }
  return (-1);
}

int             check_quota(player)
  int             player;
{
  int             total, quota;
  register int    i;

  if (iswiz(player))
    return (0);

  for (i = 0, total = 0; i < total_objects; i++) {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) == player)
      total++;
  }

  if (get_int_elt(player, QUOTA, &quota) == -1) {
    log_error("check_quota: player #%d has a bad quota ref.\r\n", player);
    return (1);
  }
  return (total > quota);
}

voidfunc        do_children(player, arg)
  int             player;
  char           *arg;
{
  int             list, obj;
  extern char     cmdwork[];

  if (arg == NULL || *arg == 0) {
    if (get_int_elt(player, LOC, &obj) == -1) {
      notify_bad(player);
      return;
    }
  } else {
    if ((obj = resolve_object(player, arg, 0)) == -1 || obj == -2) {
      notify_player(player, "No such room.\r\n");
      return;
    }
  }
  if (!exists_object(obj) || !isroom(obj)) {
    notify_player(player, "Only rooms have children.\r\n");
    return;
  }
  if (!controls(player, obj) && !isabode(obj)) {
    notify_player(player, "Permission denied.\r\n");
    return;
  }
  if (get_int_elt(obj, ROOMS, &list) == -1) {
    notify_bad(player);
    return;
  }
  if (list != -1)
    notify_list(player, list, cmdwork, BUFFSIZ, 1);
  notify_player(player, "**End of list**\r\n");
}

voidfunc        do_fixlists(player)
  int             player;
{
  register int    i;
  int             loc, flags;
  extern char     cmdwork[];

  if (player != PLAYER_GOD) {
    notify_player(player, "Someone doesn't want you doing that.\r\n");
    return;
  }
  /* SPAM SPAM SPAM */
  notify_player(player, "Spamming...\r\n");

  for (i = 0; i < db_top(); i++) {
    if (!exists_object(i))
      continue;
    if (set_int_elt(i, NEXT, -1) == -1) {
      sprintf(cmdwork, "Failed to spam object #%d - corrupt index!\r\n",
	      i);
      notify_player(player, cmdwork);
      continue;
    }
    if (set_int_elt(i, CONTENTS, -1) == -1) {
      sprintf(cmdwork, "Failed to spam object #%d - corrupt disk!\r\n", i);
      notify_player(player, cmdwork);
      continue;
    }
    if (set_int_elt(i, EXITS, -1) == -1) {
      sprintf(cmdwork, "Failed to spam object #%d - corrupt disk!\r\n", i);
      notify_player(player, cmdwork);
      continue;
    }
    if (isroom(i)) {
      if (set_int_elt(i, ROOMS, -1) == -1) {
	sprintf(cmdwork, "Failed to spam object #%d = corrupt disk!\r\n", i);
	notify_player(player, cmdwork);
	continue;
      }
    }
  }

  /* rebuild */
  notify_player(player, "Rebuilding...\r\n");

  for (i = 0; i < db_top(); i++) {
    if (!exists_object(i))
      continue;
    if (get_int_elt(i, LOC, &loc) == -1) {
      sprintf(cmdwork, "Failed to get location of object #%d.\r\n", i);
      notify_player(player, cmdwork);
      loc = 0;
    }
    if (get_int_elt(i, FLAGS, &flags) == -1) {
      sprintf(cmdwork, "Failed to get flags of object #%d.\r\n", i);
      notify_player(player, cmdwork);
      continue;
    }
    switch (flags & TYPE_MASK) {
    case TYP_ROOM:
      list_add(i, loc, ROOMS_LIST);
      break;
    case TYP_PLAYER:
    case TYP_THING:
      list_add(i, loc, CONTENTS_LIST);
      break;
    case TYP_EXIT:
      list_add(i, loc, EXITS_LIST);
      break;
    default:
      sprintf(cmdwork, "Bad type on object #%d.\r\n", i);
      notify_player(player, cmdwork);
    }
  }

  notify_player(player, "Done.\r\n");
}