lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

#include <playerflags.h>
#define SNOOP_DUMMY "/obj/secure/snoop_dummy"
#define SNOOP_CMD   "/trans/cmds/snoop"
#define UNSNOOP_CMD "/trans/cmds/unsnoop"
#define SNOOPS_CMD  "/trans/cmds/snoops"
mapping cycle_info;
mapping snoops = ([]);
mapping dummy_objects = ([]);
object  array admins;


mapping get_snoop_info()
{
  if(previous_object() != find_object(SNOOPS_CMD))
    {
      return 0;
    }
  // We trust the command, we can pass a reference.
  return snoops;
}

private object get_dummy_object(object snoopee)
{
  object ob = dummy_objects[snoopee];
  if(!ob) 
    {
      ob = new(SNOOP_DUMMY, capitalize(snoopee->query_userid()));
      snoop(ob, snoopee->query_link());
      dummy_objects[snoopee] = ob;
    }
  return ob;
}

// Return 1 if there is a cycle, 0 otherwise.
// This side effects big time, and ends up building a list of admins it
// traversed, so it can tell those people they're now being snooped by
// some new guy...
private int detect_cycle_recursive(object snooper)
{
  object array snoopees;
  int    array cycles;
  if(cycle_info[snooper])
    {
      return 1;
    }
  cycle_info[snooper] = 1;
  if(adminp(snooper)) admins += ({snooper});
  snoopees = snoops[snooper];
  if(!snoopees)
    return 0;
  cycles   = filter(snoopees, (:detect_cycle_recursive:));
  if(sizeof(cycles))
    {
      // clean up
      map_delete(cycle_info, snooper);
      return 1;
    }
  return 0;
}

private int detect_cycle(object snoopee)
{
  cycle_info = ([]);
  admins     = ({});
  return detect_cycle_recursive(snoopee);
}

// Return values:
// 0  == unsnoop OK
// -1 == uh, you weren't snooping him, dumbass.
// -2 == stay the fuck out.

int unsnoop(object snooper, object snoopee)
{
  object array snoopees;
  object target;
  if(origin() != "local"
     && previous_object() != find_object(UNSNOOP_CMD))
    return -2;
  snoopees = snoops[snooper];
  if(!snoopees || member_array(snoopee, snoopees) == -1)
  {
    return -1; // dumbass!
  }
  snoops[snooper] -= ({ snoopee, 0 });
  if(!sizeof(snoops[snooper]))
    {
      map_delete(snoops, snooper);
    }
  // Okay, I know I'm not going to get a cycle, but this function also
  // happens to put a list of admins I'm snooping in the admins array.
  detect_cycle(snoopee);
  target = get_dummy_object(snoopee);
  target->remove_snooper(snooper);
  admins->receive_private_msg(capitalize(snooper->query_userid()) +
                              " is no longer snooping you.\n");
  return 0;
}

// Return values:
// 0  == unsnoop OK
// -1 == uh, you weren't snooping anyone, dumbass.
// -2 == go home
int unsnoop_all(object snooper)
{
  if(previous_object() != find_object(UNSNOOP_CMD))
    return -2;
  if(!snoops[snooper] || !sizeof(snoops[snooper]))
    return -1;
  map(snoops[snooper], (: unsnoop($(snooper), $1) :));
}

// Return values:
// 0  == snoop ok
// -1 == already snooping
// -2 == would make cycle
// -3 == no permissions
// -4 == blow it out your ass.
int snoop(object snooper, object snoopee)
{
  object target;
  if(previous_object() != find_object(SNOOP_CMD))
    return -4;

  // Delete this check if you don't like all the snoopable crap.
  // All the shit gets logged anyway.
  if (!snoopee->test_flag(F_SNOOPABLE) && !adminp(this_user()))
    {
      return -3;
    }

  snoops[snooper] = snoops[snooper] || ({});
  if(member_array(snoopee, snoops[snooper]) != -1)
    {
      return -1;
    }
  
  snoops[snooper] += ({snoopee});
  if(detect_cycle(snoopee))
    {
      snoops[snooper] = snoops[snooper][0..<2];
      return -2;
    }
  target = get_dummy_object(snoopee);
  target->add_snooper(snooper);
  admins->receive_private_msg(capitalize(snooper->query_userid()) +
                              " is now snooping you!\n");
  return 0;
}

void remove()
{
 object array snoopers;

  snoopers = keys(snoops) - ({0});
  snoopers->receive_private_msg("Whoops! SNOOP_D is being dested!\n");
  map(snoopers, (: unsnoop_all :));
  map(values(dummy_objects), (: destruct :));
}

void bye()
{
  object who;
  object dummy;
  object array snoopers;

  who = previous_object();
  if(snoops[who] != 0)
    {
      unsnoop_all(who);
    }
  dummy = dummy_objects[who];
  if(dummy)
    {
      snoopers = dummy->get_snoopers();
      foreach(object snooper in snoopers)
	{
	  unsnoop(snooper, who);
	}
    }
}