176 lines
5.6 KiB
Executable File

#! /usr/bin/env python
import firebot
from finger import Finger
from procbot import ProcBot, Runner
import shorturl
import asyncore
import irc
import re
import os
import time
import socket
import rp
import random
import webretriever
webretriever.proxy = ('', 8080)
def esc(arg):
return "'" + arg.replace("'", r"'\''") + "'"
def lesc(args):
return [esc(arg) for arg in args]
class Arsenic(firebot.FireBot, ProcBot):
debug = False
bindings = []
ping_interval = 120
chatty = True # Maybe #x can play nice now
def __init__(self, *args, **kwargs):
firebot.FireBot.__init__(self, *args, **kwargs)
self.seen = {}
self.lusers = {}
self.lag = 0
self.whinecount = 0
def runcmd(self, sender, forum, addl, match):
command ='command')
args = lesc(lesc('args').split(' ')))
argstr = ' '.join(args)
print argstr
Runner('%s %s' % (command, argstr),
lambda l,r: self.proc_cb('%s: ' % command, sender, forum, l, r))
bindings.append((re.compile(r"^(?P<command>whois) +(?P<args>.*)$"),
bindings.append((re.compile(r"^(?P<command>host) +(?P<args>.*)$"),
def rp(self, sender, forum, addl, match):
long ='long') and True
conn = rp.make_connection()
rows = rp.rp('args').strip(), conn=conn)
ret = rp.format(rows, long=long)
if long:
forum.msg('[Sending privately]')
self.despool(sender, ret)
self.despool(forum, ret)
bindings.append((re.compile(r"^rp +(?P<long>(-l|--long) +)?(?P<args>.*)$"),
def finger(self, sender, forum, addl, match):
command = 'finger'
argstr ='args')
Finger(('', 79),
lambda l: self.proc_cb('%s: ' % command, sender, forum, l, 0))
bindings.append((re.compile(r"^(?P<command>finger) +(?P<args>.*)$"),
def lag(self, sender, forum, addl, match):
forum.msg("My server lag is %.3f seconds." % self.lag)
bindings.append((re.compile(r"^\008[,: ]+ (what is the )?(server )?lag"),
def pii(self, sender, forum, addl, match):
ssns = []
for i in range(10):
ssns.append('%03d-%02d-%04d' % (random.randint(1, 999),
random.randint(1, 99),
random.randint(1, 9999)))
forum.msg('Security incident! %s' % ' '.join(ssns))
## IRC protocol-level extensions
def add_luser(self, luser, channel):
# Keeps track of what users have been on what channels, and
# sends an invite to luser for every channel in which they're
# listed. If they're already in the channel, the server just
# sends back an error. This has the effect of letting people
# get back into invite-only channels after a disconnect.
who =
self.lusers[][who] = luser
for chan, l in self.lusers.iteritems():
if chan ==
t = l.get(who)
if t and ==
self.write(['INVITE', who, chan])
def cmd_join(self, sender, forum, addl):
if == self.nick:
# If it was me, get a channel listing and beg for ops
forum.notice('If you op me, I will op everyone who joins this channel.')
self.lusers[] = {}
# Otherwise, add the user
self.add_luser(sender, forum)
forum.write(['MODE',, '+o'],
def cmd_352(self, sender, forum, addl):
# Response to WHO
forum = irc.Channel(self, addl[0])
who = irc.User(self, addl[4], addl[1], addl[2])
self.add_luser(who, forum)
def cmd_invite(self, sender, forum, addl):
# Join any channel to which we're invited
def cmd_pong(self, sender, forum, addl):
now = time.time()
self.lag = now - float(addl[0])
def cmd_482(self, sender, forum, addl):
forum = self.recipient(addl[0])
self.whinecount += 1
if (self.whinecount == 2 or
self.whinecount == 4 or
self.whinecount == 8):
forum.notice("Just a reminder: I can't op anyone unless I'm opped myself.")
elif (self.whinecount == 16):
forum.notice("This is the last time I'm going to beg for ops. Puh-leaze?")
if __name__ == '__main__':
import daemon
import sys
debug = False
if "-d" in sys.argv:
debug = True
if not debug:
# Become a daemon
log = file('arsenic.log', 'a')
daemon.daemon('', log, log)
# Short URL server
us = shorturl.start(('', 0))
firebot.URLSERVER = (socket.gethostbyaddr(socket.gethostname())[0],
NICK = ['arsenic']
INFO = "I'm a little printf, short and stdout"
l1 = Arsenic(('', 6667),
["#x", "#csirt"],
l1.debug = debug