game/bin/
game/data/
/*
 * comsys.c 
 */
/*
 * $Id: comsys.c,v 1.4 1995/11/22 23:33:17 root Exp $ 
 */

#include <ctype.h>
#include <sys/types.h>

#include "copyright.h"
#include "autoconf.h"
#include "db.h"
#include "interface.h"
#include "attrs.h"
#include "match.h"
#include "config.h"
#include "externs.h"
#include "flags.h"
#include "powers.h"

#include "comsys.h"

/*
 * This is the hash table for channel names 
 */

void NDECL(init_chantab)
{
	hashinit(&mudstate.channel_htab, 30 * HASH_FACTOR);
}

char *get_channel_from_alias(player, alias)
dbref player;
char *alias;
{
	struct commac *c;
	int first, last, current;
	int dir;

	c = get_commac(player);

	first = 0;
	last = c->numchannels - 1;
	dir = 1;

	while (dir && (first <= last)) {
		current = (first + last) / 2;
		dir = strcmp(alias, c->alias + 6 * current);
		if (dir < 0)
			last = current - 1;
		else
			first = current + 1;
	}

	if (!dir)
		return c->channels[current];
	else
		return "";
}

char *load_comsystem(fp)
FILE *fp;
{
	int i, j, dummy;
	int nc, new = 0;
	struct channel *ch;
	struct comuser *user;
	char temp[1000];
	char buf[8];

	num_channels = 0;


	fgets(buf, sizeof(buf), fp);
	if (!strncmp(buf, "+V1", 3)) {
		new = 1;
		fscanf(fp, "%d\n", &nc);
	} else {
		nc = atoi(buf);
	}

	num_channels = nc;

	for (i = 0; i < nc; i++) {
		ch = (struct channel *)malloc(sizeof(struct channel));

		fscanf(fp, "%[^\n]\n", temp);

		StringCopy(ch->name, temp);
		ch->on_users = NULL;

		hashadd(ch->name, (int *)ch, &mudstate.channel_htab);

		if (new) {
			fscanf(fp, "%d %d %d %d %d %d %d %d\n",
			       &(ch->type), &(ch->temp1), &(ch->temp2),
			       &(ch->charge), &(ch->charge_who),
			       &(ch->amount_col), &(ch->num_messages), &(ch->chan_obj));
		} else {
			fscanf(fp, "%d %d %d %d %d %d %d %d %d %d\n",
			  &(ch->type), &(dummy), &(ch->temp1), &(ch->temp2),
			       &(dummy), &(ch->charge), &(ch->charge_who),
			       &(ch->amount_col), &(ch->num_messages), &(ch->chan_obj));
		}

		fscanf(fp, "%d\n", &(ch->num_users));
		ch->max_users = ch->num_users;
		if (ch->num_users > 0) {
			ch->users = (struct comuser **)
				calloc(ch->max_users, sizeof(struct comuser *));

			for (j = 0; j < ch->num_users; j++) {
				user = (struct comuser *)malloc(sizeof(struct comuser));

				ch->users[j] = user;

				if (new) {
					fscanf(fp, "%d %d\n", &(user->who), &(user->on));
				} else {
					fscanf(fp, "%d %d %d", &(user->who),
					       &(dummy), &(dummy));
					fscanf(fp, "%d\n", &(user->on));
				}

				fscanf(fp, "%[^\n]\n", temp);

				if (strlen(temp + 2) > 0) {
					user->title = (char *)malloc(strlen(temp + 2) + 1);
					StringCopy(user->title, temp + 2);
				} else {
					user->title = (char *)malloc(1);
					user->title[0] = 0;
				}
				if (!(isPlayer(user->who)) && !(Going(user->who) &&
						 (God(Owner(user->who))))) {
					do_joinchannel(user->who, ch);
					user->on_next = ch->on_users;
					ch->on_users = user;
				} else {
					user->on_next = ch->on_users;
					ch->on_users = user;
				}
			}
			sort_users(ch);
		} else
			ch->users = NULL;
	}
}

char *save_comsystem(fp)
FILE *fp;
{
	struct channel *ch;
	struct comuser *user;
	int i, j;

	fprintf(fp, "+V1\n");
	fprintf(fp, "%d\n", num_channels);
	for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
	ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) {
		fprintf(fp, "%s\n", ch->name);

		fprintf(fp, "%d %d %d %d %d %d %d %d\n",
			ch->type, ch->temp1, ch->temp2,
			ch->charge, ch->charge_who,
			ch->amount_col, ch->num_messages, ch->chan_obj);

		fprintf(fp, "%d\n", ch->num_users);
		for (j = 0; j < ch->num_users; j++) {
			user = ch->users[j];
			fprintf(fp, "%d %d\n", user->who, user->on);
			if (strlen(user->title))
				fprintf(fp, "t:%s\n", user->title);
			else
				fprintf(fp, "t:\n");
		}
	}
}

char *do_processcom(player, arg1, arg2)
dbref player;
char *arg1;
char *arg2;
{
	char mess[LBUF_SIZE];
	struct channel *ch;
	struct comuser *user;

	if ((strlen(arg1) + strlen(arg2)) > 3500) {
		arg2[3500] = '\0';
	}
	if (!*arg2) {
		raw_notify(player, "No message.");
		return;
	}
	if (!(ch = select_channel(arg1))) {
		raw_notify(player, tprintf("Unknown channel %s.", arg1));
		return;
	}
	if (!(user = select_user(ch, player))) {
		raw_notify(player,
			   "You are not listed as on that channel.  Delete this alias and readd.");
		return;
	}
	if (!strcmp(arg2, "on")) {
		do_joinchannel(player, ch);
	} else if (!strcmp(arg2, "off")) {
		do_leavechannel(player, ch);
	} else if (!user->on) {
		raw_notify(player, tprintf("You must be on %s to do that.", arg1));
		return;
	} else if (!strcmp(arg2, "who")) {
		do_comwho(player, ch);
	} else if (!(do_test_access(player, CHANNEL_TRANSMIT, ch))) {
		raw_notify(player, "That channel type cannot be transmitted on.");
		return;
	} else {
		if (!payfor(player, Guest(player) ? 0 : ch->charge)) {
			notify(player, tprintf("You don't have enough %s.",
					       mudconf.many_coins));
			return;
		} else {
			ch->amount_col += ch->charge;
			giveto(ch->charge_who, ch->charge);
		}

		if ((*arg2) == ':') {
			if (strlen(user->title))
				sprintf(mess, "[%s] %s %s %s", arg1, user->title, names[player], arg2 + 1);
			else
				sprintf(mess, "[%s] %s %s", arg1, names[player], arg2 + 1);
		} else if ((*arg2) == ';') {
			if (strlen(user->title))
				sprintf(mess, "[%s] %s %s%s", arg1, user->title, names[player], arg2 + 1);
			else
				sprintf(mess, "[%s] %s%s", arg1, names[player], arg2 + 1);
		} else if (strlen(user->title))
			sprintf(mess,
				"[%s] %s %s says, \"%s\"", arg1, user->title, names[player], arg2);
		else
			sprintf(mess, "[%s] %s says, \"%s\"", arg1, names[player], arg2);

		do_comsend(ch, mess);
	}
}

char *do_comsend(ch, mess)
struct channel *ch;
char *mess;
{
	struct comuser *user;

	ch->num_messages++;
	for (user = ch->on_users; user; user = user->on_next) {
		if (user->on && Connected(user->who))
			if (do_test_access(user->who, CHANNEL_RECIEVE, ch))
				raw_notify(user->who, mess);
	}
}

char *do_joinchannel(player, ch)
dbref player;
struct channel *ch;
{
	char temp[1000];
	struct comuser *user;
	struct comuser **cu;
	int i;

	user = select_user(ch, player);

	if (!user) {
		ch->num_users++;
		if (ch->num_users >= ch->max_users) {
			ch->max_users += 10;
			cu = (struct comuser **)
				malloc(sizeof(struct comuser *) * ch->max_users);

			for (i = 0; i < (ch->num_users - 1); i++)
				cu[i] = ch->users[i];
			free(ch->users);
			ch->users = cu;
		}
		user = (struct comuser *)malloc(sizeof(struct comuser));

		for (i = ch->num_users - 1; i > 0 && ch->users[i - 1]->who > player; i--)
			ch->users[i] = ch->users[i - 1];
		ch->users[i] = user;

		user->who = player;
		user->on = 1;
		user->title = (char *)malloc(1);
		user->title[0] = 0;

/*
 * if (Connected(player))&&(isPlayer(player)) 
 */
		if UNDEAD
			(player) {
			user->on_next = ch->on_users;
			ch->on_users = user;
			}
	} else if (!user->on) {
		raw_notify(player, tprintf("You have joined channel %s.", ch->name));
		user->on = 1;
	} else {
		raw_notify(player, tprintf("You are already on channel %s.", ch->name));
		return;
	}

	sprintf(temp, "[%s] %s has joined this channel.", ch->name,
		names[player]);
	do_comsend(ch, temp);
}

char *do_leavechannel(player, ch)
dbref player;
struct channel *ch;
{
	struct comuser *user;
	char temp[1000];

	user = select_user(ch, player);

	if (user->on) {
		sprintf(temp, "[%s] %s has left this channel.", ch->name, names[player]);
		do_comsend(ch, temp);
	}
	user->on = 0;
}

char *do_comwho(player, ch)
dbref player;
struct channel *ch;
{
	struct comuser *user;
	char *buff;

	raw_notify(player, "-- Players --");
	for (user = ch->on_users; user; user = user->on_next) {
		if (Typeof(user->who) == TYPE_PLAYER)
			if (Connected(user->who) && (!Dark(user->who) || WizRoy(player))) {
				if (user->on) {
					buff = unparse_object(player, user->who, 0);
					raw_notify(player, tprintf("%s", buff));
					free_lbuf(buff);
				}
			} else if (!Dark(user->who))
				do_comdisconnectchannel(user->who, ch->name);
	}
	raw_notify(player, "-- Objects --");
	for (user = ch->on_users; user; user = user->on_next) {
		if (Typeof(user->who) != TYPE_PLAYER)
			if ((Going(user->who)) &&
			    (God(Owner(user->who))))
				do_comdisconnectchannel(user->who, ch->name);
			else if (user->on) {
				buff = unparse_object(player, user->who, 0);
				raw_notify(player, tprintf("%s", buff));
				free_lbuf(buff);
			}
	}
	raw_notify(player, tprintf("-- %s --", ch->name));
}

