Simple help system with command descriptions
[people/stefanha/gpxebot.git] / cmds.py
diff --git a/cmds.py b/cmds.py
index 2914442..7d0d164 100644 (file)
--- a/cmds.py
+++ b/cmds.py
@@ -1,9 +1,15 @@
 import re
+import sys
 import time
 
 import config
 import utils
-import errcode
+
+# For development an errcode database may not be available
+try:
+    import errcode
+except ImportError:
+    sys.stderr.write('running without errcode support\n')
 
 logs = {}
 commands = {}
@@ -11,8 +17,12 @@ op_commands = {}
 op_members = [config.NICK]
 aliases = {}
 
-def readrc_command(target=None, replyto=None, words=None):
-    f = open(config.RCFILE).readlines()
+def readrc_command(who=None, target=None, replyto=None, words=None):
+    '''Source bot command file (readrc)'''
+    try:
+        f = open(config.RCFILE).readlines()
+    except IOError:
+        return 'PRIVMSG', (replyto, 'unable to open file')
     cmd = []
     for line in f:
         response = do_command(config.NICK, config.NICK, config.NICK, line.split())
@@ -23,8 +33,8 @@ def readrc_command(target=None, replyto=None, words=None):
     return cmd
 op_commands['readrc'] = readrc_command
 
-def alias_command(_, replyto, words):
-    # alias stefanha stefanha@gmail.com
+def alias_command(who, _, replyto, words):
+    '''Add or list email aliases (alias stefanha stefanha@gmail.com)'''
     if len(words) == 2:
         if words[1].lower() == 'list':
             return [('PRIVMSG', (replyto, '%s    %s' % (user, email))) for (user, email) in aliases.items()]
@@ -35,8 +45,11 @@ def alias_command(_, replyto, words):
     aliases[user] = email
 op_commands['alias'] = alias_command
 
-def op_command(target, replyto, words):
-    # op stefanha
+def op_command(who, target, replyto, words):
+    '''Add or list bot operators (op stefanha, op list)'''
+    if len(words) == 2:
+        if words[1].lower() == 'list':
+            return [('PRIVMSG', (replyto, '%s' % nick)) for nick in op_members]
     if len(words) < 2:
         return
     nick = words[1]
@@ -44,8 +57,8 @@ def op_command(target, replyto, words):
         op_members.append(nick)
 op_commands['op'] = op_command
 
-def deop_command(target, replyto, words):
-    # deop stefanha
+def deop_command(who, target, replyto, words):
+    '''Remove bot operators (deop stefanha)'''
     if len(words) < 2:
         return
     nick = words[1]
@@ -55,7 +68,8 @@ op_commands['deop'] = deop_command
 
 ERRCODE_RE = re.compile(r'((?:0x)?[0-9a-fA-F]{8})')
 
-def errcode_command(_, replyto, words):
+def errcode_command(who, _, replyto, words):
+    '''Look up gPXE error code (errcode 0x12345678)'''
     # errcode 0x12345678
     msg = ' '.join(words)
     m = ERRCODE_RE.search(msg)
@@ -67,14 +81,25 @@ def errcode_command(_, replyto, words):
 commands['errcode'] = errcode_command
 commands['error'] = errcode_command
 
-def help_command(_, replyto, msg):
-    cmd = []
-    cmd.append(('PRIVMSG', (replyto, 'I look up gPXE error codes.  Message me like this:')))
-    cmd.append(('PRIVMSG', (replyto, 'errcode 0x12345678  OR  Error 0x12345678')))
-    return cmd
+def help_command(who, _, replyto, msg):
+    '''List commands (help)'''
+    def do_help(vocabulary):
+        output = []
+        names = sorted(vocabulary.keys())
+        max_width = max(len(name) for name in names)
+        for name in names:
+            cmd = vocabulary[name]
+            if hasattr(cmd, '__doc__'):
+                output.append(('PRIVMSG', (replyto, '%s    %s' % (name.ljust(max_width), cmd.__doc__))))
+        return output
+    output = do_help(commands)
+    if utils.nick_from_mask(who) in op_members:
+        output.extend(do_help(op_commands))
+    return output
 commands['help'] = help_command
 
-def log_command(target, replyto, words):
+def log_command(who, target, replyto, words):
+    '''Control channel logging (log start, log stop, log list)'''
     if len(words) < 2:
         return
     channel = target
@@ -110,20 +135,31 @@ def log_command(target, replyto, words):
         return 'PRIVMSG', (replyto, 'Logging: %s' % ','.join(logs.keys()))
 op_commands['log'] = log_command
 
-def join_command(target, replyto, words):
+def join_command(who, target, replyto, words):
+    '''Join a channel (join #etherboot)'''
     index = words.index('join') + 1
     if index < len(words):
         channel = words[index]
         return 'CMD', ('JOIN %s' % (channel.startswith('#') and channel or '#' + channel),)
 op_commands['join'] = join_command
 
-def privmsg_command(target, replyto, words):
+def part_command(who, target, replyto, words):
+    '''Leave a channel (part #etherboot)'''
+    index = words.index('part') + 1
+    if index < len(words):
+        channel = words[index]
+        return 'CMD', ('PART %s' % (channel.startswith('#') and channel or '#' + channel),)
+op_commands['part'] = part_command
+
+def privmsg_command(who, target, replyto, words):
+    '''Send a chat message (privmsg #etherboot Hello all!)'''
     if len(words) < 3:
         return
     return ('PRIVMSG', (words[1], ' '.join(words[2:])))
 op_commands['privmsg'] = privmsg_command
 
-def restart_command(target, replyto, words):
+def restart_command(who, target, replyto, words):
+    '''Restart bot (restart)'''
     return ('RESTART', ())
 op_commands['restart'] = restart_command
 
@@ -132,7 +168,7 @@ def do_command(who, target, replyto, words):
         return
     command = words[0].lower()
 
-    if command in commands:
-        return commands[command](target, replyto, words)
     if utils.nick_from_mask(who) in op_members and command in op_commands:
-        return op_commands[command](target, replyto, words)
+        return op_commands[command](who, target, replyto, words)
+    if command in commands:
+        return commands[command](who, target, replyto, words)