foundation2_fluffos_v1/
foundation2_fluffos_v1/bin/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/ChangeLog.old/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/Win32/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/compat/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/compat/simuls/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/include/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/clone/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/command/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/data/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/etc/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/include/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/inherit/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/inherit/master/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/log/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/tests/compiler/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/tests/efuns/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/single/tests/operators/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/testsuite/u/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/tmp/
foundation2_fluffos_v1/fluffos-2.9-ds2.13/windows/
foundation2_fluffos_v1/lib/cfg/
foundation2_fluffos_v1/lib/cmds/adm/
foundation2_fluffos_v1/lib/daemon/save/
foundation2_fluffos_v1/lib/daemon/services/
foundation2_fluffos_v1/lib/daemon/soul/
foundation2_fluffos_v1/lib/doc/build/
foundation2_fluffos_v1/lib/doc/classes/
foundation2_fluffos_v1/lib/doc/driver/
foundation2_fluffos_v1/lib/doc/driver/applies/
foundation2_fluffos_v1/lib/doc/driver/applies/interactive/
foundation2_fluffos_v1/lib/doc/driver/concepts/
foundation2_fluffos_v1/lib/doc/driver/driver/
foundation2_fluffos_v1/lib/doc/driver/efuns/arrays/
foundation2_fluffos_v1/lib/doc/driver/efuns/buffers/
foundation2_fluffos_v1/lib/doc/driver/efuns/calls/
foundation2_fluffos_v1/lib/doc/driver/efuns/compile/
foundation2_fluffos_v1/lib/doc/driver/efuns/filesystem/
foundation2_fluffos_v1/lib/doc/driver/efuns/floats/
foundation2_fluffos_v1/lib/doc/driver/efuns/functions/
foundation2_fluffos_v1/lib/doc/driver/efuns/general/
foundation2_fluffos_v1/lib/doc/driver/efuns/mappings/
foundation2_fluffos_v1/lib/doc/driver/efuns/numbers/
foundation2_fluffos_v1/lib/doc/driver/efuns/parsing/
foundation2_fluffos_v1/lib/doc/driver/lpc/constructs/
foundation2_fluffos_v1/lib/doc/driver/lpc/types/
foundation2_fluffos_v1/lib/doc/driver/platforms/
foundation2_fluffos_v1/lib/doc/efun/
foundation2_fluffos_v1/lib/doc/etc/
foundation2_fluffos_v1/lib/doc/faq/
foundation2_fluffos_v1/lib/doc/help/creator/
foundation2_fluffos_v1/lib/doc/help/player/
foundation2_fluffos_v1/lib/doc/lpc/basic/
foundation2_fluffos_v1/lib/doc/lpc/data_types/
foundation2_fluffos_v1/lib/doc/lpc/etc/
foundation2_fluffos_v1/lib/doc/lpc/intermediate/
foundation2_fluffos_v1/lib/doc/lpc/types/
foundation2_fluffos_v1/lib/doc/mudlib/
foundation2_fluffos_v1/lib/doc/mudlib/Features/
foundation2_fluffos_v1/lib/domains/Examples/armour/
foundation2_fluffos_v1/lib/domains/Examples/etc/
foundation2_fluffos_v1/lib/domains/Examples/npc/
foundation2_fluffos_v1/lib/domains/Examples/room/
foundation2_fluffos_v1/lib/domains/Examples/virtual/
foundation2_fluffos_v1/lib/domains/Examples/virtual/exaA/
foundation2_fluffos_v1/lib/domains/Examples/virtual/exaB/
foundation2_fluffos_v1/lib/domains/Examples/weapon/
foundation2_fluffos_v1/lib/domains/School/doc/
foundation2_fluffos_v1/lib/domains/School/room/
foundation2_fluffos_v1/lib/domains/School/room/Classes/
foundation2_fluffos_v1/lib/domains/School/room/Offices/
foundation2_fluffos_v1/lib/domains/Standard/
foundation2_fluffos_v1/lib/domains/Standard/pools/
foundation2_fluffos_v1/lib/domains/Standard/std/
foundation2_fluffos_v1/lib/domains/Standard/xtra/
foundation2_fluffos_v1/lib/include/
foundation2_fluffos_v1/lib/lib/obj/
foundation2_fluffos_v1/lib/news/
foundation2_fluffos_v1/lib/save/
foundation2_fluffos_v1/lib/secure/cfg/
foundation2_fluffos_v1/lib/secure/cmds/player/
foundation2_fluffos_v1/lib/secure/lib/
foundation2_fluffos_v1/old/
foundation2_fluffos_v1/win32/
/*    /adm/obj/master.c
 *    from Nightmare 3.3
 *    the master object, responsible for security
 *    created by Descartes of Borg 940910
 *    error handling by Beek@The Idea Exchange 941004
 */

#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 "master.h"

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;
    new_read();
    new_write();
    new_groups();
}

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 ref) {
    string *lines;
    string file, fl, ac;
    int i, maxi;

    if(!(file = read_file(cfg)))
      error("Failed to find config file: "+cfg);
    maxi = sizeof(lines = explode(file, "\n"));
    for(i=0; i<maxi; i++) {
        if(!lines[i] || lines[i] == "" || lines[i][0] == '#') continue;
        if(sscanf(lines[i], "(%s) %s", fl, ac) != 2)
          error("Error in loading config file "+cfg+" at line "+
            (i+1));
        ref[fl] = explode(ac, ":");
    }
}

void flag(string str) {
    string file, arg;
    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;

    file = "/" + file;
#ifdef PLAYERS
    if( !strsrch(file, DIR_PLAYERS) )
	sscanf(file, DIR_PLAYERS "/%*s/%s", nom);
    else
#endif
    if( !strsrch(file, DIR_CRES) ) sscanf(file, DIR_CRES "/%*s/%s", nom);
    if( nom ) {
	if( file == DIR_CRES + "/" + nom[0..0] +"/"+ nom) {
	    string *grps;
	    string str;
	    int i;
	    
	    str = nom;
	    i = sizeof(grps = keys(Groups));
	    while(i--)
	      if(member_array(nom, Groups[grps[i]]) != -1)
		str = str + ":" + grps[i];
            //tc("privs_file("+file+"): "+str):
	    return str;
	}
#ifdef PLAYERS
	else if(file == DIR_PLAYERS+"/" + nom[0..0] + "/" + nom){ 
          //tc("privs_file("+file+"): "+nom):
	  return nom;
        }
#endif
	else{
            //tc("privs_file("+file+"): 0");
            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;
    if( file[0] != '/' ) file = "/"+file;
    ok = match_path(WriteAccess, file);
    return check_access(ob, fun, file, ok, "write");
    return 0;
}

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

    if( ob == master() ) return 1;
    if( file[0] != '/' ) file = "/"+file;
    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;

    //tc("check_access("+identify(ob)+", "+identify(fun)+", "+
        //identify(file)+", "+identify(ok)+", "+identify(oper)+
            //")");

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

#ifdef PLAYERS
        if( (tmp = base_name(ob)) == LIB_PLAYER || tmp == LIB_CREATOR) {
#else
	if( (tmp = base_name(ob)) == LIB_CREATOR ) {
#endif
            if( !PlayerName ) i = sizeof(stack = ({ob})+previous_object(-1));
#ifdef PLAYERS
            else if( file == DIR_PLAYERS+"/"+PlayerName[0..0]+"/"+
                PlayerName + __SAVE_EXTENSION__ )
              return 1;
#endif
            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]))){
            //tc("query_privs("+identify(stack[i])+") failed.");
            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 {
                //tc("check_user("+identify(stack[i])+", "+
                  //identify(fun)+", "+identify(file)+
                    //","+identify(oper)+") failed.");
                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, achar;
    int x;

#ifdef SUB_REALMS
    if( sscanf(file, REALMS_DIRS "/%s/%s/%*s", achar, nom) != 2 ) return 0;
#else
    if( !sscanf(file, REALMS_DIRS "/%s/%*s", nom) ) return 0;
#endif
    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() {
    object ob;
    string err;

    if(err=catch(ob = clone_object(OB_LOGIN))) {
        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, achar;
    object ob;

#ifdef SUB_REALMS
    if( sscanf(str, REALMS_DIRS "/%s/%s/%*s", achar, nom) == 2 )
#else
    if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom))
#endif
      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);
#ifdef PLAYERS
    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;
    }
#endif
    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);
        else if(file_size(DIR_CRES) != -2) mkdir(DIR_CRES);
        else if(file_size(DIR_CRES "/" + nom[0..0]) != -2)
            mkdir(DIR_CRES "/" + nom[0..0]);
        ob->SetKeyName(nom);
        PlayerName = 0;
        return ob;
    }
    if(file_size(tmp+",c") < 0) {
        if(sscanf(str, "%s.%s", where, which) != 2) return 0;
#ifdef SUB_REALMS
	if( sscanf(str, REALMS_DIRS "/%s/%s/%*s", achar, nom) == 2 )
#else
        if(sscanf(str, REALMS_DIRS+"/%s/%*s", nom))
#endif
          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( member_array(PRIV_SECURE, explode(query_privs(new_owner), ":")) != -1)
      return 0;
    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[0..6] == "/secure"); }

int valid_shadow(object ob) {
    return (!virtualp(ob) && !strsrch(file_name(ob), 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;
    string tmp;
    int i;

    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_GENERAL, PRIV_CMDS })) )
	  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) ) {
	if( find_object(SEFUN) && creatorp(this_player(1)) ) {
	    message("error", mp["error"] + "Trace written to " + file, 
		    this_player(1));
	    this_player(1)->SetLastError(mp);
	}
    }
    return 0;
}

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

    if( this_player(1) ) {
	if( find_object(SEFUN) && creatorp(this_player(1)) )
	  message("error", msg, this_player(1));
    }
    if( file[0] != '/' ) file = "/"+file;
#ifdef SUB_REALMS
    if( sscanf(file, REALMS_DIRS "/%s/%s/%s", achar, nom, tmp) != 3 &&
#else
    if( sscanf(file, REALMS_DIRS+"/%s/%s", nom, tmp) != 2  && 
#endif
      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()->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(str[0] != '/') str = "/"+str;
    if(sscanf(str, DOMAINS_DIRS+"/%s/%s", nom, tmp) == 2) return nom;
    return 0;
}

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

    if(str[0] != '/') str = "/"+str;
#ifdef SUB_REALMS
    if( sscanf(str, REALMS_DIRS "/%s/%s/%s", achar, nom, tmp) == 3 ) 
      return nom;
#else
    if(sscanf(str, REALMS_DIRS+"/%s/%s", nom, tmp) == 2) return nom;
#endif
    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()->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",
      "from", "between", "at", "to", "over", "near" });
}

string parse_command_all_word() { return "all"; }

void create_save() {
    string str;

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

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 != OB_LOGIN ) return 0;
    old_limit = max_eval_cost();
    set_eval_limit(1000000000);
    NewPlayer = ob;
#ifdef PLAYERS
    if(file_size(DIR_CRES + "/" + nom[0..0]+ "/" +nom+__SAVE_EXTENSION__) > -1) 
#endif
      err = catch(ob = load_object(DIR_CRES+"/"+nom[0..0]+"/"+nom));
#ifdef PLAYERS
    else err = catch(ob = load_object(DIR_PLAYERS+"/"+nom[0..0]+"/"+nom));
#endif
    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;
#ifdef PLAYERS
    if( file_size(tmp + __SAVE_EXTENSION__) > -1 ) return tmp;
    else return DIR_PLAYERS + "/" + nom[0..0] + "/" + nom;
#else
    return tmp;
#endif
}

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

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

int valid_save_binary() {
    return 1;
}