diff --git a/#firebot.py# b/#firebot.py# deleted file mode 100755 index d676162..0000000 --- a/#firebot.py# +++ /dev/null @@ -1,451 +0,0 @@ -#! /usr/bin/env python - -import os -import sys -import re -import random -from webretriever import WebRetriever -import asynchat, asyncore -import socket -import csv -import adns -import time - -import procbot -import shorturl -import infobot - -Runner = procbot.Runner -esc = procbot.esc - -URLSERVER = ("", 0) - -class SSLSock: - def __init__(self, sock): - self.sock = sock - self.sock.setblocking(1) - self.ssl = socket.ssl(sock) - - def send(self, data): - self.ssl.write(data) - - def recv(self, bufsize): - return self.ssl.read(bufsize) - - def close(self): - self.sock.close() - -class FireBot(infobot.InfoBot, procbot.ProcBot): - #debug = True - - bindings = [] - msg_cat = {} - heartbeat_interval = 0.5 - ping_interval = 120 - - def __init__(self, host, nicks, gecos, channels, dbname='info.db', ssl=False, **kwargs): - infobot.InfoBot.__init__(self, host, nicks, gecos, channels, - **kwargs) - self.ssl = ssl - self.nosy = True - self.seen = {} - - def handle_connect(self): - if self.ssl: - self.plain_sock = self.socket - self.socket = SSLSock(self.socket) - infobot.InfoBot.handle_connect(self) - - def send_ping(self): - # Send keepalives to the server to see if we've lost - # connection. For some reason, using SSL prevents us from - # getting a RST. - self.write('PING %f' % time.time()) - self.add_timer(self.ping_interval, - self.send_ping) - - def cmd_001(self, sender, forum, addl): - infobot.InfoBot.cmd_001(self, sender, forum, addl) - self.add_timer(self.ping_interval, - self.send_ping) - - def note(self, sender, forum, addl, match): - whom = match.group('whom') - what = match.group('what') - when = time.time() - note = "%f:%s:%s" % (when, sender.name(), what) - n = self.getall(whom, special="note") - n.append(note) - self.set(whom, n, special="note") - forum.msg(self.gettext('okay', sender=sender.name())) - bindings.append((re.compile(r"^\008[:, ]+note (to )?(?P[^: ]+):? +(?P.*)"), - note)) - bindings.append((re.compile(r"^\008[:, ]+later tell (?P[^: ]+):? +(?P.*)"), - note)) - - def cmd_privmsg(self, sender, forum, addl): - infobot.InfoBot.cmd_privmsg(self, sender, forum, addl) - - if forum.is_channel(): - who = sender.name() - - # Update seen - text = addl[0] - now = time.time() - self.seen[who] = (now, text) - - # Deliver notes - n = self.getall(who, special="note") - if n: - notes = ["Welcome back, %s. You have %d notes:" % (who, len(n))] - for note in n: - when, whom, what = note.split(':', 2) - try: - notes.append(u"%s: %s <%s> %s" % (who, - time.ctime(float(when)), - whom, - what)) - except UnicodeDecodeError: - notes.append(u"%s" % ((who, - time.ctime(note[0]), - note[1], - note[2]),)) - self.despool(forum, notes) - self.delete(who, special="note") - - ## - ## Firebot stuff - ## - - def seen(self, sender, forum, addl, match): - whom = match.group('whom') - if whom == sender.name(): - forum.msg('Cute, %s.' % whom) - return - last = self.seen.get(whom) - now = time.time() - if last: - when = now - last[0] - units = 'seconds' - if when > 120: - when /= 60 - units = 'minutes' - if when > 120: - when /= 60 - units = 'hours' - if when > 48: - when /= 24 - units = 'days' - forum.msg('I last saw %s %d %s ago, saying "%s"' % - (whom, when, units, last[1])) - else: - forum.msg("I've never seen %s!" % (whom)) - bindings.append((re.compile(r"^seen +(?P.*)$"), - seen)) - - def evalstr(self, sender, forum, addl, match): - code = match.group('code') - if code in (')', '-)'): - return True - try: - ret = repr(eval(code, {"__builtins__": {}}, {})) - if len(ret) > 400: - ret = ret[:400] + '\026...\026' - except: - t, v, tb = sys.exc_info() - forum.msg(self.gettext('eval', code=code, ret='\002%s\002: %s' % (t, v), sender=sender.name())) - else: - forum.msg(self.gettext('eval', code=code, ret=ret, sender=sender.name())) - #bindings.append((re.compile(r"^\; *(?P.+)$"), evalstr)) - #msg_cat['eval'] = ('%(code)s ==> %(ret)s',) - - def shorturl(self, sender, forum, addl, match): - url = match.group('url') - print ('url', url) - idx = shorturl.add(url) - forum.msg('http://%s:%d/%d' % (URLSERVER[0], URLSERVER[1], idx)) - bindings.append((re.compile(r".*\b(?P\b[a-z]+://[-a-z0-9_=!?#$@~%&*+/:;.,\w]+[-a-z0-9_=#$@~%&*+/\w])"), - shorturl)) - - def cdecl(self, sender, forum, addl, match): - jibberish = match.group('jibberish') - o, i = os.popen2('/usr/bin/cdecl') - o.write(jibberish + '\n') - o.close() - res = i.read().strip() - if '\n' in res: - forum.msg("Lots of output, sending in private message") - self.despool(sender, res.split('\n')) - else: - forum.msg('cdecl | %s' % res) - bindings.append((re.compile(r"^cdecl (?P.*)$"), - cdecl)) - - def delayed_say(self, sender, forum, addl, match): - delay = int(match.group('delay')) - unit = match.group('unit') - what = match.group('what') - - if not unit or unit[0] == 's': - pass - elif unit[0] == 'm': - delay *= 60 - elif unit[0] == 'h': - delay *= 3600 - elif unit[0] == 'd': - delay *= 86400 - elif unit[0] == 'w': - delay *= 604800 - else: - forum.msg("I don't know what a %s is." % unit) - return - - self.add_timer(delay, lambda : forum.msg(what)) - forum.msg(self.gettext('okay', sender=sender.name())) - bindings.append((re.compile(r"^\008[:, ]+in (?P[0-9]+) ?(?P[a-z]*) say (?P.*)"), - delayed_say)) - - msg_cat['nodict'] = ("Sorry, boss, dict returns no lines for %(jibberish)s",) - def dict(self, sender, forum, addl, match): - jibberish = match.group('jibberish') - i = os.popen('/usr/bin/dict %s 2>&1' % esc(jibberish)) - res = i.readlines() - if not res: - forum.msg(self.gettext('nodict', jibberish=jibberish)) - return - res = [l.strip() for l in res] - if match.group('long'): - self.despool(sender, res) - else: - if len(res) <= 5: - self.despool(forum, res) - else: - del res[:4] - short = res[:] - while short and ((not short[0]) or (short[0][0] not in '0123456789')): - del short[0] - if not short: - short = res - short = ['%s: %s' % (jibberish, r) for r in short[:4]] - self.despool(forum, short + ['[truncated: use the --long option to see it all]']) - bindings.append((re.compile(r"^dict (?P--?l(ong)? +)?(?P.*)$"), - dict)) - - def units(self, sender, forum, addl, match): - f = match.group('from') - t = match.group('to') - if f.startswith('a '): - f = '1 ' + f[2:] - Runner('/usr/bin/units -v %s %s' % (esc(f), esc(t)), - lambda l,r: self.proc_cb(None, sender, forum, l, r)) - bindings.append((re.compile(r"^units +(?P.*) +in +(?P.*)$"), - units)) - bindings.append((re.compile(r"^how many (?P.*) in (?P[^?]*)[?.!]*$"), - units)) - - def calc(self, sender, forum, addl, match): - e = match.group('expr') - Runner("echo %s | /usr/bin/bc -l" % procbot.esc(e), - lambda l,r: self.proc_cb('%s = ' % e, sender, forum, l, r)) - bindings.append((re.compile(r"^(?P[0-9.]+\s*[-+*/^%]\s*[0-9.]+)$"), - calc)) - bindings.append((re.compile(r"^calc (?P.+)$"), - calc)) - - def generic_cmd(self, sender, forum, addl, match): - cmd = match.group('cmd') - args = match.group('args').split(' ') - argstr = ' '.join(procbot.lesc(args)) - Runner('%s %s' % (cmd, argstr), - lambda l,r: self.proc_cb(None, sender, forum, l, r)) - bindings.append((re.compile(r"^(?Phost) (?P.+)$"), - generic_cmd)) - bindings.append((re.compile(r"^(?Pwhois) (?P.+)$"), - generic_cmd)) - - def pollen(self, sender, forum, addl, match): - forecast_re = re.compile('fimages/std/(?P[0-9]+\.[0-9])\.gif') - predom_re = re.compile('Predominant pollen: (?P[^<]*)') - zip = match.group('zip') - def cb(lines): - forecast = [] - predom = '' - for line in lines: - match = forecast_re.search(line) - if match: - forecast.append(match.group('count')) - match = predom_re.search(line) - if match: - predom = match.group('pollens') - forum.msg('%s: 4-day forecast (out of 12.0): %s; predominant pollen: %s' % - (zip, ', '.join(forecast), predom)) - WebRetriever('http://www.pollen.com/forecast.asp?PostalCode=%s&Logon=Enter' % zip, - cb) - bindings.append((re.compile('pollen (?P[0-9]{5})'), - pollen)) - - - bindings.append((re.compile('weather (?P[0-9]{5})'), - weather)) - - def quote(self, sender, forum, addl, match): - def cb(lines): - if not lines: - forum.msg('oops, no data from server') - return - c = csv.reader([lines[0].strip()]) - vals = zip(('symbol', 'value', 'day', 'time', 'change', - 'open', 'high', 'low', 'volume', - 'market cap', 'previous close', - 'percent change', 'open2', 'range', - 'eps', 'pe_ratio', 'name'), - c.next()) - d = dict(vals) - forum.msg(('%(name)s (%(symbol)s)' - ' last:%(value)s@%(time)s' - ' vol:%(volume)s' - ' cap:%(market cap)s' - ' prev-close:%(previous close)s' - ' chg:%(change)s(%(percent change)s)' - ' open:%(open)s' - ' 1d:%(low)s - %(high)s' - ' 52wk:%(range)s') % - d) - - symbol = match.group('symbol') - WebRetriever('http://quote.yahoo.com/d/quotes.csv?s=%s&f=sl1d1t1c1ohgvj1pp2owern&e=.csv' % symbol, - cb) - bindings.append((re.compile(r"^quote +(?P[.a-zA-Z]+)$"), - quote)) - - def currency(self, sender, forum, addl, match): - amt = float(match.group('amt')) - frm = match.group('from') - to = match.group('to') - - def cb(lines): - if not lines: - forum.msg('oops, no data from server') - return - c = csv.reader([lines[0].strip()]) - vals = zip(('symbol', 'value', 'day', 'time', 'change', - 'open', 'high', 'low', 'volume', - 'market cap', 'previous close', - 'percent change', 'open2', 'range', - 'eps', 'pe_ratio', 'name'), - c.next()) - d = dict(vals) - v = float(d['value']) - ans = v * amt - forum.msg(('%0.4f %s = %0.4f %s') % - (amt, frm, ans, to)) - - WebRetriever(('http://quote.yahoo.com/d/quotes.csv?s=%s%s%%3DX&f=sl1d1t1c1ohgvj1pp2owern&e=.csv' % - (frm, to)), - cb) - bindings.append((re.compile(r"^how much is (?P[0-9.]+) ?(?P[A-Z]{3}) in (?P[A-Z]{3})\??$"), - currency)) - - def whuffie_mod(self, nick, amt): - vs = self.get(nick, "0", special="whuffie") - try: - val = int(vs) - except: - val = 0 - val += amt - self.set(nick, [str(val)], special="whuffie") - - def whuffie_modify(self, sender, forum, addl, match): - nick = match.group('nick') - if nick.lower() == sender.name().lower(): - forum.msg(self.gettext('whuffie whore', sender=sender.name())) - return - if match.group('mod') == '++': - amt = 1 - else: - amt = -1 - self.whuffie_mod(nick, amt) - bindings.append((re.compile(r"^(?P\w+)(?P\+\+|\-\-)[? ]*$"), - whuffie_modify)) - msg_cat['whuffie whore'] = ("Nothing happens.", - 'A hollow voice says, "Fool."') - - def whuffie(self, sender, forum, addl, match): - nick = match.group('nick') - val = self.get(nick, special="whuffie") - if val and val != "0": - forum.msg("%s has whuffie of %s" % (nick, val)) - else: - forum.msg("%s has neutral whuffie" % nick) - bindings.append((re.compile(r"^(\008[,:] +)?([Ww]huffie|[Kk]arma) (for )?(?P\w+)[? ]*$"), - whuffie)) - - # - # This is all stuff that should just be stored in the usual manner. - # But I wrote it here before I realized how programmable an Infobot - # really is, so here it stays. - # - - msg_cat['8ball'] = ("%(sender)s: Outlook good.", - "%(sender)s: Outlook not so good.", - "%(sender)s: My reply is no.", - "%(sender)s: Don't count on it.", - "%(sender)s: You may rely on it.", - "%(sender)s: Ask again later.", - "%(sender)s: Most likely.", - "%(sender)s: Cannot predict now.", - "%(sender)s: Yes.", - "%(sender)s: Yes, definitely.", - "%(sender)s: Better not tell you now.", - "%(sender)s: It is certain.", - "%(sender)s: Very doubtful.", - "%(sender)s: It is decidedly so.", - "%(sender)s: Concentrate and ask again.", - "%(sender)s: Signs point to yes.", - "%(sender)s: My sources say no.", - "%(sender)s: Without a doubt.", - "%(sender)s: Reply hazy, try again.", - "%(sender)s: As I see it, yes.") - msg_cat['me'] = ('%(sender)s?', - '%(sender)s: Yes?', - 'At your service, %(sender)s.', - 'May I help you, %(sender)s?') - msg_cat['thanks'] = ('It is my pleasure, %(sender)s.', - 'Of course, %(sender)s.', - 'I live but to serve, %(sender)s.', - "All in a day's work, %(sender)s.") - bindings.append((re.compile(r"^(magic )?(8|eight ?)-?ball", re.IGNORECASE), - '8ball')) - bindings.append((re.compile(r"^\008\?$", re.IGNORECASE), - 'me')) - bindings.append((re.compile(r"^thank(s| you),? *\008", re.IGNORECASE), - 'thanks')) - - msg_cat.update(infobot.InfoBot.msg_cat) - bindings.extend(infobot.InfoBot.bindings) - - -if __name__ == "__main__": - import irc - - # Short URL server - us = shorturl.start(('', 0)) - URLSERVER = (socket.gethostbyaddr(socket.gethostname())[0], - us.getsockname()[1]) - - - NICK = ['hal'] - INFO = 'Daisy, Daisy...' - - l1 = FireBot(("server1", 6667), - NICK, - INFO, - ["#ch1", "#ch2"]) - l2 = FireBot(('server2', 6667), - NICK, - INFO, - ["#ch3"]) - l1.set_others([l2]) - l2.set_others([l1]) - - irc.run_forever(0.5)