//
// File: channels.c (A daemon)
// Author: Inspiral@Tabor, et al
// Created: 93-05-10
// Purpose: To efficiently handle player communication.
//
// REVISON HISTORY:
// 930725 - Fixed problem with creating spurious channels! -- Inspiral
// 930801 - Added scan_config() -- Inspiral
// 930803 - Reformatted data structure to use
// more arrays than mappings -- Inspiral
// 930811 - Removed all reliances on query() and set() lfuns. -- Inspiral
// 930818 - Added log(), tell_user(), secure() -- Inspiral
// 930826 - fixed bug in del user -- Pallando
// 931004 - added emotes -- Rust
// 940322 - Rewritten to be faster, and to index users by object
// -- Inspiral
// 940911 - Added missing prototpye -- Leto
// 950408 - Fixed minor bug with adminp -- Pallando
// 950422 - Added restrictions on Intermud for guest -- Leto
#include <channels.h>
#define RESTRICTED_GUEST
int register_channel( string chan, object user, int state );
int log( string log_mesg );
mapping channels; // contains all our channel stats
mapping alias; // a rude alias mechanism
// Begin tell_user()
int tell_user( object user, string mesg ) {
tell_object( user, wrap( sprintf( "CHANNELS:\t%s\n", mesg ) ) );
return 1;
}
// End tell_user()
// Begin create_channel()
static
varargs
int create_channel( string chan ) {
if( channels[chan] ) return 1;
channels[chan] = ([ ]);
channels[chan]["vis"] = ({ });
return 1;
}
// End of create_channel()
// Begin delete_channel()
static int kill_user( object user, string chan ) {
if( undefinedp( channels[chan] ) ) return 0;
channels[chan]["vis"] -= ({ user });
return 1;
}
static varargs
int delete_channel( string chan ) {
if( undefinedp( channels[chan] ) )
return 0;
map_delete( channels, chan );
return 1;
}
// End of delete_channel()
// Beginning of add_user()
static
varargs
int add_user(string chan, object user) {
string *toggle_list;
string priv;
if( !chan || !user ) return 0;
if( !pointerp( toggle_list = ( string * ) user-> query( "channels" ) ) ) {
user-> set( "channels", ({ }) );
toggle_list = ({ });
}
// chan doesn't exist...do we have permission to create it?
if( undefinedp( channels[chan] ) ) {
#ifdef NO_NEW_CHANNELS
return 0;
#endif
create_channel( chan, user );
}
if( !undefinedp( priv = channels[chan]["priv"] ) )
if( !member_group( geteuid( user ), priv ) )
if(!adminp(user))return 0;
if( member_array( chan, toggle_list ) == - 1 )
user -> add( "channels", ({ chan }) );
channels[chan]["vis"] =
uniq_array( channels[chan]["vis"] + ({ user }) );
return 1;
}
// End of add_user()
static
int kill_users( mixed chan ) {
int i;
if( !chan ) chan = keys( channels );
else chan = ({ chan });
i = sizeof( chan );
while( i-- )
channels[chan[i]]["vis"] -= ({ 0 });
return 1;
}
// Beginning of initialize_user()
varargs int initialize_user( object whom ) {
int i, j;
object *list;
string *current_list;
if( !whom || !living( whom ) ) list = users();
else list = ({ whom }); // We have one user.
i = sizeof( list );
while( i-- ) {
current_list = ( string * ) list[i] -> query( "channels" );
if( !pointerp( current_list ) ) {
list[i]-> set( "channels", ({ }) );
current_list = ({ });
}
j = sizeof( current_list );
while( j-- )
register_channel( current_list[j], list[i], ADD );
}
return 1;
}
// End of initialize_user()
// Beginning of parse_channel()
varargs int parse_channel( string chan, string mesg, string name, int emote ) {
int i;
string *ignore;
object *list, foo_ob;
string ext_ob, err, plural;
if( alias[chan] ) chan = alias[chan];
if( undefinedp( channels[chan] ) ) return 0;
kill_users( chan );
if( undefinedp( ( list = channels[chan]["vis"] ) ) ) return 0;
i = sizeof( list ); // Optimize is.
// Channel format is wrong in the daemon..Attempt a fix, but log.
if( !pointerp( list ) ) {
channels[chan]["vis"] = ({ });
initialize_user(); // Shall we reconfigure?
return log( sprintf( "parse_channel: channel %s "
"is not a pointer! Fixing.", identify( chan ) ) );
}
// Is the name flag not given? or, is name not even in the list?
if( this_player() )
if( member_array( this_player(), list ) == - 1 ) return 0;
if( this_player() && !name )
name = (string) this_player() -> query( "cap_name" );
if( !mesg || mesg == "" )
return tell_user( this_player(), "Cannot broadcast blank messages!" );
if( undefinedp( ( plural = channels[chan]["plural"] ) ) )
plural = pluralize_verb( chan );
while( i-- ) {
if( mesg[0..5] == ":emote" ) {
mesg = mesg[7..<1];
emote = 1;
}
if( objectp( list[i] ) && list[i] != this_player() ) {
ignore = (string *) list[i] -> query( "ignore" );
if( !pointerp( ignore ) ) ignore = ({ });
if( member_array( lower_case( name ), ignore ) != -1 ) continue;
if( list[i]-> getenv( "add_newline" ) )
tell_object( list[i], "\n" );
if( emote )
message( "channels",
iwrap(capitalize(chan)+": "+name+" "+mesg), list[i]);
else
message( "channels",
iwrap( name + " " + plural + ": " + mesg ), list[i] );
continue;
}
if( list[i] == this_player() )
if( emote )
message( "channels",
iwrap(capitalize(chan)+": "+name+" "+mesg), list[i]);
else
message( "channels",
iwrap( "You " + chan + ": " + mesg ), list[i] );
} // while()
// Do we have an apply to an external object?
chan = lower_case( chan );
if( !undefinedp( ( ext_ob = channels[chan]["object"] ) ) ) {
// format of object flag: alias#object
sscanf( ext_ob, "%s#%s", chan, ext_ob );
#ifdef RESTRICTED_GUEST
if (this_player() && getuid(this_player()) == "guest") {
notify_fail("Due to abuse, guest isn't allowed on the Intermud.\n");
return 0;
}
#endif RESTRICTED_GUEST
// Attempt the apply, log all errors
foo_ob = find_object_or_load(ext_ob);
if( err = catch( foo_ob->
daemon_apply( this_player(), chan, mesg, emote ) ) )
log( sprintf( "parse_channel:\tError in %s:\n%s",
ext_ob, err ) );
}
return 1;
}
// End of parse_channel()
// Begin of display_channel()
varargs mixed display_channel( string chan, object viewer ) {
mixed list;
if( !chan || chan == "" ) list = keys( channels );
else {
if( undefinedp( list = channels[chan] ) )
return sprintf( "There is no such channel: %s.",
identify( chan ) );
list = channels[chan]["vis"];
}
if( !pointerp( list ) || !sizeof( list ) ) {
channels[chan]["vis"] = ({ });
return sprintf( "CHANNELS:\tNo Users Subscribed to %s",
identify( chan ) );
}
if( chan && chan != "" )
list = filter_array( list, "flush_list", this_object(), viewer );
list = map_array( list, "get_cap", this_object() );
list = ( implode( list, " " ) + " <End>" );
return list;
}
// End of display_channel()
// Begin scan_config()
static
int scan_config() {
string *list, *split_line;
string line;
int i, j;
list = update_file( CHANNELS_CONFIG );
i = sizeof( list );
// Once through the i for each non-"#" line in config file
while( i-- ) {
line = list[i];
if( line ) {
split_line = explode( line, ":" );
j = sizeof( split_line );
channels[split_line[0]] = allocate_mapping( 6 );
channels[split_line[0]]["vis"] = ({ });
while( j-- ) {
if( ( split_line[j] != "X" ) &&
( CHANNELS_INFO[j] != "" ) )
channels[split_line[0]][CHANNELS_INFO[j]] =
split_line[j];
} // while (j)
} // IF (LINE)
} // while (i)
return 1;
}
// Begin log()
int log( string log_mesg ) {
if( !log_mesg || log_mesg == "" ) return 0; ;
log_file( CHANNELS_LOG, sprintf( "%s %O - %s\n",
intl_date_stamp( 1 ), previous_object(), log_mesg ) );
return 0;
}
// End of log()
mixed q() { return copy( channels ); }
mixed a() { return copy( alias ); }
// Begin process_alias()
void process_alias() {
int i;
string *list;
string temp1;
list = keys( channels );
i = sizeof( list );
while( i-- ) {
if( !undefinedp( temp1 = channels[list[i]]["object"] ) )
if( sscanf( temp1, "%s#%*s", temp1 ) == 2 )
alias += ([ temp1 : list[i] ]);
}
}
// Begin get_cap()
string get_cap( object ob ) {
return (string) ob -> query( "cap_name" );
}
// End get_cap()
// Begin flush_list()
int flush_list( object user, object viewer ) {
return (objectp(user) && visible(user, viewer) && interactive(user));
}
// end flush_list()
// Begin create()
void create() {
channels = allocate_mapping( 20 );
alias = allocate_mapping( 20 );
seteuid( getuid() );
scan_config();
process_alias();
call_out( "initialize_user", 2 );
}
// End of create()
// Begin register_channel()
varargs
int register_channel( string chan, object user, int state) {
int ret;
if( nullp( state ) ) {
notify_fail( "register_channel: no state given!" );
return 0;
}
switch( state ) {
case DEL: ret = delete_channel( chan, user ); break;
case CRE: ret = create_channel( chan, user, state ); break;
case ADD: ret = add_user( chan, user ); break;
case KIL: ret = kill_user( user, chan );
break;
default: ret = 0; break;
}
return ret;
}
// End of register_channel()