struct channel *select_channel(channel)
char *channel;
{
	struct channel *cp;

	cp = (struct channel *)hashfind(channel, &mudstate.channel_htab);
	if (!cp)
		return NULL;
	else
		return cp;
}

struct comuser *select_user(ch, player)
struct channel *ch;
dbref player;
{
	int first, last, current;
	int dir;

	if (!ch)
		return NULL;

	first = 0;
	last = ch->num_users - 1;
	dir = 1;
	current = (first + last) / 2;

	while (dir && (first <= last)) {
		current = (first + last) / 2;
		if (ch->users[current] == NULL) {
			last--;
			continue;
		}
		if (ch->users[current]->who == player)
			dir = 0;
		else if (ch->users[current]->who < player) {
			dir = 1;
			first = current + 1;
		} else {
			dir = -1;
			last = current - 1;
		}
	}

	if (!dir)
		return ch->users[current];
	else
		return NULL;
}

void do_addcom(player, cause, key, arg1, arg2)
dbref player, cause;
int key;
char *arg1;
char *arg2;
{
	char channel[200];
	char title[1000];
	char buffer[100];
	struct channel *ch;
	char *s, *t;
	int i, j, where;
	struct commac *c;
	char *na;
	char **nc;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	if (!*arg1) {
		raw_notify(player, "You need to specify an alias.");
		return;
	}
	s = arg2;
	if (!*s) {
		raw_notify(player, "You need to specify a channel.");
		return;
	}
	t = channel;
	while (*s && *s != ',') {
		if (*s != ' ')
			*t++ = *s++;
		else
			s++;
	}
	*t = '\0';

	t = title;
	*t = '\0';
	if (*s) {		/*
				 * Read title 
				 */
		s++;
		while (*s)
			*t++ = *s++;
		*t = '\0';
	}
	if (!(ch = select_channel(channel))) {
		raw_notify(player, tprintf("Channel %s does not exist yet.", channel));
		return;
	}
	if (!(do_test_access(player, CHANNEL_JOIN, ch))) {
		raw_notify(player, "Sorry, this channel type does not allow you to join.");
		return;
	}
	if (select_user(ch, player)) {
		raw_notify(player, tprintf("Warning: You are already on that channel."));
	}
	c = get_commac(player);
	for (j = 0; j < c->numchannels && (strcmp(arg1, c->alias + j * 6) > 0); j++) ;
	if (j < c->numchannels && !strcmp(arg1, c->alias + j * 6)) {
		sprintf(buffer, "That alias is already in use for channel %s.",
			c->channels[j]);
		raw_notify(player, buffer);
		return;
	}
	if (c->numchannels >= c->maxchannels) {
		c->maxchannels += 10;

		na = (char *)malloc(6 * c->maxchannels);
		nc = (char **)malloc(sizeof(char *) * c->maxchannels);

		for (i = 0; i < c->numchannels; i++) {
			StringCopy(na + i * 6, c->alias + i * 6);
			nc[i] = c->channels[i];
		}
		free(c->alias);
		free(c->channels);
		c->alias = na;
		c->channels = nc;
	}
	where = c->numchannels++;
	for (i = where; i > j; i--) {
		StringCopy(c->alias + i * 6, c->alias + (i - 1) * 6);
		c->channels[i] = c->channels[i - 1];
	}

	where = j;
	StringCopyTrunc(c->alias + where * 6, arg1, 5);
	*(c->alias + where * 6 + 5) = '\0';
	c->channels[where] = (char *)malloc(strlen(channel) + 1);
	StringCopy(c->channels[where], channel);

	do_joinchannel(player, ch);
	do_setnewtitle(player, ch, title);

	if (title[0])
		raw_notify(player, tprintf(
						  "Channel %s added with alias %s and title %s.", channel, arg1, title));
	else
		raw_notify(player, tprintf(
			 "Channel %s added with alias %s.", channel, arg1));
}

char *do_setnewtitle(player, ch, title)
dbref player;
struct channel *ch;
char *title;
{
	struct comuser *user;

	user = select_user(ch, player);

	if (ch && user) {
		if (user->title)
			free(user->title);
		if (strlen(title) > 0) {
			user->title = (char *)malloc(strlen(title) + 1);
			StringCopy(user->title, title);
		} else {
			user->title = (char *)malloc(1);
			user->title[0] = 0;
		}
	}
}

void do_delcom(player, cause, key, arg1)
dbref player, cause;
int key;
char *arg1;
{
	int i;
	struct commac *c;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	if (!arg1) {
		raw_notify(player, "Need an alias to delete.");
		return;
	}
	c = get_commac(player);

	for (i = 0; i < c->numchannels; i++) {
		if (!strcmp(arg1, c->alias + i * 6)) {
			do_delcomchannel(player, c->channels[i]);
			raw_notify(player, tprintf("Channel %s deleted.", c->channels[i]));
			free(c->channels[i]);

			c->numchannels--;
			for (; i < c->numchannels; i++) {
				StringCopy(c->alias + i * 6, c->alias + i * 6 + 6);
				c->channels[i] = c->channels[i + 1];
			}
			return;
		}
	}
	raw_notify(player, "Unable to find that alias.");
}

char *do_delcomchannel(player, channel)
dbref player;
char *channel;
{
	struct channel *ch;
	struct comuser *user;
	char temp[1000];
	int i;
	int j;

	if (!(ch = select_channel(channel))) {
		raw_notify(player, tprintf("Unknown channel %s.", channel));
	} else {
		j = 0;
		for (i = 0; i < ch->num_users && !j; i++) {
			user = ch->users[i];
			if (user->who == player) {
				do_comdisconnectchannel(player, channel);
				if (user->on) {
					sprintf(temp, "[%s] %s has left this channel.",
						channel, names[player]);
					do_comsend(ch, temp);
				}
				raw_notify(player, tprintf("You have left channel %s.", channel));

				if (user->title)
					free(user->title);
				free(user);
				j = 1;
			}
		}

		if (j) {
			ch->num_users--;
			for (i--; i < ch->num_users; i++)
				ch->users[i] = ch->users[i + 1];
		}
	}
}

void do_createchannel(player, cause, key, channel)
dbref player, cause;
int key;
char *channel;
{
	struct channel *newchannel;
	struct channel **nc;
	int i;


	if (select_channel(channel)) {
		raw_notify(player, tprintf("Channel %s already exists.", channel));
		return;
	}
	if (!*channel) {
		raw_notify(player, "You must specify a channel to create.");
		return;
	}
	if (!(Comm_All(player))) {
		raw_notify(player, "You do not have permission to do that.");
		return;
	}
	newchannel = (struct channel *)malloc(sizeof(struct channel));

	StringCopyTrunc(newchannel->name, channel, CHAN_NAME_LEN - 1);
	newchannel->name[CHAN_NAME_LEN - 1] = '\0';
	newchannel->type = 127;
	newchannel->temp1 = 0;
	newchannel->temp2 = 0;
	newchannel->charge = 0;
	newchannel->charge_who = player;
	newchannel->amount_col = 0;
	newchannel->num_users = 0;
	newchannel->max_users = 0;
	newchannel->users = NULL;
	newchannel->on_users = NULL;
	newchannel->chan_obj = NOTHING;
	newchannel->num_messages = 0;

	num_channels++;

	hashadd(newchannel->name, (int *)newchannel, &mudstate.channel_htab);

	raw_notify(player, tprintf("Channel %s created.", channel));
}

void do_destroychannel(player, cause, key, channel)
dbref player, cause;
int key;
char *channel;
{
	struct channel *ch;
	int j;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	ch = (struct channel *)hashfind(channel, &mudstate.channel_htab);

	if (!ch) {
		raw_notify(player, tprintf("Could not find channel %s.", channel));
		return;
	} else if (!(Comm_All(player) || (player != ch->charge_who))) {
		raw_notify(player, "You do not have permission to do that. ");
		return;
	}
	num_channels--;
	hashdelete(channel, &mudstate.channel_htab);

	for (j = 0; j < ch->num_users; j++) {
		free(ch->users[j]);
	}
	free(ch->users);
	free(ch);
	raw_notify(player, tprintf("Channel %s destroyed.", channel));
}

char *do_listchannels(player)
dbref player;
{
	struct channel *ch;
	char temp[1000];
	int i, perm;

	if (!(perm = Comm_All(player))) {
		raw_notify(player, "Warning: Only public channels and your channels will be shown.");
	}
	raw_notify(player,
		   "** Channel      --Flags--  Obj   Own   Charge  Balance  Users   Messages");

	for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
	  ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab))
		if (perm || (ch->type & CHANNEL_PUBLIC) || ch->charge_who == player) {

			sprintf(temp, "%c%c %-13.13s %c%c%c/%c%c%c %5d %5d %8d %8d %6d %10d",
				(ch->type & (CHANNEL_PUBLIC)) ? 'P' : '-',
				(ch->type & (CHANNEL_LOUD)) ? 'L' : '-',
				ch->name,
				(ch->type & (CHANNEL_PL_MULT * CHANNEL_JOIN)) ? 'J' : '-',
				(ch->type & (CHANNEL_PL_MULT * CHANNEL_TRANSMIT)) ? 'X' : '-',
				(ch->type & (CHANNEL_PL_MULT * CHANNEL_RECIEVE)) ? 'R' : '-',
				(ch->type & (CHANNEL_OBJ_MULT * CHANNEL_JOIN)) ? 'j' : '-',
				(ch->type & (CHANNEL_OBJ_MULT * CHANNEL_TRANSMIT)) ? 'x' : '-',
				(ch->type & (CHANNEL_OBJ_MULT * CHANNEL_RECIEVE)) ? 'r' : '-',
			      (ch->chan_obj != NOTHING) ? ch->chan_obj : -1,
				ch->charge_who, ch->charge, ch->amount_col, ch->num_users, ch->num_messages);
			raw_notify(player, temp);
		}
	raw_notify(player, "-- End of list of Channels --");
}

