skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * A hander to allow the testing of values on players when they aren't logged
 * in.  These methods used to exist in the login object but now they're here.
 * <p>
 * @author Ceres
 * @change Partly rewritten to make it faster, and added support for finger
 * info - Sandoz, 2002.
 */

#include <finger.h>

inherit "/global/player/family";

#define MAX_CACHE_SIZE 100
#define CACHE_TIMEOUT  900
#define INACTIVE_LIMIT 604800

class player_info {
    int cached;
    int touched;
    int gender;
    int active;
    int level;
    int age;
    int last;
    int start_time;
    string password;
    string real_name;
    string email;
    string icq;
    string homepage;
    string birthday;
    string location;
    string home_dir;
    string last_on_from;
    string deity;
    string family_name;
    string signature;
    string project;
    string plan;
    string reference;
    mapping map_prop;
}

private int gender, time_on, last_log_on, activity_counter, start_time;
private string password, deity, last_on_from, home_dir;
private mapping aliases, map_prop, new_skills, player_info;

private nosave mapping player_cache;
private nosave int requests, cache_hits;

/** @ignore yes */
void create() {
    player_cache = ([ ]);
} /* create() */

/** @ignore yes */
void clean_cache() {
    string name;

    foreach( name in keys(player_cache) )
        if( player_cache[name]->cached < time() - CACHE_TIMEOUT )
            map_delete( player_cache, name );

} /* clean_cache() */

/** @ignore yes */
private varargs string make_sig( mixed stuff, int flag ) {
    string ret;
    int i, lines;

    if( !sizeof(stuff) ) {
        if( flag )
            return 0;
        return "";
    }

    ret = replace( (string)FINGER_H->make_string( stuff ), ";", "\n");

    if( flag )
        return ret;

    ret += "\n";

    for( i = lines = 0; i < sizeof( ret ) && lines < 4; i++ ) {
        if( ret[ i ] == '\n')
            lines++;
    }

    return "\n--\n"+ret[0..i-1]+"%^RESET%^";

} /* make_sig() */

/** @ignore yes */
private int validate_name( string name ) {
    if( !name || !stringp(name) || name == "logon" || name[0] == '.' ||
        ( sscanf( name, "%*s %*s") == 2 ) || strlen(name) < 2 ||
        sizeof( explode( name, "..") ) > 1 )
        return 0;

    return 1;

} /* validate_name() */

/**
 * This method will load in the player file.  It will return 0 if the player
 * file either does not exist or the input string is incorrect.
 * @param name the name to try and read in
 * @return 1 if the player file exists, 0 if not
 */
int load_player( string name ) {
    class player_info tmp;
    string pfile, dfile;
    mixed file;
    int diff;

    if( !validate_name(name) )
        return 0;

    requests++;

    // Check if we have a cached copy of this file.
    // If so, only use the cached copy if the cached time * 10 is less
    // than the last touched time ie. files which were modified recently
    // should be cached for less time.
    if( player_cache[name] ) {
        if( ( time() - player_cache[name]->cached ) * 10 <
            ( time() - player_cache[name]->touched ) ) {
            cache_hits++;
            return 1;
        }
    }

    pfile = LOGIN_OBJ->query_player_file_name(name);
    dfile = LOGIN_OBJ->query_delete_player_file_name(name);

    // Check if the file exists and get info about it.
    file = unguarded( (: get_dir, pfile+".o", -1 :) );
      if( !sizeof(file) || file[0][1] < 0 ) {
        file = unguarded( (: get_dir, dfile+".o", -1 :) );
        if( !sizeof(file) || file[0][1] < 0 )
            return 0;
    }

    // If we've got a cached copy of this file see if the original's touched
    // time is the same as that for our copy, if so use the cached copy
    // and update the 'cached' time.
    if( player_cache[name] && player_cache[name]->touched == file[0][2] ) {
        player_cache[name]->cached = time();
        cache_hits++;
        return 1;
    }

    // Restore the file and setup the data.
    if( !unguarded( (: restore_object, pfile :) ) &&
        !unguarded( (: restore_object, dfile :) ) )
        return 0;

    if( !mapp( map_prop ) )
        map_prop = ([ ]);
    if( !mapp(aliases) )
        aliases = ([ ]);
    if( !mapp(player_info) )
        player_info = ([ ]);

    tmp = new( class player_info,
               cached       : time(),
               touched      : file[0][2],
               gender       : gender,
               active       : 0,
               level        : 0,
               age          : time_on,
               last         : last_log_on,
               start_time   : start_time,
               password     : password,
               real_name    : player_info["real_name"],
               email        : player_info["email"],
               icq          : player_info["icq"],
               homepage     : player_info["homepage"],
               birthday     : player_info["birthday"],
               location     : player_info["location"],
               home_dir     : home_dir,
               last_on_from : last_on_from,
               deity        : deity,
               family_name  : query_family_name(),
               signature    : make_sig( aliases[".signature"] ),
               project      : make_sig( aliases[".project"], 1 ),
               plan         : make_sig( aliases[".plan"], 1 ),
               reference    : make_sig( aliases[".reference"], 1 ),
               map_prop     : map_prop );

    // Are they active.
    diff = ( time() - last_log_on ) / (3600 * 24 * 7);
    diff *= 10;
    tmp->active = ( activity_counter - diff ) > -50;

    // Calculate their level
    tmp->level = (int)STD_GUILD_OBJ->query_level(TO);
    player_cache[name] = tmp;

    if( sizeof(player_cache) > MAX_CACHE_SIZE &&
        find_call_out("clean_cache") == -1 )
        call_out("clean_cache", 60 );

    return 1;

} /* load_player() */

/**
 * This method returns all the info needed for a player's finger.
 * If the player is online, the updated values will be gotten
 * straight from the player object.
 * @param name the player to get the data for
 * @return the player info for the player
 */
class finger_info query_finger_info( string name ) {
    object ob;
    class player_info tmp;

    if( !ob = find_player(name) ) {
        if( !load_player(name) )
            return 0;
        tmp = player_cache[name];
    }

    if( ob ) {
        return new( class finger_info,
            gender       : ob->query_gender(),
            age          : ob->query_time_on(),
            last         : ob->query_last_log_on(),
            start_time   : ob->query_start_time(),
            real_name    : ob->query_real_name(),
            email        : ob->query_email(),
            icq          : ob->query_icq(),
            homepage     : ob->query_homepage(),
            birthday     : ob->query_birthday(),
            location     : ob->query_where(),
            home_dir     : ob->query_home_dir(),
            last_on_from : ob->query_last_on_from(),
            project      : make_sig( ob->query_player_alias(".project"), 1 ),
            plan         : make_sig( ob->query_player_alias(".plan"), 1 ) );
    }

    return new( class finger_info,
           gender       : tmp->gender,
           age          : tmp->age,
           last         : tmp->last,
           start_time   : tmp->start_time,
           real_name    : tmp->real_name,
           email        : tmp->email,
           icq          : tmp->icq,
           homepage     : tmp->homepage,
           birthday     : tmp->birthday,
           location     : tmp->location,
           home_dir     : tmp->home_dir,
           last_on_from : tmp->last_on_from,
           project      : tmp->project,
           plan         : tmp->plan );

} /* query_finger_info() */

/**
 * This method figures out if the user exists even if they are not on.
 * @param str the name of the user
 * @return 1 if they exist, 0 if they do not
 */
int test_user( string str ) {
    if( find_player(str) )
        return 1;

    if( !validate_name(str) )
        return 0;

    return file_size( LOGIN_OBJ->query_player_file_name(str)+".o") > 0 ||
           file_size( LOGIN_OBJ->query_delete_player_file_name(str)+".o") > 0;

} /* test_user() */

/**
 * This method determines the gender of the player even if they are
 * not currently on
 * @param str the name of the user
 * @return the player's gender
 * @see /std/living/gender.c
 */
