/*
// File : /cmds/std/_who.c
// Comment : A command to let users know who else is on this mud
// It has the option to see who is on other muds
// There was a "who" command in MUD1, but the code for
// this one was written from scratch for TMI and is part
// of the TMI-2 distribution mudlib. If you use any of
// this code, please keep this header.
// 91-**-** : Jubal @ TMI wrote it
// 92-01-02 : Sulam @ TMI changed the title stuff
// 92-01-20 : DocZ @ TMI modified it for time zones
// 92-02-15 : Truilkan @ TMI modified it for players (removed wizard only info)
// Original TMI _who is now _people
// 92-10-10 : Mobydick modified it to respect invisibility
// 93-02-22 : Pallando changed [0] to <login> on aesthetic grounds
// 93-03-22 : Watcher removed user inhabited monsters from the display
// 93-04-14 : Watcher change the query("invisible") to a visible() check
// 93-07-13 : Grendel added sorting alphabetically
// 93-07-26 : Grendel added -d option, optimised
// 93-08-18 : Grendel added @mud option, optimised
// 94-06-06 : Leto split do_who() off from cmd_who() for the use of http.c
// 94-06-12 : Pallando fixed a few bugs
// 94-06-14 : Leto added the checks for this_player for the http.c
// 94-09-04 : Beek added some code for % ^FOO% ^ support
// XX-OO-XX : Drizzt@Tmi-2 added support for I3 rwho requests
// Bugs: wont detect netdead wizards in monster bodies (!)
// Don't know whether to get round this by checking for connection
// objects or not - haven't looked at connection objects
// closely yet to figure out if it is safe
// Could be optimised some more...
*/
#include <writef.h>
#include <mudlib.h>
#include <net/daemons.h>
#include <net/macros.h>
#include <net/ftpd.h>
#define SYNTAX "Usage: who [ @<mud> | -d | -f ]\n"
inherit "/adm/daemons/timezone";
inherit DAEMON;
string do_who( string args );
string divide;
create()
{
int i;
::create();
for( divide = "", i = 0; i < 78; i++ )
divide += "_";
divide += "\n";
}
// sort array doesn't allow the optional argument the way filter array
// does, so we have to make it global
// This mapping is used so we don't have to do player->query("name")
// several zillion times in the sort function
mapping names;
int cmd_who( string arg )
{
write( do_who( arg ) );
return 1;
}
string ansi_kludge(string f1, string f2) {
// Remember % ^FOO% ^ takes up no space
string *tmp = explode(f1, "%^");
int i,n;
n = (sizeof(tmp)+1)/2;
for (i=0; i<n; i++) tmp[i] = tmp[2*i];
tmp = tmp[0..n-1];
n = strlen(implode(tmp,""));
return sprintf("%s%"+(65-n)+"s %4s\n", f1, "", f2);
}
string do_who( string arg )
{
mixed *list;
string lines, zone_name, str;
int i, time_zone;
int dead;
string mud;
names = ([]);
// check args
if( arg && arg != "" )
{
// linkdead option
if( arg == "-d" )
{
this_player()-> block_attack( 2 );
list = filter_array( children( USER ), "deadp", this_object() );
list = filter_array( list, "filter_users", this_object() );
if( !sizeof( list ) )
return sprintf(
"%sThere are no linkdead users at this time\n%s",
divide, divide );
list = sort_array( list, "sort_users", this_object() );
write( divide + " Linkdead users\n" + divide );
i = sizeof( list );
while( i-- )
write( capitalize( geteuid( list[i] ) ) + "\n" );
write( divide );
return "";
} else
if( arg == "-f" )
{
this_player()-> block_attack( 2 );
if (find_object(FTP_D) &&
catch( list = (mapping *)FTP_D->query_connections() ) )
return "";
if( !sizeof( list ) )
{
write( divide + "There are no FTP users at this time.\n"
+ divide );
return "";
}
list = sort_array( list, "sort_users_in_mapping",
this_object() );
write( divide + " FTP users\n" + divide );
i = sizeof( list );
if( adminp(geteuid( previous_object() )) )
while( i-- )
{
write( sprintf( "%-16s %s\n", ( list[i][USER_NAME] ),
( list[i][USER_SITE] ) ) );
}
else
while( i-- )
{
write( ( list[i][USER_NAME] ) + "\n" );
}
write( divide );
return "";
// rwho option
} else if( sscanf( arg, "@%s", mud ) == 1 ) {
return "/adm/daemons/network/I3/who"->send_who_req(mud, this_player()->query("name"));
} else {
// bad option
notify_fail( SYNTAX );
return "";
}
}
if( this_player() ) this_player()-> block_attack( 2 );
lines = divide;
list = filter_array( users(), "filter_users", this_object() );
list = sort_array( list, "sort_users", this_object() );
if( !sizeof( list ) )
{
return( divide +
"\tLooks like no one is logged on. Strange beans, huh?\n" + divide );
}
if( sizeof( list ) > 1 )
lines += "\t\t There are " + sizeof( list ) +
" users connected.\n";
else // (Buddha claims this message ;-)
lines += "\t\tHow lonely! You're the only one here.\n";
if( this_player() )
zone_name = (string)this_player()-> getenv( "TZONE" );
else
zone_name = "GMT";
if( !time_zone = query_tzone( zone_name ) )
{
lines += "\t\tMud time is " + ctime( time() ) + "\n" +
"\t\t[Those contained in brackets are editing.]\n";
} else {
lines += "\t\t" + zone_name + " time is " + ctime( time_zone ) + "\n";
}
lines += divide +
"Name Idle\n"
+ divide;
i = sizeof( list );
while( i-- )
{
string field1, field2;
mixed val;
if( !list[i] ) continue;
if( (int)list[i]-> query( "npc" ) )
field1 = "(" + capitalize( (string)list[i]-> link_data( "name" ) ) +
" is inhabiting " +
(string)list[i]-> query( "short" ) + ")";
else field1 = (string)list[i]-> query( "short" );
if( in_edit( list[i] ) || in_input( list[i] ) )
field1 = "[" + field1 + "]";
if( !field1 ) field1 = "(null)";
if( field1 == "[0]" ) field1 = "<login>";
val = query_idle( list[i] );
if( val >= 3600 )
field2 = val/3600 + "h";
else if( val >= 60 )
field2 = val/60 + "m";
else field2 = "";
// lines += writef(field1,65,QUIET|TRUNC_RIGHT) + " "+
// writef(field2,4,QUIET|JFY_RIGHT) + "\n";
// lines += sprintf( "%-:65s %4s\n", field1, field2 );
lines += ansi_kludge( field1, field2 );
}
lines += divide;
return( lines );
}
// note this returns the list in REVERSE order - this is a speed
// optimisation, instead of doing for(i=0;i<sizeof(foo);i++)
// we can do i=sizeof(foo); while(i--)
int sort_users( object u1, object u2 )
{
// use the names mapping for speed
return strcmp( names[u2], names[u1] );
}
int sort_users_in_mapping( mapping u1, mapping u2 )
{
return strcmp( u1[USER_NAME], u2[USER_NAME] );
}
int filter_users( object who )
{
if( (int)who-> query( "npc" ) && !wizardp( this_player() ) ) return 0;
if( !who-> query( "name" ) ) return 0;
if( visible( who, this_player() ) )
{
// build up the names mapping
names[who] = (string)who-> query( "name" );
return 1;
}
return 0;
}
// used by linkdead option
int deadp( object who )
{
if( !geteuid( who ) )
return 0;
return (int)who-> query_linkdead();
}
int help()
{
write( SYNTAX + "\n" + @HELP
The who command will give you a list of all user's presently logged
onto the MUD, and whether or not they are idle at this time.
The "@<mud>" options requests a list of users at the remote mud.
This is usually shorter than the finger output, though that depends
on the remote mud.
The "-d" option gives a list of linkdead users.
The "-f" options lists all current FTP users.
HELP
);
return 1;
}
/* EOF */