void do_comtitle(player, cause, key, arg1, arg2)
dbref player, cause;
int key;
char *arg1;
char *arg2;
{
	struct channel *ch;
	char channel[50];

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	if (!*arg1) {
		raw_notify(player, "Need an alias to do comtitle.");
		return;
	}
	StringCopy(channel, get_channel_from_alias(player, arg1));

	if (strlen(channel) == 0) {
		raw_notify(player, "Unknown alias");
		return;
	}
	if ((ch = select_channel(channel)) && select_user(ch, player)) {
		raw_notify(player, tprintf("Title set to '%s' on channel %s.", arg2, channel));
		do_setnewtitle(player, ch, arg2);
	}
	if (!ch) {
		raw_notify(player, "Illegal comsys alias, please delete.");
		return;
	}
}

void do_comlist(player, cause, key)
dbref player, cause;
int key;
{
	struct comuser *user;
	struct commac *c;
	int i;
	char temp[200];

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	c = get_commac(player);

	raw_notify(player,
		   "Alias     Channel             Title                                   Status");

	for (i = 0; i < c->numchannels; i++) {
		if ((user = select_user(select_channel(c->channels[i]), player))) {
			sprintf(temp, "%-9.9s %-19.19s %-39.39s %s", c->alias + i * 6,
				c->channels[i], user->title, (user->on ? "on" : "off"));
			raw_notify(player, temp);
		} else {
			raw_notify(player,
			     tprintf("Bad Comsys Alias: %s for Channel: %s",
				     c->alias + i * 6, c->channels[i]));
		}
	}
	raw_notify(player, "-- End of comlist --");
}

char *do_channelnuke(player)
dbref player;
{
	struct channel *ch;
	int i, j;

	for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
	ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) {
		if (ch->charge_who == player) {
			num_channels--;
			hashdelete(ch->name, &mudstate.channel_htab);

			for (j = 0; j < ch->num_users; j++)
				free(ch->users[j]);
			free(ch->users);
			free(ch);
		}
	}
}

void do_clearcom(player, cause, key)
dbref player, cause;
int key;
{
	int i;
	struct commac *c;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	c = get_commac(player);

	for (i = (c->numchannels) - 1; i > -1; --i) {
		do_delcom(player, player, 0, c->alias + i * 6);
	}
}

void do_allcom(player, cause, key, arg1)
dbref player, cause;
int key;
char *arg1;
{
	int i;
	struct commac *c;
	char temparg[50];;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	c = get_commac(player);

	if ((strcmp(arg1, "who") != 0) &&
	    (strcmp(arg1, "on") != 0) &&
	    (strcmp(arg1, "off") != 0)) {
		raw_notify(player, "Only options available are: on, off and who.");
		return;
	}
	for (i = 0; i < c->numchannels; i++) {
		do_processcom(player, c->channels[i], arg1);
		if (strcmp(arg1, "who") == 0)
			raw_notify(player, "");
	}

}

char *sort_users(ch)
struct channel *ch;
{
	int i;
	int nu;
	int done;
	struct comuser *user;

	nu = ch->num_users;
	done = 0;
	while (!done) {
		done = 1;
		for (i = 0; i < (nu - 1); i++) {
			if (ch->users[i]->who > ch->users[i + 1]->who) {
				user = ch->users[i];
				ch->users[i] = ch->users[i + 1];
				ch->users[i + 1] = user;
				done = 0;
			}
		}
	}
}

void do_channelwho(player, cause, key, arg1)
dbref player, cause;
int key;
char *arg1;
{
	struct channel *ch;
	struct comuser *user;
	char channel[100];
	int flag;
	char *s;
	char *t;
	char *buff;
	char temp[100];
	int i;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	s = arg1;
	t = channel;
	while (*s && *s != '/')
		*t++ = *s++;
	*t = 0;

	flag = 0;
	if (*s && *(s + 1))
		flag = (*(s + 1) == 'a');

	if (!(ch = select_channel(channel))) {
		raw_notify(player, tprintf("Unknown channel %s.", channel));
		return;
	}
	if (!((Comm_All(player)) || (player == ch->charge_who))) {
		raw_notify(player,
			   "You do not have permission to do that. (Not owner or admin.)");
		return;
	}
	raw_notify(player, tprintf("-- %s --", ch->name));
	raw_notify(player, tprintf("%-29.29s %-6.6s %-6.6s",
				   "Name", "Status", "Player"));
	for (i = 0; i < ch->num_users; i++) {
		user = ch->users[i];
		if (flag || UNDEAD(user->who)) {
			buff = unparse_object(player, user->who, 0);
			sprintf(temp, "%-29.29s %-6.6s %-6.6s",
			     strip_ansi(buff), ((user->on) ? "on " : "off"),
			(Typeof(user->who) == TYPE_PLAYER) ? "yes" : "no ");
			raw_notify(player, temp);
			free_lbuf(buff);
		}
	}
	raw_notify(player, tprintf("-- %s --", ch->name));
}

char *do_comdisconnectraw_notify(player, chan)
dbref player;
char *chan;
{
	struct channel *ch;
	struct comuser *cu;
	char *buff;

	if (!(ch = select_channel(chan)))
		return;
	if (!(cu = select_user(ch, player)))
		return;

	if ((ch->type & CHANNEL_LOUD) && (cu->on) && (!Dark(player))) {
		buff = alloc_lbuf("do_comconnect");
		sprintf(buff, "[%s] %s has disconnected.", ch->name, Name(player));
		do_comsend(ch, buff);
		free_lbuf(buff);
	}
}

