btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * comsys.c 
 */

/*
 * $Id: comsys.c,v 1.6 2005/08/08 09:43:05 murrayma Exp $ 
 */

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

#include "copyright.h"
#include "config.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"
#include "p.comsys.h"
#include "p.functions.h"
#include "create.h"

/* Static functions */
static void do_save_com(chmsg *);
static void do_show_com(chmsg *);
static void do_comlast(dbref, struct channel *);
static void do_comsend(struct channel *, char *);
static void do_joinchannel(dbref, struct channel *);
static void do_leavechannel(dbref, struct channel *);
static void do_comwho(dbref, struct channel *);
static void do_setnewtitle(dbref, struct channel *, char *);
static void sort_users(struct channel *);
static int do_test_access(dbref, long, struct channel *);

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

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

void send_channel(char *chan, const char *format, ...) {
    struct channel *ch;
    char buf[LBUF_SIZE];
    char data[LBUF_SIZE];
    char *newline;
    va_list ap;

    if (!(ch = select_channel(chan)))
        return;
    va_start(ap, format);
    vsnprintf(data, LBUF_SIZE, format, ap);
    va_end(ap);
    
    snprintf(buf, LBUF_SIZE, "[%s] %s", chan, data);
    while ((newline = strchr(buf, '\n')))
        *newline = ' ';
    do_comsend(ch, buf);
}

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

    c = get_commac(player);

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

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

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

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

    num_channels = 0;


    fgets(buf, sizeof(buf), fp);
    if (!strncmp(buf, "+V2", 3)) {
        new = 2;
        fscanf(fp, "%d\n", &nc);
    } else 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);

        strncpy(ch->name, temp, CHAN_NAME_LEN);
        ch->name[CHAN_NAME_LEN-1] = '\0';
        ch->on_users = NULL;

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

#ifdef CHANNEL_HISTORY
        ch->last_messages = NULL;
#endif

        if (new) {		/* V1 or higher */

            if (fscanf(fp,
                        new ==
                        1 ? "%d %d %d %d %d %d %d %d\n" :
                        "%d %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), &dummy) >= 9 &&
                    new > 1) {
                /* Do things with 'dummy' */
                if (dummy > 0) {
                    for (j = 0; j < dummy; j++) {
#ifdef CHANNEL_HISTORY
                        chmsg *c;
#endif

                        fscanf(fp, "%d %[^\n]\n", &k, temp);
#ifdef CHANNEL_HISTORY
                        Create(c, chmsg, 1);
                        c->msg = strdup(temp);
                        c->time = k;
                        myfifo_push(&ch->last_messages, c);
#endif
                    }
                }
            }
        } 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);

                user->title = strdup(temp + 2);

                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;
    }
}

static FILE *temp_file;

static void do_save_com(chmsg * d) {
    fprintf(temp_file, "%d %s\n", (int) d->time, d->msg);
}


void save_comsystem(FILE * fp) {
    struct channel *ch;
    struct comuser *user;
    int j, k, player_users;

    fprintf(fp, "+V2\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);
        k = myfifo_length(&ch->last_messages);
        /*            1  2  3  4  5  6  7  8  9 */
        fprintf(fp, "%d %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, k);

        if (k) {
            temp_file = fp;
            myfifo_trav_r(&ch->last_messages, do_save_com);
        }
        player_users = 0;
        for (j = 0; j < ch->num_users; j++)
            if (isPlayer(ch->users[j]->who) || isRobot(ch->users[j]->who))
                player_users++;

        fprintf(fp, "%d\n", player_users);
        for (j = 0; j < ch->num_users; j++) {
            user = ch->users[j];
            if (!isPlayer(user->who) && !isRobot(user->who))
                continue;
            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");
        }
    }
}

static dbref cheat_player;

static void do_show_com(chmsg * d) {
    struct tm *t;
    int day;
    char buf[LBUF_SIZE];

    t = localtime(&mudstate.now);
    day = t->tm_mday;
    t = localtime(&d->time);
    if (day == t->tm_mday) {
        sprintf(buf, "[%02d:%02d] %s", t->tm_hour, t->tm_min, d->msg);
    } else
        sprintf(buf, "[%02d.%02d / %02d:%02d] %s", t->tm_mon + 1,
                t->tm_mday, t->tm_hour, t->tm_min, d->msg);
    notify(cheat_player, buf);
}

static void do_comlast(dbref player, struct channel *ch) {
#ifdef CHANNEL_HISTORY
    if (!myfifo_length(&ch->last_messages)) {
        notify_printf(player, "There haven't been any messages on %s.",
                    ch->name);
        return;
    }
    cheat_player = player;
    myfifo_trav_r(&ch->last_messages, do_show_com);
#endif
}

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

    if ((strlen(arg1) + strlen(arg2)) > LBUF_SIZE / 2) {
        arg2[LBUF_SIZE / 2 - strlen(arg1)] = '\0';
    }
    if (!*arg2) {
        raw_notify(player, "No message.");
        return;
    }

    if (!Wizard(player) && In_IC_Loc(player)) {
        raw_notify(player, "Permission denied.");
        return;
    }

    if (!(ch = select_channel(arg1))) {
        notify_printf(player, "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 re-add.");
        return;
    }
    if (!strcasecmp(arg2, "on")) {
        do_joinchannel(player, ch);
    } else if (!strcasecmp(arg2, "off")) {
        do_leavechannel(player, ch);
    } else if (!user->on && !Wizard(player) && !mudconf.allow_chanlurking) {
        notify_printf(player, "You must be on %s to do that.", arg1);
        return;
    } else if (!strcasecmp(arg2, "who")) {
        do_comwho(player, ch);
    } else if (!strcasecmp(arg2, "last")) {
        do_comlast(player, ch);
    } else if (!user->on) {
        notify_printf(player, "You must be on %s to do that.", arg1);
        return;
    } 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_printf(player, "You don't have enough %s.", mudconf.many_coins);
            return;
        } else {
            ch->amount_col += ch->charge;
            giveto(ch->charge_who, ch->charge);
        }

        if ((*arg2) == ':')
            snprintf(mess, LBUF_SIZE, "[%s] %s %s", arg1, Name(player),
                    arg2 + 1);
        else if ((*arg2) == ';')
            snprintf(mess, LBUF_SIZE, "[%s] %s%s", arg1, Name(player),
                    arg2 + 1);
        else if (strlen(user->title))
            snprintf(mess, LBUF_SIZE, "[%s] %s: <%s> %s", arg1,
                    Name(player), user->title, arg2);
        else
            snprintf(mess, LBUF_SIZE, "[%s] %s: %s", arg1, Name(player),
                    arg2);
        do_comsend(ch, mess);
    }
}

static void do_comsend(struct channel *ch, char *mess) {
    struct comuser *user;
    chmsg *c;

    ch->num_messages++;
    for (user = ch->on_users; user; user = user->on_next) {
        if (user->on && do_test_access(user->who, CHANNEL_RECIEVE, ch) &&
                (Wizard(user->who) || !In_IC_Loc(user->who))) {
            if (Typeof(user->who) == TYPE_PLAYER && Connected(user->who))
                raw_notify(user->who, mess);
            else
                notify(user->who, mess);
        }
    }
    /* Also, add it to the history of channel */
#ifdef CHANNEL_HISTORY
    if (myfifo_length(&ch->last_messages) >= CHANNEL_HISTORY_LEN) {
        c = myfifo_pop(&ch->last_messages);
        free((void *) c->msg);
    } else
        Create(c, chmsg, 1);
    c->msg = strdup(mess);
    c->time = mudstate.now;
    myfifo_push(&ch->last_messages, c);
#endif
}

static void do_joinchannel(dbref player, struct channel *ch) {
    struct comuser *user;
    int i;

    user = select_user(ch, player);

    if (!user) {
        ch->num_users++;
        if (ch->num_users >= ch->max_users) {
            ch->max_users += 10;
            ch->users = realloc(ch->users, sizeof(struct comuser *) *
                    ch->max_users);
        }
        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 = strdup("");

        if UNDEAD(player) {
            user->on_next = ch->on_users;
            ch->on_users = user;
        }
    } else if (!user->on) {
        user->on = 1;
    } else {
        notify_printf(player, "You are already on channel %s.",
                    ch->name);
        return;
    }

    if (!Dark(player)) {
        do_comsend(ch, tprintf("[%s] %s has joined this channel.",
                    ch->name, Name(player)));
    }
}

static void do_leavechannel(dbref player, struct channel *ch) {
    struct comuser *user;

    user = select_user(ch, player);

    if (!user)
        return;

    notify_printf(player, "You have left channel %s.", ch->name);

    if ((user->on) && (!Dark(player))) {
        char *c = Name(player);

        if (c && *c) {
            do_comsend(ch, tprintf("[%s] %s has left this channel.",
                        ch->name, c));
        }
    }
    user->on = 0;
}

static void do_comwho(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 && user->on &&
                Connected(user->who) && (!Hidden(user->who) ||
                    ((ch->type & CHANNEL_TRANSPARENT) && !Dark(user->who)) ||
                    Wizard_Who(player))
                && (!In_IC_Loc(user->who) || Wizard(user->who))) {

            int i = fetch_idle(user->who);

            buff = unparse_object(player, user->who, 0);
            if (i > 30) {
                char *c = get_uptime_to_string(i);

                notify_printf(player, "%s [idle %s]", buff, c);
                free_sbuf(c);
            } else
                notify_printf(player, "%s", buff);
            free_lbuf(buff);
        }
    }

    raw_notify(player, "-- Objects --");
    for (user = ch->on_users; user; user = user->on_next) {
        if (Typeof(user->who) != TYPE_PLAYER && user->on &&
                !(Going(user->who) && God(Owner(user->who)))) {
            buff = unparse_object(player, user->who, 0);
            notify_printf(player, "%s", buff);
            free_lbuf(buff);
        }
    }
    notify_printf(player, "-- %s --", ch->name);
}

struct channel *select_channel(char *channel) {
    return (struct channel *) hashfind(channel, &mudstate.channel_htab);
}

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

    if (!ch)
        return NULL;

    last = ch->num_users - 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(dbref player, dbref cause, int key, char *arg1, char *arg2) {
    char channel[200];
    char title[100];
    struct channel *ch;
    char *s;
    int where;
    struct commac *c;

    if (!mudconf.have_comsys) {
        raw_notify(player, "Comsys disabled.");
        return;
    }
    if (!*arg1) {
        raw_notify(player, "You need to specify an alias.");
        return;
    }
    if (!*arg2) {
        raw_notify(player, "You need to specify a channel.");
        return;
    }

    s = strchr(arg2, ',');

    if (s) {
        /* channelname,title */
        if (s >= arg2 + 200) {
            raw_notify(player, "Channel name too long.");
            return;
        }
        strncpy(channel, arg2, s - arg2);
        channel[s - arg2] = '\0';
        strncpy(title, s + 1, 100);
        title[99] = '\0';
    } else {
        /* just channelname */
        if (strlen(arg2) >= 200) {
            raw_notify(player, "Channel name too long.");
            return;
        }
        strcpy(channel, arg2);
        title[0] = '\0';
    }

    if (strchr(channel, ' ')) {
        raw_notify(player, "Channel name cannot contain spaces.");
        return;
    }

    if (!(ch = select_channel(channel))) {
        notify_printf(player, "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,
                "Warning: you are already listed on that channel.");
    }
    c = get_commac(player);
    for (where = 0; where < c->numchannels &&
            (strcasecmp(arg1, c->alias + where * 6) > 0); where++);
    if (where < c->numchannels && !strcasecmp(arg1, c->alias + where * 6)) {
        notify_printf(player, "That alias is already in use for channel %s.",
                    c->channels[where]);
        return;
    }
    if (c->numchannels >= c->maxchannels) {
        c->maxchannels += 10;
        c->alias = realloc(c->alias, sizeof(char) * 6 * c->maxchannels);
        c->channels =
            realloc(c->channels, sizeof(char *) * c->maxchannels);
    }
    if (where < c->numchannels) {
        memmove(c->alias + 6 * (where + 1), c->alias + 6 * where,
                6 * (c->numchannels - where));
        memmove(c->channels + where + 1, c->channels + where,
                sizeof(c->channels) * (c->numchannels - where));
    }

    c->numchannels++;

    strncpy(c->alias + 6 * where, arg1, 5);
    c->alias[where * 6 + 5] = '\0';
    c->channels[where] = strdup(channel);

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

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

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

    user = select_user(ch, player);

    /* Make sure there can be no embedded newlines from %r */

    if (!ch || !user)
        return;

    new = replace_string("\r\n", "", title);
    if (user->title)
        free(user->title);
    user->title = strdup(new);   /* strdup so we can free() safely */
    free_lbuf(new);
}

void do_delcom(dbref player, dbref 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 (!strcasecmp(arg1, c->alias + i * 6)) {
            do_delcomchannel(player, c->channels[i]);
            notify_printf(player, "Channel %s deleted.",
                        c->channels[i]);
            free(c->channels[i]);

            c->numchannels--;
            if (i < c->numchannels) {
                memmove(c->alias + 6 * i, c->alias + 6 * (i + 1),
                        6 * (c->numchannels - i));
                memmove(c->channels + i, c->channels + i + 1,
                        sizeof(c->channels) * (c->numchannels - i));
            }
            return;
        }
    }
    raw_notify(player, "Unable to find that alias.");
}

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

    if (!(ch = select_channel(channel))) {
        notify_printf(player, "Unknown channel %s.", channel);
    } else {
        for (i = 0; i < ch->num_users; i++) {
            user = ch->users[i];
            if (user->who == player) {
                do_comdisconnectchannel(player, channel);
                if (user->on && !Dark(player)) {
                    char *c = Name(player);

                    if (c && *c)
                        do_comsend(ch,
                                tprintf("[%s] %s has left this channel.",
                                    channel, c));
                }
                notify_printf(player, "You have left channel %s.", channel);

                if (user->title)
                    free(user->title);
                free(user);
                ch->num_users--;
                if (i < ch->num_users)
                    memmove(ch->users + i, ch->users + i + 1,
                            sizeof(ch->users) * (ch->num_users - i));
            }
        }
    }
}

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

    if (!mudconf.have_comsys) {
        raw_notify(player, "Comsys disabled.");
        return;
    }
    if (select_channel(channel)) {
        notify_printf(player, "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));

    strncpy(newchannel->name, channel, CHAN_NAME_LEN - 1);
    newchannel->name[CHAN_NAME_LEN - 1] = '\0';
#ifdef CHANNEL_HISTORY
    newchannel->last_messages = NULL;
#endif
    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);

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

void do_destroychannel(dbref player, dbref 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) {
        notify_printf(player, "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);
    notify_printf(player, "Channel %s destroyed.", channel);
}

void do_listchannels(dbref player) {
    struct channel *ch;
    int 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) {

            notify_printf(player,
                    "%c%c %-20.20s %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, "-- End of list of Channels --");
}

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

    if (!mudconf.have_comsys) {
        raw_notify(player, "Comsys disabled.");
        return;
    }
    if (!*arg1) {
        raw_notify(player, "Need an alias to do comtitle.");
        return;
    }
    strncpy(channel, get_channel_from_alias(player, arg1), 100);
    channel[99] = '\0';

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

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

    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))) {
            notify_printf(player, "%-9.9s %-19.19s %-39.39s %s",
                        c->alias + i * 6, c->channels[i],
                        user->title, (user->on ? "on" : "off"));
        } else {
            notify_printf(player, "Bad Comsys Alias: %s for Channel: %s",
                        c->alias + i * 6, c->channels[i]);
        }
    }
    raw_notify(player, "-- End of comlist --");
}

