/* look.c */

#include "copyright.h"

/* commands which look at things */

#ifdef WANT_ANSI
#ifdef __STDC__
#include <stddef.h>
#endif /* __STDC__ */
#endif /* WANT_ANSI */
#include <ctype.h>

#include "mudconf.h"
#include "config.h"
#include "db.h"
#include "interface.h"
#include "match.h"
#include "externs.h"
#include "flags.h"
#include "command.h"

static void look_exits(dbref player, dbref loc, const char *exit_name)
{
dbref	thing, parent;
char	*buff, *e, *s;
int	foundany, lev;

	/* make sure location is a room and is not dark */

	if (!Good_obj(loc) || (Flags(loc) & DARK))
		return;

	/* make sure there is at least one visible exit */

	foundany = 0;
	for (lev=0, parent=loc;
	     (Good_obj(parent) && !foundany &&
	      (lev < mudconf.parent_nest_lim));
	     parent=Parent(parent), lev++) {
		DOLIST(thing, Exits(parent)) {
			if (!(Flags(thing) & DARK)) {
				foundany = 1;
				break;
			}
		}
	}

	if (!foundany) return;

	/* Display the list of exit names */

	notify(player, exit_name);
	e = buff = alloc_lbuf("look_exits");
	for (lev=0, parent=loc;
	     (Good_obj(parent) &&
	      (lev < mudconf.parent_nest_lim));
	     parent=Parent(parent), lev++) {
		DOLIST(thing, Exits(parent)) {
			if (!(Flags(thing) & DARK)) {

				/* chop off first exit alias to display */

				for (s=Name(thing); *s && (*s!=';'); s++)
					safe_chr(*s, buff, &e);
				safe_str((char *)"  ", buff, &e);
			}
		}
	}
	*e = 0;
	notify(player, buff);
	free_lbuf(buff);
}

static void look_contents(dbref player, dbref loc, const char *contents_name)
{
dbref	thing;
dbref	can_see_loc;
char	*buff;

	/* check to see if he can see the location */

	can_see_loc = (!Dark(loc) || Examinable(player, loc));

	/* check to see if there is anything there */

	DOLIST(thing, Contents(loc)) {
		if (can_see(player, thing, can_see_loc)) {

			/* something exists!  show him everything */

			notify(player, contents_name);
			DOLIST(thing, Contents(loc)) {
				if (can_see(player, thing, can_see_loc)) {
					buff = unparse_object(player, thing);
					notify(player, buff);
					free_lbuf(buff);
				}
			}
			break;			/* we're done */
		}
	}
}

static void view_atr (dbref player, dbref thing, ATTR *ap, char *text,
	dbref aowner, int aflags, int skip_tag)
{
char	*buf;
char	xbuf[4];
char	*xbufp;
struct boolexp *bool;

	if (ap->flags & AF_IS_LOCK) {
		bool = parse_boolexp(player, text);
		text = unparse_boolexp(player, bool);
		free_boolexp(bool);
	}

	/* If we don't control the object or own the attribute, hide the
	 * attr owner and flag info.
	 */

	if (!Controls(player, thing) && (Owner(player) != aowner)) {
		if (skip_tag && (ap->number == A_DESC))
			buf = text;
		else
			buf = tprintf("%s:%s", ap->name, text);
		notify(player, buf);
		return;
	}

	/* Generate flags */

	xbufp = xbuf;
	if (aflags & AF_LOCK)
		*xbufp++ = '+';
	if (aflags & AF_NOPROG)
		*xbufp++ = '$';
	*xbufp = '\0';

	if ((aowner != Owner(thing)) && (aowner != NOTHING)) {
		buf = tprintf("%s(#%d%s):%s", ap->name, aowner, xbuf, text);
	} else if (*xbuf) {
		buf = tprintf("%s(%s):%s", ap->name, xbuf, text);
	} else if (!skip_tag || (ap->number != A_DESC)) {
		buf = tprintf("%s:%s", ap->name, text);
	} else {
		buf = text;
	}
	notify(player, buf);
}

static void look_atrs(dbref player, dbref thing)
{
dbref	aowner;
int	ca, aflags;
ATTR	*attr;
char	*as, *buf;

	for (ca=atr_head(thing,&as); ca; ca=atr_next(&as)) {
		if ((ca == A_DESC) || (ca == A_LOCK)) continue;
		attr = atr_num(ca);
		if (!attr) continue;

		buf = atr_get(thing, ca, &aowner, &aflags);
		if (Read_attr(player, thing, attr, aowner))
			view_atr(player, thing, attr, buf, aowner, aflags, 0);
		free_lbuf(buf);
	}
}

static void look_simple(dbref player, dbref thing)
{
char	*buff;

	/* Only makes sense for things that can hear */

	if (!Hearer(player))
		return;

	/* Get the name and db-number if we can examine it. */

	if (Examinable(player, thing)) {
		buff = unparse_object(player, thing);
		notify(player, buff);
		free_lbuf(buff);
	}
  
	did_it(player, thing, A_DESC, "You see nothing special.",
		A_ODESC, NULL, A_ADESC, (char **)NULL, 0);
}

static void show_desc (dbref player, dbref loc, int use_idesc)
{
char	*got;
dbref	aowner;
int	aflags;

	if ((Typeof(loc) != TYPE_ROOM) && use_idesc) {
		if (*(got = atr_pget(loc, A_IDESC, &aowner, &aflags)))
			did_it(player, loc, A_IDESC, NULL, A_ODESC, NULL,
				A_ADESC, (char **)NULL, 0);
		else
			did_it(player, loc, A_DESC, NULL, A_ODESC, NULL,
				A_ADESC, (char **)NULL, 0);
		free_lbuf(got);
	} else {
		did_it(player, loc, A_DESC, NULL, A_ODESC, NULL, A_ADESC,
			(char **)NULL, 0);
	}
}

void look_in(dbref player, dbref loc, int show_exits)
{
char	*s;

	/* Only makes sense for things that can hear */

	if (!Hearer(player))
		return;

	/* tell him the name, and the number if he can link to it */

	s = unparse_object(player, loc);
	notify(player, s);
	free_lbuf(s);
	if (!Good_obj(loc)) return;  /* If we went to NOTHING et al, 
					skip the rest */

	/* tell him the description */

	show_desc(player, loc, (loc == Location(player) ? 1 : 0));

	/* tell him the appropriate messages if he has the key */

	if (Typeof(loc) == TYPE_ROOM) {
		if (could_doit(player, loc, A_LOCK))
			did_it(player, loc, A_SUCC, NULL, A_OSUCC, NULL,
				A_ASUCC, (char **)NULL, 0);
		else
			did_it(player, loc, A_FAIL, NULL, A_OFAIL, NULL,
				A_AFAIL, (char **)NULL, 0);
	}

	/* tell him the contents */

	look_contents(player, loc, "Contents:");
	if (show_exits)
		look_exits(player, loc, "Obvious exits:");
}

void do_look(dbref player, dbref cause, int key, char *name)
{
dbref thing;

	if (!name || !*name) {
		if ((thing = Location(player)) != NOTHING) {
			look_in(player, thing, 1);
			if(!mudconf.quiet_look)
				look_atrs(player, thing);
		}
		return;
	}

	/* Check for possessive look.  If that fails, do the standard look. */

	thing = is_possess(player, (char *)name);
	if (thing == NOTHING) {
		init_match(player, name, NOTYPE);
		match_exit();
		match_neighbor();
		match_possession();
		if (Wizard(player)) {
			match_absolute();
			match_player();
		}
		match_here();
		match_me();
		thing = noisy_match_result();
	}

	/* If we found something, go handle it */

	if (thing != NOTHING) {
		switch (Typeof(thing)) {
		case TYPE_ROOM:
			look_in(player, thing, 1);
			if(!mudconf.quiet_look)
				look_atrs(player, thing);
			break;
		case TYPE_THING:
		case TYPE_PLAYER:
			look_simple(player, thing);
			if(!mudconf.quiet_look)
				look_atrs(player, thing);
			if (!(Flags(thing) & OPAQUE)) {
				look_contents(player, thing, "Carrying:");
			}
			break;
		case TYPE_EXIT:
			look_simple(player, thing);
			if ((Flags(thing) & EXIT_SEETHRU) &&
			    (Location(thing) != NOTHING)) {
				look_in(player, Location(thing), 0);
			}			
			if(!mudconf.quiet_look)
				look_atrs(player, thing);
			break;
		default:
			look_simple(player, thing);
			if(!mudconf.quiet_look)
				look_atrs(player, thing);
		}
	}
}

static void debug_examine(dbref player, dbref thing)
{
  dbref	aowner;
  char	*buf;
  int	aflags, ca;
  struct boolexp *bool;
  ATTR	*attr;
  char	*as, *cp;

  notify(player, tprintf("Number  = %d", thing));
  if (!Good_obj(thing))
     return;

  notify(player, tprintf("Name    = %s", Name(thing)));
  notify(player, tprintf("Location= %d", Location(thing)));
  notify(player, tprintf("Contents= %d", Contents(thing)));
  notify(player, tprintf("Exits   = %d", Exits(thing)));
  notify(player, tprintf("Link    = %d", Link(thing)));
  notify(player, tprintf("Next    = %d", Next(thing)));
  notify(player, tprintf("Owner   = %d", Owner(thing)));
  notify(player, tprintf("Pennies = %d", Pennies(thing)));
  buf = flag_description(player, thing);
  notify(player, tprintf("Flags   = %s", buf));
  free_mbuf(buf);
  buf = atr_get(thing, A_LOCK, &aowner, &aflags);
  bool = parse_boolexp(player, buf);
  free_lbuf(buf);
  notify(player, tprintf("Lock    = %s", unparse_boolexp(player, bool)));
  free_boolexp(bool);

	buf = alloc_lbuf("debug_dexamine");
	cp = buf;
	safe_str((char *)"Attr list: ", buf, &cp);

	for (ca=atr_head(thing,&as); ca; ca=atr_next(&as)) {
		attr = atr_num(ca);
		if (!attr) continue;

		atr_get_info(thing, ca, &aowner, &aflags);
		if (Read_attr(player, thing, attr, aowner)) {
			if (attr) { /* Valid attr. */
				safe_str((char *)attr->name, buf, &cp);
				safe_chr(' ', buf, &cp);
			} else {
				safe_str(tprintf("%d ", ca), buf, &cp);
			}
		}
	}
	*cp = '\0';
	notify(player, buf);
	free_lbuf(buf);

	for (ca=atr_head(thing,&as); ca; ca=atr_next(&as)) {
		attr = atr_num(ca);
		if (!attr) continue;

		buf = atr_get(thing, ca, &aowner, &aflags);
		if (Read_attr(player, thing, attr, aowner))
			view_atr(player, thing, attr, buf, aowner, aflags, 0);
		free_lbuf(buf);
	}
}

static void exam_wildattrs (dbref player, dbref thing, int do_parent)
{
int	atr, aflags, got_any;
char	*buf;
dbref	aowner;
ATTR	*ap;

	got_any = 0;
	for (atr = olist_first(); atr!=NOTHING; atr=olist_next()) {
		ap = atr_num(atr);
		if (!ap) continue;

		if (do_parent)
			buf = atr_pget(thing, atr, &aowner, &aflags);
		else
			buf = atr_get(thing, atr, &aowner, &aflags);
		ap = atr_num(atr);

		/* Decide if the player should see the attr:
		 * If obj is Examinable and has rights to see, yes.
		 * If a player and has rights to see, yes...
		 *   except if faraway, attr=DESC, and
		 *   remote DESC-reading is not turned on.
		 * If I own the attrib and have rights to see, yes...
		 *   except if faraway, attr=DESC, and
		 *   remote DESC-reading is not turned on.
		 */

		if (Examinable(player, thing) &&
		    Read_attr(player, thing, ap, aowner)) {
			got_any = 1;
			view_atr(player, thing, ap, buf,
				aowner, aflags, 0);
		} else if ((Typeof(thing) == TYPE_PLAYER) &&
		    Read_attr(player, thing, ap, aowner)) {
			got_any = 1;
			if (aowner == Owner(player)) {
				view_atr(player, thing, ap, buf,
					aowner, aflags, 0);
			} else if ((atr == A_DESC) &&
			    (mudconf.read_rem_desc ||
			     nearby(player, thing))) {
				show_desc(player, thing, 0);
			} else if (atr != A_DESC) {
				view_atr(player, thing, ap, buf,
					aowner, aflags, 0);
			} else {				    
				notify(player,
					"<Too far away to get a good look>");
			}
		} else if (Read_attr(player, thing, ap, aowner)) {
			got_any = 1;
			if (aowner == Owner(player)) {
				view_atr(player, thing, ap, buf,
					aowner, aflags, 0);
			} else if ((atr == A_DESC) &&
			    (mudconf.read_rem_desc ||
			     nearby(player, thing))) {
				show_desc(player, thing, 0);
			} else if (nearby(player, thing)) {
				view_atr(player, thing, ap, buf,
					aowner, aflags, 0);
			} else {				    
				notify(player,
					"<Too far away to get a good look>");
			}
		}
		free_lbuf(buf);
	}
	olist_init();
	if (!got_any)
		notify(player, "No matching attributes found.");

}

void do_examine(dbref player, dbref cause, int key, char *name)
{
dbref	thing, content, exit, aowner, loc;
char	savec;
char	*temp, *buf, *buf2;
struct boolexp	*bool;
int	control, aflags, anum;

	/* This command is pointless if the player can't hear. */

	if (!Hearer(player))
		return;

	if (!name || !*name) {
		if ((thing = Location(player)) == NOTHING)
			return;
	} else {
		/* Check for obj/attr first.  If we are doing a parent lookup,
		 * check for an exact match (parent lookups only do the actual
		 * search up the parent list on exact matches).
		 */

		if (key & EXAM_PARENT) {
			if (parse_attrib(player, name, &thing, &anum)) {
				if (anum != NOTHING) {
					olist_init();
					olist_add(anum);
					exam_wildattrs(player, thing, 1);
					return;
				}
			}
		}

		/* Do wildcard lookup if not looking in parents or if the
		 * parent lookup failed (because the attr included a wildcard
		 * or didn't exist, etc)
		 */

		if (parse_attrib_wild(player, name, &thing, 1)) {
			exam_wildattrs(player, thing, 0);
			return;
		}

		/* Look it up */

		init_match(player, name, NOTYPE);
		match_everything();	
		if ((thing = noisy_match_result()) == NOTHING)
			return;
	}

	/* Check for the /debug switch */

	if (key == EXAM_DEBUG) {
		if (!Examinable(player, thing)) {
			notify(player, "Permission denied.");
		} else {
			debug_examine (player, thing);
		}
		return;
	}

	control = (Examinable(player, thing) || Link_exit(player, thing));

	if (control && (key != EXAM_BRIEF)) {
		buf2 = unparse_object(player, thing);
		notify(player, buf2);
		free_lbuf(buf2);
		if(mudconf.ex_flags) {
			buf2 = flag_description(player, thing);
			notify(player, buf2);
			free_mbuf(buf2);
		}
	} else {
		if ((key == EXAM_BRIEF) ||
		    ((key == EXAM_DEFAULT) && !mudconf.exam_public)) {
			if (mudconf.read_rem_name) {
				buf2 = alloc_lbuf("do_examine.pub_name");
				strcpy(buf2, Name(thing));
				notify(player,
					tprintf("%s is owned by %s",
						buf2, Name(Owner(thing))));
				free_lbuf(buf2);
			} else {
				notify(player,
					tprintf("Owned by %s",
						Name(Owner(thing))));
			}
			return;
		}
	}

	temp=alloc_lbuf("do_examine.info");

	if (control || mudconf.read_rem_desc || nearby(player, thing)) {
		temp = atr_get_str(temp, thing, A_DESC, &aowner, &aflags);
		if (*temp) {
			if (Examinable(player, thing) ||
			    (aowner == Owner(player))) {
				view_atr(player, thing, atr_num(A_DESC), temp,
					aowner, aflags, 1);
			} else {
				show_desc(player, thing, 0);
			}
		}
	} else {
		notify(player, "<Too far away to get a good look>");
	}

	if (control) {

		/* print owner, key, and value */

		savec = mudconf.many_coins[0];
		mudconf.many_coins[0] =
			(islower(savec) ? toupper(savec) : savec);
		buf2 = atr_get(thing, A_LOCK, &aowner, &aflags);
		bool = parse_boolexp(player, buf2);
		buf = unparse_boolexp(player, bool);
		free_boolexp(bool);
		strcpy(buf2, Name(Owner(thing)));
		notify(player,
			tprintf("Owner: %s  Key: %s %s: %d", buf2, buf,
				mudconf.many_coins, Pennies(thing)));
		free_lbuf(buf2);
		mudconf.many_coins[0] = savec;

		/* print parent */

		loc = Parent(thing);
		if (loc != NOTHING) {
			buf2 = unparse_object(player, loc);
			notify(player, tprintf("Parent: %s", buf2));
			free_lbuf(buf2);
		}


	}

	look_atrs(player, thing);

	/* show him interesting stuff */

	if (control) {

		/* Contents */

		if (Contents(thing) != NOTHING) {
			notify(player, "Contents:");
			DOLIST(content, Contents(thing)) {
				buf2 = unparse_object(player, content);
				notify(player, buf2);
				free_lbuf(buf2);
			}
		}

		/* Show stuff that depends on the object type */

		switch (Typeof(thing)) {
		case TYPE_ROOM:

			/* tell him about exits */

			if (Exits(thing) != NOTHING) {
				notify(player, "Exits:");
				DOLIST(exit, Exits(thing)) {
					buf2 = unparse_object(player, exit);
					notify(player, buf2);
					free_lbuf(buf2);
				}
			} else {
				notify(player, "No exits.");
			}

			/* print dropto if present */

			if (Dropto(thing) != NOTHING) {
				buf2 = unparse_object(player, Dropto(thing));
				notify(player,
					tprintf("Dropped objects go to: %s",
						buf2));
				free_lbuf(buf2);
			}
			break;
		case TYPE_THING:
		case TYPE_PLAYER:

			/* tell him about exits */

			if (Exits(thing) != NOTHING) {
				notify(player, "Exits:");
				DOLIST(exit, Exits(thing)) {
					buf2 = unparse_object(player, exit);
					notify(player, buf2);
					free_lbuf(buf2);
				}
			} else {
				notify(player, "No exits.");
			}

			/* print home */

			loc = Home(thing);
			buf2 = unparse_object(player, loc);
			notify(player, tprintf("Home: %s", buf2));
			free_lbuf(buf2);

			/* print location if player can link to it */

			loc = Location(thing);
			if ((Location(thing) != NOTHING) &&
			    (Examinable(player, loc) ||
			     Examinable(player, thing) ||
			     Linkable(player, loc))) {
				buf2 = unparse_object(player, loc);
				notify(player, tprintf("Location: %s", buf2));
				free_lbuf(buf2);
			}
			break;
		case TYPE_EXIT:
			buf2 = unparse_object(player, Exits(thing));
			notify(player, tprintf("Source: %s", buf2));
			free_lbuf(buf2);

			/* print destination */

			switch (Location(thing)) {
			case NOTHING:
				break;
			case HOME:
				notify(player, "Destination: *HOME*");
				break;
			default:
				buf2 = unparse_object(player, Location(thing));
				notify(player, tprintf("Destination: %s", buf2));
				free_lbuf(buf2);
				break;
			}
			break;
		default:
			break;
		}
	} else if (!(Flags(thing) & OPAQUE) && nearby(player, thing)) {
		if (Has_contents(thing))
			look_contents(player, thing, "Contents:");
		if (Typeof(thing) != TYPE_EXIT)
			look_exits(player, thing, "Obvious exits:");
	}
	free_lbuf(temp);

	if (!control)
		if (mudconf.read_rem_name) {
			buf2 = alloc_lbuf("do_examine.pub_name");
			strcpy(buf2, Name(thing));
			notify(player,
				tprintf("%s is owned by %s",
					buf2, Name(Owner(thing))));
			free_lbuf(buf2);
		} else {
			notify(player,
				tprintf("Owned by %s",
					Name(Owner(thing))));
		}

}

void do_score(dbref player, dbref cause, int key)
{
	notify(player,
		tprintf("You have %d %s.", Pennies(player),
			(Pennies(player) == 1) ?
				mudconf.one_coin : mudconf.many_coins));
}

void do_inventory(dbref player, dbref cause, int key)
{
dbref	thing;
char	*buff, *s, *e;

	thing = Contents(player);
	if (thing == NOTHING) {
		notify(player, "You aren't carrying anything.");
	} else {
		notify(player, "You are carrying:");
		DOLIST(thing, thing) {
			buff = unparse_object(player, thing);
			notify(player, buff);
			free_lbuf(buff);
		}
	}

	thing = Exits(player);
	if (thing != NOTHING) {
		notify(player, "Exits:");
		e = buff = alloc_lbuf("look_exits");
		DOLIST(thing, thing) {

			/* chop off first exit alias to display */

			for (s=Name(thing); *s && (*s!=';'); s++)
				safe_chr(*s, buff, &e);
			safe_str((char *)"  ", buff, &e);
		}
		*e = 0;
		notify(player, buff);
		free_lbuf(buff);
	}
	do_score(player, player, 0);
}

void do_entrances(dbref player, dbref cause, int key, char *name)
{
dbref	thing, i;
char	*exit, *message;
int	control_thing;

	if (!name || !*name) {
		if ((thing = Location(player)) == NOTHING)
			return;
	} else {
		/* look it up */

		init_match(player, name, NOTYPE);
		match_everything();	
		if ((thing = noisy_match_result()) == NOTHING)
			return;
	}

	message = alloc_lbuf("do_entrances");
	control_thing = Examinable(player, thing);
	if (!payfor(player, mudconf.searchcost)) {
		notify(player,
			tprintf("You don't have enough %s.",
				mudconf.many_coins));
		return;
	}
	DO_WHOLE_DB(i) {
		if (control_thing || Examinable(player, i))  {
			switch (Typeof(i)) {
			case TYPE_EXIT:
				if (Location(i) == thing) {
					exit = unparse_object(player, Exits(i));
					notify(player,
						tprintf("%s (%s)",
							exit, Name(i)));
					free_lbuf(exit);
				}
				break;
			case TYPE_ROOM:
				if (Dropto(i) == thing) {
					exit = unparse_object(player, i);
					notify(player,
						tprintf("%s [dropto]", exit));
					free_lbuf(exit);
				}
				break;
			case TYPE_THING:
			case TYPE_PLAYER:
				if (Home(i) == thing) {
					exit = unparse_object(player, i);
					notify(player,
						tprintf("%s [home]", exit));
					free_lbuf(exit);
				}
				break;
			}
			if (Parent(i) == thing) {
				exit = unparse_object(player, i);
				notify(player,
					tprintf("%s [parent]", exit));
				free_lbuf(exit);
			}
		}
	}
	free_lbuf(message);
}

/* check the current location for bugs */

static void sweep_check (dbref player, dbref what, int key, int is_loc)
{
dbref	aowner, parent;
int	canhear, cancom, isplayer, ispuppet, isconnected, attr, aflags;
int	is_parent, lev;
char	*buf, *buf2, *bp, *as, *buff, *s;
ATTR	*ap;

	canhear = 0;
	cancom = 0;
	isplayer = 0;
	ispuppet = 0;
	isconnected = 0;
	is_parent = 0;

	if ((key & SWEEP_LISTEN) &&
	    (IS(what, TYPE_EXIT, HEARTHRU) || (is_loc && Audible(what))))
		canhear = 1;
	else if (key & SWEEP_LISTEN) {
		if (Monitor(what))
			buff = alloc_lbuf("Hearer");
		else
			buff = NULL;

		for (attr=atr_head(what,&as); attr; attr=atr_next(&as)) {
			if (attr == A_LISTEN) {
				canhear = 1;
				break;
			}
			if (Monitor(what)) {
				ap = atr_num(attr);
				if (!ap || (ap->flags & AF_NOPROG))
					continue;

				atr_get_str(buff, what, attr, &aowner,
					&aflags);

				/* Make sure we can execute it */

				if ((buff[0] != AMATCH_LISTEN) ||
				    (aflags & AF_NOPROG))
					continue;

				/* Make sure there's a : in it */

				for (s = buff + 1; *s && (*s != ':'); s++) ;
				if (s) {
					canhear = 1;
					break;
				}
			}
		}
		if (buff)
			free_lbuf(buff);
	}

	if ((key & SWEEP_COMMANDS) && (Typeof(what) != TYPE_EXIT)) {
		cancom = Commer(what);
		if (!cancom) {

			/* Look for commands on parents */

			for (lev=0, parent=Parent(what);
			     (Good_obj(parent) &&
			      (lev < mudconf.parent_nest_lim) && !cancom);
			     parent=Parent(parent), lev++)
				cancom = Commer(parent);
			if (cancom) is_parent = 1;
		}
	}

	if (key & SWEEP_CONNECT) {
		if (IS(what, TYPE_PLAYER, PLAYER_CONNECT) ||
		    ((IS(what, TYPE_THING, PUPPET) ||
		     (mudconf.player_listen &&
		      IS(what, TYPE_PLAYER, PUPPET))) &&
		     IS(Owner(what), TYPE_PLAYER, PLAYER_CONNECT)))
			isconnected = 1;
	}
	if (key & SWEEP_PLAYER || isconnected) {
		if (Typeof(what) == TYPE_PLAYER)
			isplayer = 1;
		if (IS(what, TYPE_THING, PUPPET))
			ispuppet = 1;
		else if (mudconf.player_listen &&
			 IS(what, TYPE_PLAYER, PUPPET))
			ispuppet = 1;
	}
	
	if (canhear || cancom || isplayer || ispuppet || isconnected) {
		buf = alloc_lbuf("sweep_check.types");
		bp = buf;

		if (cancom)
			safe_str((char *)"commands ", buf, &bp);
		if (canhear)
			safe_str((char *)"messages ", buf, &bp);
		if (isplayer)
			safe_str((char *)"player ", buf, &bp);
		if (ispuppet) {
			safe_str((char *)"puppet(", buf, &bp);
			safe_str(Name(Owner(what)), buf, &bp);
			safe_str((char *)") ", buf, &bp);
		}
		if (isconnected)
			safe_str((char *)"connected ", buf, &bp);
		if (is_parent)
			safe_str((char *)"parent ", buf, &bp);
		bp[-1] = '\0';
		if (Typeof(what) != TYPE_EXIT) {
			notify(player,
				tprintf("  %s is listening. [%s]",
					Name(what), buf));
		} else {
			buf2 = alloc_lbuf("sweep_check.name");
			strcpy(buf2, Name(what));
			for (bp=buf2; *bp && (*bp!=';'); bp++) ;
			*bp = '\0';
			notify(player,
				tprintf("  %s is listening. [%s]", buf2, buf));
			free_lbuf(buf2);
		}
		free_lbuf(buf);
	}
}

void do_sweep(dbref player, dbref cause, int key)
{
dbref	here;
int	where_key, what_key;

	where_key = key & (SWEEP_ME|SWEEP_HERE|SWEEP_EXITS);
	what_key =
		key & (SWEEP_COMMANDS|SWEEP_LISTEN|SWEEP_PLAYER|SWEEP_CONNECT);
	if (!where_key) where_key = -1;
	if (!what_key) what_key = -1;

	/* Check my location.  If I have none or it is dark, check just me. */

	if (where_key & SWEEP_HERE) {
		notify(player,"Sweeping location...");
		if (Has_location(player)) {
			here = Location(player);
			if ((here == NOTHING) ||
			    (Dark(here) && !mudconf.sweep_dark &&
			     !Examinable(player, here))) {
				notify(player,
					"Sorry, it is dark here and you can't search for bugs");
				sweep_check(player, player, what_key, 0);
			} else {
				sweep_check(player, here, what_key, 1);
				for (here=Contents(here); here!=NOTHING; here=Next(here))
					sweep_check(player, here, what_key, 0);
			}
		} else {
			sweep_check(player, player, what_key, 0);
		}
	}

	/* Check exits in my location */
 
	if ((where_key & SWEEP_EXITS) && Has_location(player)) {
		notify(player, "Sweeping exits...");
		for (here=Exits(Location(player)); here!=NOTHING; here=Next(here))
			sweep_check(player, here, what_key, 0);
	}

	/* Check my inventory */

	if ((where_key & SWEEP_ME) && Has_contents(player)) {
		notify(player, "Sweeping inventory...");
		for (here=Contents(player); here!=NOTHING; here=Next(here))
			sweep_check(player, here, what_key, 0);
	}

	/* Check carried exits */

	if ((where_key & SWEEP_EXITS) && Has_exits(player)) {
		notify(player, "Sweeping carried exits...");
		for (here=Exits(player); here!=NOTHING; here=Next(here))
			sweep_check(player, here, what_key, 0);
	}

	notify(player, "Sweep complete.");
}

void do_whereis(dbref player, dbref cause, int key, char *name)
{
  dbref thing;
  char *buff;

  if (!name || !*name) {
    notify(player, "You must specify a valid player name.");
    return;
  }
  if ((thing = lookup_player(player, name, 1)) == NOTHING) {
    notify(player, "That player does not seem to exist.");
    return;
  }
  /*
   * init_match(player, name, TYPE_PLAYER); match_player(); match_exit();
   * match_neighbor(); match_possession(); match_absolute();      match_me();
   */

  if (!Wizard(player) && Unfindable(thing)) {
    notify(player, "That player wishes to have some privacy.");
    if (mudconf.whereis_notify && !Haven(player))
	notify(thing, tprintf("%s tried to locate you and failed.",
			  Name(player)));
    return;
  }
  buff = unparse_object(player, Location(thing));
  notify(player, tprintf("%s is in %s.", Name(thing), buff));
  if (mudconf.whereis_notify && !Haven(player))
     notify(thing, tprintf("%s has just located your position.", Name(player)));
  free_lbuf(buff);
  return;
}

