/
lib/banish/
lib/d/
lib/doc/
lib/doc/domains/
lib/doc/efun/
lib/doc/examples/
lib/doc/examples/armour/
lib/doc/examples/contain/
lib/doc/examples/food/
lib/doc/examples/magic/
lib/doc/examples/monster/
lib/doc/examples/room/
lib/doc/examples/weapons/
lib/function/
lib/include/
lib/include/fn_specs/
lib/include/skills/
lib/info/
lib/inherit/base/
lib/log/
lib/manuals/312/
lib/news/
lib/obj/party/
lib/objects/components/
lib/open/
lib/open/library/
lib/open/party/
lib/players/
lib/players/zilanthius/
lib/room/
lib/room/city/arena/
lib/room/city/creator/
lib/room/city/garden/monst/
lib/room/city/obj/
lib/room/city/shop/
lib/room/death/
lib/room/registry/
lib/secure/
lib/secure/UDP_CMD_DIR/
lib/skills/
lib/skills/fighter/
lib/skills/thief/
lib/usr/
lib/usr/creators/
lib/usr/players/
#pragma strict_types

/* Master File for HEAVEN7 mudlib */

#include "/include/mudlib.h"
#include "/include/cfg/levels.h"
#include "/include/cfg/master.cfg"

#ifdef AMYLAAR321
#include "/include/cfg/driver_hook.h"
#endif

#ifdef NATIVE_MODE /* in case master loads before simul-efun */

string master_file_name(object ob) {
  string file;

  file = file_name(ob);
  if(file[0] == '/') file = file[1..(strlen(file)-1)];
  return file;
}

#define file_name master_file_name

#endif /* NATIVE */

/***************************************************************************/
/* start-up flags */

void flag(string str) {
    string file, arg;

    if(sscanf(str, "echo %s", arg) == 1) {
       write(arg + "\n");
       return;
    }
    if(sscanf(str, "call %s %s", file, arg) == 2) {
       arg = (string)call_other(file, arg);
       write("Call Flag: "+ arg +"\n");
       return;
    }
    write("Master: Unknown flag " + str + "\n");
}



/***************************************************************************/
/* object player is connected */

/*
 * This function is called every time a player connects.
 * input_to() can't be called from here.
 */

object connect() {
    object ob;
    string ret1, ret2;

    write("\n");
#ifdef USE_DEBUG
    return clone_object(DEBUG);
#endif /* force usuage of DEBUG-player */

#ifdef DEBUG
    /* attempt to load WIZARD,
       loads "inherit/base/base_obj",
          "inherit/base/living",
          "obj/player",
          "obj/wizard"
    */
    ret1 = (string)catch(call_other(WIZARD,"??")); 
    if(ret1) {
      write("SWITCHING TO DEBUG OBJECT!!\n");
      ret2 = (string)catch((ob = clone_object(DEBUG)));
      if(ret2) {
     write("FAILED!\n");
     write("Error1: "+ret1+"\n");
     write("Error2: "+ret2+"\n");
     return 0;
      }
      else {
     ob->set_error_msg(ret1);
      }
    }
    else {
      ob = clone_object(PLAYER);
    }   
#else
    ob = clone_object(PLAYER);
#endif
    return ob;
}


/****************************************************************************/
/* where are error logs written */

/*
 * Get the owner of a file. This is called from the game driver, so as
 * to be able to know which wizard should have the error.
 */

string get_wiz_name(string file) {
    string name, domain, rest;

    file = "/"+ file;
    if (sscanf(file, WIZARD_DIR +"%s/%s", name, rest) == 2) {
      return name;
    }
    if(sscanf(file, DOMAIN_DIR +"%s/w/%s/%s", domain, name, rest) == 3) {
      return name;
    }
    return 0;
}


/*
 * Write an error message into a log file. The error occured in the object
 * 'file', giving the error message 'message'.
 */

void log_error(string file, string message) {
    string name;

    name = get_wiz_name(file);
    if(!name)  name = "log";
    write_file("/log/"+name, message);
}


/****************************************************************************/
/* edit setup save */

/*
 * The wizard object 'who' wants to save his ed setup. It is saved in the
 * file /players/wiz_name/.edrc . A test should be added to make sure it is
 * a call from a wizard.
 *
 * Don't care to prevent unauthorized access of this file. Only make sure
 * that a number is given as argument.
 */

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

    if(!intp(code)) return 0;
    file = WIZARD_DIR+(string)who->query_name(1)+"/"+ ED_SAVE;
    rm(file);
    return write_file(file,code+"");
}


/*
 * Retrieve the ed setup. No meaning to defend this file read from
 * unauthorized access.
 */

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

    file = WIZARD_DIR+(string)who->query_name(1)+"/"+ ED_SAVE;
    if (file_size(file) <= 0) return 0;
    sscanf(read_file(file), "%d", code);
    return code;
}

/************************************************************************/
/* changed to security_level */

/*
 * There are several occasions when the game driver wants to check if
 * a player has permission to specific things.
 *
 * These types are implemented so far:
 * "error messages":     If the player is allowed to see runtime error
 *             messages.
 * "trace":         If the player is allowed to use tracing.
 * "wizard":        Is the player considered at least a "minimal" wizard ?
 * "error messages":     Is the player allowed to get run time error messages ?
 */

int query_player_level(string what) {
  int security_level;

  if(!this_player()) return 0;
  security_level = (int)this_player()->query_security_level();
  switch(what) {
    case "wizard":
      return (security_level >= SEC1);
    case "error messages":
      return (security_level >= SEC1);
    case "trace":
      return (security_level >= SEC4);
    case "arch":
      return (security_level >= SEC8);
  }
}

