/* Bastards.c takes care of suspension, banished sites and now also banished
 * playernames.
 * Baldrick, oct '95
 */
/* Tweaked Sept 1995 -- Hamlet
   Trying to fix NO_NEW and add NO_GUEST
*/
#include "access.h"
#include "mail.h"
#define POSTAL_D "/obj/handlers/postal_d"
static string *names;
static string def;
mapping access;  /* Site access control */
string *preferred;
mapping suspended, banished;
int query_access(string *address, string ident);
mapping query_access_mapping() { return access; }
string get_nomulti_string(string site, string userid);
void create() {
    names = ({ "root", "/global/player",
      "failsafe", "/global/failsafe", });
    def = "/global/player";
    seteuid("Root");
    access = ([ ]);
    suspended = ([ ]);
    banished = ([ ]);
    restore_object(file_name(this_object()),1);
    move_object("/room/void");  /* Make it unclonable... */
    preferred = ({ });
} /* create() */
int check_access(object ob, int existing)
{
    string *tmp = explode(query_ip_name(ob),".");
    switch (query_access(explode(query_ip_number(ob), "."), 
    ob->query_ident())) {
    case NO_NEW :
    if (!existing) {
        write("Site banned for new players.\n");
        return NO_NEW;
    }
    else
        return ACCESS;
    case NO_ACCESS :
    write("Site banned for all players.\n");
    return NO_ACCESS;
    case NO_GUEST :
    if(ob->query_name() == "guest") {
        write("Site banned for guests.\n");
        return NO_GUEST;
    }
    else
        return ACCESS;
    case NO_IMMORTS :
    if(ob->query_creator()) {
        write("Site banned for immortals.\n");
        return NO_IMMORTS;
    }
    else
        return ACCESS;
    case NO_PLAYERS :
    if(!ob->query_creator()) {
        write("Site banned for players.\n");
        return NO_PLAYERS;
    }
    else
        return ACCESS;
    case ACCESS :
    return ACCESS;
    case NO_MULTIPLAY:
      ob->add_static_property("NOMULTI",
                              get_nomulti_string(query_ip_number(ob),
                                                 ob->query_ident()));
    return DEFAULT;
    default :
    return DEFAULT;
    }
} /* check_access() */
/* The flag skips the initial check for query_creator().  This is
   needed for the first call to the fcn, when restore_object() hasn't
   been called yet.  Only purpose of this first call is to determine
   whether the person is banished, so security isn't really an issue.
   Check for query_creator() needs skipped so I can install immortal
   slots, which have to decide whether let person in according to whether
   this fcn returns "global/player" or not.  flag should not be passed in
   any subsequent calls to the function. -- Hamlet
*/
varargs string query_player_ob(string name, int flag)
{
    int i;
    int existing;
    int reason;
    if (POSTAL_D->query_mailing_list(name))
    {
    write("Name is a mailing list.\n");
    return 0;
    }
    if(member_array(name,get_dir("/d/")) != -1) {
    write("Name is a domain.\n");
    return 0;
    }
    i = member_array(name, names);
    if (i != -1) 
    {
    return names[i+1];
    }
    if (banished[name])
    {
    write("This name is banished, pick a different one.\n");
    return 0;
    }
    if (suspended[name] > time()) 
    {
    write("You have been suspended until "+ctime(suspended[name])+".\n");
    return 0;
    }
    suspended = m_delete(suspended, name);
    /*
    if ("secure/master"->query_lord(name)) 
      {
      return "global/lord";
      }
    */
    if(file_size("/players/" + name[0..0] + "/" + name + ".o") < 1)
    existing = 0;
    else
    existing = 1;
    reason = check_access(previous_object(), existing);
    if(reason != ACCESS)
    return "";
    /* I hope this is the right place to put this code in.
     * Baldrick, sept '93 
     * Added more files, oct '95. 
     * First, a check if the player is a creator..
     * to be sure it isn't a new player using a non-existing .o
     */
    if(previous_object()->query_creator() ||flag)
    {
    if ("/secure/gods"->query_boo(name))
        return "global/god";
    if ("/secure/lords"->query_boo(name))
        return "global/lord";
    if ("/secure/mudlibber"->query_boo(name))
        return "global/lord";
    if ("/secure/thanes"->query_of(name))
        return "global/thane";
    if ("/secure/patrons"->query_patronage(name))
        return "global/patron";
    if(previous_object()->query_creator()) /* Will actually need this now. */
        return "global/creator";
    }
    return def;
} /* query_player_ob() */
int query_prevent_shadow() { return 1; }
/*
 * Ok, acces checking stuff...
 */
mapping query_all_access() { return access + ([ ]); }
/*
 * Look up the address and find out if it is nice and floppy
 * Adress is of the format ({ "130", "95", "100", "2" })
 */
int query_access(string *address, string ident) {
    mixed rest;
    if (!pointerp(address) || sizeof(address) != 4)
    return ERROR;
    if (!(rest = access[address[0]]))
    return DEFAULT;
    address = address[1..4];
    while (sizeof(address)) {
    if (!rest[address[0]])
        if (!rest["*"])
        return DEFAULT;
        else
        rest = rest["*"];
    else
        rest = rest[address[0]];
    address = address[1..4];
    }
    if (rest[ident])
    return rest[ident];
    if (rest["*"])
    return rest["*"];
    return DEFAULT;
} /* query_access() */
static mixed add_access(mixed bing, string *address, string ident,
  int level) {
    if (!mappingp(bing))
    bing = ([ ]);
    if (!sizeof(address)) {
    if (!level)
        bing = m_delete(bing, ident);
    else
        bing[ident] = level;
    if (!m_sizeof(bing))
        return 0;
    return bing;
    }
    bing[address[0]] = add_access(bing[address[0]], address[1..4], ident, level);
    if (!bing[address[0]])
    bing = m_delete(bing, address[0]);
    if (!m_sizeof(bing))
    return 0;
    return bing;
} /* add_access() */
int change_access(string *address, string ident, int level, string reason) {
    if (!"/secure/master"->high_programmer(geteuid(previous_object())) ||
      this_player() != this_player(1)) {
    notify_fail("Wrong euid.\n");
    return 0;
    }
    if (!pointerp(address) || sizeof(address) != 4 || !reason) {
    notify_fail("Invalid paramters.\n");
    return 0;
    }
    access = add_access(access, address, ident, level);
    if (!access)
    access = ([ ]);
    save_object(file_name(this_object()),1);
    switch (level) {
    case NO_NEW :
    reason = "no new for "+reason;
    break;
    case NO_ACCESS :
    reason = "no access for "+reason;
    break;
    case ACCESS :
    reason = "access for "+reason;
    break;
    case 0 :
    reason = "deleted for "+reason;
    break;
    }
    write_file("/log/ACCESS",
      ident+"@"+implode(address, ".")+" set to "+reason+" by "+
      this_player()->query_name()+".\n");
    return 1;
} /* check_access() */
int suspend_person(string str, int tim) 
{
    if (!"/secure/master"->query_lord(geteuid(previous_object())))
    return 0;
    if (file_size("/players/"+str[0..0]+"/"+str+".o") < 0)
    return 0;
    suspended[str] = time()+tim;
    save_object(file_name(this_object()),1);
    write_file("/log/SUSPEND", str+" suspended until "+ctime(time()+tim)+
      " by "+this_player()->query_name()+".\n");
    return 1;
} /* suspend_person() */
int unsuspend_person(string str) 
{
    if (!"/secure/master"->query_lord(geteuid(previous_object())))
    return 0;
    suspended = m_delete(suspended, str);
    save_object(file_name(this_object()),1);
    // Radix...
    write_file("/log/SUSPEND", str+" unsuspended by "+
      this_player()->query_name()+".\n");
    // write_file("/log/SUSPEND", str+" unsuspended.\n");
    return 1;
} /* unsuspend_person() */
/* Banish code: 
 * Added by Baldrick for simplifying banishing.. 
 */
int banish_playername(string str, string reason)
{
    if (!"/secure/master"->query_lord(geteuid(previous_object())))
    return 0;
    /*
    if (file_size("/players/"+str[0..0]+"/"+str+".o") < 0)
      return 0;
    */
    banished[str] = reason;
    save_object(file_name(this_object()),1);
    write_file("/log/BANISHED", str+" banished because of " + reason + 
      " by "+this_player()->query_name()+".\n");
    return 1;
} /* banish player name */
int unbanish_playername(string str)
{
    if (!"/secure/master"->query_lord(geteuid(previous_object())))
    return 0;
    banished = m_delete(banished, str);
    save_object(file_name(this_object()),1);
    write_file("/log/BANISHED", str+" unbanished.\n");
    return 1;
} /* unbanish playername */
string get_nomulti_string(string site, string userid) {
  string *ret;
  string *thesite;
  int i;
  mapping acc;
  acc = copy(access);
  thesite = explode(site, ".");
  ret = ({ thesite[0] });
  acc = acc[thesite[0]];
  for(i=1; i < sizeof(thesite); i++) {
    if(acc["*"]) {
      acc = acc["*"];
      ret += ({ "*" });
    }
    else {
      acc = acc[thesite[i]];
      ret += ({ thesite[i] });
    }
  }
  if(acc["*"])
    userid = "*";
  return userid + "@" + implode(ret, ".");    
}