/
2.0.5/doc/
2.0.5/gnu/
2.0.5/sha/
/* dbcmds.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.
 *
 */

#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_STDLIB_H
#include <stdlib.h>
#endif			/* HAVE_STDIB_H */

#include "conf.h"
#include "teeny.h"
#include "commands.h"
#include "teenydb.h"
#include "externs.h"

/*
 * Database intensive commands.
 */

static char elist[] = "***End of list***";

VOID do_owned(player, cause, switches, argone, argtwo)
    int player, cause, switches;
    char *argone, *argtwo;
{
  int matchfor, i, type, flags[FLAGS_LEN], not;
  char *p;

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

  type = -1;
  not = 0;
  bzero((VOID *)flags, sizeof(flags));
  if (argtwo && *argtwo) {
    if(*argtwo == '!') {
      not++;
      argtwo++;
    }

    for (p = argtwo; *p && *p != '/'; p++);
    if (*p == '/') {
      *p++ = '\0';
      parse_flags(p, flags);
      if ((flags[0] == -1) && (flags[1] == -1)) {
        if(!(switches & CMD_QUIET))
	  notify_player(player, cause, player, "Illegal flags.", NOT_QUIET);
	return;
      }
    }
    if (*argtwo) {
      parse_type(argtwo, &type);
      if (type == -1) {
        if(!(switches & CMD_QUIET))
	  notify_player(player, cause, player, "Illegal type.", 0);
	return;
      }
    }
  }
  for (i = 0; i < mudstat.total_objects; i++) {
    if (main_index[i] == NULL)
      continue;
    if (DSC_OWNER(main_index[i]) != DSC_OWNER(main_index[matchfor]))
      continue;

    /* they own this object */
    if (not) {
      if ((type != -1) && (DSC_TYPE(main_index[i]) == type))
	continue;
      if (((flags[0] != 0) && (DSC_FLAG1(main_index[i]) & flags[0]))
	  || ((flags[1] != 0) && (DSC_FLAG2(main_index[i]) & flags[1])))
	continue;
    } else {
      if ((type != -1) && (DSC_TYPE(main_index[i]) != type))
        continue;
      if (((flags[0] != 0) && (!(DSC_FLAG1(main_index[i]) & flags[0])))
	  || ((flags[1] != 0) && (!(DSC_FLAG2(main_index[i]) & flags[1]))))
        continue;
    }

    notify_player(player, cause, player, display_name(player, cause, i), 0);
    cache_trim();
  }
  notify_player(player, cause, player, elist, 0);
}

VOID do_entrances(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  register int indx;
  int search_for;
  int done, obj;
  char buf[MEDBUFFSIZ];

  if ((argone == (char *)NULL) || (argone[0] == '\0')) {
    if (get_int_elt(player, LOC, &search_for) == -1) {
      notify_bad(player);
      return;
    }
  } else {
    search_for = resolve_object(player, cause, argone,
    				(!(switches & CMD_QUIET) ? RSLV_NOISY : 0));
    if(search_for == -1)
      return;
    if (DSC_TYPE(main_index[search_for]) == TYP_EXIT) {
      if(!(switches & CMD_QUIET))
        notify_player(player, cause, player,
		      "That won't have anything linked to it.", NOT_QUIET);
      return;
    }
  }
  if (!controls(player, cause, search_for)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Permission denied.", NOT_QUIET);
    return;
  }

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

    if(DSC_TYPE(main_index[obj]) == TYP_EXIT) {
      if (DSC_DESTS(main_index[obj]) != (int *)NULL) {
        for(indx = 1, done = 0;
	    !done && (indx <= (DSC_DESTS(main_index[obj]))[0]); indx++) {
	  if((DSC_DESTS(main_index[obj]))[indx] == search_for) {
	    strcpy(buf, "Exit: ");
	    strcat(buf, display_name(player, cause, obj));
	    notify_player(player, cause, player, buf, 0);

	    done++;
	  }
	}
      }
    } else {
      if(DSC_HOME(main_index[obj]) != search_for)
        continue;

      if(DSC_TYPE(main_index[obj]) == TYP_ROOM) {
        strcpy(buf, "Drop to: ");
      } else {
        strcpy(buf, "Home: ");
      }
      strcat(buf, display_name(player, cause, obj));
      notify_player(player, cause, player, buf, 0);
    }
    cache_trim();
  }
  notify_player(player, cause, player, elist, 0);
}

VOID do_find(player, cause, switches, argone, argtwo)
    int player, cause, switches;
    char *argone, *argtwo;
{
  char *p, *name;
  int type, flags[FLAGS_LEN], not;
  register int i;
  register int cost = mudconf.find_cost;

  type = -1;
  not = 0;
  bzero((VOID *)flags, sizeof(flags));
  if (argtwo && *argtwo) {
    if (*argtwo == '!') {
      not++;
      argtwo++;
    }

    for (p = argtwo; *p && (*p != '/'); p++);
    if (*p == '/') {
      *p++ = '\0';
      parse_flags(p, flags);
      if ((flags[0] == -1) && (flags[1] == -1)) {
        if(!(switches & CMD_QUIET))
	  notify_player(player, cause, player, "Illegal flag.", NOT_QUIET);
	return;
      }
    }
    if (*argtwo) {
      parse_type(argtwo, &type);
      if (type == -1) {
        if(!(switches & CMD_QUIET))
	  notify_player(player, cause, player, "Illegal type.", NOT_QUIET);
	return;
      }
    }
    cost = mudconf.limfind_cost;
  }

  if (!can_afford(player, cause, cost, (switches & CMD_QUIET)))
    return;

  for (i = 0; i < mudstat.total_objects; i++) {
    if (main_index[i] == (struct dsc *)NULL)
      continue;

    if (not) {
      if ((type != -1) && (DSC_TYPE(main_index[i]) == type))
	continue;
      if (((flags[0] != 0) && (DSC_FLAG1(main_index[i]) & flags[0]))
	  || ((flags[1] != 0) && (DSC_FLAG2(main_index[i]) & flags[1])))
	continue;
    } else {
      if ((type != -1) && (DSC_TYPE(main_index[i]) != type))
        continue;
      if (((flags[0] != 0) && (!(DSC_FLAG1(main_index[i]) & flags[0])))
	  || ((flags[1] != 0) && (!(DSC_FLAG2(main_index[i]) & flags[1]))))
        continue;
    }

    if ((switches & FIND_OWNED) && (DSC_OWNER(main_index[i]) != player))
      continue;
    if (!controls(player, cause, i))
      continue;
    if ((get_str_elt(i, NAME, &name) == -1) || !name || !name[0]) {
      logfile(LOG_ERROR, "do_find: object #%d has a bad name.\n");
      continue;
    }

    if ((argone == (char *)NULL) || (argone[0] == '\0')
    	|| quick_wild_prefix(argone, name))
      notify_player(player, cause, player, display_name(player, cause, i), 0);
    cache_trim();
  }
  notify_player(player, cause, player, elist, 0);
}

VOID do_trace(player, cause, switches, argone, argtwo)
    int player, cause, switches;
    char *argone, *argtwo;
{
  int obj, max_depth, loc, depth;
  char *ptr;

  if ((get_int_elt(player, LOC, &loc) == -1) || !_exists_object(loc)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "You have no location!", NOT_QUIET);
    return;
  }
  if ((argone == (char *)NULL) || (argone[0] == '\0')) {
    obj = loc;
  } else {
    obj = resolve_object(player, cause, argone,
    			 (!(switches & CMD_QUIET) ? RSLV_NOISY : 0));
    if(obj == -1)
      return;
  }
  if ((argtwo == (char *)NULL) || (argtwo[0] == '\0')) {
    max_depth = mudconf.max_list;
  } else {
    max_depth = (int)strtol(argtwo, &ptr, 10);
    if ((ptr == argtwo) || (max_depth < 1)){
      if(!(switches & CMD_QUIET))
        notify_player(player, cause, player,
		      "That's not a reasonable depth.", NOT_QUIET);
      return;
    }
  }
  depth = 0;
  do {
    notify_player(player, cause, player, display_name(player, cause, obj), 0);

    depth++;
    cache_trim();
  }
  while ((depth < max_depth) && (obj != mudconf.root_location)
	 && (get_int_elt(obj, LOC, &obj) != -1) && _exists_object(obj));
  notify_player(player, cause, player, elist, 0);
}

VOID do_stats(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  int matchfor;
  char buf[MEDBUFFSIZ];
  static const char stats_frmt[] =
"%d object%s = %d room%s, %d exit%s, %d thing%s, %d player%s (%d garbage).";

  if ((argone == (char *)NULL) || (argone[0] == '\0')) {
    matchfor = -2;
  } else {
    matchfor = resolve_player(player, cause, argone,
    			      (!(switches & CMD_QUIET) ? RSLV_NOISY : 0));
    if(matchfor == -1)
      return;
    if ((matchfor != player) && !isWIZARD(player)) {
      if(!(switches & CMD_QUIET))
        notify_player(player, cause, player, "You can't stat other players!",
		      NOT_QUIET);
      return;
    }
    /* matchfor should now contain a valid player number */
  }
  if (!isWIZARD(player) && (matchfor == -2) && !(switches & STATS_FULL)) {
    snprintf(buf, sizeof(buf), "The universe contains %d objects.",
	    mudstat.actual_objects);
    notify_player(player, cause, player, buf, 0);
  } else {
    int totals[TYPE_TOTAL];
    register int i, total = 0;
    float ratio = 0.0;

    if (!can_afford(player, cause, ((switches == STATS_FULL) ?
				    mudconf.fullstat_cost :
				    mudconf.stat_cost), (switches & CMD_QUIET)))
      return;

    bzero((VOID *)totals, sizeof(int) * TYPE_TOTAL);
    for (i = 0; i < mudstat.total_objects; i++) {
      if (main_index[i] == (struct dsc *)NULL)
	continue;
      if ((matchfor == -2) || (DSC_OWNER(main_index[i]) == matchfor)) {
	total++;
	totals[DSC_TYPE(main_index[i])]++;
      }
    }

    if(totals[TYP_ROOM] > 0)
      ratio = (float)totals[TYP_EXIT] / (float)totals[TYP_ROOM];
    snprintf(buf, sizeof(buf), stats_frmt, total, (total == 1) ? "" : "s",
	    totals[TYP_ROOM], (totals[TYP_ROOM] == 1) ? "" : "s",
	    totals[TYP_EXIT], (totals[TYP_EXIT] == 1) ? "" : "s",
	    totals[TYP_THING], (totals[TYP_THING] == 1) ? "" : "s",
	    totals[TYP_PLAYER], (totals[TYP_PLAYER] == 1) ? "" : "s", 
	    (matchfor == -2) ? mudstat.garbage_count : 0);
    notify_player(player, cause, player, buf, 0);
    snprintf(buf, sizeof(buf), "Exit/Room Ratio: %.2f", ratio);
    notify_player(player, cause, player, buf, 0);

    if (isWIZARD(player) && (matchfor == -2)) {
      snprintf(buf, sizeof(buf), "Cache stats: %d bytes in use of %d max. %d cache hits with %d misses. %d database errors.", mudstat.cache_usage, mudconf.cache_size,
	      mudstat.cache_hits, mudstat.cache_misses, mudstat.cache_errors);
      notify_player(player, cause, player, buf, 0);
    }
  }
}

VOID do_children(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  int obj;
  register int i;

  if ((argone == (char *)NULL) || (argone[0] == '\0')) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "List the children of what?",
      		    NOT_QUIET);
    return;
  }
  obj = resolve_object(player, cause, argone,
  		       (!(switches & CMD_QUIET) ? RSLV_EXITS|RSLV_NOISY
		       				: RSLV_EXITS));
  if(obj == -1)
    return;
  if (!controls(player, cause, obj) && !isPARENT_OK(obj)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Permission denied.", NOT_QUIET);
    return;
  }
  for (i = 0; i < mudstat.total_objects; i++) {
    if (main_index[i] == (struct dsc *)NULL)
      continue;
    if (DSC_PARENT(main_index[i]) == obj) {
      notify_player(player, cause, player, display_name(player, cause, i), 0);
      cache_trim();
    }
  }
  notify_player(player, cause, player, elist, 0);
}

