mirror of https://github.com/nealey/firebot
115 lines
3.1 KiB
Python
115 lines
3.1 KiB
Python
|
import irc
|
||
|
import re
|
||
|
import random
|
||
|
import types
|
||
|
|
||
|
class Match:
|
||
|
"""A wrapper around a regex match, to replace \008 with a word.
|
||
|
|
||
|
"""
|
||
|
|
||
|
def __init__(self, m, txt):
|
||
|
self.m = m
|
||
|
self.txt = txt
|
||
|
|
||
|
def group(self, grp):
|
||
|
g = self.m.group(grp)
|
||
|
if g:
|
||
|
g = g.replace('\008', self.txt)
|
||
|
return g
|
||
|
|
||
|
|
||
|
class BindingsBot(irc.Bot):
|
||
|
"""An IRC bot with regex function bindings
|
||
|
|
||
|
You can bind functions to things said in the channel by regular
|
||
|
expression with this. See wouldmatch for an example of how to do
|
||
|
this.
|
||
|
"""
|
||
|
|
||
|
msg_cat = {} # message catalog
|
||
|
bindings = [] # function/catalog bindings to regexen
|
||
|
|
||
|
def __init__(self, *gar):
|
||
|
irc.Bot.__init__(self, *gar)
|
||
|
self.last_tb = "Nothing's gone wrong yet!"
|
||
|
|
||
|
def err(self, exception):
|
||
|
"""Save the traceback for later inspection"""
|
||
|
irc.Bot.err(self, exception)
|
||
|
t,v,tb = exception
|
||
|
tbinfo = []
|
||
|
while 1:
|
||
|
tbinfo.append ((
|
||
|
tb.tb_frame.f_code.co_filename,
|
||
|
tb.tb_frame.f_code.co_name,
|
||
|
str(tb.tb_lineno)
|
||
|
))
|
||
|
tb = tb.tb_next
|
||
|
if not tb:
|
||
|
break
|
||
|
# just to be safe
|
||
|
del tb
|
||
|
file, function, line = tbinfo[-1]
|
||
|
info = '[' + '] ['.join(map(lambda x: '|'.join(x), tbinfo)) + ']'
|
||
|
self.last_tb = '%s %s %s' % (t, v, info)
|
||
|
print self.last_tb
|
||
|
|
||
|
def matches(self, text):
|
||
|
matches = []
|
||
|
btext = text.replace(self.nick, '\008')
|
||
|
for b in self.bindings:
|
||
|
m = b[0].match(btext)
|
||
|
if m:
|
||
|
matches.append((m, b))
|
||
|
return matches
|
||
|
|
||
|
def cmd_privmsg(self, sender, forum, addl):
|
||
|
for m, b in self.matches(addl[0]):
|
||
|
f = b[1]
|
||
|
if callable(f):
|
||
|
cont = f(self, sender, forum, addl, Match(m, self.nick))
|
||
|
elif type(f) == types.StringType:
|
||
|
forum.msg(self.gettext(f, sender=sender.name(),
|
||
|
forum=forum.name(), me=self.nick))
|
||
|
cont = False
|
||
|
else:
|
||
|
raise ValueError("Can't handle type of %s", `f`)
|
||
|
if not cont:
|
||
|
break
|
||
|
|
||
|
def gettext(self, msg, **dict):
|
||
|
"""Format a message from the message catalog.
|
||
|
|
||
|
Retrieve from the message catalog the message specified by msg,
|
||
|
filling in arguments as specified by dict.
|
||
|
|
||
|
"""
|
||
|
|
||
|
m = random.choice(self.msg_cat[msg])
|
||
|
return m % dict
|
||
|
|
||
|
def tbinfo(self, sender, forum, addl, match):
|
||
|
forum.msg(self.last_tb)
|
||
|
bindings.append((re.compile(r"^\008[,: ]+(tbinfo|traceback)$"),
|
||
|
tbinfo))
|
||
|
|
||
|
def wouldmatch(self, sender, forum, addl, match):
|
||
|
"""Show what binding would be matched"""
|
||
|
|
||
|
text = match.group(1)
|
||
|
matches = self.matches(text)
|
||
|
m = [i[1][1] for i in matches]
|
||
|
forum.msg('%s => %s' % (`text`, `m`))
|
||
|
bindings.append((re.compile(r"^\008[,: ]+match (.+)$"),
|
||
|
wouldmatch))
|
||
|
|
||
|
#
|
||
|
# Message catalog
|
||
|
#
|
||
|
|
||
|
msg_cat['okay'] = ('Okay, %(sender)s.',)
|
||
|
|
||
|
|
||
|
|