/***************************************************************************/
/* a number of fn() in master will accept calls only from specific objects */
/* they form the basis of the security of the mud                          */


status valid_master_call(object ob) {
  int i;
  string file, *valid_master;

  if(!ob) return 0;
  file = file_name(ob);
  
  for(i = sizeof(MASTER_FILES); i--; ) {
    if(file == MASTER_FILES[i]) return 1;
  }
  
#ifdef MASTER_DIR
  for(i = sizeof(MASTER_DIR); i--; ) {
    if(sscanf("/"+ file, MASTER_DIR[i], file)) return 1;
  }
#endif /* MASTER_DIR */
  return 0;
}


status valid_player_call(object ob) {
  int i, arg;
  string file, *valid_player;

  if(!ob) {
    return 0;
  }
  if(valid_master_call(ob)) return 1;

  /* valid player files - are all cloned objects */
  valid_player = ({
    PLAYER, WIZARD,
#ifdef DEBUG
    DEBUG,
#endif /* DEBUG */
  });

  file = file_name(ob);
  for(i = sizeof(valid_player); i--; ) {
    if(sscanf(file, valid_player[i] +"#%d", arg)) return 1;
  }
  return 0;
}
 



/****************************************************************************/
/*
 * When an object is destructed, this function is called with every
 * item in that room. We get the chance to save players !
 */

void destruct_environment_of(object ob) {
  if(!interactive(ob)) return;
  tell_object(ob,
  "Everything you see is disolved.\n"+
  "Luckily, you are transported somewhere...\n");
  ob->move_player("is transfered#"+ VOID,0,1); /* domain safe move */
}


#ifndef MUDOS_DR   /* mudos loads these at startup in config */

/**********************************************************************/
/* include directories */

/*
 * Define where the '#include' statement is supposed to search for files.
 * "." will automatically be searched first, followed in order as given
 * below. The path should contain a '%s', which will be replaced by the file
 * searched for.
 */

string *define_include_dirs() {
 return 
   ({"/include/%s", "/include/fn_specs/%s","/include/cfg/%s",
     "/include/fn/%s","/include/skills/%s",});
}

#endif /* MUDOS_DR */

/**********************************************************************/

/*
 * The master object is asked if it is ok to shadow object ob. Use
 * previous_object() to find out who is asking.
 *
 * In this example, we allow shadowing as long as the victim object
 * hasn't denied it with a query_prevent_shadow() returning 1.
 */

#ifdef MUSOS_DR 
int valid_shadow(object ob) {
#else
int query_allow_shadow(object ob) {
#endif /* MUDOS_DR */
    string file;

    if(!sscanf(file_name(previous_object()),"obj/shadows/%s",file)) {
      return 0; /* only shadows that have been inspected can be used */
    }
    /* do not allow shadows with our security fns in them */
    if(function_exists("valid_read",previous_object())
    || function_exists("valid_write",previous_object())) {
      return 0;
    }
    return !ob->query_prevent_shadow(previous_object());
}


/************************************************************************/
/* 3.2 allows two people to edit same file simultaneously!!
 * here is a hack to stop that
 */

string *current_edit; /* list of files currently edited */

string *query_current_edit() { return current_edit; }


static status add_current_edit(string file) {
  string name;
  int i;

  name = capitalize((string)this_player()->query_name(1));
  if(!current_edit) current_edit = ({});
  if((i = member_array(file, current_edit)) != -1) {
    write("Sorry, "+ file +" is being edited by "+ current_edit[i+1] +".\n"); 
    return 0;
  }
  current_edit += ({ file, name, });
  return 1;
}  

void remove_current_edit(string file) {
  int i;

  if(!current_edit) current_edit = ({});
  if((i = member_array(file, current_edit)) == -1) return;
  current_edit = current_edit[0..(i-1)]
            + current_edit[(i+2)..(sizeof(current_edit)-1)];
}



/************************************************************************/
/* where is file written if wizard goes net-dead during edit */

/*
 * Give a file name for edit preferences to be saved in.
 */

string get_ed_buffer_save_file_name(string file) {
  string *file_ar;

  if(file && file != "")
  remove_current_edit(((file[0] != '/') ? "/" : "")+ file); 
  file_ar=explode(file,"/");
  file=file_ar[sizeof(file_ar)-1];
  return WIZARD_DIR+(string)this_player()->query_name(1)+"/"+DEAD_ED+"/"+file;
}


#ifndef MUDOS_DR /* mudos loads simul efun before master */
/***************************************************************************/

/*
 * Give a path to a simul_efun file. Observe that it is a string returned,
 * not an object. But the object has to be loaded here. Return 0 if this
 * feature isn't wanted.
 */

static string get_simul_efun_file() {
  if(catch(call_other(SIMUL_EFUN, "??"))) {
    write("Failed to load " + SIMUL_EFUN + "\n");
    if(catch(call_other(SPARE_SIMUL_EFUN_FILE, "??"))) {
      write("Failed to load spare " + SPARE_SIMUL_EFUN_FILE + "\n");
      shutdown();
      return 0;
    }
    return SPARE_SIMUL_EFUN_FILE;
  }  
  return SIMUL_EFUN;
}

string get_simul_efun() {
#ifdef AMYLAAR321
  return "/"+ get_simul_efun_file();
#else
  return get_simul_efun_file();
#endif /* AMYLAAR321 */
}

#endif /* !MUDOS_DR */

/****************************************************************************/
/* file_size that can be used by all objects */

int master_file_size(string file) {
  return file_size(file);
}


/****************************************************************************/
/* remove file for player object */

status master_remove_file(string file) {
  return (valid_player_call(previous_object())) ? rm(file) : 0;
}


/**************************************************************************/
/* exec() is called in player.c */

/*
 * Function name:   valid_exec
 * Description:     Checks if a certain 'program' has the right to use exec()
 * Arguments:       name: Name of the 'program' that attempts to use exec()
 *                        Note that this is different from file_name(),
 *                        Programname is what 'function_exists' returns.
 *                  NOTE, the absence of a leading slash in the name.
 * Returns:         True if exec() is allowed.
 */

int valid_exec(string name) {
  if(name && name != "" && name[0] == '/') { 
    name = name[1..(strlen(name)-1)];
  }
  switch(name) {
    case  PLAYER+".c":
    case  WIZARD+".c":
      return 1;
    break;
  }
  write("Invalid Exec() call by object: "+name+"\n");
  return 0;
}


#ifdef AMYLAAR

void runtime_error(string error,
           string program,
       string current_object,
                 int line) {
  if(this_player() && query_ip_number(this_player())) {
    if(!query_player_level("error messages") || !error) {
#ifdef ADMIN_NAME
      write(ADMIN_NAME +" exclaims: Woops!!\n"+
         "                    You have found a Space-Time Anomaly.\n");
#else
      write("Kingbilly exclaims: Woops!!\n"+
         "                    You have found a Space-Time Anomaly.\n");

#endif /* ADMIN_NAME */
    }
    else {
      write(error +"\n");
      write(((current_object) 
        ? "program: "+ program +", object: "+ current_object 
         +" line "+ line +"\n"
        : ""));
    }
  }
}


int heart_beat_error(object heart_beat,
                 string error,
               string program,
           string current_object,
                     int line) {
  string wiz_name;

  if(heart_beat && query_ip_number(heart_beat) ) {
#ifdef ADMIN_NAME
    tell_object(heart_beat,ADMIN_NAME 
           +" tells you: You have no heart beat !\n");
#else
    tell_object(heart_beat,"Kingbilly tells you: You have no heart beat !\n");
#endif /* ADMIN_NAME */
    if(query_player_level("error messages")) {
      tell_object(heart_beat, error +"\n");
      tell_object(heart_beat, ((current_object)
     ? "program: "+program+", object: "+current_object+" line "+line+"\n"
     : ""));
    }
  }
#ifdef LOG_HB_ERROR
  if(environment(this_player())) {
    write_file(LOG_HB_ERROR,"Room: "+ file_name(environment(this_player())) +
                  "\nError: "+ error +
                  "Program: "+ program +"\n"+
                  "Object: "+ current_object + 
                 "\nLine: "+ line +"\n\n");
    if(!(wiz_name = get_wiz_name(file_name(environment(this_player()))))) {
      if(!(wiz_name = get_wiz_name(current_object))) {
     return 0;
      }
    }
    write_file(WIZARD_DIR+ wiz_name +"/HB_ERRORS",
     "Room: "+ file_name(environment(this_player())) +"\n"+
     "Error: "+ error +
     "Program: "+ program +"\n"+
     "Object: "+ current_object +"\n"+
     "Line: "+ line +"\n\n");
  }
#endif
    
  return 0; /* Don't restart */
}

#endif /* AMYLAAR */


/************************************************************************/
/* used by ed() to resolve a full path name */

#ifdef AMYLAAR

mixed make_path_absolute(string path) { 
  return (string)this_player()->valid_read(path); 
}

#endif /* AMYLAAR */


/*************************************************************************/
/* validates whether an object can be loaded  */
/* in native it gives object its uid          */

static mixed master_creator_file(string object_name) {
  string wiz_name, domain, trailer;

  if(sscanf("/"+object_name,WIZARD_DIR+"%s/%s",wiz_name,trailer)) {
    return wiz_name;
  }
  if(sscanf("/"+object_name,DOMAIN_DIR+"%s/w/%s/%s",domain,wiz_name,trailer)) {
    return wiz_name;
  } 
  if(sscanf(object_name,"open/%s/%s", wiz_name, trailer)) {
    if(wiz_name == "paste") return 0;
    return wiz_name;
  }
  /* directories that should not have objects in them */
  if(sscanf(object_name,"usr/%s", trailer))                       return 0; 
  if(sscanf(object_name,"doc/%s", trailer))                       return 0;
  if(sscanf(object_name,"info/%s", trailer))                      return 0;
  if(sscanf("/"+object_name,WIZARD_DIR+"%s",trailer))             return 0;
  if(sscanf("/"+object_name,DOMAIN_DIR+"%s/w/%s",domain,trailer)) return 0;
  if(sscanf(object_name,"open/%s", trailer))                      return 0;      
  if(sscanf(object_name,"log/%s", trailer))                       return 0;
  return 1;  /* else legal */
}


mixed creator_file(string object_name) {
  mixed creator_status;

  if((creator_status = master_creator_file(object_name))) {
#ifdef NATIVE_MODE
    return UID_ROOT;
#else
    return creator_status;
#endif
  }
  return 0;
}



void move_or_destruct(object what, object to)
/* An error in this function can be very nasty. Note that unlimited recursion
 * is likely to cause errors when environments are deeply nested
 */
{
#ifdef COMPAT_FLAG
    do {
     int res;
     if (catch( res = transfer(what, to) )) res = 5;
     if ( !(res && what) ) return;
    } while( (res == 1 || res == 4 || res == 5) && (to = environment(to)) );
#else /* !COMPAT_FLAG */
    if ( !catch( what->move(to, 1) ) ) return;
#endif /*COMPAT_FLAG */
    
    /*
     * Failed to move the object. Then, it is destroyed.
     */
    destruct(what);
}


/******************************************************************/
/* snoops must routed via simul_efun */

int valid_snoop(object snooper, object snoopee) {
#ifndef MUDOS_DR
   if(file_name(previous_object()) == get_simul_efun()) return 1;
#else
   if(file_name(previous_object()) == SIMUL_EFUN) return 1;
#endif /* MUDOS_DR */
}


/****************************************************************/
/* snoops are usable by priviledged people */

int valid_query_snoop(object wiz) {
  return (int)this_player()->query_security_level() >= SEC5;
}


#ifdef AMYLAAR

#ifdef COMPAT_FLAG

mixed *prepare_destruct1(object ob) {
    object super;

    super = environment(ob);
    if (super) {
     mixed error, *errors;
     mixed weight;
     object me;
     me = this_object();
     set_this_object(ob);
     errors = ({});
     if ( living(ob) ) {
      if (error = catch(super->exit(ob),0))
       errors = ({"exit"+": "+error});
     }
     if ( error = catch((weight = (mixed)ob->query_weight()),0) ) {
      set_this_object(me);
      return ({"query_weight"+": "+error}) + errors;
     }
     if (weight && intp(weight)) {
      if (error = catch(super->add_weight(-weight),0)) {
       set_this_object(me);
       return ({"add_weight"+": "+error}) + errors;
      }
     }
     set_this_object(me);
    }
    return ({});
}
#endif /* COMPAT_FLAG */


mixed prepare_destruct(object ob) {
    object super;
    mixed *errors;
    int i;

#if 6 * 7 != 42 || 6 * 9 == 42
    return "Preprocessor error";
#endif

#ifdef COMPAT_FLAG
    errors = prepare_destruct1(ob);
    for(i = sizeof(errors); i--; ) {
     write(errors[i]);
    }
#endif /* COMPAT_FLAG */
    super = environment(ob);
    if (!super) {
     object item;

     while ( item = first_inventory(ob) ) {
      destruct_environment_of(item);
      if (item && environment(item) == ob) destruct(item);
     }
    } else {
     while ( first_inventory(ob) )
      move_or_destruct(first_inventory(ob), super);
    }
    return 0; /* success */
}

/* privilege_violation is called when objects try to do illegal things,
 * or files being compiled request a privileged efun.
 *
 * return values: 
 *   1: The caller/file is allowed to use the privilege.
 *   0: The caller was probably misleaded; try to fix the error.
 *  -1: A real privilege violation. Handle it as error.
 */

int privilege_violation(string what, mixed who, mixed arg) {
    switch(what) {
     case "call_out_info":
       return (valid_player_call(who)) ? 1 : -1;
     break;


#ifdef INTERMUD
     case "send_imp":
     case "wizlist_info":
       return (valid_player_call(who) || file_name(who) == INETD) ? 1 : -1;
     break;
#else
     case "wizlist_info":
       return (valid_player_call(who)) ? 1 : -1;
     break;
#endif /* INTERMUD */ 

     case "shutdown":
       return (valid_player_call(who) || file_name(who) == SHUTD) ? 1 : -1;
     break;
     
     case "nomask simul_efun":
     case "set_auto_include_string":
     case "add_worth":
     case "bind_lambda":
     case "get_extra_wizinfo":
     case "rename_object":
     case "set_extra_wizinfo":
     case "set_extra_wizinfo_size":
     case "set_this_object":
     case "shadow_add_action":
       return (valid_master_call(who)) ? 1 : -1;
     break;

     default:
         return -1;
    }
    return -1;
}



#ifdef INTERMUD

void receive_imp(string sender,string msg) {
    INETD->receive_udp(sender,msg);
}

#endif  /* INTERMUD */


void dangling_lfun_closure() {
  raise_error("dangling lfun closure\n");
}

#endif  /* AMYLAAR */



void slow_shut_down(int minutes) {
  shout("Game driver shouts: The memory is getting low !\n");
  SHUTD->shut(minutes);
}


void remove_player(object victim) {
  catch(victim->quit());
  if(victim) destruct(victim);
}


#ifndef 312MASTER

/************************************************************************/
/* I don't know anyone who uses it?
 * Parse_command() is a heavy load */

/*
 * Default language functions used by parse_command() in non -o mode
 */

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 ({ "iffish" });
}