VOID do_wipe(player, cause, switches, argc, argv)
    int player, cause, switches, argc;
    char *argv[];
{
  int thing, count;
  struct attr *atptr;
  struct asearch srch;
  char buf[MEDBUFFSIZ];

  if ((argc < 1) || (argc > 2)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Wipe what?", NOT_QUIET);
    return;
  }

  thing = resolve_object(player, cause, argv[0],
  			 (!(switches & CMD_QUIET) ? RSLV_EXITS|RSLV_NOISY
			 			  : RSLV_EXITS));
  if(thing == -1)
    return;

  count = 0;
  for (atptr = attr_first(thing, &srch); atptr != (struct attr *)NULL;
       atptr = attr_next(thing, &srch)) {
    
    if (((argc == 2) && !quick_wild(argv[1], atptr->name))
        || ((atptr->dat).str == (char *)NULL)
	|| (((atptr->dat).str)[0] == '\0'))
      continue;

    if (!can_see_attr(player, cause, thing, atptr->flags)
	|| !can_set_attr(player, cause, thing, atptr->flags)) {
      if(!(switches & CMD_QUIET)) {
        snprintf(buf, sizeof(buf), "%s(#%d): Permission denied.",
	         atptr->name, thing);
        notify_player(player, cause, player, buf, NOT_QUIET);
      }
      continue;
    }

    if(!(switches & CMD_QUIET)) {
      snprintf(buf, sizeof(buf), "Removing attribute %s.", atptr->name);
      notify_player(player, cause, player, buf, NOT_QUIET);
    }

    if(attr_delete(thing, atptr->name) == -1) {
      notify_bad(player);
      return;
    }

    count++;
  }

  if(!(switches & CMD_QUIET)) {
    if(count) {
      snprintf(buf, sizeof(buf), "Removed %d attributes.", count);
      notify_player(player, cause, player, buf, NOT_QUIET);
    } else
      notify_player(player, cause, player, "No matching attributes.",
		    NOT_QUIET);
  }
}

VOID do_edit(player, cause, switches, argc, argv)
    int player, cause, switches, argc;
    char *argv[];
{
  int thing;
  int d, len, doneone = 0;
  char *r, *val, *s;
  struct attr *atptr;
  struct asearch srch;
  char dest[MEDBUFFSIZ], buf[MEDBUFFSIZ];
  int (*mfunc) _ANSI_ARGS_((char *, char *));

  if (argc == 0) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Edit what?", NOT_QUIET);
    return;
  }
  if ((argv[1] == (char *)NULL) || (argv[1][0] == '\0')) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "You must specify an attribute.",
      		    NOT_QUIET);
    return;
  }
  if ((argc < 3) || (argv[2] == (char *)NULL) || (argv[2][0] == '\0')) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Nothing to do.", NOT_QUIET);
    return;
  }

  thing = resolve_object(player, cause, argv[0],
  			 (!(switches & CMD_QUIET) ? RSLV_EXITS|RSLV_NOISY
			 			  : RSLV_EXITS));
  if(thing == -1)
    return;
  val = argv[2];
  if(argv[3] == NULL)
    r = "";
  else
    r = argv[3];

  /*
   * Set the mfunc.  If /all was given, use quick_wild(), otherwise use
   * quick_wild_prefix().
   */
  if (switches & EDIT_ALL)
    mfunc = quick_wild;
  else
    mfunc = quick_wild_prefix;

  for (atptr = attr_first(thing, &srch); atptr != (struct attr *)NULL;
       atptr = attr_next(thing, &srch)) {
    if (atptr->type != ATTR_STRING)
      continue;
    
    if (!(mfunc)(argv[1], atptr->name)
        || ((atptr->dat).str == (char *)NULL)
	|| (((atptr->dat).str)[0] == '\0'))
      continue;

    if (!can_see_attr(player, cause, thing, atptr->flags)
	|| !can_set_attr(player, cause, thing, atptr->flags)) {
      if(!(switches & CMD_QUIET)) {
        snprintf(buf, sizeof(buf), "%s(#%d): Permission denied.",
	         atptr->name, thing);
        notify_player(player, cause, player, buf, NOT_QUIET);
      }
      continue;
    }

    /*
     * Decide what to do.
     */
    if((val[0] == '$') && (val[1] == '\0')) {	/* Append */
      s = (atptr->dat).str;
      d = 0;
      while((d < sizeof(dest)-2) && *s)
	dest[d++] = *s++;
      if(!(switches & EDIT_NOSPACE))
	dest[d++] = ' ';
      s = r;
      while((d < sizeof(dest)-1) && *s)
	dest[d++] = *s++;
    } else if((val[0] == '^') && (val[1] == '\0')) {	/* Prepend */
      s = r;
      d = 0;
      while((d < sizeof(dest)-2) && *s)
	dest[d++] = *s++;
      if(!(switches & EDIT_NOSPACE))
	dest[d++] = ' ';
      s = (atptr->dat).str;
      while((d < sizeof(dest)-1) && *s)
	dest[d++] = *s++;
    } else {				 /* Replacement. */
      len = strlen(val);
      s = (atptr->dat).str;
      d = 0;
      while((d < sizeof(dest)) && *s) {
        if (strncmp(val, s, len) == 0) {
	  if ((d + strlen(r)) < sizeof(dest)-1) {
	    strcpy(dest + d, r);
	    d += strlen(r);
	    s += len;
	  } else if(d < (sizeof(dest)-1)) {
	    dest[d++] = *s++;
	  }
        } else
	  dest[d++] = *s++;
      }
    }
    dest[d] = '\0';

    if (!ok_attr_value(dest)) {
      if(!(switches & CMD_QUIET))
        notify_player(player, cause, player,
		      "You can't set an attribute to that!", NOT_QUIET);
      return;
    }

    /* XXX - this only works because the attribute already exists! */
    if (attr_add(thing, atptr->name, dest, atptr->flags) == -1) {
      notify_bad(player);
      return;
    }
    if(!(switches & CMD_QUIET)) {
      snprintf(buf, sizeof(buf), "%s set.", atptr->name);
      notify_player(player, cause, player, buf, NOT_QUIET);
    }

    doneone++;

    /* If /all wasn't given, we're done. */
    if(!(switches & EDIT_ALL))
      break;
  }

  if (doneone) {
    stamp(thing, STAMP_MODIFIED);
  } else {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "No matching attributes.",
      		    NOT_QUIET);
  }
}

VOID do_sweep(player, cause, switches, argone)
    int player, cause, switches;
    char *argone;
{
  int here, list, obj, owner;
  char *name, buf[MEDBUFFSIZ];

  if ((get_int_elt(player, LOC, &here) == -1) || !_exists_object(here)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "You have no location!", NOT_QUIET);
    return;
  }
  if (argone && *argone) {
    obj = resolve_object(player, cause, argone,
    			 (!(switches & CMD_QUIET) ? RSLV_NOISY : 0));
    if(obj == -1)
      return;
  } else
    obj = here;
  if ((obj != here) && !controls(player, cause, obj)) {
    if(!(switches & CMD_QUIET))
      notify_player(player, cause, player, "Permission denied.", NOT_QUIET);
    return;
  }
  if (get_int_elt(obj, CONTENTS, &list) != -1) {
    while (list != -1) {
      if((get_str_elt(list, NAME, &name) != -1)
	 && (get_int_elt(list, OWNER, &owner) != -1)) {
        if (isALIVE(list) || (isPUPPET(list) && isALIVE(owner))
	    || isLISTENER(list)) {
	  snprintf(buf, sizeof(buf), "%s is listening.", name);
	  notify_player(player, cause, player, buf, 0);
        }
        if (isAUDIBLE(list)) {
	  snprintf(buf, sizeof(buf), "%s will echo things.", name);
	  notify_player(player, cause, player, buf, 0);
        }
      }
      if (get_int_elt(list, NEXT, &list) == -1)
	break;
    }
  } else {
    notify_bad(player);
    return;
  }
  if (get_int_elt(obj, EXITS, &list) != -1) {
    while (list != -1) {
      if (isAUDIBLE(list) && (get_str_elt(list, NAME, &name) != -1)) {
	snprintf(buf, sizeof(buf), "%s will echo things.", name);
	notify_player(player, cause, player, buf, 0);
      }
      if (get_int_elt(list, NEXT, &list) == -1)
	break;
    }
  }
  notify_player(player, cause, player, elist, 0);
}