~venzor/nakedmud/cmd-snoop

« back to all changes in this revision

Viewing changes to lib/pymodules/cmd_snoop.py

  • Committer: Andrew Venzor
  • Date: 2010-12-04 03:09:19 UTC
  • Revision ID: andrew@andrewvenzor.com-20101204030919-37kx64seumf9othz
Feature: Adds 'snoop' command for admins to listen to a player's input. Allows for multiple players to be snooped at one time.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
###############################################################################
 
2
# cmd_snoop.py 
 
3
#
 
4
# Adds the 'snoop' command to NakedMUD. It relays all input from the target
 
5
# to the snooper. You can snoop multiple players. Snooping persists if a 
 
6
# snooped player logs off (except during reboots). If the snooper logs off,
 
7
# their snooping is cleared.
 
8
#
 
9
# Author: Andrew Venzor (andrew@andrewvenzor.com)
 
10
# Revision: 1
 
11
###############################################################################
 
12
 
 
13
import mud, mudsys, mudsock, hooks
 
14
 
 
15
_snooptbl = {} # snooper : [snoopees,...] table
 
16
 
 
17
def cmd_snoop(admin, cmd, arg):
 
18
    """Usage: snoop [ <player name> | off | listall ]
 
19
    
 
20
    Relays all input from the snoopee player(s) to you. Type snoop without any 
 
21
    arguments to see who you are currently snooping. Specifying a player name
 
22
    will toggle snooping on that player. 'Off' will turn off all snooping.
 
23
    'Listall' will show who is snooping who.
 
24
    """
 
25
    snoop_cleanup()
 
26
    snoopers = get_snoopers()
 
27
    
 
28
    if arg.lower() == "off":
 
29
        # Turn off all snooping
 
30
        if admin in get_snoopers():
 
31
            admin.send("You stop all snooping.")
 
32
            del_snoop(admin)
 
33
        else:
 
34
            admin.send("You are not snooping anyone.")
 
35
    
 
36
    elif arg.lower() == "listall":
 
37
        # Show all snoopers
 
38
        buf = ''
 
39
        for snooper in snoopers:
 
40
            buf += "%s snooping:\r\n" % \
 
41
                ('You are' if snooper is admin else snooper.name + ' is')
 
42
            buf += "  " + ", ".join([ch.name for ch in snoopers[snooper]]) + \
 
43
                    "\r\n"
 
44
        admin.send(buf if buf != '' else 'Nobody is snooping right now.')
 
45
    ############################################################################
 
46
    # DEBUGGING - REMOVE ME
 
47
    elif arg.lower() == 'debug':
 
48
        buf = []
 
49
        buf.append("_snooptbl: %r" % _snooptbl)
 
50
        buf.append("get_snoopers: %r" % get_snoopers(False, False))
 
51
        buf.append("get_snoopees: %r" % get_snoopees(False, False))
 
52
        buf.append("Online:")
 
53
        buf.append("    Snoopers:")
 
54
        for snooper in snoopers:
 
55
            buf.append("        %s: %r" % (snooper.name, 
 
56
                        [ch.name for ch in snoopers[snooper]]))
 
57
        buf.append("    Snoopees:")
 
58
        snoopees = get_snoopees()
 
59
        for snoopee in get_snoopees():
 
60
            buf.append("        %s: %r" % (snoopee.name, 
 
61
                        [ch.name for ch in snoopees[snoopee]]))
 
62
        admin.send("\r\n".join(buf))
 
63
    # END DEBUGGING
 
64
    ############################################################################
 
65
    elif not arg:
 
66
        # Show your snoopers if you are snooping
 
67
        if admin in snoopers:
 
68
                admin.send("You are snooping:\r\n" + 
 
69
                        "  " + ", ".join([ch.name for ch in snoopers[admin]]))
 
70
                return
 
71
        admin.send("Who would you like to snoop?")
 
72
    
 
73
    else:
 
74
        try:
 
75
            tgt, = mud.parse_args(admin, True, cmd, arg,
 
76
                    "[on] ch.world.noself")
 
77
        except:
 
78
            return
 
79
        if del_snoop(admin, tgt):
 
80
            admin.send("You stop snooping %s." % tgt.name)
 
81
        elif tgt is admin:
 
82
            admin.send("Do you really need help snooping yourself?")
 
83
        #elif tgt.isInGroup("admin"):
 
84
        #    admin.send("I doubt the other admin would appreciate that.")
 
85
        elif tgt and tgt.sock:
 
86
            add_snoop(admin, tgt)
 
87
            admin.send("You begin snooping %s." % tgt.name)
 
88
        else:
 
89
            admin.send("%s is not a valid character or not online." %
 
90
                    (arg[0].upper() + arg[1:].lower()))
 
91
 
 
92
def snoop_hook(info):
 
93
    """Performs the relaying to the appropriate individuals and cleanup of the
 
94
    snoop table."""
 
95
    ch, cmd = hooks.parse_info(info)
 
96
    snoopees = get_snoopees(False)
 
97
    
 
98
    if ch not in snoopees:
 
99
        # Remove orphaned hooks
 
100
        #   This is here because the way I have things set up, I cannot remove a
 
101
        #   hook while a char is offline (ch.name is unavailable)
 
102
        hooks.remove("snoop_%s" % ch.name, snoop_hook)
 
103
        return
 
104
    
 
105
    # Send the snooped text
 
106
    for snooper in snoopees[ch]:
 
107
        snooper.send("[SNOOP] %s: %s" % (ch.name, cmd))
 
108
 
 
109
def snoop_cleanup():
 
110
    """Checks for orphaned snoopees and cleans up the table."""
 
111
    chars_online = [sock.ch for sock in mudsock.socket_list()]
 
112
    snoopers = get_snoopers(False)
 
113
    
 
114
    # Remove inactive snoopers
 
115
    for char in snoopers:
 
116
        if char not in chars_online:
 
117
            del_snoop(char)
 
118
 
 
119
def get_snoopees(snoopees_online=True, snooper_online=True):
 
120
    """Returns a dict of all online players being snoopees, with their snoopers
 
121
    contained in the value as a list.
 
122
    It's essentially the inverse of _snooptbl.
 
123
    snoop(ed/er)_online set to False will return offline character objects for
 
124
    each respectively."""
 
125
    result = {}
 
126
    online_chs = [sock.ch for sock in mudsock.socket_list()]
 
127
    for snooper in _snooptbl:
 
128
        if snooper_online and snooper not in online_chs: continue
 
129
        for char in _snooptbl[snooper]:
 
130
            if snoopees_online and char not in online_chs: continue
 
131
            if char not in result:
 
132
                result[char] = [snooper]
 
133
            else:
 
134
                result[char].append(snooper)
 
135
    return result
 
136
 
 
137
def get_snoopers(snooper_online=True, snoopees_online=True):
 
138
    """Returns a dict of all online snooping players, with the snoopee player(s)
 
139
    contained in the value as a list.
 
140
    snoop(er/ed)_online set to False will return offline character objects for
 
141
    each respectively."""
 
142
    result = {}
 
143
    online_chs = [sock.ch for sock in mudsock.socket_list()]
 
144
    for snooper in _snooptbl:
 
145
        if snooper_online and snooper not in online_chs: continue
 
146
        for char in _snooptbl[snooper]:
 
147
            if snoopees_online and char not in online_chs: continue
 
148
            if snooper not in result:
 
149
                result[snooper] = [char]
 
150
            else:
 
151
                result[snooper].append(char)
 
152
    return result
 
153
 
 
154
def add_snoop(snooper, snoopee):
 
155
    """Adds a snoop pair to the snoop table and activates the snooping hook for
 
156
    the snooped character"""
 
157
    if snoopee not in get_snoopees(False):
 
158
        hooks.add("snoop_%s" % snoopee.name, snoop_hook)
 
159
    if snooper in _snooptbl:
 
160
        _snooptbl[snooper].append(snoopee)
 
161
    else:
 
162
        _snooptbl[snooper] = [snoopee]
 
163
    return True
 
164
 
 
165
def del_snoop(snooper, snoopee=None):
 
166
    """Removes a snoop pair from the snoop table, and removes the hook if
 
167
    necessary.
 
168
    If snoopee is None, it will remove the snooper completely from the table.
 
169
    
 
170
    Returns True if something was deleted, else False"""
 
171
    snoopees = get_snoopees()
 
172
    
 
173
    if not snooper in _snooptbl:
 
174
        return False
 
175
    elif not snoopee:
 
176
        for char in _snooptbl[snooper]:
 
177
            if char in snoopees:
 
178
                hooks.remove("snoop_%s" % char.name, snoop_hook)
 
179
        del _snooptbl[snooper]
 
180
        return True
 
181
    elif snoopee in _snooptbl[snooper]:
 
182
        if snoopee in snoopees:
 
183
           hooks.remove("snoop_%s" % snoopee.name, snoop_hook)
 
184
        _snooptbl[snooper].remove(snoopee)
 
185
        # Was that the last one? If so, clean up
 
186
        if len(_snooptbl[snooper]) == 0:
 
187
            del _snooptbl[snooper]
 
188
        return True
 
189
    return False
 
190
    
 
191
 
 
192
def check_snoop_enter_game(info):
 
193
    ch, = hooks.parse_info(info)
 
194
    if not ch.is_pc:
 
195
        return
 
196
    snptable = get_snoopees()
 
197
    if ch in snptable:
 
198
        for snooper in snptable[ch]:
 
199
            snooper.send('[SNOOP: %s has come online. Snooping resumed.]'
 
200
                         % ch.name)
 
201
 
 
202
def check_snoop_leave_game(info):
 
203
    ch, = hooks.parse_info(info)
 
204
    if not ch.is_pc:
 
205
        return
 
206
    snoopees = get_snoopees(False, True)
 
207
    snoopers = get_snoopers(False)
 
208
    
 
209
    if ch in snoopees:
 
210
        for snooper in snoopees[ch]:
 
211
            snooper.send('[SNOOP: %s has gone offline. Snooping suspended.]'
 
212
                             % ch.name)
 
213
    if ch in snoopers:
 
214
        del_snoop(ch)
 
215
 
 
216
mudsys.add_cmd("snoop", None, cmd_snoop, "admin", False)
 
217
 
 
218
hooks.add("char_to_game", check_snoop_enter_game)
 
219
hooks.add("char_from_game", check_snoop_leave_game)
 
220