string *parse_command_prepos_list()
{
    return ({ "in", "on", "under", "behind", "beside" });
}

string parse_command_all_word()
{
    return "all";
}

#endif /* 312MASTER */


UID_TYPE get_root_uid() { return UID_ROOT; }


#ifdef NATIVE_MODE /* mudos/native master fns */

string get_bb_uid()   { return UID_BACKBONE; }

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

    if(str[0] != '/') str = "/"+str;
    if(sscanf(str, DOMAIN_DIR+"%s/%s", nom, tmp) == 2) return nom;
    return 0;
}

string author_file(string str) {  return get_wiz_name(str);  }

int valid_seteuid(object ob, string id) {
    return 1;
}

int valid_override(string file, string efun_call) { return 1; }


#endif /* mudos */



/***********************************************************************/
/* promote new wizards and domain wizards */


string master_create_wizard(string owner,string domain,object caller) {
  string txt, tmp1, tmp2;
  object access;
  int tmp;

  if(!owner) return 0;
  
  if(!valid_player_call(caller)) {
    write_file("/log/ILLEGALS",
      "Create_wizard() called for owner, "+ owner
     +" by object, "+ file_name(caller) +" at "+ ctime(time())+"\n");
    return 0;
  }
  write_file("/log/WIZ",
    "Name:"+ owner +", By: "+ (string)this_player()->query_name(1)
   +" Time: "+ ctime(time()) +"\n");

  /* promote wizard */
  if(!domain) {
    if(file_size(WIZARD_DIR+ owner) != -2) {
      tell_object(caller,"Adding Wizard Directory...\n");
      mkdir(WIZARD_DIR+ owner); 
    }
    if(file_size(WIZARD_DIR+ owner +"/open") != -2) {
      tell_object(caller,"Adding Open directory, ~ /open\n");
      mkdir(WIZARD_DIR+owner+"/open"); 
    }
    if(file_size(WIZARD_DIR+ owner +"/private") != -2) {
      tell_object(caller,"Adding Private directory, ~ /private\n");
      mkdir(WIZARD_DIR+owner+"/private");
    }
    if(file_size(WIZARD_DIR +owner+"/"+DEAD_ED) != -2) {
      tell_object(caller,"Adding dead edit directory, ~ /"+DEAD_ED+"\n");
      mkdir(WIZARD_DIR+owner+"/"+DEAD_ED);
    }
    if(file_size(INIT_ACCESS) > 0 
    && file_size(WIZARD_DIR+owner+"/access.c") < 0) {  
      tell_object(caller,"Adding Configurable Access Object...\n");
      txt = "#define NAME \""+owner+"\"\n";
      write_file(WIZARD_DIR+owner+"/access.c",txt);
      txt = read_file(INIT_ACCESS); 
      write_file(WIZARD_DIR+owner+"/access.c",txt);
    }
    if(file_size(INIT_WORKROOM) > 0
    && file_size(WIZARD_DIR+owner+"/workroom.c") < 0) {  
      tell_object(caller,"Adding Workroom...\n");
      txt = "inherit \"inherit/room2\"\;\n\n#define NAME \""+owner+"\"\n\n";
      write_file(WIZARD_DIR+owner+"/workroom.c",txt);
      txt = read_file(INIT_WORKROOM); 
      write_file(WIZARD_DIR+owner+"/workroom.c",txt);
    }
  }
  else { /* Add wizard to domain */
    if(file_size(DOMAIN_DIR+domain) != -2) {
      if(query_player_level("arch")) { /* only arches can make New Domains */
     write("Adding New Domain...\nMaking "+owner+" the High Lord.\n");
     if(this_player() != caller) {
       tell_object(caller,"Adding New Domain...\n"+
                    "You are now High Lord over "+ domain +".\n"); 
     }
     mkdir(DOMAIN_DIR+ domain);
     txt = read_bytes(DOMAIN_DIR +"access.c",
                               0,
           file_size(DOMAIN_DIR +"access.c"));
     sscanf(txt, "%s});%s", tmp1, tmp2);
     txt = "\""+owner+"\",                     ";
     txt = extract(txt,0,15);
     txt += "\""+domain+"\",\n";
     txt = tmp1+txt +"    });"+ tmp2;
     rm(DOMAIN_DIR +"access.c");
     write_file(DOMAIN_DIR +"access.c",txt);
     if((access = find_object(DOMAIN_DIR +"access"))) {
       destruct(access);
     }
     if(catch(call_other(DOMAIN_DIR +"access","??"))) {
       write("Error In Reloading Head Domain Access Object!\n");
     }
      }
      else {
     write("You cannot add a New Domain.\n");
     return 0;
      }
    }
    if(file_size(DOMAIN_DIR+domain+"/access.c") < 0) {
      txt = read_bytes(DOMAIN_DIR +"access.dom",
                               0,
         file_size(DOMAIN_DIR +"access.dom"));
      write_file(DOMAIN_DIR+domain+"/access.c",txt);
      if(catch(call_other(DOMAIN_DIR+domain+"/access","??"))) {
     write("Error In Reloading Domain Access Object!\n");
      }
    }           
    if(file_size(DOMAIN_DIR+ domain +"/w") != -2) {
      mkdir(DOMAIN_DIR+ domain +"/w");
    }
    if(file_size(DOMAIN_DIR+ domain +"/w/"+ owner) != -2) {
      tell_object(caller,"Adding Domain directory...\n");
      mkdir(DOMAIN_DIR+ domain +"/w/"+ owner);
    }
    if(file_size(DOMAIN_DIR+ domain +"/w/"+ owner +"/access.c") < 0) {  
      tell_object(caller,"Adding Configurable Access Object...\n");
      txt = read_bytes(DOMAIN_DIR +"p_access.dom",
                              0,
         file_size(DOMAIN_DIR +"p_access.dom"));
      write_file(DOMAIN_DIR+domain+"/w/"+owner+"/access.c",txt);
      if(catch(call_other(DOMAIN_DIR+domain+"/w/"+owner+"/access","??"))) {
     write("Error In Reloading Domain Creator Access Object!\n");
      }
    }
  }
}



/*********************************************/
/* set up file security for amylaar or mudos */

#if defined(AMYLAAR) || defined(MUDOS_DR)

status restricted_path(string file) {
  string *path;
  int i;
  
  /* these are paths that can only be write-accessed by objects that
   * valid_player_call(object) returns 1.  
   */
   
  path = ({ 
    "/include/%s", "/obj/%s", "/usr/%s", "/secure/%s", "/inherit/%s",
    "/function/%s", "/skills/%s", "/objects/%s",  
  });
#ifdef MASTER_DIR
  path += MASTER_DIR;
#endif /* MASTER_DIR */
  for(i = sizeof(path); i--; ) {
    if(sscanf(file, path[i], file)) return 1;
  }
  return 0;
}


#ifdef AMYLAAR

mixed valid_write(string path, 
           string eff_user,
           string call_fun,
          object caller) {
#else  /* mudos */

mixed valid_write(string path, 
           mixed caller,
           string call_fun) {

#endif /* mudos */

  string domain, who, file;
  int i;

  if(!caller || stringp(caller)) caller = previous_object();

  /* clean up file path */

  if(!path) return 0;
  path = "/"+ path;
  while(sscanf(path,"%s//%s",path,file)) path += "/"+ file;
  if(sscanf(path,"%s..%s",path,file)) return 0; /* illegal path */ 


  /* master objects have access to everything */

  if(valid_master_call(caller)) { 
    return extract(path,1);
  }

  /* validate caller for restricted paths */
  
  if(restricted_path(path) && !valid_player_call(caller)) {
    if(query_player_level("error messages")) {
      write("Invalid Write Access by "+ file_name(caller) 
        +" for path "+ path +",\nEfun: "+ call_fun +"\n");
    }
    return 0;
  }
  
  /* make validations for specific efuns */

  switch(call_fun) {
    case "save_object":
      if(sscanf(path,"/usr/%s",file)) {
     return extract(path,1);
      }
#if defined(MAIL_DIR) && defined(MAILER)
      if(sscanf(path,"/"+ MAIL_DIR +"%s", file)) { /* only mailer here */
     file = file_name(caller);
     sscanf(file,"%s#%d",file,i);
#ifdef INTERMUD
     if(file == "secure/UDP_CMD_DIR/mail") return extract(path,1);
#endif /* INTERMUD */
     return (file == MAILER) ? extract(path,1) : 0;
      }
#endif /* MAILER */

      if(sscanf(path,"/banish/%s",file)) { 
     if(valid_player_call(caller)) return extract(path,1);
      }
      else {
#ifdef PARANOIA
     if(!(who = get_wiz_name(extract(path,1)))) {
       if(!sscanf(path,"/ob_saves/%s",file)) return 0;
       return extract(path,1);
     }
     if(who == get_wiz_name(file_name(caller))) {
       return extract(path,1);
     }
     return 0;
#else
     return extract(path,1);
#endif /* PARANOIA */        
      }
    break;

    case "ed_start":
      if(!valid_player_call(caller)) return 0;
      remove_current_edit(path);
    break;

    case "mkdir":  /* domain stuff */
      if(!valid_player_call(caller)) return 0;
      
      /* Necassary to make sure Access objects are automatically made! */
      if(sscanf(path,DOMAIN_DIR +"%s",domain) == 1) {
     if(sscanf(domain,"%s/%s",domain,file) != 2) {
       write("Use 'domain' command to make a New Domain.\n");
       return 0; /* only create_wizard() fn can add domain creators */
     }
     if(sscanf(path,DOMAIN_DIR +"%s/w/%s",domain,file) ==  2) {
       if(sscanf(file,"%s/%s",who,file) != 2) {
         write("Use 'domain' command to add a New Creator Directory.\n");
         return 0; /* only create_wizard() fn can add domain creators */
       }
     }
      }
      if(sscanf(path,WIZARD_DIR +"%s", file) == 1) {
     if(sscanf(file,"%s/%s",who,file) != 2) {
       write("Use 'promote' command to add a New Creator Directory.\n");
       return 0; /* only create_wizard() fn can add creators */
     }
      }
    break;

    case "write_file":
      if(sscanf(path,"/log/%s",file)) {
     return extract(path,1);
      }
    case "cindent":
    case "rmdir":
    case "do_rename":
    case "remove_file":
    case "write_bytes":
#ifdef PARANOIA 
     if(get_wiz_name(extract(path,1)) == get_wiz_name(file_name(caller))) {
       break;
     }
     if(!valid_player_call(caller)) return 0;
#endif /* PARANOIA */
    break;
  }

/* check the original interactive caller's access */
#ifdef AMYLAAR
  if(this_interactive()) {
    if(this_interactive() != this_player()) {
      funcall(bind_lambda(#'enable_commands,this_interactive()));
    }
    caller = this_interactive();
#else  /* mudos */
  if(this_player(1)) {
    caller = this_player(1);
#endif /* mudos */

    /* validate unique master objects */
    
    if((file = (string)caller->valid_write(path))) {
      for(i = sizeof(MASTER_FILES); i--; ) {
     if(path == MASTER_FILES[i]
     && !this_player()->secure(MASTER_SECURITY)) {
       file = 0;
       break;
     }
      }
    }

    /* validate master directories */
#ifdef MASTER_DIR
    if(file) {
      for(i = sizeof(MASTER_DIR); i--; ) {
     if(sscanf(path,MASTER_DIR[i],who) == 1
     && !this_player()->secure(MASTER_SECURITY)) {
       file = 0;
       break;
     }
      }
    }
#endif /* MASTER_DIR */

    if(!stringp(file)) {
      if(query_player_level("error messages")) {
     write("Invalid Write Access: "+ path +", Efun: "+ call_fun +"\n"); 
      }
      else {
     write("Bad file name.\n");
      }
      return 0;
    }
    return file;
  }
  path = (string)PLAYER->valid_write(path);
  if(stringp(path)) return path;
  return 0; /* access denied */
}


#ifdef AMYLAAR

mixed valid_read(string path, 
          string eff_user, 
          string call_fun, 
            object caller) {
#else  /* mudos */

mixed valid_read(string path, 
          mixed caller,
           string call_fun) {

#endif /* mudos */
  mixed *error;
  string file;
  int i;

  if(!caller || stringp(caller)) caller = previous_object();
#ifdef AMYLAAR
  if(!path) {
    if(call_fun == "ed_start") {
      error = get_error_file((string)this_player()->query_real_name());
      if(!error || error[3]) {
     write("No error.\n");
     return 0;
      }
      write(extract(error[0],1)+" line "+error[1]+": "+error[2]+"\n");
      return error[0];
    }
    return 0;
  }
#else
  if(!path) return 0;
#endif /* AMYLAAR */

  path = "/"+ path;
  while(sscanf(path,"%s//%s",path,file)) path += "/"+ file;


  /* master objects have access to everything */

  if(valid_master_call(caller)) {
    return extract(path,1);
  }

  switch(call_fun) {
    case "restore_object": /* we have made the mail reader more secure */
#if defined(MAIL_DIR) && defined(MAILER)
      if(sscanf(path,MAIL_DIR +"%s",file)) {
     file = file_name(caller);
     sscanf(file,"%s#%d",file,i);
#ifdef INTERMUD
     if(file == "secure/UDP_CMD_DIR/mail") return 1;
#endif INTERMUD
     if(file != MAILER) { 
       return 0;
     }
      }
#endif /* MAILER */
      return 1;
    break;

    case "do_rename":
#ifdef INETRMUD
      if(file_name(caller) == INETD) return 1;
#endif
    break;

    case "file_size":
      return extract(path,1); /* allow valid read access to everyone */
    break;

    case "tail":
    case "read_bytes":
    case "read_file":
      if(member_array(path, OPEN_FILES) != -1) {
     return extract(path,1);
      }
    break;

    case "ed_start":
      if(!valid_player_call(caller)) return 0;
      if(!add_current_edit(path)) return 0; /* someone is already editing */
    break;

#ifdef MUDOS_DR
    case "stat":
#endif
    case "get_dir":
      if(valid_player_call(caller)) {
     return extract(path,1);
      }
    break;

    case "print_file":
    break;
  }

  if(this_player() && interactive(this_player())) {
    file = (string)this_player()->valid_read(path);
    if(!stringp(file)) {
      if(query_player_level("error messages")) {
     write("Invalid Read Access: "+ path +", Efun: "+ call_fun +"\n"); 
      }
      else {
     write("Bad file name.\n");
      }
      return 0;
    }
    return file;
  }
  path = (string)PLAYER->valid_read(path);
  if(stringp(path)) return path;
  return 0;
}

#endif /* AMYLAAR || MUDOS */


/**************************************************************************/
/* wizlist */

#if defined(AMYLAAR)

#if HAVE_WIZLIST == 0

#include "/include/cfg/wizlist.h"


static void wiz_decay() {
    mixed *wl;
    int i;

    wl = wizlist_info();
    for (i=sizeof(wl); i--; ) {
     set_extra_wizinfo(wl[i][WL_NAME], wl[i][WL_EXTRA] * 99 / 100);
    }
    call_out("wiz_decay", 3600);
}


void save_wiz_file() {
    rm("/WIZLIST");
    write_file(
      "/WIZLIST",
      implode(
     map_array(wizlist_info(),
       lambda(({'a}),
         ({#'sprintf, "%s %d %d\n",
           ({#'[, 'a, WL_NAME}),
           ({#'[, 'a, WL_COMMANDS}),
           ({#'[, 'a, WL_EXTRA})
         })
       )
     ), ""
      )
    );
}

void notify_shutdown() {
  if(!valid_master_call(previous_object())) return;
  save_wiz_file();
}

#endif /* WIZLIST */


void inaugurate_master(int arg)
{

#if HAVE_WIZLIST == 0
    if (!arg)
        set_extra_wizinfo(0, allocate(BACKBONE_WIZINFO_SIZE));
    if (find_call_out("wiz_decay") < 0)
        call_out("wiz_decay", 3600);
#endif /* HAVE_WIZLIST */

#if defined(AMYLAAR321)
    set_driver_hook(
      H_MOVE_OBJECT0,
      unbound_lambda( ({'item, 'dest}), ({#',,
#ifdef NATIVE_MODE
     ({#'?, ({#'!=, 'item, ({#'this_object})}),
       ({#'raise_error,
         "Illegal to move other object than this_object()\n"}) }),
#endif
#ifdef COMPAT_FLAG
     ({#'&&, ({#'living, 'item}), ({#'environment, 'item}), ({#',,
       ({#'efun::set_this_player, 'item}),
       ({#'call_other, ({#'environment, 'item}), "exit", 'item}),
     }) }),
#endif
     ({#'efun::efun308, 'item, 'dest}),
     ({#'?, ({#'living, 'item}), ({#',,
       ({#'efun::set_this_player, 'item}),
       ({#'call_other, 'dest, "init"}),
       ({#'?, ({#'!=, ({#'environment, 'item}), 'dest}), ({#'return})}),
     }) }),
     ({#'=, 'others, ({#'all_inventory, 'dest}) }),
     ({#'=, ({#'[, 'others, ({#'member, 'others, 'item}) }), 0}),
     ({#'filter_array, 'others,
       ({#'bind_lambda,
         unbound_lambda( ({'ob, 'item}),
           ({#'?, ({#'living, 'ob}), ({#',,
          ({#'efun::set_this_player, 'ob}),
          ({#'call_other, 'item, "init"}),
           }) })
         )
       }),
       'item,
     }),
     ({#'?, ({#'living, 'item}), ({#',,
       ({#'efun::set_this_player, 'item}),
       ({#'filter_objects, 'others, "init"}),
     }) }),
     ({#'?, ({#'living, 'dest}), ({#',,
       ({#'efun::set_this_player, 'dest}),
       ({#'call_other, 'item, "init"}),
     }) }),
      }) )
    );
#ifdef COMPAT_FLAG
    set_driver_hook(
      H_LOAD_UIDS,
      unbound_lambda( ({'object_name}),
     ({#'?,
       ({#'==,
         ({#'sscanf, 'object_name, "players/%s", 'wiz_name}),
         1,
       }),
       ({#'?,
         ({#'==,
           ({#'sscanf, 'wiz_name, "%s/%s", 'start, 'trailer}),
           2,
         }),
         ({#'&&, ({#'strlen, 'start}), 'start}),
         'wiz_name
       }),
       ({#'&&,
         ({#'!=, ({#'[..], 'object_name, 0, 3}), "ftp/"}),
         ({#'!=, ({#'[..], 'object_name, 0, 4}), "open/"}),
       })
     })
      )
    );
    set_driver_hook(
      H_CLONE_UIDS,
      unbound_lambda( ({'blueprint, 'new_name}), ({
     #'||,
       ({#'creator, 'blueprint}),
       ({#'creator, ({#'previous_object})}),
       1
      }) )
    );
    set_driver_hook(H_CREATE_SUPER, "reset");
    set_driver_hook(H_CREATE_OB,    "reset");
    set_driver_hook(H_CREATE_CLONE, "reset");
#else
    /* the following closures illustrate how the 3.1.2 driver used to
     * set (e)uids. It should be usable for tests, but to get better
     * performance, you are encouraged to replace the function
     * calls to get_bb_uid() and creator_file() by the equivalent code,
     * even if you are satisfied with the current behaviour.
     */
    set_driver_hook(
      H_LOAD_UIDS,
      unbound_lambda( ({'object_name}), ({
     #'?,
     ({#'==,
       ({#'=, 'creator_name, ({#'creator_file, 'object_name})}),
       ({#'getuid, ({#'previous_object})}),
     }),
      ({#'geteuid, ({#'previous_object})}),
     ({#'==, 'creator_name, ({#'get_bb_uid})}),
      ({#'geteuid, ({#'previous_object})}),
      ({#'({, 'creator_name, 1}),
      }) )
    );
    set_driver_hook(
      H_CLONE_UIDS,
      unbound_lambda( ({ /* object */ 'blueprint, 'new_name}), ({
     #'?,
     ({#'==,
       ({#'=, 'creator_name, ({#'creator_file, 'new_name})}),
       ({#'getuid, ({#'previous_object})}),
     }),
      ({#'geteuid, ({#'previous_object})}),
     ({#'==, 'creator_name, ({#'get_bb_uid})}),
      ({#'geteuid, ({#'previous_object})}),
      ({#'({, 'creator_name, 1}),
      }) )
    );
#ifdef NATIVE_MODE
    set_driver_hook(H_CREATE_OB,    "create");
    set_driver_hook(H_CREATE_CLONE, "create");
#else
    set_driver_hook(H_CREATE_SUPER,
      unbound_lambda(0, ({#',,
       ({#'call_other, ({#'this_object}), "create"}),
       ({#'call_other, ({#'this_object}), "reset"})
     })
      )
    );
    set_driver_hook(H_CREATE_OB,
      unbound_lambda(0, ({#',,
       ({#'call_other, ({#'this_object}), "create"}),
       ({#'call_other, ({#'this_object}), "reset"})
     })
      )
    );
    set_driver_hook(H_CREATE_CLONE,
      unbound_lambda(0, ({#',,
       ({#'call_other, ({#'this_object}), "create"}),
       ({#'call_other, ({#'this_object}), "reset"})
     })
      )
    );
#endif
#endif
    set_driver_hook(H_RESET,        "reset");
    set_driver_hook(H_CLEAN_UP,     "clean_up");

#endif /* AMYLAAR321 */
}


#if defined(AMYLAAR321)

mixed current_time;

string *epilog(int eflag) {
    if (eflag) return ({});
    debug_message(sprintf("Loading init file %s\n", INIT_FILE));
    current_time = rusage();
    current_time = current_time[0] + current_time[1];
    return explode(read_file(INIT_FILE), "\n");
}

void preload(string file) {
    int last_time;

    if (strlen(file) && file[0] != '#') {
        last_time = current_time;
        debug_message(sprintf("Preloading: %s", file));
        call_other(file, "");
        current_time = rusage();
        current_time = current_time[0] + current_time[1];
        debug_message(sprintf(" %.2f\n", (current_time - last_time)/1000.));
    }
}

#endif /* AMYLAAR321 */
#endif /* AMYLAAR */