mirror of https://github.com/nealey/firebot
Remove evil tabs
This commit is contained in:
parent
09e9796758
commit
201558ca14
298
irc.py
298
irc.py
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue