tinymush-3.1p2/game/backups/
tinymush-3.1p2/game/bin/
tinymush-3.1p2/game/data/
tinymush-3.1p2/game/modules/
tinymush-3.1p2/game/modules/old/
tinymush-3.1p2/src/modules/comsys/
tinymush-3.1p2/src/modules/hello/
tinymush-3.1p2/src/modules/mail/
tinymush-3.1p2/src/tools/
/* speech.c - Commands which involve speaking */
/* $Id: speech.c,v 1.49 2004/08/17 21:47:25 lwl Exp $ */

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

#include "alloc.h"	/* required by mudconf */
#include "flags.h"	/* required by mudconf */
#include "htab.h"	/* required by mudconf */
#include "mudconf.h"	/* required by code */

#include "db.h"		/* required by externs */
#include "externs.h"	/* required by code */

#include "match.h"	/* required by code */
#include "powers.h"	/* required by code */
#include "attrs.h"	/* required by code */
#include "ansi.h"	/* required by code */

#define SAY_STRING	(mudconf.comma_say ? "say," : "say")
#define SAYS_STRING	(mudconf.comma_say ? "says," : "says")

int sp_ok(player)
dbref player;
{
	if (Gagged(player) && (!(Wizard(player)))) {
		notify(player, "Sorry. Gagged players cannot speak.");
		return 0;
	}
	
	if (!mudconf.robot_speak) {
		if (Robot(player) && !controls(player, Location(player))) {
			notify(player, "Sorry robots may not speak in public.");
			return 0;
		}
	}
	if (Auditorium(Location(player))) {
		if (!could_doit(player, Location(player), A_LSPEECH)) {
			notify(player, "Sorry, you may not speak in this place.");
			return 0;
		}
	}
	return 1;
}

static void say_shout(target, prefix, flags, player, message)
int target, flags;
dbref player;
char *message;
const char *prefix;
{
	if (flags & SAY_NOTAG)
		raw_broadcast(target, "%s%s", Name(player), message);
	else
		raw_broadcast(target, "%s%s%s", prefix, Name(player), message);
}

static const char *announce_msg = "Announcement: ";
static const char *broadcast_msg = "Broadcast: ";
static const char *admin_msg = "Admin: ";

void do_think(player, cause, key, message)
dbref player, cause;
int key;
char *message;
{
	char *str, *buf, *bp;

	buf = bp = alloc_lbuf("do_think");
	str = message;
	exec(buf, &bp, player, cause, cause,
	     EV_FCHECK | EV_EVAL | EV_TOP, &str, (char **)NULL, 0);
	notify(player, buf);
	free_lbuf(buf);
}

static int check_speechformat(player, speaker, loc, thing, message, key)
    dbref player, speaker, loc, thing;
    char *message;
    int key;
{
    char *sargs[2], tokbuf[2], *buff, msgbuf[LBUF_SIZE];
    int aflags;

    /* We have to make a copy of our arguments, because the exec() we
     * pass it through later can nibble those arguments, and we may
     * need to call this function more than once on the same message.
     */

    strcpy(msgbuf, message);

    switch (key) {
	case SAY_SAY:
	    tokbuf[0] = '"';
	    break;
	case SAY_POSE:
	    tokbuf[0] = ':';
	    break;
	case SAY_POSE_NOSPC:
	    tokbuf[0] = ';';
	    break;
	default:
	    tokbuf[0] = '|';
    }
    tokbuf[1] = '\0';

    sargs[0] = msgbuf;
    sargs[1] = tokbuf;

    /* Go get it. An empty evaluation is considered equivalent to no
     * attribute, unless the attribute has a no_name flag.
     */

    buff = master_attr(speaker, thing, A_SPEECHFMT, sargs, 2, &aflags);
			   
    if (buff) {
	if (*buff) {
	    notify_all_from_inside_speech(loc, player, buff);
	    free_lbuf(buff);
	    return 1;
	} else if (aflags & AF_NONAME) {
	    free_lbuf(buff);
	    return 1;
	}
	free_lbuf(buff);
    }

    return 0;
}

static void format_speech(player, speaker, loc, message, key)
    dbref player, speaker, loc;
    char *message;
    int key;
{
    if (H_Speechmod(speaker) &&
	check_speechformat(player, speaker, loc, speaker, message, key))
	return;

    if (H_Speechmod(loc) &&
	check_speechformat(player, speaker, loc, loc, message, key))
	return;

    switch (key) {
	case SAY_SAY:
	    if (mudconf.you_say) {
		notify(speaker, tprintf("You %s \"%s\"", SAY_STRING, message));
		if (loc != NOTHING) {
		    notify_except(loc, player, speaker,
				  tprintf("%s %s \"%s\"", Name(speaker),
					  SAYS_STRING, message), MSG_SPEECH);
		}
	    } else {
		notify_all_from_inside_speech(loc, player,
					tprintf("%s %s \"%s\"", Name(speaker),
						SAYS_STRING, message));
	    }
	    break;
	case SAY_POSE:
	    notify_all_from_inside_speech(loc, player,
				tprintf("%s %s", Name(speaker), message));
	    break;
	case SAY_POSE_NOSPC:
	    notify_all_from_inside_speech(loc, player,
				tprintf("%s%s", Name(speaker), message));
	    break;
	default:
	    /* NOTREACHED */
	    notify_all_from_inside_speech(loc, player, message);
    }
}

void do_say(player, cause, key, message)
dbref player, cause;
int key;
char *message;
{
	dbref loc;
	char *buf2, *bp;
	int say_flags, depth;

	/* Check for shouts. Need to have Announce power. */

	if ((key & SAY_SHOUT) && !Announce(player)) {
	    notify(player, NOPERM_MESSAGE);
	    return;
	}

	/*
	 * Convert prefix-coded messages into the normal type 
	 */

	say_flags = key & (SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML);
	key &= ~(SAY_NOTAG | SAY_HERE | SAY_ROOM | SAY_HTML);

	if (key & SAY_PREFIX) {
		key &= ~SAY_PREFIX;
		switch (key) {
		case SAY_POSE:
			message++;
			if (*message == ' ') {
				message++;
				key = SAY_POSE_NOSPC;
			}
			break;
		case SAY_SAY:
		case SAY_POSE_NOSPC:
			message++;
			break;
		case SAY_EMIT:
			/* if they doubled the backslash, remove it. Otherwise
			 * it's already been removed by evaluation.
			 */
			if (*message == '\\')
				message++;
			break;
		default:
			return;
		}
	}
	/*
	 * Make sure speaker is somewhere if speaking in a place 
	 */

	loc = where_is(player);
	switch (key) {
	case SAY_SAY:
	case SAY_POSE:
	case SAY_POSE_NOSPC:
	case SAY_EMIT:
		if (loc == NOTHING)
			return;
		if (!sp_ok(player))
			return;
	}

	/*
	 * Send the message on its way  
	 */

	switch (key) {
	case SAY_SAY:
		format_speech(player, player, loc, message, SAY_SAY);
		break;
	case SAY_POSE:
		format_speech(player, player, loc, message, SAY_POSE);
		break;
	case SAY_POSE_NOSPC:
		format_speech(player, player, loc, message, SAY_POSE_NOSPC);
		break;
	case SAY_EMIT:
	        if (!say_flags || (say_flags & SAY_HERE) ||
		    ((say_flags & SAY_HTML) && !(say_flags & SAY_ROOM))) {
			if (say_flags & SAY_HTML) {
				notify_all_from_inside_html_speech(loc, player,
							    message);
			} else {
				notify_all_from_inside_speech(loc, player,
							      message);
			}
		}
		if (say_flags & SAY_ROOM) {
			if ((Typeof(loc) == TYPE_ROOM) &&
			    (say_flags & SAY_HERE)) {
				return;
			}
			depth = 0;
			while ((Typeof(loc) != TYPE_ROOM) &&
			       (depth++ < 20)) {
				loc = Location(loc);
				if ((loc == NOTHING) ||
				    (loc == Location(loc)))
					return;
			}
			if (Typeof(loc) == TYPE_ROOM) {
			    if (say_flags & SAY_HTML) {
				notify_all_from_inside_html_speech(loc, player,
							    message);
			    } else {
				notify_all_from_inside_speech(loc, player,
							      message);
			    }
			}
		}
		break;
	case SAY_SHOUT:
		switch (*message) {
		case ':':
			message[0] = ' ';
			say_shout(0, announce_msg, say_flags, player, message);
			break;
		case ';':
			message++;
			say_shout(0, announce_msg, say_flags, player, message);
			break;
		case '"':
			message++;
		default:
			buf2 = alloc_lbuf("do_say.shout");
			bp = buf2;
			safe_str((char *)" shouts, \"", buf2, &bp);
			safe_str(message, buf2, &bp);
			safe_chr('"', buf2, &bp);
			say_shout(0, announce_msg, say_flags, player, buf2);
			free_lbuf(buf2);
		}
		STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT")
			log_name(player);
			log_printf(" shouts: '%s'", strip_ansi(message));
		ENDLOG
		break;
	case SAY_WIZSHOUT:
		switch (*message) {
		case ':':
			message[0] = ' ';
			say_shout(WIZARD, broadcast_msg, say_flags, player,
				  message);
			break;
		case ';':
			message++;
			say_shout(WIZARD, broadcast_msg, say_flags, player,
				  message);
			break;
		case '"':
			message++;
		default:
			buf2 = alloc_lbuf("do_say.wizshout");
			bp = buf2;
			safe_str((char *)" says, \"", buf2, &bp);
			safe_str(message, buf2, &bp);
			safe_chr('"', buf2, &bp);
			say_shout(WIZARD, broadcast_msg, say_flags, player,
				  buf2);
			free_lbuf(buf2);
		}
		STARTLOG(LOG_SHOUTS, "WIZ", "BCAST")
			log_name(player);
			log_printf(" broadcasts: '%s'", strip_ansi(message));
		ENDLOG
		break;
	case SAY_ADMINSHOUT:
		switch (*message) {
		case ':':
			message[0] = ' ';
			say_shout(WIZARD, admin_msg, say_flags, player,
				  message);
			say_shout(ROYALTY, admin_msg, say_flags, player,
				  message);
			break;
		case ';':
			message++;
			say_shout(WIZARD, admin_msg, say_flags, player,
				  message);
			say_shout(ROYALTY, admin_msg, say_flags, player,
				  message);
			break;
		case '"':
			message++;
		default:
			buf2 = alloc_lbuf("do_say.adminshout");
			bp = buf2;
			safe_str((char *)" says, \"", buf2, &bp);
			safe_str(message, buf2, &bp);
			safe_chr('"', buf2, &bp);
			*bp = '\0';
			say_shout(WIZARD, admin_msg, say_flags, player,
				  buf2);
			say_shout(ROYALTY, admin_msg, say_flags, player,
				  buf2);
			free_lbuf(buf2);
		}
		STARTLOG(LOG_SHOUTS, "WIZ", "ASHOUT")
			log_name(player);
			log_printf(" yells: '%s'", strip_ansi(message));
		ENDLOG
		break;
	case SAY_WALLPOSE:
		if (say_flags & SAY_NOTAG)
			raw_broadcast(0, "%s %s", Name(player), message);
		else
			raw_broadcast(0, "Announcement: %s %s", Name(player),
				      message);
		STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT")
			log_name(player);
			log_printf(" WALLposes: '%s'", strip_ansi(message));
		ENDLOG
		break;
	case SAY_WIZPOSE:
		if (say_flags & SAY_NOTAG)
			raw_broadcast(WIZARD, "%s %s", Name(player), message);
		else
			raw_broadcast(WIZARD, "Broadcast: %s %s", Name(player),
				      message);
		STARTLOG(LOG_SHOUTS, "WIZ", "BCAST")
			log_name(player);
			log_printf(" WIZposes: '%s'", strip_ansi(message));
		ENDLOG
		break;
	case SAY_WALLEMIT:
		if (say_flags & SAY_NOTAG)
			raw_broadcast(0, "%s", message);
		else
			raw_broadcast(0, "Announcement: %s", message);
		STARTLOG(LOG_SHOUTS, "WIZ", "SHOUT")
			log_name(player);
			log_printf(" WALLemits: '%s'", strip_ansi(message));
		ENDLOG
		break;
	case SAY_WIZEMIT:
		if (say_flags & SAY_NOTAG)
			raw_broadcast(WIZARD, "%s", message);
		else
			raw_broadcast(WIZARD, "Broadcast: %s", message);
		STARTLOG(LOG_SHOUTS, "WIZ", "BCAST")
			log_name(player);
			log_printf(" WIZemits: '%s'", strip_ansi(message));
		ENDLOG
		break;
	}
}

/*
 * ---------------------------------------------------------------------------
 * * do_page: Handle the page command.
 * * Page-pose code from shadow@prelude.cc.purdue.
 */

static void page_return(player, target, tag, anum, dflt)
dbref player, target;
int anum;
const char *tag, *dflt;
{
	dbref aowner;
	int aflags, alen;
	char *str, *str2, *buf, *bp;
	struct tm *tp;
	time_t t;

	str = atr_pget(target, anum, &aowner, &aflags, &alen);
	if (*str) {
		str2 = bp = alloc_lbuf("page_return");
		buf = str;
		exec(str2, &bp, target, player, player,
		     EV_FCHECK | EV_EVAL | EV_TOP | EV_NO_LOCATION, &buf,
		     (char **)NULL, 0);
		if (*str2) {
			t = time(NULL);
			tp = localtime(&t);
			notify_with_cause(player, target,
					  tprintf("%s message from %s: %s",
						  tag, Name(target), str2));
			notify_with_cause(target, player,
					  tprintf("[%d:%02d] %s message sent to %s.",
				       tp->tm_hour, tp->tm_min, tag, Name(player)));
		}
		free_lbuf(str2);
	} else if (dflt && *dflt) {
		notify_with_cause(player, target, dflt);
	}
	free_lbuf(str);
}

static int page_check(player, target)
dbref player, target;
{
	if (!payfor(player, Guest(player) ? 0 : mudconf.pagecost)) {
		notify(player,
		       tprintf("You don't have enough %s.",
			       mudconf.many_coins));
	} else if (!Connected(target)) {
		page_return(player, target, "Away", A_AWAY,
			    tprintf("Sorry, %s is not connected.",
				    Name(target)));
	} else if (!could_doit(player, target, A_LPAGE)) {
		if (Can_Hide(target) && Hidden(target) && !See_Hidden(player))
			page_return(player, target, "Away", A_AWAY,
				    tprintf("Sorry, %s is not connected.",
					    Name(target)));
		else
			page_return(player, target, "Reject", A_REJECT,
				tprintf("Sorry, %s is not accepting pages.",
					Name(target)));
	} else if (!could_doit(target, player, A_LPAGE)) {
		if (Wizard(player)) {
			notify(player,
			       tprintf("Warning: %s can't return your page.",
				       Name(target)));
			return 1;
		} else {
			notify(player,
			       tprintf("Sorry, %s can't return your page.",
				       Name(target)));
			return 0;
		}
	} else {
		return 1;
	}
	return 0;
}

void do_page(player, cause, key, tname, message)
    dbref player, cause;
    int key;
    char *tname, *message;
{
    char *dbref_list, *ddp;
    char *clean_tname, *tnp;
    char *omessage, *omp, *imessage, *imp;
    int count = 0;
    int aowner, aflags, alen;
    dbref target;
    int n_dbrefs, i;
    int *dbrefs_array = NULL;
    char *str, *tokst;

    /* If we have to have an equals sign in the page command, if
     * there's no message, it's an error (otherwise tname would
     * be null and message would contain text).
     * Otherwise we handle repage by swapping args.
     * Unfortunately, we have no way of differentiating
     * 'page foo=' from 'page foo' -- both result in a valid tname.
     */

    if (!*message) {
	if (mudconf.page_req_equals) {
	    notify(player, "No one to page.");
	    return;
	}
	tnp = message;
	message = tname;
	tname = tnp;
    }

    if (!*tname) {		/* no recipient list; use lastpaged */

	/* Clean junk objects out of their lastpaged dbref list */

	dbref_list = atr_get(player, A_LASTPAGE, &aowner, &aflags, &alen);

	/* How many words in the list of targets? */

	if (!*dbref_list) {
	    count = 0; 
	} else {

	    for (n_dbrefs = 1, str = dbref_list; ; n_dbrefs++) {
		if ((str = strchr(str, ' ')) != NULL)
		    str++;
		else
		    break;
	    }

	    dbrefs_array = (int *) XCALLOC(n_dbrefs, sizeof(int),
					   "do_page.dbrefs");

	    /* Convert the list into an array of targets. Validate. */

	    for (ddp = strtok_r(dbref_list, " ", &tokst);
		 ddp;
		 ddp = strtok_r(NULL, " ", &tokst)) {
		target = atoi(ddp);
		if (!Good_obj(target) || !isPlayer(target)) {
		    notify(player, tprintf("I don't recognize #%d.", target));
		    continue;
		}
		dbrefs_array[count] = target;
		count++;
	    }
	}

	free_lbuf(dbref_list);

    } else {			/* normal page; build new recipient list */

	if ((target = lookup_player(player, tname, 1)) != NOTHING) {
	    dbrefs_array = (int *) XCALLOC(1, sizeof(int), "do_page.dbrefs");
	    dbrefs_array[0] = target;
	    count++;
	} else {

	    /* How many words in the list of targets? Note that we separate
	     * with either a comma or a space!
	     */

	    n_dbrefs = 1;
	    for (str = tname; *str; str++) {
		if ((*str == ' ') || (*str == ','))
		    n_dbrefs++;
	    }
	    dbrefs_array = (int *) XCALLOC(n_dbrefs, sizeof(int), "do_page.dbrefs");

	    /* Go look 'em up */

	    for (tnp = strtok_r(tname, ", ", &tokst);
		 tnp;
		 tnp = strtok_r(NULL, ", ", &tokst)) {
		if ((target = lookup_player(player, tnp, 1)) != NOTHING) {
		    dbrefs_array[count] = target;
		    count++;
		} else {
		    notify(player, tprintf("I don't recognize %s.", tnp));
		}
	    }
	}
    }

    n_dbrefs = count;

    /* Filter out disconnected and pagelocked, if we're actually sending
     * a message.
     */

    if (*message) {
	for (i = 0; i < n_dbrefs; i++) {
	    if (!page_check(player, dbrefs_array[i])) {
		dbrefs_array[i] = NOTHING;
		count--;
	    }
	}
    }

    /* Write back the lastpaged attribute. */

    dbref_list = ddp = alloc_lbuf("do_page.lastpage");
    for (i = 0; i < n_dbrefs; i++) {
	if (dbrefs_array[i] != NOTHING) {
	    if (ddp != dbref_list)
		safe_chr(' ', dbref_list, &ddp);
	    safe_ltos(dbref_list, &ddp, dbrefs_array[i]);
	}
    }
    *ddp = '\0';
    atr_add_raw(player, A_LASTPAGE, dbref_list);
    free_lbuf(dbref_list);

    /* Check to make sure we have something. */

    if (count == 0) {
	if (!*message)
	    notify(player, "You have not paged anyone.");
	else
	    notify(player, "No one to page.");
	if (dbrefs_array)
	    XFREE(dbrefs_array, "do_page.dbrefs");
	return;
    }

    /* Build name list. Even if we only have one name, we have to go
     * through the array, because the first entries might be invalid.
     */

    clean_tname = tnp = alloc_lbuf("do_page.namelist");
    if (count == 1) {
	for (i = 0; i < n_dbrefs; i++) {
	    if (dbrefs_array[i] != NOTHING) {
		safe_name(dbrefs_array[i], clean_tname, &tnp);
		break;
	    }
	}
    } else {
	safe_chr('(', clean_tname, &tnp);
	for (i = 0; i < n_dbrefs; i++) {
	    if (dbrefs_array[i] != NOTHING) {
		if (tnp != clean_tname + 1)
		    safe_known_str(", ", 2, clean_tname, &tnp);
		safe_name(dbrefs_array[i], clean_tname, &tnp);
	    }
	}
	safe_chr(')', clean_tname, &tnp);
    }
    *tnp = '\0';

    /* Mess with message */

    omessage = omp = alloc_lbuf("do_page.omessage");
    imessage = imp = alloc_lbuf("do_page.imessage");
    switch (*message) {
    case '\0':
	notify(player, tprintf("You last paged %s.", clean_tname));
	free_lbuf(clean_tname);
	free_lbuf(omessage);
	free_lbuf(imessage);
	XFREE(dbrefs_array, "do_page.dbrefs");
	return;
    case ':':
	message++;
	safe_str("From afar, ", omessage, &omp);
	if (count != 1)
	    safe_tprintf_str(omessage, &omp, "to %s: ", clean_tname);
	safe_tprintf_str(omessage, &omp, "%s %s", Name(player), message);
	safe_tprintf_str(imessage, &imp, "Long distance to %s: %s %s",
			 clean_tname, Name(player), message);
	break;
    case ';':
	message++;
	safe_str("From afar, ", omessage, &omp);
	if (count != 1)
	    safe_tprintf_str(omessage, &omp, "to %s: ", clean_tname);
	safe_tprintf_str(omessage, &omp, "%s%s", Name(player), message);
	safe_tprintf_str(imessage, &imp, "Long distance to %s: %s%s",
			 clean_tname, Name(player), message);
	break;
    case '"':
	message++;
    default:
	if (count != 1)
	    safe_tprintf_str(omessage, &omp, "To %s, ", clean_tname);
	safe_tprintf_str(omessage, &omp, "%s pages: %s",
			 Name(player), message);
	safe_tprintf_str(imessage, &imp, "You paged %s with '%s'.",
			 clean_tname, message);
    }
    free_lbuf(clean_tname);

    /* Send the message out, checking for idlers */

    for (i = 0; i < n_dbrefs; i++) {
	if (dbrefs_array[i] != NOTHING) {
	    notify_with_cause(dbrefs_array[i], player, omessage);
	    page_return(player, dbrefs_array[i], "Idle", A_IDLE, NULL);
	}
    }
    free_lbuf(omessage);
    XFREE(dbrefs_array, "do_page.dbrefs");

    /* Tell the sender */

    notify(player, imessage);
    free_lbuf(imessage);
}

/*
 * ---------------------------------------------------------------------------
 * * do_pemit: Messages to specific players, or to all but specific players.
 */

void whisper_pose(player, target, message)
dbref player, target;
char *message;
{
	char *buff;

	buff = alloc_lbuf("do_pemit.whisper.pose");
	StringCopy(buff, Name(player));
	notify(player,
	       tprintf("%s senses \"%s%s\"", Name(target), buff, message));
	notify_with_cause(target, player,
			  tprintf("You sense %s%s", buff, message));
	free_lbuf(buff);
}

void do_pemit_list(player, list, message, do_contents)
dbref player;
char *list;
const char *message;
int do_contents;
{
	/*
	 * Send a message to a list of dbrefs. To avoid repeated generation * 
	 * of the NOSPOOF string, we set it up the first time we
	 * encounter something Nospoof, and then check for it
	 * thereafter. The list is destructively modified. 
	 */

	char *p, *tokst;
	dbref who, *recips;
	int n_recips, r, ok_to_do;

	if (!message || !*message || !list || !*list)
		return;

	n_recips = 1;
	for (p = list; *p; ++p) {
		if (*p == ' ')
			++n_recips;
	}

	recips = (dbref *) XCALLOC(n_recips, sizeof(dbref),
				   "do_pemit_list.recips");

	n_recips = 0;
	for (p = strtok_r(list, " ", &tokst);
	     p != NULL;
	     p = strtok_r(NULL, " ", &tokst)) {

		init_match(player, p, TYPE_PLAYER);
		match_everything(0);
		who = match_result();

		switch (who) {
		case NOTHING:
			notify(player, "Emit to whom?");
			break;
		case AMBIGUOUS:
			notify(player, "I don't know who you mean!");
			break;
		default:
			if (!Good_obj(who))
				continue;
			/* avoid pemitting to this dbref if already done */
			for (r = 0; r < n_recips; ++r) {
				if (recips[r] == who)
					break;
			}
			if (r < n_recips)
				continue;
			/* see if player can pemit to this dbref */
			ok_to_do = mudconf.pemit_any;
			if (!ok_to_do &&
			    (Long_Fingers(player) || nearby(player, who) || 
			     Controls(player, who))) {
				ok_to_do = 1;
			}
			if (!ok_to_do && (isPlayer(who))
			    && mudconf.pemit_players) {
				if (!page_check(player, who))
					continue;
				ok_to_do = 1;
			}
			if (do_contents && !mudconf.pemit_any &&
			    !Controls(player, who)) {
				ok_to_do = 0;
			}
			if (!ok_to_do) {
				notify(player, "You cannot do that.");
				continue;
			}
			/* fine, send the message */
			if (do_contents && Has_contents(who))
				notify_all_from_inside(who, player, message);
			    else 
				notify_with_cause(who, player, message);
			/* avoid pemitting to this dbref again */
			recips[n_recips] = who;
			++n_recips;
		}
	}
	XFREE(recips, "do_pemit_list.recips");
}


void do_pemit(player, cause, key, recipient, message)
dbref player, cause;
int key;
char *recipient, *message;
{
	dbref target, loc;
	char *buf2, *bp;
	int do_contents, ok_to_do, depth, pemit_flags;

	if (key & PEMIT_CONTENTS) {
		do_contents = 1;
		key &= ~PEMIT_CONTENTS;
	} else {
		do_contents = 0;
	}
	if (key & PEMIT_LIST) {
		do_pemit_list(player, recipient, message, do_contents);
		return;
	}

	pemit_flags = key & (PEMIT_HERE | PEMIT_ROOM | PEMIT_SPEECH | PEMIT_MOVE | PEMIT_HTML | PEMIT_SPOOF);
	key &= ~(PEMIT_HERE | PEMIT_ROOM | PEMIT_SPEECH | PEMIT_MOVE | PEMIT_HTML | PEMIT_SPOOF);
	ok_to_do = 0;


	switch (key) {
	case PEMIT_FSAY:
	case PEMIT_FPOSE:
	case PEMIT_FPOSE_NS:
	case PEMIT_FEMIT:
		target = match_affected(player, recipient);
		if (target == NOTHING)
			return;
		ok_to_do = 1;
		break;
	default:
		init_match(player, recipient, TYPE_PLAYER);
		match_everything(0);
		target = match_result();
	}

	switch (target) {
	case NOTHING:
		switch (key) {
		case PEMIT_WHISPER:
			notify(player, "Whisper to whom?");
			break;
		case PEMIT_PEMIT:
			notify(player, "Emit to whom?");
			break;
		case PEMIT_OEMIT:
			notify(player, "Emit except to whom?");
			break;
		default:
			notify(player, "Sorry.");
		}
		break;
	case AMBIGUOUS:
		notify(player, "I don't know who you mean!");
		break;
	default:
		/*
		 * Enforce locality constraints 
		 */

		if (!ok_to_do &&
		    (nearby(player, target) || Long_Fingers(player)
		     || Controls(player, target))) {
			ok_to_do = 1;
		}
		if (!ok_to_do && (key == PEMIT_PEMIT) &&
		 (Typeof(target) == TYPE_PLAYER) && mudconf.pemit_players) {
			if (!page_check(player, target))
				return;
			ok_to_do = 1;
		}
		if (!ok_to_do &&
		    (!mudconf.pemit_any || (key != PEMIT_PEMIT))) {
			notify(player, "You are too far away to do that.");
			return;
		}
		if (do_contents && !Controls(player, target) &&
		    !mudconf.pemit_any) {
			notify(player, NOPERM_MESSAGE);
			return;
		}
		loc = where_is(target);

		switch (key) {
		case PEMIT_PEMIT:
			if (do_contents) {
				if (Has_contents(target)) {
				    if (pemit_flags & PEMIT_SPEECH) {
					notify_all_from_inside_speech(target,
							      player, message);
				    } else if (pemit_flags & PEMIT_MOVE) {
					notify_all_from_inside_move(target,
							      player, message);
				    } else {
					notify_all_from_inside(target, player,
							       message);
				    }
				}
			} else {
				notify_with_cause_extra(target, player,
				message,
				((pemit_flags & PEMIT_HTML) ? MSG_HTML : 0) |
				((pemit_flags & PEMIT_SPEECH) ? MSG_SPEECH : 0));
			}
			break;
		case PEMIT_OEMIT:
		        notify_except(Location(target), player, target,
			    message,
			    ((pemit_flags & PEMIT_SPEECH) ? MSG_SPEECH : 0) |
			    ((pemit_flags & PEMIT_MOVE) ? MSG_MOVE : 0));
			break;
		case PEMIT_WHISPER:
		        if ((Unreal(player) && !Check_Heard(target, player)) ||
			    (Unreal(target) && !Check_Hears(player, target))) {
			    notify(player, CANNOT_HEAR_MSG);
			} else {
			    switch (*message) {
				case ':':
				    message[0] = ' ';
				    whisper_pose(player, target, message);
				    break;
				case ';':
				    message++;
				    whisper_pose(player, target, message);
				    break;
				case '"':
				    message++;
				default:
				    notify(player,
					   tprintf("You whisper \"%s\" to %s.",
						   message, Name(target)));
				    notify_with_cause(target, player,
						  tprintf("%s whispers \"%s\"",
						  Name(player), message));
			    }
			    if ((!mudconf.quiet_whisper) && !Wizard(player)) {
				loc = where_is(player);
				if (loc != NOTHING) {
					buf2 = alloc_lbuf("do_pemit.whisper.buzz");
					bp = buf2;
					safe_name(player, buf2, &bp);
					safe_str((char *)" whispers something to ",
						 buf2, &bp);
					safe_name(target, buf2, &bp);
					*bp = '\0';
					notify_except2(loc, player, player,
						       target, buf2,
						       MSG_SPEECH);
					free_lbuf(buf2);
				}
			    }
			}
			break;
		case PEMIT_FSAY:
			format_speech(((pemit_flags & PEMIT_SPOOF) ?
				       target : player),
				      target, loc, message, SAY_SAY);
			break;
		case PEMIT_FPOSE:
			format_speech(((pemit_flags & PEMIT_SPOOF) ?
				       target : player),
				      target, loc, message, SAY_POSE);
			break;
		case PEMIT_FPOSE_NS:
			format_speech(((pemit_flags & PEMIT_SPOOF) ?
				       target : player),
				      target, loc, message, SAY_POSE_NOSPC);
			break;
		case PEMIT_FEMIT:
			if ((pemit_flags & PEMIT_HERE) || !pemit_flags)
				notify_all_from_inside_speech(loc,
					((pemit_flags & PEMIT_SPOOF) ?
					 target : player), message);
			if (pemit_flags & PEMIT_ROOM) {
				if ((Typeof(loc) == TYPE_ROOM) &&
				    (pemit_flags & PEMIT_HERE)) {
					return;
				}
				depth = 0;
				while ((Typeof(loc) != TYPE_ROOM) &&
				       (depth++ < 20)) {
					loc = Location(loc);
					if ((loc == NOTHING) ||
					    (loc == Location(loc)))
						return;
				}
				if (Typeof(loc) == TYPE_ROOM) {
					notify_all_from_inside_speech(loc,
					        ((pemit_flags & PEMIT_SPOOF) ?
						 target : player), message);
				}
			}
			break;

		}
	}
}