Update to freenode's new capability mechanism
[people/stefanha/gpxebot.git] / cmds.py
diff --git a/cmds.py b/cmds.py
index 7d0d164..82defdf 100644 (file)
--- a/cmds.py
+++ b/cmds.py
@@ -17,20 +17,28 @@ op_commands = {}
 op_members = [config.NICK]
 aliases = {}
 
 op_members = [config.NICK]
 aliases = {}
 
+class Who(object):
+    def __init__(self, mask, is_identified=False):
+        self.mask = mask
+        self.nick = mask.split('!', 1)[0]
+        self.is_identified = is_identified
+
+    def is_op(self):
+        return self.is_identified and self.nick in op_members
+
 def readrc_command(who=None, target=None, replyto=None, words=None):
     '''Source bot command file (readrc)'''
     try:
 def readrc_command(who=None, target=None, replyto=None, words=None):
     '''Source bot command file (readrc)'''
     try:
-        f = open(config.RCFILE).readlines()
+        cmd = []
+        for line in open(config.RCFILE):
+            response = do_command(Who(config.NICK, True), config.NICK, config.NICK, line.split())
+            if isinstance(response, list):
+                cmd += response
+            elif response:
+                cmd.append(response)
+        return cmd
     except IOError:
         return 'PRIVMSG', (replyto, 'unable to open file')
     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())
-        if isinstance(response, list):
-            cmd += response
-        elif response:
-            cmd.append(response)
-    return cmd
 op_commands['readrc'] = readrc_command
 
 def alias_command(who, _, replyto, words):
 op_commands['readrc'] = readrc_command
 
 def alias_command(who, _, replyto, words):
@@ -70,7 +78,6 @@ ERRCODE_RE = re.compile(r'((?:0x)?[0-9a-fA-F]{8})')
 
 def errcode_command(who, _, replyto, words):
     '''Look up gPXE error code (errcode 0x12345678)'''
 
 def errcode_command(who, _, replyto, words):
     '''Look up gPXE error code (errcode 0x12345678)'''
-    # errcode 0x12345678
     msg = ' '.join(words)
     m = ERRCODE_RE.search(msg)
     if m:
     msg = ' '.join(words)
     m = ERRCODE_RE.search(msg)
     if m:
@@ -81,6 +88,45 @@ def errcode_command(who, _, replyto, words):
 commands['errcode'] = errcode_command
 commands['error'] = errcode_command
 
 commands['errcode'] = errcode_command
 commands['error'] = errcode_command
 
+def lspci_command(who, _, replyto, words):
+    '''Look up driver for PCI ID (lspci 10ec:8139)'''
+    ids = []
+    if len(words) == 2:
+        ids = words[1].split(':')
+    elif len(words) == 3:
+        ids = words[1:3]
+    if len(ids) != 2:
+        return 'PRIVMSG', (replyto, 'Invalid arguments')
+
+    try:
+        vendor_id, device_id = [int(s, 16) for s in ids]
+    except ValueError:
+        return 'PRIVMSG', (replyto, 'Invalid arguments')
+    pci_id = '%04x,%04x' % (vendor_id, device_id)
+
+    try:
+        for line in open(config.NICFILE):
+            line = line.rstrip('\r\n')
+            if not line or line.startswith('#'):
+                continue
+            fields = line.split('\t')
+
+            if fields[0] == 'family':
+                driver = fields[1].split('/')[-1]
+                continue
+
+            if fields[1] == pci_id:
+                return 'PRIVMSG', (replyto, driver)
+    except IndexError, e:
+        utils.dbg(str(e))
+    except IOError, e:
+        utils.dbg(str(e))
+    return 'PRIVMSG', (replyto, 'No driver found')
+if config.NICFILE:
+    commands['lspci'] = lspci_command
+else:
+    sys.stderr.write('running without lspci support (NICFILE not given)\n')
+
 def help_command(who, _, replyto, msg):
     '''List commands (help)'''
     def do_help(vocabulary):
 def help_command(who, _, replyto, msg):
     '''List commands (help)'''
     def do_help(vocabulary):
@@ -93,7 +139,7 @@ def help_command(who, _, replyto, msg):
                 output.append(('PRIVMSG', (replyto, '%s    %s' % (name.ljust(max_width), cmd.__doc__))))
         return output
     output = do_help(commands)
                 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:
+    if who.is_op():
         output.extend(do_help(op_commands))
     return output
 commands['help'] = help_command
         output.extend(do_help(op_commands))
     return output
 commands['help'] = help_command
@@ -102,60 +148,73 @@ def log_command(who, target, replyto, words):
     '''Control channel logging (log start, log stop, log list)'''
     if len(words) < 2:
         return
     '''Control channel logging (log start, log stop, log list)'''
     if len(words) < 2:
         return
-    channel = target
-    if len(words) >= 3:
-        channel = words[2].startswith('#') and words[2] or target
-    if words[1] == 'start':
+
+    # Parse arguments
+    words.pop(0)
+    cmd     = words.pop(0)
+    channel = words and words[0].startswith('#') and words.pop(0) or target
+    emails  = words and words.pop(0) or ''
+    subject = ' '.join(words)
+
+    if cmd == 'start':
         if channel in logs:
             return 'PRIVMSG', (replyto, 'Logging %s already started' % channel)
         if channel in logs:
             return 'PRIVMSG', (replyto, 'Logging %s already started' % channel)
-        cmd = []
+        output = []
         if channel.startswith('#') and channel != target:
         if channel.startswith('#') and channel != target:
-            cmd.append(('CMD', ('JOIN %s' % channel,)))
-        name = utils.make_log(channel)
-        f = open(name, 'w')
-        logs[channel] = (name, f)
-        cmd.append(('PRIVMSG', (replyto, 'Start logging %s...' % channel)))
-        return cmd
+            output.append(('CMD', ('JOIN %s' % channel,)))
+        filename = utils.make_log(channel)
+        logs[channel] = {
+            'filename': filename,
+            'fileobj': open(filename, 'w'),
+            'emails': emails,
+            'subject': subject,
+        }
+        output.append(('PRIVMSG', (replyto, 'Start logging %s...' % channel)))
+        return output
 
 
-    elif words[1] == 'stop':
+    elif cmd == 'stop':
         if not channel in logs:
             return 'PRIVMSG', (replyto, 'Logging %s not started yet' % channel)
         if not channel in logs:
             return 'PRIVMSG', (replyto, 'Logging %s not started yet' % channel)
-        (name, f) = logs.pop(channel)
-        f.close()
-
-        to_address = None
-        if len(words) >= 3 and words[-1] != channel:
-            to_address = words[-1]
-        if to_address:
-            unrecognized = utils.email_log(to_address, channel, name, aliases)
-            cmd = [('PRIVMSG', (replyto, 'Unrecognized user %s' % user)) for user in unrecognized]
-        return [('PRIVMSG', (replyto, 'Stop logging %s.  Saved log file (%s)' % (channel, name)))] + cmd
-
-    elif words[1] == 'list':
-        return 'PRIVMSG', (replyto, 'Logging: %s' % ','.join(logs.keys()))
+        log = logs.pop(channel)
+        log['fileobj'].close()
+
+        if not emails:
+            emails = log['emails']
+        if not subject:
+            subject = log['subject']
+        if not subject:
+            subject = 'IRC logs for ' + channel
+
+        unrecognized = utils.email_log(emails, subject, log['filename'], aliases)
+        output = [('PRIVMSG', (replyto, 'Unrecognized alias %s' % user)) for user in unrecognized]
+        output.append(('PRIVMSG', (replyto, 'Stop logging %s.  Saved log file (%s)' % (channel, log['filename']))))
+        return output
+
+    elif cmd == 'list':
+        return [('PRIVMSG', (replyto, channel)) for channel in logs.keys()]
 op_commands['log'] = log_command
 
 def join_command(who, target, replyto, words):
     '''Join a channel (join #etherboot)'''
 op_commands['log'] = log_command
 
 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),)
+    if len(words) != 2:
+        return
+    channel = words[1]
+    return 'CMD', ('JOIN %s' % (channel.startswith('#') and channel or '#' + channel),)
 op_commands['join'] = join_command
 
 def part_command(who, target, replyto, words):
     '''Leave a channel (part #etherboot)'''
 op_commands['join'] = join_command
 
 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),)
+    if len(words) != 2:
+        return
+    channel = words[1]
+    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
 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:])))
+    return 'PRIVMSG', (words[1], ' '.join(words[2:]))
 op_commands['privmsg'] = privmsg_command
 
 def restart_command(who, target, replyto, words):
 op_commands['privmsg'] = privmsg_command
 
 def restart_command(who, target, replyto, words):
@@ -168,7 +227,7 @@ def do_command(who, target, replyto, words):
         return
     command = words[0].lower()
 
         return
     command = words[0].lower()
 
-    if utils.nick_from_mask(who) in op_members and command in op_commands:
+    if who.is_op() and command in op_commands:
         return op_commands[command](who, target, replyto, words)
     if command in commands:
         return commands[command](who, target, replyto, words)
         return op_commands[command](who, target, replyto, words)
     if command in commands:
         return commands[command](who, target, replyto, words)