/* 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);
}
}
}