void do_channelnuke(dbref player) {
    struct channel *ch;
    int 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(dbref player, dbref 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(dbref player, dbref cause, int key, char *arg1) {
    int i;
    struct commac *c;

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

    if ((strcasecmp(arg1, "who") != 0) && (strcasecmp(arg1, "on") != 0) &&
            (strcasecmp(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 (strcasecmp(arg1, "who") == 0)
            raw_notify(player, "");
    }

}

static void sort_users(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(dbref player, dbref cause, int key, char *arg1) {
    struct channel *ch;
    struct comuser *user;
    char channel[100];
    int flag = 0;
    char *cp;
    int i;
    char ansibuffer[LBUF_SIZE];
    char outputbuffer[LBUF_SIZE];

    if (!mudconf.have_comsys) {
        raw_notify(player, "Comsys disabled.");
        return;
    }
    cp = strchr(arg1, '/');
    if (!cp) {
        strncpy(channel, arg1, 100);
        channel[99] = '\0';
    } else {
        /* channelname/all */
        if (cp - arg1 >= 100) {
            raw_notify(player, "Channel name too long.");
            return;
        }
        strncpy(channel, arg1, cp - arg1);
        channel[cp - arg1] = '\0';
        if (*++cp == 'a')
            flag = 1;
    }

    if (!(ch = select_channel(channel))) {
        notify_printf(player, "Unknown channel \"%s\".", channel);
        return;
    }
    if (!((Comm_All(player)) || (player == ch->charge_who))) {
        raw_notify(player, "You do not have permission to do that.");
        return;
    }
    notify_printf(player, "-- %s --", ch->name);
    notify_printf(player, "%-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)) && (!Hidden(user->who) ||
                    ((ch->type & CHANNEL_TRANSPARENT) && !Dark(user->who)) ||
                    Wizard_Who(player))) {
            cp = unparse_object(player, user->who, 0);
            strip_ansi_r(ansibuffer, cp, LBUF_SIZE);
            notify_printf(player, "%-29.29s %-6.6s %-6.6s", ansibuffer,
                        ((user->on) ? "on " : "off"),
                        (Typeof(user->who) == TYPE_PLAYER) ? "yes" : "no ");
            free_lbuf(cp);
        }
    }
    notify_printf(player, "-- %s --", ch->name);
}

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

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

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

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

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

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

void do_comconnectchannel(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
                notify_printf(player,"Bad Comsys Alias: %s for Channel: %s",
                            alias + i * 6, channel);
        }
    } else
        notify_printf(player, "Bad Comsys Alias: %s for Channel: %s",
                    alias + i * 6, channel);
}

void do_comdisconnect(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
    }
    send_channel("MUXConnections", tprintf("* %s has disconnected *",
                Name(player)));
}

void do_comconnect(dbref player, DESC * d) {
    struct commac *c;
    int i;
    char *lsite;

    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]);
    }
    lsite = d->addr;
    if (lsite && *lsite)
        send_channel("MUXConnections",
                tprintf("* %s has connected from %s *", Name(player), lsite));
    else
        send_channel("MUXConnections",
                tprintf("* %s has connected from somewhere *", Name(player)));
}


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

    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(dbref player, dbref 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))) {
        notify_printf(player, "Unknown channel %s.", arg1);
        return;
    }
    if (!((Comm_All(player)) || (player == ch->charge_who))) {
        raw_notify(player, "Permission denied.");
        return;
    }
    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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(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 (strcasecmp(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;
}

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

    if (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(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++)
        /* nothing */ ;

    *s = '\0';

    if (*t)
        t++;

    ch = get_channel_from_alias(who, alias);
    if (ch && *ch) {
        do_processcom(who, ch, t);
        free_lbuf(alias);
        return 0;
    }
    free_lbuf(alias);
    return 1;

}

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

    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@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));
    notify_printf(player,
            "@cset: Channel %s taken off the public listings.", chan);
    return;
}

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


    if (!mudconf.have_comsys) {
        raw_notify(player, "Comsys disabled.");
        return;
    }
    if (!(ch = select_channel(chan))) {
        notify_printf(player, "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(dbref player, dbref cause, int key, char *chan, char *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;
        case CSET_STATUS:
            do_chanstatus(player, NOTHING, 1, chan);
            return;
        case CSET_TRANSPARENT:
            do_chtransparent(player, chan);
            return;
        case CSET_OPAQUE:
            do_chopaque(player, chan);
            return;
    }

    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@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);
    notify_printf(player, "@cset: Channel %s placed on the public listings.", 
            chan);
    return;
}

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

    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@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);
    notify_printf(player,
            "@cset: Channel %s now sends connect/disconnect msgs.",
                chan);
    return;
}

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

    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@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);
    notify_printf(player,
            "@cset: Channel %s connect/disconnect msgs muted.", chan);
    return;
}

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

    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@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_TRANSPARENT;
    notify_printf(player,
            "@cset: Channel %s now shows all listeners to everyone.",
                chan);
    return;
}

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

    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@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_TRANSPARENT;
    notify_printf(player,
            "@cset: Channel %s now does not show all listeners to everyone.",
                chan);
    return;
}

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

    /*
     * * 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 (!((ch->charge_who == player) || Comm_All(player))) {
        raw_notify(player, "Permission denied.");
        return;
    }
    thing = match_thing(player, victim);

    if (thing == NOTHING) {
        return;
    }
    if (!(vu = select_user(ch, thing))) {
        notify_printf(player, "@cboot: %s in not on the channel.",
                    Name(thing));
        return;
    }
    /*
     * We should be in the clear now. :) 
     */

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

}

void do_chanobj(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);
    notify_printf(player,
            "Channel %s is now using %s as channel object.", ch->name,
                buff);
    free_lbuf(buff);
}

void do_chanlist(dbref player, dbref cause, int key) {
    dbref owner;
    struct channel *ch;
    int 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 --");
}

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


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

    if (key & CSTATUS_FULL) {
        struct channel *ch;
        int 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");

        if (!(ch = select_channel(chan))) {
            notify_printf(player,
                    "@cstatus: Channel %s does not exist.", chan);
            return;
        }
        if (perm || (ch->type & CHANNEL_PUBLIC) ||
                ch->charge_who == player) {

            notify_printf(player, "%c%c %-20.20s %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, "-- End of list of Channels --");
        return;
    }
    temp = alloc_mbuf("do_chanstatus_temp");
    buf = alloc_mbuf("do_chanstatus_buf");

    raw_notify(player, "** Channel       Owner           Description");
    if (!(ch = select_channel(chan))) {
        notify_printf(player, "@cstatus: Channel %s does not exist.",
                    chan);
        return;
    }
    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);
        snprintf(temp, MBUF_SIZE,  "%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 --");
}

void fun_cemit(char *buff, char **bufc, dbref player, dbref cause, char *fargs[], char *nfargs[], int cargs, int ncargs) {
    struct channel *ch;
    static char smbuf[LBUF_SIZE];

    if (!(ch = select_channel(fargs[0]))) {
        safe_str("#-1 CHANNEL NOT FOUND", buff, bufc);
        return;
    }

    if (!mudconf.have_comsys || (!Comm_All(player) && (player != ch->charge_who))) {
        safe_str("#-1 NO PERMISSION TO USE", buff, bufc);
        return;
    }

    snprintf(smbuf, LBUF_SIZE-1, "[%s] %s", fargs[0], fargs[1]);
    do_comsend(ch, smbuf);
    *buff = '\0';
}