/* Output the sequence of commands needed to duplicate the specified
   object.  If you're moving things to another system, your milage
   will almost certainly vary.  (i.e. different flags, etc.)
*/
void do_decomp(dbref player, dbref cause, int key, char *name, char *qual)
{
struct boolexp *bool;
char	*got, *thingname, *as, *ltext;
FLAG	f;
FLAGENT	*fp;
dbref	aowner;
int	val, aflags, ca;
dbref	thing;
ATTR	*attr;

	init_match(player, name, TYPE_THING);
	match_everything();
  	thing = noisy_match_result();

	/* get result */
	if (thing == NOTHING)
		return;

	if (!Examinable(player, thing)) {
		notify(player,
			"You can only decompile things you can examine.");
		return;
	}

	thingname = atr_get(thing, A_LOCK, &aowner, &aflags);
	bool = parse_boolexp(player, thingname);

	if (qual && *qual) {
		strcpy(thingname, qual);
	} else {
		switch (Typeof(thing)) {
		case TYPE_THING:
			strcpy(thingname, Name(thing));
			val = OBJECT_DEPOSIT(Pennies(thing));
			notify(player,
				tprintf("@create %s=%d", thingname, val));
			break;
		case TYPE_ROOM:
			strcpy(thingname, "here");
			notify(player,
				tprintf("@dig/teleport %s", Name(thing)));
			break;
		case TYPE_EXIT:
			strcpy(thingname, Name(thing));
			notify(player,
				tprintf("@open %s", Name(thing)));
			for (got=thingname; *got; got++) {
				if (*got == EXIT_DELIMITER) {
					*got = '\0';
					break;
				}
			}
			break;
		case TYPE_PLAYER:
			strcpy(thingname, "me");
			break;
		}
	}

	if (bool != TRUE_BOOLEXP) {
		notify(player, tprintf("@lock %s=%s", thingname,
			unparse_boolexp_decompile(player, bool)));
	}
	free_boolexp(bool);

	for (ca=atr_head(thing,&as); ca; ca=atr_next(&as)) {
		if ((ca == A_NAME) || (ca == A_LOCK)) continue;
		attr = atr_num(ca);
		if (!attr) continue;
		if ((attr->flags & AF_NOCMD) && !(attr->flags & AF_IS_LOCK))
			continue;

		got = atr_get(thing, ca, &aowner, &aflags);
		if (Read_attr(player, thing, attr, aowner)) {
			if (attr->flags & AF_IS_LOCK) {
				bool = parse_boolexp(player, got);
				ltext = unparse_boolexp_decompile(player,
					bool);
				free_boolexp(bool);
				notify(player,
					tprintf("@lock/%s %s=%s",
						attr->name, thingname, ltext));
			} else {
				notify(player,
					tprintf("%c%s %s=%s",
						((ca < A_USER_START) ?
							'@' : '&'),
						attr->name, thingname, got));
				if (aflags & AF_LOCK) {
					notify(player, tprintf("@lock %s/%s",
						thingname, attr->name));
				}
				if (aflags & AF_NOPROG) {
					notify(player,
						tprintf("@set %s/%s = no_command",
							thingname,
							attr->name));
				}
			}
		}
		free_lbuf(got);
	}

	f = Flags(thing);
	for (fp=gen_flags; fp->flagname; fp++) {
		if ((f & fp->flagvalue) &&
		    check_access(player, fp->listperm)) {
			notify(player,
				tprintf("@set %s=%s",
					thingname, fp->flagname));
		}
	}

	if ((fp=object_types[Typeof(thing)].flaglist) != NULL) {
		for (; fp->flagname; fp++) {
			if ((f & fp->flagvalue) &&
			    check_access(player, fp->listperm)) {
				notify(player,
					tprintf("@set %s=%s",
						thingname, fp->flagname));
			}
		}
	}
	free_lbuf(thingname);
}