melville/
melville/cmds/
melville/cmds/admin/
melville/data/
melville/data/mail/
melville/data/player/
melville/data/system/
melville/data/user/
melville/doc/functions/
melville/doc/help/
melville/inherit/
melville/log/
melville/obj/
melville/system/auto/
melville/system/player/
melville/system/user/
melville/users/
melville/users/mobydick/
melville/world/
/* channel_d.c
   A very simple channel daemon. The implementation is this: the
   command /cmds/[player|wizard|admin]/[name] sends a message to
   the daemon requesting that the message it passes be sent to all
   tuned-in users. The tune command makes calls in to maintain the
   list of tuned-in users, and the show command displays it. The
   disadvantage of this method is that you have to have one command
   for each channel you want to implement. The alternative is to
   have the command processing try to implement any input it does
   not recognize as a channel; this is more elegant in some ways
   but makes the code rather harder to follow. I've chosen to do
   it with the one-command-per-channel method to keep it simple. The
   advantage to this system is that it doesn't need to maintain
   security over each channel; the security on command access
   (which already exists) does that. It's also the most natural
   way to code it IMHO.
   Mobydick, 6-2-98
*/

#include <config.h>
#include <options.h>


/* This mapping keeps track of each channel and who's listening.
   I put the user ob in, rather than the player ob, so that you
   can switch bodies and not lose your channel settings. Also
   if you go linkdead you will drop out naturally. You could
   do it the other way if you wanted to, though.
*/

mapping channel_users ;

/* Return codes for add_user_to_channel and remove_user_from_channel:
    0 : no such channel
   -1 : not a user object
   -2 : already tuned in/not tuned in
    1 : success
*/

int add_user_to_channel (object user, string channel) {
    if (member_array(channel, CHANNELS)==-1) return 0 ;
/* Users only! */
    if (base_name(user)!=USER) return -1 ;
/* Are you already listening? */
    if (member_array(user,channel_users[channel])!=-1) return -2 ;
/* OK, add it. */
    channel_users[channel] += ({ user }) ;
    return 1 ;
}

int remove_user_from_channel (object user, string channel) {
    if (member_array(channel, CHANNELS)==-1) return 0 ;
    if (base_name(user)!=USER) return -1 ;
    if (member_array(user,channel_users[channel])==-1) return -2 ;
    channel_users[channel] -= ({ user }) ;
    return 1 ;
}

/* This is invoked by the player object to get someone out of all
   channels when they quit. */

int remove_user_from_all (object user) {

    int i ;

    if (base_name(user)!=USER) return -1 ;
    for (i=0;i<sizeof(CHANNELS);i++) {
	channel_users[CHANNELS[i]] -= ({ user }) ;
    }
    return 1 ;
}

object *listening_to_channel (string channel) {
    if (member_array(channel, CHANNELS)==-1) return ({ }) ;
    return channel_users[channel] ;
}

/* Return codes for user_listening_to_channel:
    0: not listening
    1: listening
   -1: no such channel
*/

int user_listening_to_channel (object user, string channel) {
    if (member_array(channel, CHANNELS)==-1) return 0 ;
    if (member_array(user,channel_users[channel])==-1) return 0 ;
    return 1 ;
}

/* Return codes for send_channel message:
    0: you're not tuned in
   -1: no such channel
    1: success
*/

int send_channel_message (object user, string channel, string message) {

    int i ;

    if (member_array(channel, CHANNELS)==-1) return -1 ;
    if (member_array(user,channel_users[channel])==-1) return -2 ;
    for (i=0;i<sizeof(channel_users[channel]);i++) {
/* Might be 0 somehow if a user is gone and not removed from the list. */
       if (!channel_users[channel][i]) continue ;
/* Don't send to yourself */
       if (channel_users[channel][i]==user) continue ;
       channel_users[channel][i]->catch_tell("["+channel+"] "+
	    capitalize(user->query_name())+": "+message+"\n") ;
    }
    write ("You "+channel+": "+message+"\n") ;
    return 1 ;
}

void create() {

    int i ;

    channel_users = ([ ]) ;
    for (i=0;i<NUM_CHANNELS;i++) {
	channel_users[CHANNELS[i]]=({ }) ;
    }
    return ;
}

/* When the object is removed, tune everyone out. */

int destruct() {

    int i, j ;

    for (i=0;i<sizeof(CHANNELS);i++) {
	for (j=0;j<sizeof(channel_users[CHANNELS[i]]);j++) {
	    channel_users[CHANNELS[i]][j]->catch_tell(
		"Tuning you out of "+CHANNELS[i]+" channel!\n") ;
	}
    }
    return ::destruct() ;
}