Allow multiple nicks, refactored irclib.Irc a bit.

This commit is contained in:
Jeremy Fincher 2004-07-26 06:05:39 +00:00
parent dc4d78774d
commit 7dbbf16dcc
5 changed files with 107 additions and 69 deletions

View File

@ -208,7 +208,6 @@ if __name__ == '__main__':
defaultNetwork = conf.supybot.networks.default() defaultNetwork = conf.supybot.networks.default()
network = conf.supybot.networks.get(defaultNetwork) network = conf.supybot.networks.get(defaultNetwork)
server = network.server() server = network.server()
password = network.password()
if ':' in server: if ':' in server:
serverAndPort = server.split(':', 1) serverAndPort = server.split(':', 1)
serverAndPort[1] = int(serverAndPort[1]) serverAndPort[1] = int(serverAndPort[1])
@ -251,8 +250,7 @@ if __name__ == '__main__':
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
import supybot.Owner as Owner import supybot.Owner as Owner
irc = irclib.Irc(nick, user=user, ident=ident, irc = irclib.Irc(network=defaultNetwork)
network=defaultNetwork, password=password)
callback = Owner.Class() callback = Owner.Class()
irc.addCallback(callback) irc.addCallback(callback)
driver = drivers.newDriver(server, irc) driver = drivers.newDriver(server, irc)

View File

@ -129,6 +129,9 @@ class ValidNick(registry.String):
else: else:
registry.String.setValue(self, v) registry.String.setValue(self, v)
class ValidNicks(registry.SpaceSeparatedListOf):
Value = ValidNick
class ValidChannel(registry.String): class ValidChannel(registry.String):
"""Value must be a valid IRC channel name.""" """Value must be a valid IRC channel name."""
def setValue(self, v): def setValue(self, v):
@ -142,7 +145,12 @@ class ValidChannel(registry.String):
registry.String.setValue(self, v) registry.String.setValue(self, v)
registerGlobalValue(supybot, 'nick', registerGlobalValue(supybot, 'nick',
ValidNick('supybot', """Determines the bot's nick.""")) ValidNick('supybot', """Determines the bot's default nick."""))
registerGlobalValue(supybot.nick, 'alternates', ValidNicks([], """Determines
what alternative nicks will be used if the primary nick (supybot.nick)
isn't available. If none are given, or if all are taken, the primary nick
will be perturbed appropriately until an unused nick is found."""))
registerGlobalValue(supybot, 'ident', registerGlobalValue(supybot, 'ident',
ValidNick('supybot', """Determines the bot's ident string, if the server ValidNick('supybot', """Determines the bot's ident string, if the server
@ -450,13 +458,6 @@ registerChannelValue(supybot.replies, 'possibleBug',
# End supybot.replies. # End supybot.replies.
### ###
# XXX: This should be SpaceSeparated, if it survives.
supybot.register('nickmods', registry.CommaSeparatedListOfStrings(
'__%s__,%s^,%s`,%s_,%s__,_%s,__%s,[%s]'.split(','),
"""A list of modifications to be made to a nick when the nick the bot tries
to get from the server is in use. There should be one %s in each string;
this will get replaced with the original nick."""))
registerGlobalValue(supybot, 'snarfThrottle', registerGlobalValue(supybot, 'snarfThrottle',
registry.Float(10.0, """A floating point number of seconds to throttle registry.Float(10.0, """A floating point number of seconds to throttle
snarfed URLs, in order to prevent loops between two bots snarfing the same snarfed URLs, in order to prevent loops between two bots snarfing the same

View File

@ -36,6 +36,7 @@ import supybot.fix as fix
import copy import copy
import sets import sets
import time import time
import operator
from itertools import imap, chain, cycle from itertools import imap, chain, cycle
import supybot.log as log import supybot.log as log
@ -332,7 +333,8 @@ class IrcState(IrcCommandDispatcher):
chan = ChannelState() chan = ChannelState()
chan.addUser(msg.nick) chan.addUser(msg.nick)
self.channels[channel] = chan self.channels[channel] = chan
assert msg.nick == irc.nick, msg # I don't know why this assert was here.
#assert msg.nick == irc.nick, msg
def doMode(self, irc, msg): def doMode(self, irc, msg):
channel = msg.args[0] channel = msg.args[0]
@ -441,65 +443,86 @@ class Irc(IrcCommandDispatcher):
_nickSetters = sets.Set(['001', '002', '003', '004', '250', '251', '252', _nickSetters = sets.Set(['001', '002', '003', '004', '250', '251', '252',
'254', '255', '265', '266', '372', '375', '376', '254', '255', '265', '266', '372', '375', '376',
'333', '353', '332', '366', '005']) '333', '353', '332', '366', '005'])
def __init__(self, nick, user='', ident='', def __init__(self, network, callbacks=None):
network='unset', password='', callbacks=None):
world.ircs.append(self) world.ircs.append(self)
self.originalNick = intern(nick) self.network = network
self.originalNetwork = intern(network)
self.nick = self.originalNick
self.network = self.originalNetwork
self.nickmods = cycle(conf.supybot.nickmods())
self.password = password
self.user = intern(user or nick) # Default to nick
self.ident = intern(ident or nick) # Ditto.
self.prefix = '%s!%s@%s' % (nick, ident, 'unset.domain')
if callbacks is None: if callbacks is None:
self.callbacks = [] self.callbacks = []
else: else:
self.callbacks = callbacks self.callbacks = callbacks
self.state = IrcState() self.state = IrcState()
self.queue = IrcMsgQueue() self.queue = IrcMsgQueue()
self.lastTake = 0
self.server = 'unset'
self.afterConnect = False
self.fastqueue = smallqueue() self.fastqueue = smallqueue()
self.lastping = time.time()
self.outstandingPing = False
self.driver = None # The driver should set this later. self.driver = None # The driver should set this later.
if self.password: self._setNonResettingVariables()
self.queue.enqueue(ircmsgs.password(self.password)) self._queueConnectMessages()
log.info('Sending NICK command, nick is %s.', self.nick)
self.queue.enqueue(ircmsgs.nick(self.nick))
log.info('Sending USER command, ident is %s, user is %s.',
self.nick, self.user)
self.queue.enqueue(ircmsgs.user(self.ident, self.user))
def reset(self): def reset(self):
"""Resets the Irc object. Called when the driver reconnects.""" """Resets the Irc object. Called when the driver reconnects."""
self.nick = self.originalNick self._setNonResettingVariables()
self.network = self.originalNetwork self._queueConnectMessages()
self.prefix = '%s!%s@%s' % (self.nick, self.ident, 'unset.domain')
self.state.reset() self.state.reset()
self.queue.reset() self.queue.reset()
self.fastqueue.reset()
for callback in self.callbacks:
callback.reset()
def _setNonResettingVariables(self):
# Configuration stuff.
self.nick = conf.supybot.nick()
self.user = conf.supybot.user()
self.ident = conf.supybot.ident()
self.alternateNicks = conf.supybot.nick.alternates()[:]
self.password = conf.supybot.networks.get(self.network).password()
self.prefix = '%s!%s@%s' % (self.nick, self.ident, 'unset.domain')
# The rest.
self.lastTake = 0
self.server = 'unset' self.server = 'unset'
self.afterConnect = False self.afterConnect = False
self.lastping = time.time() self.lastping = time.time()
self.outstandingPing = False self.outstandingPing = False
self.fastqueue = queue()
def _queueConnectMessages(self):
if self.password: if self.password:
self.queue.enqueue(ircmsgs.password(self.password)) log.info('Sending PASS command, not logging the password.')
self.queue.enqueue(ircmsgs.nick(self.nick)) self.queueMsg(ircmsgs.password(self.password))
self.queue.enqueue(ircmsgs.user(self.ident, self.user)) log.info('Sending NICK command, nick is %s.', self.nick)
for callback in self.callbacks: self.queueMsg(ircmsgs.nick(self.nick))
callback.reset() log.info('Sending USER command, ident is %s, user is %s.',
self.ident, self.user)
self.queueMsg(ircmsgs.user(self.ident, self.user))
def _getNextNick(self):
if self.alternateNicks:
return self.alternateNicks.pop(0)
else:
nick = conf.supybot.nick()
for c in '`_^':
if nick.endswith(c):
if len(nick) >= 9: # The max length on many servers.
nick = nick.rstrip(c)
continue
else:
return nick + c
else:
return nick + c
for c in '`_^':
if nick.startswith(c):
if len(nick) >= 9:
nick = nick.lstrip(c)
continue
else:
return c + nick
else:
return c + nick
def __repr__(self): def __repr__(self):
return '<irclib.Irc object for %s>' % self.server return '<irclib.Irc object for %s>' % self.network
def addCallback(self, callback): def addCallback(self, callback):
"""Adds a callback to the callbacks list.""" """Adds a callback to the callbacks list."""
self.callbacks.append(callback) self.callbacks.append(callback)
utils.sortBy(lambda cb: cb.priority, self.callbacks) utils.sortBy(operator.attrgetter('priority'), self.callbacks)
def getCallback(self, name): def getCallback(self, name):
"""Gets a given callback by name.""" """Gets a given callback by name."""
@ -600,15 +623,16 @@ class Irc(IrcCommandDispatcher):
def do376(self, msg): def do376(self, msg):
log.info('Got end of MOTD from %s', self.server) log.info('Got end of MOTD from %s', self.server)
self.afterConnect = True self.afterConnect = True
# Let's reset nicks in case we had to use a weird one.
self.alternateNicks = conf.supybot.nick.alternates()[:]
do377 = do422 = do376 do377 = do422 = do376
def do433(self, msg): def do433(self, msg):
"""Handles 'nickname already in use' messages.""" """Handles 'nickname already in use' messages."""
if self.nick != self.originalNick or not self.afterConnect: newNick = self._getNextNick()
newNick = self.nickmods.next() % self.originalNick log.info('Got 433: %s is in use. Trying %s.', self.nick, newNick)
log.info('Got 433: %s is in use. Trying %s.', self.nick, newNick) self.sendMsg(ircmsgs.nick(newNick))
self.sendMsg(ircmsgs.nick(newNick)) do432 = do433 # 432: Erroneous nickname.
do432 = do433
def doJoin(self, msg): def doJoin(self, msg):
if msg.nick == self.nick: if msg.nick == self.nick:

View File

@ -52,6 +52,7 @@ supybot.log.detailedTracebacks: False
supybot.throttleTime: 0 supybot.throttleTime: 0
supybot.prefixChars: @ supybot.prefixChars: @
supybot.protocols.irc.throttleTime: -1 supybot.protocols.irc.throttleTime: -1
supybot.networks.test.server: should.not.need.this
""") """)
fd.close() fd.close()

View File

@ -304,7 +304,7 @@ class IrcStateTestCase(SupyTestCase):
class IrcTestCase(SupyTestCase): class IrcTestCase(SupyTestCase):
def setUp(self): def setUp(self):
self.irc = irclib.Irc('nick') self.irc = irclib.Irc('test')
_ = self.irc.takeMsg() # NICK _ = self.irc.takeMsg() # NICK
_ = self.irc.takeMsg() # USER _ = self.irc.takeMsg() # USER
@ -325,6 +325,8 @@ class IrcTestCase(SupyTestCase):
self.failUnless(msg.command == 'NICK' and msg.args[0] != self.irc.nick) self.failUnless(msg.command == 'NICK' and msg.args[0] != self.irc.nick)
def testSendBeforeQueue(self): def testSendBeforeQueue(self):
while self.irc.takeMsg() is not None:
self.irc.takeMsg()
self.irc.queueMsg(ircmsgs.IrcMsg('NOTICE #foo bar')) self.irc.queueMsg(ircmsgs.IrcMsg('NOTICE #foo bar'))
self.irc.sendMsg(ircmsgs.IrcMsg('PRIVMSG #foo yeah!')) self.irc.sendMsg(ircmsgs.IrcMsg('PRIVMSG #foo yeah!'))
msg = self.irc.takeMsg() msg = self.irc.takeMsg()
@ -392,23 +394,35 @@ class IrcCallbackTestCase(SupyTestCase):
self.assertEqual(doCommandCatcher.L, commands) self.assertEqual(doCommandCatcher.L, commands)
def testFirstCommands(self): def testFirstCommands(self):
nick = 'nick' try:
user = 'user any user' originalNick = conf.supybot.nick()
password = 'password' originalUser = conf.supybot.user()
expected = [ircmsgs.nick(nick), ircmsgs.user(nick, user)] originalPassword = conf.supybot.networks.test.password()
irc = irclib.Irc(nick, user) nick = 'nick'
msgs = [irc.takeMsg()] conf.supybot.nick.setValue(nick)
while msgs[-1] != None: user = 'user any user'
msgs.append(irc.takeMsg()) conf.supybot.user.setValue(user)
msgs.pop() expected = [ircmsgs.nick(nick), ircmsgs.user('supybot', user)]
self.assertEqual(msgs, expected) irc = irclib.Irc('test')
irc = irclib.Irc(nick, user, password=password) msgs = [irc.takeMsg()]
msgs = [irc.takeMsg()] while msgs[-1] != None:
while msgs[-1] != None: msgs.append(irc.takeMsg())
msgs.append(irc.takeMsg()) msgs.pop()
msgs.pop() self.assertEqual(msgs, expected)
expected.insert(0, ircmsgs.password(password)) password = 'password'
self.assertEqual(msgs, expected) conf.supybot.networks.test.password.setValue(password)
irc = irclib.Irc('test')
msgs = [irc.takeMsg()]
while msgs[-1] != None:
msgs.append(irc.takeMsg())
msgs.pop()
expected.insert(0, ircmsgs.password(password))
self.assertEqual(msgs, expected)
finally:
conf.supybot.nick.setValue(nick)
conf.supybot.user.setValue(user)
conf.supybot.networks.test.password.setValue(password)
conf.supybot.nick.setValue(nick)
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: