diff --git a/plugins/NickAuth/plugin.py b/plugins/NickAuth/plugin.py index 60ac7075b..59eaff8d8 100644 --- a/plugins/NickAuth/plugin.py +++ b/plugins/NickAuth/plugin.py @@ -167,6 +167,59 @@ class NickAuth(callbacks.Plugin): else: irc.error(_('No user has this nick on this network.')) + def doAccount(self, irc, msg): + account = msg.args[0] + user = ircdb.users.getUserFromNick(irc.network, account) + + if not user: + try: + user = ircdb.users.getUser(msg.prefix) + except KeyError: + user = None + + if user: + if account == '*': + user.clearAuth() + else: + user.addAuth(msg.prefix) + ircdb.users.setUser(user, flush=False) + + + def doJoin(self, irc, msg): + if len(msg.args) < 2: + # extended-join is not supported + return + + account = msg.args[1] + user = ircdb.users.getUserFromNick(irc.network, account) + + if not user: + try: + user = ircdb.users.getUser(msg.prefix) + except KeyError: + user = None + + if user: + if account != '*': + user.addAuth(msg.prefix) + ircdb.users.setUser(user, flush=False) + + def do354(self, irc, msg): + (__, ident, host, nick, account) = msg.args + prefix = '%s!%s@%s' % (nick, ident, host) + user = ircdb.users.getUserFromNick(irc.network, account) + + if not user: + try: + user = ircdb.users.getUser(prefix) + except KeyError: + user = None + + if user: + if account != '0': + user.addAuth(prefix) + ircdb.users.setUser(user, flush=False) + Class = NickAuth diff --git a/src/irclib.py b/src/irclib.py index baeb93137..b2c5378f6 100644 --- a/src/irclib.py +++ b/src/irclib.py @@ -483,13 +483,21 @@ class IrcState(IrcCommandDispatcher): def do352(self, irc, msg): # WHO reply. + (nick, user, host) = (msg.args[5], msg.args[2], msg.args[3]) hostmask = '%s!%s@%s' % (nick, user, host) self.nicksToHostmasks[nick] = hostmask + def do354(self, irc, msg): + # WHOX reply. + + (__, user, host, nick, ___) = msg.args + hostmask = '%s!%s@%s' % (nick, user, host) + self.nicksToHostmasks[nick] = hostmask + def do353(self, irc, msg): # NAMES reply. - (_, type, channel, names) = msg.args + (__, type, channel, names) = msg.args if channel not in self.channels: self.channels[channel] = ChannelState() c = self.channels[channel] @@ -927,25 +935,26 @@ class Irc(IrcCommandDispatcher): if self.zombie: self.driver.die() self._reallyDie() - else: - if self.sasl_password: - if not self.sasl_username: - log.warning('%s: SASL username is not set, unable to ' - 'identify.', self.network) - else: - log.debug("%s: Requesting capability 'sasl'.", - self.network) - self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('REQ', 'sasl'))) - if self.password: - log.info('%s: Queuing PASS command, not logging the password.', - self.network) - self.queueMsg(ircmsgs.password(self.password)) - log.debug('%s: Queuing NICK command, nick is %s.', - self.network, self.nick) - self.queueMsg(ircmsgs.nick(self.nick)) - log.debug('%s: Queuing USER command, ident is %s, user is %s.', - self.network, self.ident, self.user) - self.queueMsg(ircmsgs.user(self.ident, self.user)) + + return + + self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('LS',))) + + if self.password: + log.info('%s: Queuing PASS command, not logging the password.', + self.network) + + self.queueMsg(ircmsgs.password(self.password)) + + log.debug('%s: Queuing NICK command, nick is %s.', + self.network, self.nick) + + self.queueMsg(ircmsgs.nick(self.nick)) + + log.debug('%s: Queuing USER command, ident is %s, user is %s.', + self.network, self.ident, self.user) + + self.queueMsg(ircmsgs.user(self.ident, self.user)) def doAuthenticate(self, msg): if msg.args[0] == '+': @@ -960,16 +969,32 @@ class Irc(IrcCommandDispatcher): self.queueMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', args=(authstring,))) def doCap(self, msg): - if msg.args[2] == 'sasl': - if msg.args[1] == 'ACK': - log.debug("%s: Server acknowledged 'sasl' capability", - self.network) - self.queueMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', - args=('PLAIN',))) + caps = ['account-notify', 'extended-join'] + + if self.sasl_password: + if self.sasl_username: + caps.append('sasl') + else: + log.warning('%s: SASL username is not set, unable to ' + 'identify.', self.network) + + for cap in msg.args[2].split(' '): + if msg.args[1] == 'LS' and cap in caps: + log.debug('%s: Requesting capability %r', self.network, cap) + self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('REQ', cap))) + elif msg.args[1] == 'ACK': + log.info('%s: Server acknowledged capability %r', + self.network, cap) + + if cap == 'sasl': + self.queueMsg(ircmsgs.IrcMsg(command='AUTHENTICATE', + args=('PLAIN',))) elif msg.args[1] == 'NAK': - log.warning("%s: Server refused 'sasl' capability", - self.network) - self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',))) + log.warning('%s: Server refused capability %r', + self.network, cap) + + if cap == 'sasl': + self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',))) def do903(self, msg): log.info('%s: SASL authentication successful', self.network) @@ -1068,7 +1093,7 @@ class Irc(IrcCommandDispatcher): def doJoin(self, msg): if msg.nick == self.nick: channel = msg.args[0] - self.queueMsg(ircmsgs.who(channel)) # Ends with 315. + self.queueMsg(ircmsgs.who(channel, args=('%uhna',))) # Ends with 315. self.queueMsg(ircmsgs.mode(channel)) # Ends with 329. for channel in msg.args[0].split(','): self.queueMsg(ircmsgs.mode(channel, '+b')) diff --git a/src/ircmsgs.py b/src/ircmsgs.py index 9df9576ae..54ab272b3 100644 --- a/src/ircmsgs.py +++ b/src/ircmsgs.py @@ -736,7 +736,7 @@ def user(ident, user, prefix='', msg=None): return IrcMsg(prefix=prefix, command='USER', args=(ident, '0', '*', user), msg=msg) -def who(hostmaskOrChannel, prefix='', msg=None): +def who(hostmaskOrChannel, prefix='', msg=None, args=()): """Returns a WHO for the hostmask or channel hostmaskOrChannel.""" if conf.supybot.protocols.irc.strictRfc(): assert isChannel(hostmaskOrChannel) or \ @@ -744,7 +744,7 @@ def who(hostmaskOrChannel, prefix='', msg=None): if msg and not prefix: prefix = msg.prefix return IrcMsg(prefix=prefix, command='WHO', - args=(hostmaskOrChannel,), msg=msg) + args=(hostmaskOrChannel,) + args, msg=msg) def _whois(COMMAND, nick, mask='', prefix='', msg=None): """Returns a WHOIS for nick.""" diff --git a/test/test_irclib.py b/test/test_irclib.py index 190a46557..849cf9f32 100644 --- a/test/test_irclib.py +++ b/test/test_irclib.py @@ -382,6 +382,8 @@ class IrcTestCase(SupyTestCase): m = self.irc.takeMsg() self.failUnless(m.command == 'NICK', 'Expected NICK, got %r.' % m) m = self.irc.takeMsg() + self.failUnless(m.command == 'CAP', 'Expected CAP, got %r.' % m) + m = self.irc.takeMsg() self.failUnless(m.command == 'USER', 'Expected USER, got %r.' % m) def testPingResponse(self): @@ -478,7 +480,9 @@ class IrcCallbackTestCase(SupyTestCase): conf.supybot.nick.setValue(nick) user = 'user any user' conf.supybot.user.setValue(user) - expected = [ircmsgs.nick(nick), ircmsgs.user('limnoria', user)] + expected = [ircmsgs.nick(nick), + ircmsgs.IrcMsg(command='CAP', args=('LS',)), + ircmsgs.user('limnoria', user)] irc = irclib.Irc('test') msgs = [irc.takeMsg()] while msgs[-1] != None: