Added IrcCommandDispatcher as base class for IrcCallback and IrcState.

This commit is contained in:
Jeremy Fincher 2003-05-29 17:03:42 +00:00
parent db4495111c
commit f40780156e

View File

@ -52,7 +52,12 @@ import ircutils
# changes elsewhere won't be required. # changes elsewhere won't be required.
### ###
class IrcCallback(object): class IrcCommandDispatcher(object):
"""Base class for classes that must dispatch on a command."""
def dispatchCommand(self, command):
return getattr(self, 'do' + command.capitalize(), None)
class IrcCallback(IrcCommandDispatcher):
"""Base class for standard callbacks. """Base class for standard callbacks.
Callbacks derived from this class should have methods of the form Callbacks derived from this class should have methods of the form
@ -69,9 +74,8 @@ class IrcCallback(object):
return msg return msg
def __call__(self, irc, msg): def __call__(self, irc, msg):
commandName = 'do' + msg.command.capitalize() method = self.dispatchCommand(msg.command)
if hasattr(self, commandName): if method is not None:
method = getattr(self, commandName)
try: try:
method(irc, msg) method(irc, msg)
except Exception: except Exception:
@ -92,6 +96,11 @@ class IrcCallback(object):
### ###
class IrcMsgQueue(object): class IrcMsgQueue(object):
"""Class for a queue of IrcMsgs. Eventually, it should be smart. """Class for a queue of IrcMsgs. Eventually, it should be smart.
Probably smarter than it is now, though it's gotten quite a bit smarter
than it originally was. A method to "score" methods, and a heapq to
maintain a priority queue of the messages would be the ideal way to do
intelligent queueing.
""" """
__slots__ = ('msgs', 'highpriority', 'normal', 'lowpriority') __slots__ = ('msgs', 'highpriority', 'normal', 'lowpriority')
def __init__(self): def __init__(self):
@ -147,15 +156,25 @@ class Channel(object):
self.voices = set() self.voices = set()
def addUser(self, user): def addUser(self, user):
nick = user.lstrip('@%+')
while user[0] in '@%+': while user[0] in '@%+':
(marker, user) = (user[0], user[1:]) (marker, user) = (user[0], user[1:])
if marker == '@': if marker == '@':
self.ops.add(user) self.ops.add(nick)
elif marker == '%': elif marker == '%':
self.halfops.add(user) self.halfops.add(nick)
elif marker == '+': elif marker == '+':
self.voices.add(user) self.voices.add(nick)
self.users.add(user) self.users.add(nick)
def replaceUser(self, oldNick, newNick):
# Note that this doesn't have to have the sigil (@%+) that users
# have to have for addUser; it just changes the name of the user
# without changing any of his categories.
for s in (self.users, self.ops, self.halfops, self.voices):
if oldNick in s:
s.discard(oldNick)
s.add(newNick)
def removeUser(self, user): def removeUser(self, user):
self.users.discard(user) self.users.discard(user)
@ -164,7 +183,7 @@ class Channel(object):
self.voices.discard(user) self.voices.discard(user)
def __getstate__(self): def __getstate__(self):
return map(lambda name: getattr(self, name), self.__slots__) return [getattr(self, name) for name in self.__slots__]
def __setstate__(self, t): def __setstate__(self, t):
for (name, value) in zip(self.__slots__, t): for (name, value) in zip(self.__slots__, t):
@ -177,9 +196,10 @@ class Channel(object):
return ret return ret
def __ne__(self, other): def __ne__(self, other):
# This shouldn't even be necessary, grr...
return not self == other return not self == other
class IrcState(object): class IrcState(IrcCommandDispatcher):
"""Maintains state of the Irc connection. Should also become smarter. """Maintains state of the Irc connection. Should also become smarter.
""" """
__slots__ = ('history', 'nicksToHostmasks', 'channels') __slots__ = ('history', 'nicksToHostmasks', 'channels')
@ -218,73 +238,77 @@ class IrcState(object):
self.history.append(msg) self.history.append(msg)
if ircutils.isUserHostmask(msg.prefix) and not msg.command == 'NICK': if ircutils.isUserHostmask(msg.prefix) and not msg.command == 'NICK':
self.nicksToHostmasks[msg.nick] = msg.prefix self.nicksToHostmasks[msg.nick] = msg.prefix
if msg.command == '352': # Response to a WHO command. method = self.dispatchCommand(msg.command)
if method is not None:
method(irc, msg)
def getTopic(self, channel):
return self.channels[channel].topic
def nickToHostmask(self, nick):
return self.nicksToHostmasks[nick]
def do352(self, irc, msg):
(nick, user, host) = (msg.args[2], msg.args[5], msg.args[3]) (nick, user, host) = (msg.args[2], msg.args[5], msg.args[3])
hostmask = '%s!%s@%s' % (nick, user, host) hostmask = '%s!%s@%s' % (nick, user, host)
self.nicksToHostmasks[nick] = hostmask self.nicksToHostmasks[nick] = hostmask
elif msg.command == 'JOIN':
channels = [channel.lower() for channel in msg.args[0].split(',')] def doJoin(self, irc, msg):
for channel in channels: for channel in msg.args[0].split(','):
if channel in self.channels: if channel in self.channels:
# We're already on the channel. self.channels[channel].addUser(msg.nick)
self.channels[channel].users.add(msg.nick)
else: else:
chan = Channel() chan = Channel()
chan.addUser(msg.nick)
self.channels[channel] = chan self.channels[channel] = chan
chan.users.add(msg.nick)
elif msg.command == '353': def do353(self, irc, msg):
(_, _, channel, users) = msg.args (_, _, channel, users) = msg.args
chan = self.channels[channel.lower()] chan = self.channels[channel]
users = [ircutils.nick(user) for user in users.split()] users = users.split()
for user in users: for user in users:
chan.addUser(user) chan.addUser(user)
elif msg.command == 'PART':
def doPart(self, irc, msg):
for channel in msg.args[0].split(','): for channel in msg.args[0].split(','):
channel = channel.lower()
chan = self.channels[channel] chan = self.channels[channel]
if msg.nick == irc.nick: if msg.nick == irc.nick:
del self.channels[channel] del self.channels[channel]
else: else:
chan.removeUser(msg.nick) chan.removeUser(msg.nick)
elif msg.command == 'KICK':
def doKick(self, irc, msg):
(channel, users) = msg.args[:2] (channel, users) = msg.args[:2]
channel = channel.lower()
chan = self.channels[channel] chan = self.channels[channel]
for user in users.split(','): for user in users.split(','):
chan.removeUser(user) chan.removeUser(user)
elif msg.command == 'QUIT':
def doQuit(self, irc, msg):
for channel in self.channels.itervalues(): for channel in self.channels.itervalues():
channel.removeUser(msg.nick) channel.removeUser(msg.nick)
elif msg.command == 'TOPIC':
channel = msg.args[0].lower() def doTopic(self, irc, msg):
chan = self.channels[channel] chan = self.channels[msg.args[0]]
chan.topic = msg.args[1] chan.topic = msg.args[1]
elif msg.command == '332':
channel = msg.args[1].lower() def do332(self, irc, msg):
chan = self.channels[channel] chan = self.channels[msg.args[0]]
chan.topic = msg.args[2] chan.topic = msg.args[2]
elif msg.command == 'NICK':
def doNick(self, irc, msg):
newNick = msg.args[0] newNick = msg.args[0]
oldNick = msg.nick
try: try:
del self.nicksToHostmasks[msg.nick] if msg.user and msg.host:
# Nick messages being handed out from the bot itself won't
# have the necessary prefix to make a hostmask.
newHostmask = ircutils.joinHostmask(newNick,msg.user,msg.host) newHostmask = ircutils.joinHostmask(newNick,msg.user,msg.host)
self.nicksToHostmasks[newNick] = newHostmask self.nicksToHostmasks[newNick] = newHostmask
del self.nicksToHostmasks[oldNick]
except KeyError: except KeyError:
debug.printf('%s not in nicksToHostmask' % msg.nick) pass
for channel in self.channels.itervalues(): for channel in self.channels.itervalues():
for s in (channel.users, channel.ops, channel.replaceUser(oldNick, newNick)
channel.halfops, channel.voices):
#debug.printf(s)
if msg.nick in s:
s.remove(msg.nick)
s.add(newNick)
def getTopic(self, channel):
return self.channels[channel.lower()].topic
def nickToHostmask(self, nick):
return self.nicksToHostmasks[nick]
@ -298,16 +322,16 @@ class Irc(object):
Handles PING commands already. Handles PING commands already.
""" """
_nickSetters = set(('001', '002', '003', '004', '250', '251', '252', '254', _nickSetters = set(['001', '002', '003', '004', '250', '251', '252', '254',
'255', '265', '266', '372', '375', '376', '333', '353', '255', '265', '266', '372', '375', '376', '333', '353',
'332', '366')) '332', '366'])
def __init__(self, nick, user='', ident='', password='', callbacks=None): def __init__(self, nick, user='', ident='', password='', callbacks=None):
world.ircs.append(self) world.ircs.append(self)
self.nick = nick self.nick = nick
self.password = password self.password = password
self.prefix = ''
self.user = user or nick # Default to nick if user isn't provided. self.user = user or nick # Default to nick if user isn't provided.
self.ident = ident or nick # Ditto. self.ident = ident or nick # Ditto.
self.prefix = '%s!%s@%s' % (nick, ident, 'unset')
if callbacks is None: if callbacks is None:
self.callbacks = [] self.callbacks = []
else: else: