Remove evil tabs

This commit is contained in:
Neale Pickett 2010-03-16 15:19:50 -06:00
parent 09e9796758
commit 201558ca14
1 changed files with 150 additions and 150 deletions

298
irc.py
View File

@ -38,8 +38,8 @@ class IRCHandler(asynchat.async_chat):
self.connect(host) self.connect(host)
def handle_connect(self): def handle_connect(self):
self.write(['NICK', self.nick]) self.write(['NICK', self.nick])
self.write(['USER', self.nick, '+iw', self.nick], self.gecos) self.write(['USER', self.nick, '+iw', self.nick], self.gecos)
def connect(self, host): def connect(self, host):
self.waiting = False self.waiting = False
@ -90,55 +90,55 @@ class IRCHandler(asynchat.async_chat):
self.parse_line(line) self.parse_line(line)
def write(self, args, *text): def write(self, args, *text):
"""Send out an IRC command """Send out an IRC command
This function helps to prevent you from shooting yourself in the This function helps to prevent you from shooting yourself in the
foot, by forcing you to send commands that are in a valid format foot, by forcing you to send commands that are in a valid format
(although it doesn't check the validity of the actual commands). (although it doesn't check the validity of the actual commands).
As we all know, IRC commands take the form As we all know, IRC commands take the form
:COMMAND ARG1 ARG2 ARG3 ... :text string :COMMAND ARG1 ARG2 ARG3 ... :text string
where 'text string' is optional. Well, that's exactly how this where 'text string' is optional. Well, that's exactly how this
function works. Args is a list of length at least one, and text function works. Args is a list of length at least one, and text
string can be any number of strings. You can call the function string can be any number of strings. You can call the function
like this: like this:
write(['PRIVMSG', nick], 'Hello 12') write(['PRIVMSG', nick], 'Hello 12')
or like this: or like this:
write(['PRIVMSG', nick], 'Hello', '12') write(['PRIVMSG', nick], 'Hello', '12')
or even like this: or even like this:
write(['PRIVMSG', nick], 'Hello', 12) write(['PRIVMSG', nick], 'Hello', 12)
And you'll get the same result with all three. And you'll get the same result with all three.
""" """
if (type(args) == types.StringType): if (type(args) == types.StringType):
cmd = args cmd = args
else: else:
cmd = u' '.join(args) cmd = u' '.join(args)
cmdstr = cmd cmdstr = cmd
if (text): if (text):
txt = '' txt = ''
for t in (text): for t in (text):
if type(t) in (types.StringType, types.UnicodeType): if type(t) in (types.StringType, types.UnicodeType):
txt = txt + ' ' + t txt = txt + ' ' + t
elif type(t) in (types.ListType, types.TupleType): elif type(t) in (types.ListType, types.TupleType):
for i in (t): for i in (t):
try: try:
txt = ' '.join([txt, i]) txt = ' '.join([txt, i])
except TypeError: except TypeError:
txt = ' '.join([txt, repr(i)]) txt = ' '.join([txt, repr(i)])
else: else:
txt = ' '.join([txt, repr(t)]) txt = ' '.join([txt, repr(t)])
txt = txt[1:] txt = txt[1:]
cmdstr = "%s :%s" % (cmdstr, txt) cmdstr = "%s :%s" % (cmdstr, txt)
encstr = cmdstr.encode('utf8', 'replace') encstr = cmdstr.encode('utf8', 'replace')
self.dbg("-> %s " % encstr) self.dbg("-> %s " % encstr)
try: try:
@ -148,81 +148,81 @@ class IRCHandler(asynchat.async_chat):
def parse_line(self, line): def parse_line(self, line):
"""Parse a server-provided line """Parse a server-provided line
This does all the magic of parsing those ill-formatted IRC This does all the magic of parsing those ill-formatted IRC
messages. It will also decide if a PRIVMSG or NOTICE is using messages. It will also decide if a PRIVMSG or NOTICE is using
CTCP (the client-to-client protocol, which by convention is any CTCP (the client-to-client protocol, which by convention is any
of the above messages with ^A on both ends of the text. of the above messages with ^A on both ends of the text.
This function goes on to invoke self.eval_triggers on the parsed This function goes on to invoke self.eval_triggers on the parsed
data like this: data like this:
self.eval_triggers(operation, arguments, text) self.eval_triggers(operation, arguments, text)
where operation and text are strings, and arguments is a list. where operation and text are strings, and arguments is a list.
It returns the same tuple (op, args, text). It returns the same tuple (op, args, text).
""" """
line = line.decode('utf8', 'replace') line = line.decode('utf8', 'replace')
if (line[0] == ':'): if (line[0] == ':'):
with_uname = 1 with_uname = 1
line = line [1:] line = line [1:]
else: else:
with_uname = 0 with_uname = 0
try: try:
[args, text] = line.split(' :', 1) [args, text] = line.split(' :', 1)
args = args.split() args = args.split()
except ValueError: except ValueError:
args = line.split() args = line.split()
text = '' text = ''
if (with_uname != 1): if (with_uname != 1):
op = args[0] op = args[0]
elif ((args[1] in ["PRIVMSG", "NOTICE"]) and elif ((args[1] in ["PRIVMSG", "NOTICE"]) and
(text and (text[0] == '\001') and (text[-1] == '\001'))): (text and (text[0] == '\001') and (text[-1] == '\001'))):
op = "C" + args[1] op = "C" + args[1]
text = text[1:-1] text = text[1:-1]
else: else:
op = args[1] op = args[1]
self.dbg("<- %s %s %s" % (op, args, text)) self.dbg("<- %s %s %s" % (op, args, text))
self.handle(op, args, text) self.handle(op, args, text)
return (op, args, text) return (op, args, text)
def handle(self, op, args, text): def handle(self, op, args, text):
"""Take action on a server message """Take action on a server message
Right now, just invokes Right now, just invokes
self.do_[op](args, text) self.do_[op](args, text)
where [op] is the operation passed in. where [op] is the operation passed in.
This is a good method to overload if you want a really advanced This is a good method to overload if you want a really advanced
client supporting bindings. client supporting bindings.
""" """
try: try:
method = getattr(self, "do_" + lower(op)) method = getattr(self, "do_" + lower(op))
except AttributeError: except AttributeError:
self.dbg("Unhandled: %s" % (op, args, text)) self.dbg("Unhandled: %s" % (op, args, text))
return return
method(args, text) method(args, text)
class Recipient: class Recipient:
"""Abstract recipient object""" """Abstract recipient object"""
def __init__(self, interface, name): def __init__(self, interface, name):
self._interface = interface self._interface = interface
self._name = name self._name = name
def __repr__(self): def __repr__(self):
return 'Recipient(%s)' % self.name() return 'Recipient(%s)' % self.name()
def name(self): def name(self):
return self._name return self._name
def is_channel(self): def is_channel(self):
return False return False
@ -238,29 +238,29 @@ class Recipient:
self.write([cmd, self._name], text) self.write([cmd, self._name], text)
def msg(self, text): def msg(self, text):
"""Tell the recipient something""" """Tell the recipient something"""
self.cmd("PRIVMSG", text) self.cmd("PRIVMSG", text)
def notice(self, text): def notice(self, text):
"""Send a notice to the recipient""" """Send a notice to the recipient"""
self.cmd("NOTICE", text) self.cmd("NOTICE", text)
def ctcp(self, command, text): def ctcp(self, command, text):
"""Send a CTCP command to the recipient""" """Send a CTCP command to the recipient"""
return self.msg("\001%s %s\001" % (upper(command), text)) return self.msg("\001%s %s\001" % (upper(command), text))
def act(self, text): def act(self, text):
"""Send an action to the recipient""" """Send an action to the recipient"""
return self.ctcp("ACTION", text) return self.ctcp("ACTION", text)
def cnotice(self, command, text): def cnotice(self, command, text):
"""Send a CTCP notice to the recipient""" """Send a CTCP notice to the recipient"""
return self.notice("\001%s %s\001" % (upper(command), text)) return self.notice("\001%s %s\001" % (upper(command), text))
class Channel(Recipient): class Channel(Recipient):
def __repr__(self): def __repr__(self):
@ -281,9 +281,9 @@ class User(Recipient):
def recipient(interface, name): def recipient(interface, name):
if name[0] in ["&", "#"]: if name[0] in ["&", "#"]:
return Channel(interface, name) return Channel(interface, name)
else: else:
return User(interface, name, None, None) return User(interface, name, None, None)
class SmartIRCHandler(IRCHandler): class SmartIRCHandler(IRCHandler):
"""This is like the IRCHandler, except it creates Recipient objects """This is like the IRCHandler, except it creates Recipient objects
@ -300,7 +300,7 @@ class SmartIRCHandler(IRCHandler):
traceback.print_exception(*exception) traceback.print_exception(*exception)
def handle(self, op, args, text): def handle(self, op, args, text):
"""Parse more, creating objects and stuff """Parse more, creating objects and stuff
makes a call to self.handle_op(sender, forum, addl) makes a call to self.handle_op(sender, forum, addl)
@ -314,22 +314,22 @@ class SmartIRCHandler(IRCHandler):
always send a reply to forum, and it will be sent back in an always send a reply to forum, and it will be sent back in an
appropriate manner (ie. the way you expect). appropriate manner (ie. the way you expect).
addl is a tuple, containing additional information which might addl is a tuple, containing additional information which might
be relelvant. Here's what it will contain, based on the server be relelvant. Here's what it will contain, based on the server
operation: operation:
op | addl op | addl
---------+---------------- ---------+----------------
PRIVMSG | text of the message PRIVMSG | text of the message
NOTICE | text of the notice NOTICE | text of the notice
CPRIVMSG | CTCP command, text of the command CPRIVMSG | CTCP command, text of the command
CNOTICE | CTCP response, text of the response CNOTICE | CTCP response, text of the response
KICK * | victim of kick, kick text KICK * | victim of kick, kick text
MODE * | all mode args MODE * | all mode args
JOIN * | empty JOIN * | empty
PART * | empty PART * | empty
QUIT | quit message QUIT | quit message
PING | ping text PING | ping text
NICK ! | old nickname NICK ! | old nickname
others | all arguments; text is last element others | all arguments; text is last element
@ -338,16 +338,16 @@ class SmartIRCHandler(IRCHandler):
! The sender for the NICK command is the *new* nickname. This ! The sender for the NICK command is the *new* nickname. This
is so you can send messages to the sender object and they'll is so you can send messages to the sender object and they'll
go to the right place. go to the right place.
""" """
try: try:
sender = User(self, *unpack_nuhost(args)) sender = User(self, *unpack_nuhost(args))
except ValueError: except ValueError:
sender = None sender = None
forum = None forum = None
addl = () addl = ()
if op in ("PRIVMSG", "NOTICE"): if op in ("PRIVMSG", "NOTICE"):
# PRIVMSG ['neale!~user@127.0.0.1', 'PRIVMSG', '#hydra'] firebot, foo # PRIVMSG ['neale!~user@127.0.0.1', 'PRIVMSG', '#hydra'] firebot, foo
# PRIVMSG ['neale!~user@127.0.0.1', 'PRIVMSG', 'firebot'] firebot, foo # PRIVMSG ['neale!~user@127.0.0.1', 'PRIVMSG', 'firebot'] firebot, foo
try: try:
@ -358,31 +358,31 @@ class SmartIRCHandler(IRCHandler):
addl = (text,) addl = (text,)
except IndexError: except IndexError:
addl = (text, args[1]) addl = (text, args[1])
elif op in ("CPRIVMSG", "CNOTICE"): elif op in ("CPRIVMSG", "CNOTICE"):
forum = self.recipient(args[2]) forum = self.recipient(args[2])
splits = text.split(" ") splits = text.split(" ")
if splits[0] == "DCC": if splits[0] == "DCC":
op = "DC" + op op = "DC" + op
addl = (splits[1],) + tuple(splits[2:]) addl = (splits[1],) + tuple(splits[2:])
else: else:
addl = (splits[0],) + tuple(splits[1:]) addl = (splits[0],) + tuple(splits[1:])
elif op in ("KICK",): elif op in ("KICK",):
forum = self.recipient(args[2]) forum = self.recipient(args[2])
addl = (self.recipient(args[3]), text) addl = (self.recipient(args[3]), text)
elif op in ("MODE",): elif op in ("MODE",):
forum = self.recipient(args[2]) forum = self.recipient(args[2])
addl = args[3:] addl = args[3:]
elif op in ("JOIN", "PART"): elif op in ("JOIN", "PART"):
try: try:
forum = self.recipient(args[2]) forum = self.recipient(args[2])
except IndexError: except IndexError:
forum = self.recipient(text) forum = self.recipient(text)
elif op in ("QUIT",): elif op in ("QUIT",):
addl = (text,) addl = (text,)
elif op in ("PING", "PONG"): elif op in ("PING", "PONG"):
# PING ['PING'] us.boogernet.org. # PING ['PING'] us.boogernet.org.
# PONG ['irc.foonet.com', 'PONG', 'irc.foonet.com'] 1114199424 # PONG ['irc.foonet.com', 'PONG', 'irc.foonet.com'] 1114199424
addl = (text,) addl = (text,)
elif op in ("NICK",): elif op in ("NICK",):
# NICK ['brad!~brad@10.168.2.33', 'NICK'] bradaway # NICK ['brad!~brad@10.168.2.33', 'NICK'] bradaway
# #
@ -403,10 +403,10 @@ class SmartIRCHandler(IRCHandler):
forum = self.recipient(args[3]) forum = self.recipient(args[3])
else: else:
forum = self.recipient(text) forum = self.recipient(text)
else: else:
try: try:
int(op) int(op)
except ValueError: except ValueError:
self.dbg("WARNING: unknown server code: %s" % op) self.dbg("WARNING: unknown server code: %s" % op)
addl = tuple(args[3:]) + (text,) addl = tuple(args[3:]) + (text,)
@ -508,10 +508,10 @@ class Bot(SmartIRCHandler):
def close(self, final=False): def close(self, final=False):
SmartIRCHandler.close(self) SmartIRCHandler.close(self)
if not final: if not final:
self.dbg("Connection closed, reconnecting...") self.dbg("Connection closed, reconnecting...")
self.waiting = True self.waiting = True
self.connected = 0 self.connected = 0
# Wait a bit and reconnect # Wait a bit and reconnect
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.add_timer(23, lambda : self.connect(self.host)) self.add_timer(23, lambda : self.connect(self.host))
@ -530,7 +530,7 @@ lcletters = "abcdefghijklmnopqrstuvwxyz{}|"
ultrans = string.maketrans(ucletters, lcletters) ultrans = string.maketrans(ucletters, lcletters)
lutrans = string.maketrans(lcletters, ucletters) lutrans = string.maketrans(lcletters, ucletters)
casetrans = string.maketrans(''.join([ucletters, lcletters]), casetrans = string.maketrans(''.join([ucletters, lcletters]),
''.join([lcletters, ucletters])) ''.join([lcletters, ucletters]))
def upper(s): def upper(s):
"""Convert a string to upper case. """Convert a string to upper case.
@ -590,10 +590,10 @@ def unpack_nuhost(nuhost):
""" """
try: try:
[nick, uhost] = string.split(nuhost[0], '!', 1) [nick, uhost] = string.split(nuhost[0], '!', 1)
[user, host] = string.split(uhost, '@', 1) [user, host] = string.split(uhost, '@', 1)
except ValueError: except ValueError:
raise ValueError, "not in nick!user@host format" raise ValueError, "not in nick!user@host format"
return (nick, user, host) return (nick, user, host)
def run_forever(timeout=2.0): def run_forever(timeout=2.0):