char *do_comconnectraw_notify(player, chan)
dbref player;
char *chan;
{
	struct channel *ch;
	struct comuser *cu;
	char *buff;

	if (!(ch = select_channel(chan)))
		return;
	if (!(cu = select_user(ch, player)))
		return;

	if ((ch->type & CHANNEL_LOUD) && (cu->on) && (!Dark(player))) {
		buff = alloc_lbuf("do_comconnect");
		sprintf(buff, "[%s] %s has connected.", ch->name, Name(player));
		do_comsend(ch, buff);
		free_lbuf(buff);
	}
}

char *do_comconnectchannel(player, channel, alias, i)
dbref player;
char *channel;
char *alias;
int i;
{
	struct channel *ch;
	struct comuser *user;

	if ((ch = select_channel(channel))) {
		for (user = ch->on_users;
		     user && user->who != player;
		     user = user->on_next) ;

		if (!user)
			if ((user = select_user(ch, player))) {
				user->on_next = ch->on_users;
				ch->on_users = user;
			} else
				raw_notify(player,
					   tprintf("Bad Comsys Alias: %s for Channel: %s",
						   alias + i * 6, channel));
	} else
		raw_notify(player, tprintf("Bad Comsys Alias: %s for Channel: %s",
					   alias + i * 6, channel));
}

char *do_comdisconnect(player)
dbref player;
{
	int i;
	struct commac *c;

	c = get_commac(player);

	for (i = 0; i < c->numchannels; i++) {
		do_comdisconnectchannel(player, c->channels[i]);
#ifdef CHANNEL_LOUD
		do_comdisconnectraw_notify(player, c->channels[i]);
#endif
	}
}

char *do_comconnect(player)
dbref player;
{
	struct commac *c;
	int i;

	c = get_commac(player);

	for (i = 0; i < c->numchannels; i++) {
		do_comconnectchannel(player, c->channels[i], c->alias, i);
		do_comconnectraw_notify(player, c->channels[i]);
	}
}


char *do_comdisconnectchannel(player, channel)
dbref player;
char *channel;
{
	struct comuser *user, *prevuser;
	struct channel *ch;

	prevuser = NULL;
	if (!(ch = select_channel(channel)))
		return;
	for (user = ch->on_users; user;) {
		if (user->who == player) {
			if (prevuser)
				prevuser->on_next = user->on_next;
			else
				ch->on_users = user->on_next;
			return;
		} else {
			prevuser = user;
			user = user->on_next;
		}
	}
}

void do_editchannel(player, cause, flag, arg1, arg2)
dbref player, cause;
int flag;
char *arg1;
char *arg2;
{
	char *s;
	struct channel *ch;
	int add_remove = 1;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	if (!(ch = select_channel(arg1))) {
		raw_notify(player, tprintf("Unknown channel %s.", arg1));
		return;
	}
	if (!((Comm_All(player)) || (player == ch->charge_who))) {
		raw_notify(player,
			   "You do not have permission to do that. (Not owner or Admin.)");
		return;
	}
	for (s = arg2; *s; s++)
		if (isspace(*s))
			*s = *(s + 1);
	s = arg2;
	if (*s == '!') {
		add_remove = 0;
		s++;
	}
	switch (flag) {
	case 0:
		if (lookup_player(player, arg2, 1) != NOTHING) {
			ch->charge_who = lookup_player(player, arg2, 1);
			raw_notify(player, "Set.");
			return;
		} else {
			raw_notify(player, "Invalid player.");
			return;
		}
	case 1:
		ch->charge = atoi(arg2);
		raw_notify(player, "Set.");
		return;
	case 3:
		if (strcmp(s, "join") == 0) {
			add_remove ? (ch->type |= (CHANNEL_PL_MULT * CHANNEL_JOIN)) :
				(ch->type &= ~(CHANNEL_PL_MULT * CHANNEL_JOIN));
			raw_notify(player, (add_remove) ? "@cpflags: Set." : "@cpflags: Cleared.");
			return;
		}
		if (strcmp(s, "receive") == 0) {
			add_remove ? (ch->type |= (CHANNEL_PL_MULT * CHANNEL_RECIEVE)) :
				(ch->type &= ~(CHANNEL_PL_MULT * CHANNEL_RECIEVE));
			raw_notify(player, (add_remove) ? "@cpflags: Set." : "@cpflags: Cleared.");
			return;
		}
		if (strcmp(s, "transmit") == 0) {
			add_remove ? (ch->type |= (CHANNEL_PL_MULT * CHANNEL_TRANSMIT)) :
				(ch->type &= ~(CHANNEL_PL_MULT * CHANNEL_TRANSMIT));
			raw_notify(player, (add_remove) ? "@cpflags: Set." : "@cpflags: Cleared.");
			return;
		}
		raw_notify(player, "@cpflags: Unknown Flag.");
		break;
	case 4:
		if (strcmp(s, "join") == 0) {
			add_remove ? (ch->type |= (CHANNEL_OBJ_MULT * CHANNEL_JOIN)) :
				(ch->type &= ~(CHANNEL_OBJ_MULT * CHANNEL_JOIN));
			raw_notify(player, (add_remove) ? "@coflags: Set." : "@coflags: Cleared.");
			return;
		}
		if (strcmp(s, "receive") == 0) {
			add_remove ? (ch->type |= (CHANNEL_OBJ_MULT * CHANNEL_RECIEVE)) :
				(ch->type &= ~(CHANNEL_OBJ_MULT * CHANNEL_RECIEVE));
			raw_notify(player, (add_remove) ? "@coflags: Set." : "@coflags: Cleared.");
			return;
		}
		if (strcmp(s, "transmit") == 0) {
			add_remove ? (ch->type |= (CHANNEL_OBJ_MULT * CHANNEL_TRANSMIT)) :
				(ch->type &= ~(CHANNEL_OBJ_MULT * CHANNEL_TRANSMIT));
			raw_notify(player, (add_remove) ? "@coflags: Set." : "@coflags: Cleared.");
			return;
		}
		raw_notify(player, "@coflags: Unknown Flag.");
		break;
	}
	return;
}

int do_test_access(player, access, chan)
dbref player;
long access;
struct channel *chan;
{
	long flag_value = access;

	if (Comm_All(player))
		return (1);
	if ((flag_value & CHANNEL_JOIN) && Comm_All(player))
		return (1);

	/*
	 * Channel objects allow custom locks for channels.  The normal lock
	 * * * * is used to see if they can join that channel.  The enterlock
	 * * is * * checked to see if they can receive messages on it. The *
	 * Uselock is * * checked to see if they can transmit on it. Note: *
	 * These checks do * * not supercede the normal channel flags. If a *
	 * channel is set JOIN *  * for players, ALL players can join the *
	 * channel, whether or not they  * * pass the lock.  Same for all *
	 * channel  object locks. 
	 */

	if ((flag_value & CHANNEL_JOIN) && !((chan->chan_obj == NOTHING) ||
					     (chan->chan_obj == 0))) {
		if (could_doit(player, chan->chan_obj, A_LOCK))
			return (1);
	}
	if ((flag_value & CHANNEL_TRANSMIT) && !((chan->chan_obj == NOTHING) ||
						 (chan->chan_obj == 0))) {
		if (could_doit(player, chan->chan_obj, A_LUSE))
			return (1);
	}
	if ((flag_value & CHANNEL_RECIEVE) && !((chan->chan_obj == NOTHING) ||
						(chan->chan_obj == 0))) {
		if (could_doit(player, chan->chan_obj, A_LENTER))
			return (1);
	}
	if (Typeof(player) == TYPE_PLAYER)
		flag_value *= CHANNEL_PL_MULT;
	else
		flag_value *= CHANNEL_OBJ_MULT;
	flag_value &= 0xFF;	/*
				 * Mask out CHANNEL_PUBLIC and CHANNEL_LOUD * 
				 * 
				 * *  * *  * *  * *  * * just to be paranoid. 
				 * ^_^ 
				 */

	return (((long)chan->type & flag_value));
}

int do_comsystem(who, cmd)	/*
				 * * 1 means continue, 0 means stop  
				 */
dbref who;
char *cmd;
{
	char *t;
	char *ch;
	char *alias;
	char *s;


	alias = alloc_lbuf("do_comsystem");
	s = alias;
	for (t = cmd; *t && *t != ' '; *s++ = *t++) ;

	*s = '\0';

	if (*t)
		t++;

	ch = get_channel_from_alias(who, alias);
	if (strlen(ch) > 0) {
		do_processcom(who, ch, t);
		free_lbuf(alias);
		return 0;
	} else
		free_lbuf(alias);

	return 1;

}

char *do_chclose(player, chan)
dbref player;
char *chan;
{
	struct channel *ch;

	if (!(ch = select_channel(chan))) {
		raw_notify(player, tprintf("@cset: Channel %s does not exist.", chan));
		return;
	}
	if ((player != ch->charge_who) && (!Comm_All(player))) {
		raw_notify(player, "@cset: Permission denied.");
		return;
	}
	ch->type &= (~(CHANNEL_PUBLIC));
	raw_notify(player, tprintf("@cset: Channel %s taken off the public listings."
				   ,chan));
	return;
}

void do_cemit(player, cause, key, chan, text)
dbref player, cause;
int key;
char *chan, *text;
{
	struct channel *ch;


	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	if (!(ch = select_channel(chan))) {
		raw_notify(player, tprintf("Channel %s does not exist.",
					   chan));
		return;
	}
	if ((player != ch->charge_who) && (!Comm_All(player))) {
		raw_notify(player, "Permission denied.");
		return;
	}
	if (key == CEMIT_NOHEADER)
		do_comsend(ch, text);
	else
		do_comsend(ch, tprintf("[%s] %s", chan, text));
}

void do_chopen(player, cause, key, chan, object)
dbref player, cause;
int key;
char *chan, *object;
{
	struct channel *ch;

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	switch (key) {
	case CSET_PRIVATE:
		do_chclose(player, chan);
		return;
	case CSET_LOUD:
		do_chloud(player, chan);
		return;
	case CSET_QUIET:
		do_chsquelch(player, chan);
		return;
	case CSET_LIST:
		do_chanlist(player, NOTHING, 1);
		return;
	case CSET_OBJECT:
		do_chanobj(player, chan, object);
		return;
	}

	if (!(ch = select_channel(chan))) {
		raw_notify(player, tprintf("@cset: Channel %s does not exist.", chan));
		return;
	}
	if ((player != ch->charge_who) && (!Comm_All(player))) {
		raw_notify(player, "@cset: Permission denied.");
		return;
	}
	ch->type |= (CHANNEL_PUBLIC);
	raw_notify(player, tprintf("@cset: Channel %s placed on the public listings."
				   ,chan));
	return;
}

char *do_chloud(player, chan)
dbref player;
char *chan;
{
	struct channel *ch;

	if (!(ch = select_channel(chan))) {
		raw_notify(player, tprintf("@cset: Channel %s does not exist.", chan));
		return;
	}
	if ((player != ch->charge_who) && (!Comm_All(player))) {
		raw_notify(player, "@cset: Permission denied.");
		return;
	}
	ch->type |= (CHANNEL_LOUD);
	raw_notify(player, tprintf("@cset: Channel %s now sends connect/disconnect msgs."
				   ,chan));
	return;
}

char *do_chsquelch(player, chan)
dbref player;
char *chan;
{
	struct channel *ch;

	if (!(ch = select_channel(chan))) {
		raw_notify(player, tprintf("@cset: Channel %s does not exist.", chan));
		return;
	}
	if ((player != ch->charge_who) && (!Comm_All(player))) {
		raw_notify(player, "@cset: Permission denied.");
		return;
	}
	ch->type &= ~(CHANNEL_LOUD);
	raw_notify(player, tprintf("@cset: Channel %s connect/disconnect msgs muted."
				   ,chan));
	return;
}


void do_chboot(player, cause, key, channel, victim)
dbref player, cause;
int key;
char *channel;
char *victim;
{
	struct comuser *user;
	struct channel *ch;
	struct comuser *vu;
	dbref thing;
	char buff[200];		/*

				 * 
				 * * I sure hope it's not going to be that *
				 * *  * *  * *  * * long.  
				 */

	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	if (!(ch = select_channel(channel))) {
		raw_notify(player, "@cboot: Unknown channel.");
		return;
	}
	if (!(user = select_user(ch, player))) {
		raw_notify(player, "@cboot: You are not on that channel.");
		return;
	}
	if (!(Chan_Boot(user) || (ch->charge_who == player) || Comm_All(player))) {
		raw_notify(player, "@cboot:  You can't do that!");
		return;
	}
	thing = match_thing(player, victim);

	if (thing == NOTHING) {
		raw_notify(player, "I don't see that here.");
		return;
	}
	if (!(vu = select_user(ch, thing))) {
		raw_notify(player, tprintf("@cboot: %s in not on the channel.", Name(thing)));
		return;
	}
	/*
	 * We should be in the clear now. :) 
	 */

	sprintf(buff, "[%s] %s boots %s off the channel.", ch->name, Name(player), Name(thing));
	do_comsend(ch, buff);
	do_delcomchannel(thing, channel);

}

char *do_chanobj(player, channel, object)
dbref player;
char *channel;
char *object;
{
	struct channel *ch;
	dbref thing;
	char *buff;

	init_match(player, object, NOTYPE);
	match_everything(0);
	thing = match_result();

	if (!(ch = select_channel(channel))) {
		raw_notify(player, "That channel does not exist.");
		return;
	}
	if (thing == NOTHING) {
		ch->chan_obj = NOTHING;
		raw_notify(player, "Set.");
		return;
	}
	if (!(ch->charge_who == player) && !Comm_All(player)) {
		raw_notify(player, "Permission denied.");
		return;
	}
	ch->chan_obj = thing;
	buff = unparse_object(player, thing, 0);
	raw_notify(player, tprintf("Channel %s is now using %s as channel object.",
				   ch->name, buff));
	free_lbuf(buff);
}

void do_chanlist(player, cause, key)
dbref player, cause;
int key;
{
	dbref owner;
	struct channel *ch;
	int i, flags;
	char *temp;
	char *buf;
	char *atrstr;


	if (!mudconf.have_comsys) {
		raw_notify(player, "Comsys disabled.");
		return;
	}
	flags = (int)NULL;

	if (key & CLIST_FULL) {
		do_listchannels(player);
		return;
	}
	temp = alloc_mbuf("do_chanlist_temp");
	buf = alloc_mbuf("do_chanlist_buf");

	raw_notify(player, "** Channel       Owner           Description");

	for (ch = (struct channel *)hash_firstentry(&mudstate.channel_htab);
	ch; ch = (struct channel *)hash_nextentry(&mudstate.channel_htab)) {
		if (Comm_All(player) || (ch->type & CHANNEL_PUBLIC) ||
		    ch->charge_who == player) {

			atrstr = atr_pget(ch->chan_obj, A_DESC, &owner, &flags);
			if ((ch->chan_obj == NOTHING) ||
			    !*atrstr)
				sprintf(buf, "%s", "No description.");
			else
				sprintf(buf, "%-54.54s", atrstr);

			free_lbuf(atrstr);
			sprintf(temp, "%c%c %-13.13s %-15.15s %-45.45s",
				(ch->type & (CHANNEL_PUBLIC)) ? 'P' : '-',
				(ch->type & (CHANNEL_LOUD)) ? 'L' : '-',
				ch->name, Name(ch->charge_who), buf);

			raw_notify(player, temp);
		}
	}
	free_mbuf(temp);
	free_mbuf(buf);
	raw_notify(player, "-- End of list of Channels --");
}