int test_gender( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_gender();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->gender;

} /* test_gender() */

/**
 * This method determines if a player is still active.
 * If you need to perform this on a lot of players please use the noload
 * parameter. When noload is set to 1 test_active will not attempt to load
 * the player file if it isn't currently loaded and will instead just do a
 * simple calculation of the players last login time. This is less accurate
 * but avoids lagging the mud.
 * @param player the name of the user
 * @param noload optional parameter to prevent test_active() loading the
 * player file.
 * @return active or inactive (1 or 0)
 */
varargs int test_active( string player, int noload ) {
    mixed file;

    if( find_player(player) )
        return 1;

    if( noload ) {
        if( player_cache[player] )
            return ((class player_info)player_cache[player])->active;
        file = unguarded( (: stat,
               LOGIN_OBJ->query_player_file_name(player)+".o" :) );
        return ( sizeof(file) && file[1] > time() - INACTIVE_LIMIT );
    }

    if( !load_player(player) )
        return 0;

    return ((class player_info)player_cache[player])->active;

} /* test_active() */

/**
 * This method determines the level of the player even if they are
 * not currently on
 * @param str the name of the user
 * @return the players level
 */
int test_level( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_level();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->level;

} /* test_level() */

/** @ignore yes */
mapping query_skills()  {
    if( mapp( new_skills ) )
        return new_skills;
    return ([ ]);
} /* query_skills() */

/**
 * This method checks to see if the name is banished of not.
 * @param name the check for banishment.
 * @return 1 if it banished, 0 if not
 */
int test_banished( string name ) {
    return !(string)BASTARDS_H->query_player_ob( name, 0 );
} /* test_banished() */

/**
 * This method determines the real name of the player even if they are
 * not currently on
 * @param str the name of the user
 * @return the players real name
 */
string test_real_name( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_real_name();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->real_name;

} /* test_real_name() */

/**
 * This method determines the ICQ number information of the player
 * even if they are not currently on.
 * @param str the name of the user
 * @return the players ICQ number as a string
 */
string test_icq( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_icq();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->icq;

} /* test_icq() */

/**
 * This method determines the email of the player even if they are
 * not currently on.
 * @param str the name of the user
 * @return the players email
 */
string test_email( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_email();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->email;

} /* test_email() */

/**
 * This method determines the homepage of the player even if they are
 * not currently on.
 * @param str the name of the user
 * @return the players homepage
 */
string test_homepage( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_homepage();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->homepage;

} /* test_homepage() */

/**
 * This method returns the current value of the property on the
 * player, even if they are not currently on.
 * @param name the player name
 * @param str the property to query
 * @return the value of the property
 */
mixed test_property( string name, string str ) {
    object ob;

    if( ob = find_player(name) )
        return ob->query_property(str);

    if( !load_player(name) )
        return 0;

    return ((class player_info)player_cache[name])->map_prop[str];

} /* test_property() */

/**
 * This method updates the cached properties, it's called by
 * /secure/login.
 */
void special_add_property( string player, string prop, mixed value ) {
    if( player_cache[player] )
        player_cache[player]->map_prop[prop] = value;
} /* special_add_property() */

/**
 * This method determines the deity of the player even if they are
 * not currently on.
 * @param str the name of the user
 * @return the players deity
 */
string test_deity( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_deity();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->deity;

} /* test_deity() */

/**
 * This method determines the age of the player even if they are
 * not currently on.
 * @param str the name of the user
 * @return the players age
 */
int test_age( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_time_on();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->age;

} /* test_age() */

/**
 * This method determines the last log on of the player
 * even if they are not currently on.
 * @param str the name of the user
 * @return the player's last log on
 */
int test_last( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_last_log_on();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->last;

} /* test_last() */

/**
 * This method determines the time the player started at.
 * @param str the name of the user
 * @return the player's start time
 */
int test_start_time( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_start_time();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->start_time;

} /* test_start_time() */

/**
 * This method returns the player's family name.
 * @param str the name of the user
 * @return the player's family name
 */
string test_family( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_family_name();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->family_name;

} /* test_family() */

/**
 * This method returns the player's birthday date.
 * @param str the name of the user
 * @return the player's birthday
 */
string test_birthday( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_birthday();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->birthday;

} /* test_birthday() */

/**
 * This method returns the player's location.
 * @param str the name of the user
 * @return the player's location
 */
string test_location( string str ) {
    object ob;

    if( ob = find_player(str) )
        return ob->query_where();

    if( !load_player(str) )
        return 0;

    return ((class player_info)player_cache[str])->location;

} /* test_location() */

/** @ignore yes */
int test_password( string name, string pass ) {
    if( !load_player(name) )
        return 0;

    // Have to do this since its the only function that requires restoring
    // from a file if the player is active!
    if( find_player(name) && player_cache[name]->password == "") {
        unguarded( (: restore_object,
            LOGIN_OBJ->query_player_file_name(name) :) );
        player_cache[name]->password = password;
    }

    return crypt( pass, player_cache[name]->password ) ==
                        player_cache[name]->password;

} /* test_password() */

/** @ignore yes */
string get_password( string name ) {
    if( file_name(PO) != SECURE_HANDLER_DIR "/ftp_auth")
        return "x";

    if( !load_player(name) )
        return "x";

    if( find_player(name) && player_cache[name]->password == "") {
        unguarded( (: restore_object,
            LOGIN_OBJ->query_player_file_name(name) :) );
        player_cache[name]->password = password;
    }

    return ((class player_info)player_cache[name])->password;

} /* get_password() */

/**
 * This method returns the signature to use on posts for the player
 * even when they are off line.
 * @param name the name of the player
 * @return the signature, "" if none
 */
string query_signature( string name ) {
    object ob;

    if( ob = find_player(name) )
        return make_sig( ob->query_player_alias(".signature") );

    if( !load_player(name) )
        return "";

    return ((class player_info)player_cache[name])->signature;

} /* query_signature() */

/**
 * This method returns the project to use in the player's finger,
 * even when they are off line.
 * @param name the name of the player
 * @return the project or 0, if none
 */
string query_project( string name ) {
    object ob;

    if( ob = find_player(name) )
        return make_sig( ob->query_player_alias(".project"), 1 );

    if( !load_player(name) )
        return 0;

    return ((class player_info)player_cache[name])->project;

} /* query_project() */

/**
 * This method returns the plan to use in the player's finger,
 * even when they are off line.
 * @param name the name of the player
 * @return the plan or 0, if none
 */
string query_plan( string name ) {
    object ob;

    if( ob = find_player(name) )
        return make_sig( ob->query_player_alias(".plan"), 1 );

    if( !load_player(name) )
        return 0;

    return ((class player_info)player_cache[name])->plan;

} /* query_plan() */

/**
 * This method returns the reference string to use in the player's refer,
 * even when they are off line.
 * @param name the name of the player
 * @return the reference string or 0, if none
 */
string query_reference( string name ) {
    object ob;

    if( ob = find_player(name) )
        return make_sig( ob->query_player_alias(".reference"), 1 );

    if( !load_player(name) )
        return 0;

    return ((class player_info)player_cache[name])->reference;

} /* query_reference() */

/**
 * This method should be called whenever a player logs on, or
 * is refreshed, so that we wouldn't have outdated data in the cache.
 * @param name the name of the player to delete from the cache
 */
void delete_from_cache( string name ) {
    map_delete( player_cache, name );
} /* delete_from_cache() */

/** @ignore yes */
mixed stats() {
    int percentage;

    if( requests )
        percentage = ( cache_hits * 100 ) / requests;

    return ({
        ({ "cache size", sizeof(player_cache) }),
        ({ "requests", requests }),
        ({ "cache hits", cache_hits }),
        ({ "cache misses", requests - cache_hits }),
        ({ "percentage hits", percentage }),
        });
} /* stats() */

/** @ignore yes */
nomask int query_prevent_shadow( object ob ) { return 1; }