dsI/bin/
dsI/extra/creremote/
dsI/extra/mingw/
dsI/extra/wolfpaw/
dsI/fluffos-2.7-ds2.018/
dsI/fluffos-2.7-ds2.018/ChangeLog.old/
dsI/fluffos-2.7-ds2.018/Win32/
dsI/fluffos-2.7-ds2.018/compat/
dsI/fluffos-2.7-ds2.018/compat/simuls/
dsI/fluffos-2.7-ds2.018/testsuite/
dsI/fluffos-2.7-ds2.018/testsuite/clone/
dsI/fluffos-2.7-ds2.018/testsuite/command/
dsI/fluffos-2.7-ds2.018/testsuite/data/
dsI/fluffos-2.7-ds2.018/testsuite/etc/
dsI/fluffos-2.7-ds2.018/testsuite/include/
dsI/fluffos-2.7-ds2.018/testsuite/inherit/
dsI/fluffos-2.7-ds2.018/testsuite/inherit/master/
dsI/fluffos-2.7-ds2.018/testsuite/log/
dsI/fluffos-2.7-ds2.018/testsuite/single/
dsI/fluffos-2.7-ds2.018/testsuite/single/tests/compiler/
dsI/fluffos-2.7-ds2.018/testsuite/single/tests/efuns/
dsI/fluffos-2.7-ds2.018/testsuite/single/tests/operators/
dsI/fluffos-2.7-ds2.018/testsuite/u/
dsI/fluffos-2.7-ds2.018/tmp/
dsI/lib/cfg/
dsI/lib/cmds/common/
dsI/lib/cmds/creators/include/
dsI/lib/cmds/creators/include/SCCS/
dsI/lib/daemon/services/
dsI/lib/doc/
dsI/lib/domains/Ylsrim/
dsI/lib/domains/Ylsrim/adm/
dsI/lib/domains/Ylsrim/armour/
dsI/lib/domains/Ylsrim/broken/
dsI/lib/domains/Ylsrim/fish/
dsI/lib/domains/Ylsrim/meal/
dsI/lib/domains/Ylsrim/npc/
dsI/lib/domains/Ylsrim/virtual/
dsI/lib/domains/Ylsrim/weapon/
dsI/lib/domains/default/creator/
dsI/lib/domains/default/etc/
dsI/lib/domains/default/room/
dsI/lib/lib/comp/
dsI/lib/lib/lvs/
dsI/lib/lib/user/
dsI/lib/lib/virtual/
dsI/lib/obj/
dsI/lib/obj/include/
dsI/lib/realms/
dsI/lib/save/kills/a/
dsI/lib/save/kills/b/
dsI/lib/save/kills/f/
dsI/lib/save/kills/m/
dsI/lib/save/kills/q/
dsI/lib/save/kills/r/
dsI/lib/secure/cfg/
dsI/lib/secure/cfg/classes/
dsI/lib/secure/cfg/races/SCCS/
dsI/lib/secure/cmds/creators/include/
dsI/lib/secure/cmds/players/
dsI/lib/secure/cmds/players/include/
dsI/lib/secure/daemon/include/
dsI/lib/secure/lib/
dsI/lib/secure/lib/include/
dsI/lib/secure/lib/net/
dsI/lib/secure/lib/net/include/
dsI/lib/secure/lib/std/
dsI/lib/secure/obj/
dsI/lib/secure/obj/include/
dsI/lib/secure/save/
dsI/lib/spells/
dsI/lib/verbs/admins/include/
dsI/lib/verbs/common/
dsI/lib/verbs/common/include/
dsI/lib/verbs/creators/
dsI/lib/verbs/creators/include/
dsI/lib/verbs/players/include/SCCS/
dsI/lib/verbs/rooms/
dsI/lib/verbs/rooms/include/
dsI/lib/www/
dsI/v22.2b14/
dsI/win32/
/*    /secure/daemon/master.c
 *    from the Dead Souls LPC Library
 *    the master object, responsible for security
 *    created by Descartes of Borg 940910
 *    error handling by Beek@The Idea Exchange 941004
 *    Version: @(#) master.c 1.7@(#)
 *    Last modified: 96/12/14
 */

#include <config.h>
#include <rooms.h>
#include <cfg.h>
#include <lib.h>
#include <objects.h>
#include <privs.h>
#include <dirs.h>
#include <save.h>
#include <daemons.h>
#include <commands.h>
#include <network.h>
#include <parser_error.h>
#include <message_class.h>
#include "master.h"

private static int ResetNumber;
private static object Unguarded;
private static string PlayerName;
private static object NewPlayer;
private static mapping Groups, ReadAccess, WriteAccess;

void create() {
    Unguarded = 0;
    NewPlayer = 0;
    PlayerName = 0;
    ResetNumber = 1;
    new_read();
    new_write();
    new_groups();
    call_out( (: eventReset :), TIME_TO_RESET );
}

void new_read() {
    mapping tmp;

    tmp = ([]);
    load_access(CFG_READ, tmp);
    ReadAccess = tmp;
}

void new_write() {
    mapping tmp;

    tmp = ([]);
    load_access(CFG_WRITE, tmp);
    WriteAccess = tmp;
}

void new_groups() {
    mapping tmp;

    tmp = ([]);
    load_access(CFG_GROUPS, tmp);
    Groups = tmp;
}

private static void load_access(string cfg, mapping resource) {
    string *lines;
    string file;

    if( !(file = read_file(cfg)) ) {
	error("Failed to find config file: "+cfg);
    }
    lines = filter(explode(file, "\n"), function(string line) {
	                                    int i;
					    
                                            if( !line || trim(line) == "" ) {
						return 0;
					    }
					    if( line[0] == '#' ) {
						return 0;
					    }
					    return 1;
                                        });
    foreach(string line in lines) {
	string fl, ac;
	
        if( sscanf(line, "(%s) %s", fl, ac) != 2 ) {
	    error("Error in loading config file " + cfg + ".");
	}
        resource[fl] = explode(ac, ":");
    }
}

void flag(string str) {
    string file, arg;
    object ob;
    int i, x;

    if(previous_object()) return;
    if(sscanf(str, "for %d", x) == 1) {
        for(i=0; i<x; i++) {}
        return;
    }
    if(sscanf(str, "call %s %s", file, arg)) {
        write("Got "+(string)call_other(file, arg)+" back.\n");
        return;
    }
    write("Master: unknown flag.\n");
}

string *epilog(int x) {
    string *lines, *files;
    string content;
    int i;

    if(!(content = read_file(CFG_PRELOAD))) return ({});
    i = sizeof(lines = explode(content, "\n"));
    files = ({});
    while(i--) {
        if(!lines[i] || lines[i] == "" || lines[i][0] == '#') continue;
        files += ({ lines[i] });
    }
    return files;
}

string privs_file(string file) {
    string nom = 0;
    int ext;

    if( !strsrch(file, DIR_PLAYERS) ) sscanf(file, DIR_PLAYERS "/%*s/%s",nom);
    else if( !strsrch(file, DIR_CRES) ) sscanf(file, DIR_CRES "/%*s/%s",nom);
    if( nom ) {
	if( file == DIR_CRES + "/" + nom[0..0] + "/" + nom ) {
	    string str, grp;

	    str = nom;
	    foreach( grp in keys(Groups) )
	      if( member_array(nom, Groups[grp]) != -1) str = str + ":" + grp;
	    return str;
	}
	else if( file == DIR_PLAYERS + "/" + nom[0..0] + "/" + nom ) 
	  return nom;
	else return 0;
    }
    return file_privs(file);
}

void preload(string str) {
    string err;
    int t;

    if( !file_exists(str + ".c") ) return;
    t = time();
    write("Preloading: " + str + "...");
    if( err = catch(call_other(str, "???")) )
      write("\nGot error "+err+" when loading "+str+".\n");
    else {
        t = time() - t;
        write("("+(t/60)+"."+(t%60)+")\n");
    }
}

int valid_write(string file, object ob, string fun) {
    string *ok;

    if( ob == master() ) return 1;
    ok = match_path(WriteAccess, file);
    return check_access(ob, fun, file, ok, "write");
}

int valid_read(string file, object ob, string fun) {
    string *ok;

    if( ob == master() ) return 1;
    ok = match_path(ReadAccess, file);
    return check_access(ob, fun, file, ok, "read");
}

int valid_apply(string *ok) {
    return check_access(previous_object(1),0,previous_object(0), ok, "apply");
}

int check_access(object ob, string fun, mixed file, string *ok, string oper) {
    object *stack;
    string *privs;
    string priv;
    int i;

    if( objectp(file) ) file = base_name(file);
    if( ok && sizeof(ok) && ok[0] == "all" ) return 1;
    if( Unguarded == ob ) {
        string tmp;

        if( (tmp = base_name(ob)) == LIB_PLAYER || tmp == LIB_CREATOR) {
            if( !PlayerName ) i = sizeof(stack = ({ob})+previous_object(-1));
            else if( file == DIR_PLAYERS+"/"+PlayerName[0..0]+"/"+
		     PlayerName + __SAVE_EXTENSION__ )
              return 1;
            else if( file == DIR_CRES+"/"+PlayerName[0..0]+"/"+
		     PlayerName + __SAVE_EXTENSION__ )
              return 1;
            else i = sizeof(stack = ({ ob }));
        }
        else if( tmp + __SAVE_EXTENSION__ == file ) return 1;
        else i = sizeof(stack = ({ ob }));
    }
    else if(Unguarded && base_name(ob) == SEFUN) {
        if(Unguarded == previous_object(1))
          stack = ({ previous_object(1) });
        else stack = ({ ob }) + previous_object(-1);
    }
    else i = sizeof(stack = previous_object(-1) + ({ ob }));
    while(i--) {
        if(!stack[i] || stack[i] == this_object()) continue;
        if(file_name(stack[i]) == SEFUN) continue;
        if(!(priv = query_privs(stack[i]))) return 0;
        if(!ok && oper == "read") continue;
        privs = explode(priv, ":");
        if(member_array(PRIV_SECURE, privs) != -1) continue;
        if(member_array(file_privs(file), privs) != -1) continue;
        if(!ok && oper == "write") {
            if(userp(stack[i]) && check_user(stack[i], fun, file, oper))
              continue;
            else return 0;
        }
        if(sizeof(privs & ok)) continue;
        if(userp(stack[i]) && check_user(stack[i], fun, file, oper)) continue;
        if(userp(stack[i]) && check_domain(stack[i], fun, file,oper)) continue;
        return 0;
    }
    return 1;
}

nomask static int check_user(object ob, string fun, string file, string oper) {
    string nom, tmp;
    int x;

    if( !sscanf(file, REALMS_DIRS "/%s", nom) ) return 0;
    if( sscanf(nom, "%s/%*s", tmp) ) nom = tmp;
    nom = user_path(nom)+"adm/access";
    if(file_size(nom+".c") < 0) return 0;
    catch(x = (int)call_other(nom, "check_access", ob, fun, file, oper));
    return x;
}

nomask static int check_domain(object ob, string fun, string file, string o) {
    string nom;
    int x;

    if( !sscanf(file, DOMAINS_DIRS+"/%s/%*s", nom) ) return 0;
    nom = DOMAINS_DIRS+"/"+nom+"/adm/access";
    if(file_size(nom+".c") < 0) return 0;
    catch(x = (int)call_other(nom, "check_access", ob, fun, file, o));
    return x;
}

object connect(int port) {
    object ob;
    string err;
    string file;

    file = LIB_CONNECT;
    if( err  = catch(ob = new(file)) ) {
        write("It looks like someone is working on the user object.\n");
        write(err);
        destruct(ob);
    }
    return ob;
}

object compile_object(string str) {
    string nom, tmp, where, which;
    object ob;

    if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom))
      tmp = sprintf("%svirtual/server", user_path(nom));
    else if(sscanf(str, DOMAINS_DIRS+"/%s/%*s", nom))
      tmp = sprintf("%s/%s/virtual/server", DOMAINS_DIRS, nom);
    else if(strsrch(str, ESTATES_DIRS) == 0)
      tmp = sprintf("%s/adm/server", ESTATES_DIRS);
    else if(sscanf(str, DIR_PLAYERS+"/%*s/%s", nom)) {
        if(!NewPlayer) return 0;
        if((string)NewPlayer->GetKeyName() != nom) return 0;
        PlayerName = nom;
        ob = new(LIB_PLAYER);
        if(file_size(str+__SAVE_EXTENSION__) > 0) ob->restore_player(nom);
        else if(file_size(DIR_PLAYERS) != -2) mkdir(DIR_PLAYERS);
        else if(file_size(DIR_PLAYERS+"/"+nom[0..0]) != -2)
          mkdir(DIR_PLAYERS+"/"+nom[0..0]);
        ob->SetKeyName(nom);
        PlayerName = 0;
        return ob;
    }
    else if( sscanf(str, DIR_CRES+"/%*s/%s", nom) ) {
        if(!NewPlayer) return 0;
        if((string)NewPlayer->GetKeyName() != nom) return 0;
        PlayerName = nom;
        ob = new(LIB_CREATOR);
        if(file_size(str+__SAVE_EXTENSION__) > 0) ob->restore_player(nom);
        ob->SetKeyName(nom);
        PlayerName = 0;
        return ob;
    }
    if(file_size(tmp+".c") < 0) {
        if(sscanf(str, "%s.%s", where, which) != 2) return 0;
        if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom))
          tmp = sprintf("%svirtual/%s_server", user_path(nom), which);
        else if(sscanf(str, DOMAINS_DIRS+"/%s/%*s", nom))
          tmp = sprintf("%s/%s/virtual/%s_server", DOMAINS_DIRS, nom, which);
        if(file_size(tmp+".c") < 0) return 0;
        else return (object)call_other(tmp, "compile_object", where);
    }
    return (object)call_other(tmp, "compile_object", str);               
}

static void crash(string err) {
    write_file(DIR_LOGS "/crashes", 
	       mud_name() + " crashed " + ctime(time()) + " with error " + 
	       err+".\n");
    message("system", "Reality implosion!!!  Everyone duck!!!", users());
    message("system", "You are being forced to quit.", users());
    users()->cmdQuit();
}

int valid_bind(object binder, object old_owner, object new_owner) {
    if( binder == master() ) return 1;
    if( member_array(PRIV_SECURE, explode(query_privs(binder), ":")) != -1 )
      return 1;
    return 0;
}

int valid_hide(object who) {
    string priv;

    if(!objectp(who)) return 0;
    if(environment(who) && hiddenp(environment(who))) return 1;
    if(!(priv = query_privs(who))) return 0;
    else return (member_array(PRIV_SECURE, explode(priv, ":")) != -1);
}

int valid_override(string file, string nom) { return (file == SEFUN); }

int valid_save_binary(string str) { return 1; }

int valid_shadow(object ob) {
    object targ = previous_object();
    return (!virtualp(targ) && !strsrch(file_name(targ), DIR_SHADOWS));
}

int valid_object(object ob) {
    string file;

    file = file_name(ob);
    if( !strsrch(file, DIR_TMP) ) return 0;
    else if( !strsrch(file, DIR_FTP) ) return 0;
    else if( !strsrch(file, DIR_LOGS) ) return 0;
    else return 1;
}
    
int valid_socket(object ob, string fun, mixed *info) {
    object *obs;
    object who;
    int port;
    string tmp;
    int i;

    if( info && sizeof(info) == 4 ) {
	ob = info[1];
	port = info[3];
	if( port == PORT_ADMIN && ob != find_object(ADMIN_D) ) {
	    return 0;
	}
	if( port == PORT_RCP && ob != find_object(REMOTE_D) ) {
	    return 0;
	}
    }
    i = sizeof(obs = previous_object(-1));
    while(i--) {
        if( !obs[i] ) continue;
        if( userp(obs[i]) ) continue;
        if( !(tmp = query_privs(obs[i])) ) return 0;
        if( !sizeof(explode(tmp, ":") &
          ({ PRIV_SECURE, PRIV_MUDLIB, PRIV_CMDS, PRIV_GENERAL })) ) return 0;
    }
    return 1;
}

mixed apply_unguarded(function f) {
    object previous_unguarded;
    string base, err, tmp;
    mixed val;

    if(base_name(previous_object(0)) != SEFUN) {
        error("Illegal unguarded apply.");
        return 0;
    }
    previous_unguarded = Unguarded;
    Unguarded = previous_object(1);
    err = catch(val = (mixed)(*f)());
    Unguarded = previous_unguarded;
    if(err) error(err);
    return val; 
}

string error_handler(mapping mp, int caught) {
    string ret, file;

    ret = "---\n" + standard_trace(mp);
    if( caught ) write_file(file = "/log/catch", ret);
    else write_file(file = "/log/runtime", ret);
    if( this_player(1) && find_object(SEFUN) ) {
	this_player(1)->SetLastError(mp);
	if( creatorp(this_player(1)) ) {
	    this_player(1)->eventPrint(ret + "Trace written to " + file,
				       MSG_SYSTEM);
	}
	else {
	    if( !strsrch(file_name(this_player(1)), LIB_CONNECT) ) {
		return "/log/login";
	    }
	    this_player()->eventPrint("A runtime error occurred, "
				      "use \"bug -r\" to report it.",
				      MSG_SYSTEM);
	    CHAT_D->eventSendChannel("System", "error", "A runtime error "
				     "occurred to " + 
				     (string)this_player(1)->GetCapName()+".");
	}
    }
    return 0;
}

void log_error(string file, string msg) {
    string nom, home, tmp;

    if( file[0] != '/' ) {
	file = "/" + file;
    }
    if( sscanf(file, REALMS_DIRS+"/%s/%s", nom, tmp) != 2  && 
      sscanf(file, DOMAINS_DIRS+"/%s/%s", nom, tmp) != 2 ) 
      sscanf(file, "/%s/%s", nom, tmp);
    if( !nom ) nom = "log";
    catch(write_file(DIR_ERROR_LOGS "/" + nom, msg));
}

varargs string standard_trace(mapping mp, int flag) {
    string obj, ret;
    mapping *trace;
    int i,n;

    ret = mp["error"] + "Object: " + 
      trace_line(mp["object"], mp["program"], mp["file"], mp["line"]);
    ret += "\n";
    trace = mp["trace"];
    n = sizeof(trace);
    for (i=0; i<n; i++) {
	if( flag ) ret += sprintf("#%d: ", i);
        ret += sprintf("'%s' at %s", trace[i]["function"], 
		       trace_line(trace[i]["object"], trace[i]["program"], 
				  trace[i]["file"], trace[i]["line"]));
    }
    return ret;
}

string trace_line(object obj, string prog, string file, int line) {
    string ret;
    string objfn = obj ? file_name(obj) : "<none>";

    ret = objfn;
    if( different(objfn, prog) ) ret += sprintf(" (%s)", prog);
    if( file != prog ) ret += sprintf(" at %s:%d\n", file, line);
    else ret += sprintf(" at line %d\n", line);
    return ret;
}

int different(string fn, string pr) {
    int tmp;

    sscanf(fn, "%s#%d", fn, tmp);
    fn += ".c";
    return (fn != pr) && (fn != ("/" + pr));
}

void master_log_file(string file, string msg) {
    if(file_name(previous_object()) != SEFUN) return;
    if(file_size(file) > MAX_LOG_SIZE) rename(file, file+".old");
    write_file(file, msg);
}

string make_path_absolute(string file) {
    return absolute_path((string)this_player(1)->query_cwd(), file);
}

int player_exists(string nom) {
    string str;

    if( !nom ) return 0;
    str = DIR_PLAYERS "/" + nom[0..0] + "/" + nom + __SAVE_EXTENSION__;
    if( file_size(str) > -1 ) return 1;
    str = DIR_CRES "/" + nom[0..0] + "/" + nom + __SAVE_EXTENSION__;
    return (file_size(str) > -1);
}

string domain_file(string str) {
    string nom, tmp;

    if(sscanf(str, DOMAINS_DIRS+"/%s/%s", nom, tmp) == 2) return nom;
    return 0;
}

string author_file(string str) {
    string nom, tmp;

    if(sscanf(str, REALMS_DIRS+"/%s/%s", nom, tmp) == 2) return nom;
    return 0;
}

static int slow_shutdown() {
    write_file(DIR_LOGS "/audit", 
	       "Armageddon loaded by master: "+ctime(time())+".\n");
    EVENTS_D->eventRebootMud(2);
    return 1;
}

int save_ed_setup(object who, int code) {
    string file;

    if(!intp(code)) return 0;
    rm(file = user_path((string)who->GetKeyName())+".edrc");
    return write_file(file, code+"");
}

int retrieve_ed_setup(object who) {
    string file;
    int x;

    file = user_path((string)who->GetKeyName())+".edrc";
    if(!file_exists(file)) return 0;
    return to_int(read_file(file));
}

string get_save_file_name(string file) {
    string str;

    str = (string)this_player(1)->GetKeyName();
    if(file_size(user_path(str)) == -2)
      return user_path(str)+"dead.edit";
    else return DIR_TMP+"/"+str+".dead.edit";
}

int is_locked() { return MUD_IS_LOCKED; }

string *parse_command_id_list() { return ({ "one", "thing" }); }

string *parse_command_plural_id_list() { return ({ "ones", "things","them"}); }

string *parse_command_adjectiv_id_list() {
    return ({ "the", "an", "a" });
}

string *parse_command_prepos_list() {
    return ({ "in", "with", "without", "into", "for", "on", "under", "against",
      "out", "within", "of", "from", "between", "at", "to", "over", "near",
      "inside", "onto", "off", "through", "across", "up", "down",
      "around", "about" });
}

string parse_command_all_word() { return "all"; }

string parser_error_message(int type, object ob, mixed arg, int flag) {
    string err;

    if( ob ) err = (string)ob->GetShort();
    else err = "";
    switch(type) {
        case ERR_IS_NOT:
	if( flag ) err = "There is no such " + remove_article(arg) + " here.";
	else err = "There is no " + remove_article(arg) + " here.";
	break;

        case ERR_NOT_LIVING:
	if( flag )
	  err = "None of the " + pluralize(remove_article(arg)) +" are alive.";
	else err = "The " + remove_article(arg) + " is not alive.";
	break;

        case ERR_NOT_ACCESSIBLE:
	if( flag ) err = "You can't get to them.";
	else err = "You can't get to it.";
	break;

        case ERR_AMBIG:
	{
	    mixed *obs;
	    int i;
	    
	    obs = unique_array(arg, (: (string)$1->GetShort() :));
	    if( sizeof(obs) == 1 )
	      err = "Which of the " +
		consolidate(sizeof(arg), (string)obs[0][0]->GetShort()) +
	      " do you mean?";
	    else {
	        err = "Do you mean ";
	        for(i = 0; i<sizeof(obs); i++) {
		    if( sizeof(obs[i]) > 1 )
		      err += "one of the " +
			consolidate(sizeof(obs[i]),(string)obs[i][0]->GetShort());
		    else err += (string)obs[i][0]->GetShort();
		    if( i == (sizeof(obs)-2) ) err += " or ";
		    else if( i < sizeof(obs) - 1 ) err += ", ";
		}
		err += "?";
	    }
	    return err;
	}

        case ERR_ORDINAL:
	if( arg > 1 ) err = "There are only " + arg + " of them.";
	else err = "There is only one of them.";
	break;

        case ERR_ALLOCATED:
	return arg;

        case ERR_THERE_IS_NO:
	return "There is no " + remove_article(arg) + " here.";

        case ERR_BAD_MULTIPLE:
	return "You can't do that to more than one at a time.";
    }
    return err;
}

void create_save() {
    string str;

    if(!stringp(str = (string)previous_object()->GetKeyName())) return;
    if(file_size(DIR_PLAYERS+"/"+str[0..0]) == -2) return;
    if(str[0] < 'a' || str[0] > 'z') return;
    mkdir(DIR_PLAYERS+"/"+str[0..0]);
}

object player_object(string nom) {
    object ob;
    string err, tmp;
    int old_limit;

    tmp = base_name(ob = previous_object());
    if( tmp != CMD_ENCRE && tmp != CMD_DECRE && tmp != LIB_CONNECT )
	return 0;
    old_limit = max_eval_cost();
    set_eval_limit(1000000000);
    NewPlayer = ob;
    if(file_size(DIR_CRES+ "/" + nom[0..0]+ "/" +nom+__SAVE_EXTENSION__) > -1) 
      err = catch(ob = load_object(DIR_CRES+"/"+nom[0..0]+"/"+nom));
    else err = catch(ob = load_object(DIR_PLAYERS+"/"+nom[0..0]+"/"+nom));
    NewPlayer = 0;
    set_eval_limit(old_limit);
    if(err) error(err);
    return ob;
}

string player_save_file(string nom) { 
    string tmp;

    tmp = DIR_CRES + "/" + nom[0..0] + "/" + nom;
    if( file_size(tmp + __SAVE_EXTENSION__) > -1 ) return tmp;
    else return DIR_PLAYERS + "/" + nom[0..0] + "/" + nom;
}

string *query_group(string grp) { return copy(Groups[grp]); }

mapping query_groups() { return copy(Groups); }

static void eventReset() {
    object *obs;
    object ob;
    int x, y;

    ResetNumber++;
    call_out( (: eventReset :), TIME_TO_RESET );
    x = reclaim_objects();
    write_file(DIR_LOGS "/reset", "Reset " + ResetNumber + " occurred at: " +
	       ctime(time()) + "\n");
    obs = objects( (: !environment($1) && (random(100) < 26) :) );
    y = 0;
    foreach(ob in obs) {
	function f;

	if( !ob ) {
	    y++;
	    continue;
	}
	f = bind( (: call_other, ob, "clean_up" :), ob );
	if( f ) catch(evaluate(f));
	if( !ob ) {
	    y++;
	    continue;
	}
	f = bind((: call_other, ob, "reset", ResetNumber :), ob);
	if( f ) catch(evaluate(f));
    }
    write_file(DIR_LOGS "/reset", "\t" + x + " objects reclaimed, " +
	       (sizeof(obs) - y) + " objects reset, " + y + " objects "
	       "cleaned.\n");
}

int GetResetNumber() { return ResetNumber; }

object *parse_command_users() {
    return filter(users(), (: creatorp($1) || (int)$1->is_living() :));
}