/*  -*- LPC -*-  */
/*
 * $Locker:  $
 * $Id: perm_it.c,v 1.7 2003/05/13 18:25:01 ceres Exp $
 * $Log: perm_it.c,v $
 * Revision 1.7  2003/05/13 18:25:01  ceres
 * Modified to allow multiple assignments
 *
 * Revision 1.6  2003/04/18 00:14:23  pinkfish
 * Remove the update abilioty.
 *
 * Revision 1.5  2003/04/17 20:56:20  pinkfish
 * Add in some code to update the error assignments.
 *
 * Revision 1.4  2003/03/27 22:14:01  trilogy
 * Was using /secure/login.
 *
 * Revision 1.3  2003/03/21 17:14:48  drakkos
 * Added a filter option for permit assignment summary
 *
 * Revision 1.2  2003/03/05 22:46:28  pinkfish
 * Make it sort the keys correctly and make it pick up details of domain
 * directory assignments.
 *
 * Revision 1.1  2003/03/05 18:57:00  pinkfish
 * Initial revision
 *
 * Revision 1.6  2003/03/04 23:01:49  pinkfish
 * Allow you to remove permissions too.
 *
 * Revision 1.5  2003/03/04 22:29:34  pinkfish
 * Add in directory stuff.
 *
 * Revision 1.4  1999/01/21 18:35:19  ceres
 * Forgot to remove a debug statement.
 *
 * Revision 1.2  1999/01/20 00:54:55  ceres
 * Modified add_command
 *
 * Revision 1.1  1998/12/29 06:03:04  ceres
 * Initial revision
 *
 * Revision 1.1  1998/01/06 05:29:21  ceres
 * Initial revision
 * 
*/
#include <parser.h>
#include <access.h>
#include <player_handler.h>
#include <error_handler.h>
inherit "/cmds/base";
#define READ_MASK 1
#define WRITE_MASK 2
#define GRANT_MASK 4
#define LOCK_MASK 8
int help();
mixed cmd(string command, string euid, string path) {
  string* euids;
  string* bing;
  if (this_player() != this_player(1)) {
    return 0;
  }
  seteuid("Root");
  
  notify_fail("Something went wrong.\n");
  path = (string)this_player()->get_path(path);
  
  switch(command) {
  case "assign" :
    // Assign someone to the directory.
    if (file_size(path) != -2) {
       notify_fail("The path " + path + " does not exist.\n");
       return 0;
    }
    euids = explode(replace_string(euid, " ", ""), ",") - ({ "none" });
    bing = filter(euids, (: !PLAYER_HANDLER->test_creator($1) &&
                            $1 != ERROR_ASSIGNED_NO_ONE:));
    if (sizeof(bing)) {
       notify_fail("The people " + query_multiple_short(bing) +
                   " are not creators.\n");
       return 0;
    }
    if ((int)master()->assign_people_to_directory(path, euids)) {
       add_succeeded_mess("Assigned the directory " + path +
                         " to " + query_multiple_short(euids) + ".\n");
       return 1;
    }
    notify_fail("Unable to assign the directory, not creator names?\n");
    return 0;
  case "read":
    if (!master()->high_programmer(previous_object(-1)) &&
        !master()->valid_grant(this_player(), path, READ_MASK))
      return notify_fail("You do not have permission to add read access.\n");
    return (int)master()->add_read_permission(euid, path);
    break;
  case "write":
      if (!master()->high_programmer(previous_object(-1)) &&
          !master()->valid_grant(this_player(), path, WRITE_MASK))
        return notify_fail("You do not have permission to add write "
                           "access.\n");
      return (int)master()->add_write_permission(euid, path);
      break;
  case "grant":
    if (!master()->high_programmer(previous_object(-1)) &&
        !master()->valid_grant(this_player(), path, GRANT_MASK))
      return notify_fail("You do not have permission to add grant access.\n");
    return (int)master()->add_grant_permission(euid, path);
    break;
  case "lock":
    if (!master()->query_lord(previous_object(-1)))
      return notify_fail("You don't have permission to lock paths.\n");
    if ((path[0..2] != "/d/") &&
        !master()->high_programmer(previous_object(-1)))
      return notify_fail("You don't have permission to lock paths there.\n");
    return (int)master()->lock_path(path);
  case "noread":
    if (!master()->high_programmer(previous_object(-1)) &&
        !master()->valid_grant(this_player(), path, READ_MASK))
      return notify_fail("You do not have permission to remove read "
                         "access.\n");
    return (int)master()->remove_read_permission(euid, path);
  break;
  case "nowrite":
    if (!master()->high_programmer(previous_object(-1)) &&
        !master()->valid_grant(this_player(), path, WRITE_MASK))
      return notify_fail("You do not have permission to remove write "
                         "access.\n");
    return (int)master()->remove_write_permission(euid, path);
    break;
  case "nogrant":
    if (!master()->high_programmer(previous_object(-1)) &&
        !master()->valid_grant(this_player(), path, GRANT_MASK))
      return notify_fail("You do not have permission to remove grant "
                         "access.\n");
    return (int)master()->remove_grant_permission(euid, path);
    break;
  case "unlock":
    if (!master()->query_lord(previous_object(-1)))
      return notify_fail("You don't have permission to lock paths.\n");
    if ((path[0..2] != "/d/") &&
        !master()->high_programmer(previous_object(-1)))
      return notify_fail("You don't have permission to lock paths there.\n");
    return (int)master()->unlock_path(path);
    break;
  default:
    return help();
  }
} /* cmd() */
int do_directory_summary(string dir) {
   mapping assignments;
   mapping new_assignments;
   string* paths;
   string path;
   string ret;
   string domain;
   assignments = master()->query_directory_assignments();
   foreach (domain in master()->query_domains()) {
      ret = catch(new_assignments = ("/d/" + domain + "/master")->query_directory_assignments());
      if (sizeof(new_assignments)) {
         assignments += new_assignments;
      }
   }
   
   if (sizeof (dir)) {
     assignments = filter (assignments, (: strsrch ($1, $(dir)) != -1 :));
  }   
   //paths = sort_array( keys( assignments ), "list_before", this_object() );
   paths = sort_array( keys( assignments ), 1 );
   ret = sprintf("%40-s Assigned To\n", "Path");
   foreach (path in paths) {
      ret += sprintf("%-40s %s\n", path, query_multiple_short(assignments[path]));
   }
   write("$P$Directory Assignments$P$" + ret);
   return 1;
}
// This updates the directory assignments
int do_directory_update(string dir) {
   mapping assignments;
   mapping new_assignments;
   string* paths;
   string path;
   string ret;
   string domain;
   string* bits;
   assignments = master()->query_directory_assignments();
   foreach (domain in master()->query_domains()) {
      ret = catch(new_assignments = ("/d/" + domain + "/master")->query_directory_assignments());
      if (sizeof(new_assignments)) {
         assignments += new_assignments;
      }
   }
   
   if (sizeof (dir)) {
     assignments = filter (assignments, (: strsrch ($1, $(dir)) != -1 :));
  }   
   //paths = sort_array( keys( assignments ), "list_before", this_object() );
   paths = sort_array( keys( assignments ), 0 );
   foreach (path in paths) {
      if (sizeof(assignments[path])) {
         bits = explode(path, "/");
         if (bits[0] == "d") {
           ERROR_HANDLER->do_update_directory_assignment(("/d/" + bits[1] + "/master")->query_lord(), assignments[path][0], path, (: 1 :));
         } else {
           ERROR_HANDLER->do_update_directory_assignment("nobody", assignments[path][0], path, (: 1 :));
         }
         write("Updated " + path + " to " + assignments[path][0] + "\n");
      }
   }
   write("$P$Directory Assignments$P$" + ret);
   return 1;
}
int do_summary(string str) {
  mapping perms;
  string *paths, *euids, ret, creator;
  int i, j, k;
   
  perms = (mapping)master()->query_permissions();
  if (str) {
    if (!perms[str]) {
      if (!PLAYER_HANDLER->test_user(str) && !master()->valid_euid(str)) {
        write("There are no permissions for "+str+".\n");
        return 1;
      } else {
        creator = str; 
      }
    } else {
      perms = ([ str : perms[str] ]);
    }
  }
  //paths = sort_array( keys( perms ), "list_before", this_object() );
  paths = sort_array( keys( perms ), 1 );
  if (!sizeof(paths)) {
    ret = "No permissions set.\n";
  } else {
    ret = sprintf("%11-s    Path\n", "Euid");
  }
  for (i=0;i<sizeof(paths);i++) {
    euids = keys(perms[paths[i]]);
    for (j=0;j<sizeof(euids);j++) {
      if (!creator || (euids[j] == creator ) ) {
        k = perms[paths[i]][euids[j]];
        if (k & LOCK_MASK)
          ret += sprintf("%11-s LCK %s\n", euids[j], paths[i]);
        else
          ret += sprintf("%11-s %c%c%c %s\n", euids[j],(k & READ_MASK?'R':' '),
                         (k & WRITE_MASK?'W':' '), (k & GRANT_MASK?'G':' '),
                         paths[i]);
      }
    }
  }
  this_player()->more_string( ret, "Permissions", 1 );
  return 1;
} /* do_summary() */
int do_tidy() {
   int i, j, perm, same;
   string path, creator, *bits;
   mapping perms, euids, others;
   if (!sizeof(filter(previous_object(-1), (: interactive($1) :)))) {
      event( users(), "inform", "illegal attempt to call do_tidy() by "+
            (string)this_player()->query_name(), "cheat" );
      unguarded((: write_file, "/log/CHEAT", ctime( time() ) +": illegal "
                   "attempt to call do_tidy() by "+
                   (string)this_player()->query_name() +"\n" :));
      return notify_fail( "Failed.\n" );
   }
   perms = (mapping)master()->query_permissions();
   foreach( path in keys( perms ) ) {
      euids = perms[ path ];
      foreach( creator in keys( euids ) ) {
         perm = euids[ creator ];
         if ( !PLAYER_HANDLER->test_creator( creator ) &&
              !master()->valid_euid( creator ) ) {
            write( "No creator: "+ creator +".\n" );
            if ( perm & READ_MASK )
               master()->remove_read_permission( creator, path );
            if ( perm & WRITE_MASK )
               master()->remove_write_permission( creator, path );
            if ( perm & GRANT_MASK )
               master()->remove_grant_permission( creator, path );
            continue;
         }
         if ( path == "/" )
            continue;
         same = perms[ "/" ][ creator ] & perm;
         if ( same ) {
            write( "Access to / supercedes "+ path +" for "+ creator +".\n" );
            if ( same & READ_MASK )
               master()->remove_read_permission( creator, path );
            if ( same & WRITE_MASK )
               master()->remove_write_permission( creator, path );
            if ( same & GRANT_MASK )
               master()->remove_grant_permission( creator, path );
            continue;
         }
         bits = explode( path, "/" );
         j = sizeof( bits ) - 1;
         for ( i = 0; i < j; i++ ) {
            others = perms[ "/"+ implode( bits[ 0 .. i ], "/" ) ];
            if ( !others )
               continue;
            same = others[ creator ] & perm;
            if ( same ) {
               write( "Access to /"+ implode( bits[ 0 .. i ], "/" ) +
                     " supercedes "+ path +" for "+ creator +".\n" );
               if ( same & READ_MASK )
                  master()->remove_read_permission( creator, path );
               if ( same & WRITE_MASK )
                  master()->remove_write_permission( creator, path );
               if ( same & GRANT_MASK )
                  master()->remove_grant_permission( creator, path );
               break;
            }
         }
      }
   }
   return 1;
} /* do_tidy() */
int help() {
  write("Available commands:\n"
"  read    <euid> <path>     : add read permison to the path.\n"
"  write   <euid> <path>     : add write permission to the path.\n"
"  grant   <euid> <path>     : add granting privileges to the path.\n"
"  lock           <path>     : restrict access to the path.\n"
"  noread  <euid> <path>     : remove read permission from the path.\n"
"  nowrite <euid> <path>     : remove write permission from the path.\n"
"  nogrant <euid> <path>     : remove granting privileges to the path.\n"
"  unlock         <path>     : remove restrictions to path.\n"
"  summary [path|euid]       : give a list of all the read/write perms.\n"
"  tidy                      : tidy away unnecessary perms.\n"
"  assign <euid> <path>      : assigns someone to look after a directory.\n"
"  assignment summary        : summary of directory assignments.\n" );
   return 1;
}
mixed *query_patterns() {
  return ({ "summary", (: do_summary(0) :),
              "summary <string>", (: do_summary($4[0]) :),
              "assignment summary", (: do_directory_summary(0) :),
//              "assignment update", (: do_directory_update(0) :),
              "assignment summary <string'filter'>", (: do_directory_summary($4[0]) :),
              "tidy", (: do_tidy() :),
              "help", (: help() :),
              "<word'permission'> <string'euid'> <word'path'>",
              (: cmd($4[0], $4[1], $4[2] ) :)
#ifdef 0
              ,
              "write <string'euid'> <string>", (: cmd("write", $4[0], $4[1]) :),
              "grant <string'euid'> <string>", (: cmd("grant", $4[0], $4[1]) :),
              "lock <string'euid'> <string>", (: cmd("lock", $4[0], $4[1]) :),
              "noread <string'euid'> <string>", (: cmd("noread", $4[0], $4[1]) :),
              "nowrite <string'euid'> <string>", (: cmd("nowrite", $4[0], $4[1]) :),
              "nogrant <string'euid'> <string>", (: cmd("nogrant", $4[0], $4[1]) :),
              "unlock <string'euid'> <string>", (: cmd("unlock", $4[0], $4[1])
                                                 :),
#endif        
              });
} /* query_patterns() */