mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-27 05:09:23 +01:00
Merge branch 'ircv3.2' into testing
This commit is contained in:
commit
39d40ec617
@ -147,6 +147,13 @@ class NickAuth(callbacks.Plugin):
|
|||||||
irc.queueMsg(ircmsgs.whois(nick, nick))
|
irc.queueMsg(ircmsgs.whois(nick, nick))
|
||||||
auth = wrap(auth, [])
|
auth = wrap(auth, [])
|
||||||
|
|
||||||
|
def inFilter(self, irc, msg):
|
||||||
|
"""If the messages has a server tag with account name, tries to
|
||||||
|
authenticate it."""
|
||||||
|
if msg.server_tags and 'account' in msg.server_tags:
|
||||||
|
self._auth(irc, msg.prefix, msg.server_tags['account'])
|
||||||
|
return msg
|
||||||
|
|
||||||
def do330(self, irc, msg):
|
def do330(self, irc, msg):
|
||||||
mynick, theirnick, theiraccount, garbage = msg.args
|
mynick, theirnick, theiraccount, garbage = msg.args
|
||||||
# I would like to use a dict comprehension, but we have to support
|
# I would like to use a dict comprehension, but we have to support
|
||||||
@ -176,18 +183,8 @@ class NickAuth(callbacks.Plugin):
|
|||||||
account = msg.args[0]
|
account = msg.args[0]
|
||||||
user = ircdb.users.getUserFromNick(irc.network, account)
|
user = ircdb.users.getUserFromNick(irc.network, account)
|
||||||
|
|
||||||
if not user:
|
if account != '*':
|
||||||
try:
|
self._auth(irc, msg.prefix, account)
|
||||||
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):
|
def doJoin(self, irc, msg):
|
||||||
@ -196,18 +193,8 @@ class NickAuth(callbacks.Plugin):
|
|||||||
return
|
return
|
||||||
|
|
||||||
account = msg.args[1]
|
account = msg.args[1]
|
||||||
user = ircdb.users.getUserFromNick(irc.network, account)
|
if account != '*':
|
||||||
|
self._auth(irc, msg.prefix, 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):
|
def do354(self, irc, msg):
|
||||||
if len(msg.args) != 6 or msg.args[1] != '1':
|
if len(msg.args) != 6 or msg.args[1] != '1':
|
||||||
@ -217,6 +204,12 @@ class NickAuth(callbacks.Plugin):
|
|||||||
prefix = '%s!%s@%s' % (nick, ident, host)
|
prefix = '%s!%s@%s' % (nick, ident, host)
|
||||||
user = ircdb.users.getUserFromNick(irc.network, account)
|
user = ircdb.users.getUserFromNick(irc.network, account)
|
||||||
|
|
||||||
|
if account != '0':
|
||||||
|
self._auth(irc, prefix, account)
|
||||||
|
|
||||||
|
def _auth(self, irc, prefix, account):
|
||||||
|
user = ircdb.users.getUserFromNick(irc.network, account)
|
||||||
|
|
||||||
if not user:
|
if not user:
|
||||||
try:
|
try:
|
||||||
user = ircdb.users.getUser(prefix)
|
user = ircdb.users.getUser(prefix)
|
||||||
@ -224,7 +217,6 @@ class NickAuth(callbacks.Plugin):
|
|||||||
user = None
|
user = None
|
||||||
|
|
||||||
if user:
|
if user:
|
||||||
if account != '0':
|
|
||||||
user.addAuth(prefix)
|
user.addAuth(prefix)
|
||||||
ircdb.users.setUser(user, flush=False)
|
ircdb.users.setUser(user, flush=False)
|
||||||
|
|
||||||
|
@ -45,6 +45,12 @@ class NickCapture(callbacks.Plugin):
|
|||||||
self.__parent = super(NickCapture, self)
|
self.__parent = super(NickCapture, self)
|
||||||
self.__parent.__init__(irc)
|
self.__parent.__init__(irc)
|
||||||
self.lastIson = 0
|
self.lastIson = 0
|
||||||
|
self.monitoring = []
|
||||||
|
|
||||||
|
def die(self):
|
||||||
|
for irc in self.monitoring:
|
||||||
|
nick = self._getNick(irc.network)
|
||||||
|
irc.unmonitor(nick)
|
||||||
|
|
||||||
def _getNick(self, network):
|
def _getNick(self, network):
|
||||||
network_nick = conf.supybot.networks.get(network).nick()
|
network_nick = conf.supybot.networks.get(network).nick()
|
||||||
@ -60,10 +66,16 @@ class NickCapture(callbacks.Plugin):
|
|||||||
# We used to check this, but nicksToHostmasks is never cleared
|
# We used to check this, but nicksToHostmasks is never cleared
|
||||||
# except on reconnects, which can cause trouble.
|
# except on reconnects, which can cause trouble.
|
||||||
# if nick not in irc.state.nicksToHostmasks:
|
# if nick not in irc.state.nicksToHostmasks:
|
||||||
self._ison(irc, nick)
|
if 'monitor' in irc.state.supported:
|
||||||
|
if irc not in self.monitoring:
|
||||||
|
irc.monitor(nick)
|
||||||
|
self.monitoring.append(irc)
|
||||||
|
else:
|
||||||
|
self._ison(irc, nick)
|
||||||
self.__parent.__call__(irc, msg)
|
self.__parent.__call__(irc, msg)
|
||||||
|
|
||||||
def _ison(self, irc, nick):
|
def _ison(self, irc, nick):
|
||||||
|
assert 'monitor' not in irc.state.supported
|
||||||
if self.registryValue('ison'):
|
if self.registryValue('ison'):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now - self.lastIson > self.registryValue('ison.period'):
|
if now - self.lastIson > self.registryValue('ison.period'):
|
||||||
@ -95,6 +107,16 @@ class NickCapture(callbacks.Plugin):
|
|||||||
nick = self._getNick(irc.network)
|
nick = self._getNick(irc.network)
|
||||||
if nick:
|
if nick:
|
||||||
self._sendNick(irc, nick)
|
self._sendNick(irc, nick)
|
||||||
|
|
||||||
|
def do731(self, irc, msg):
|
||||||
|
"""This is sent by the MONITOR when a nick goes offline."""
|
||||||
|
nick = self._getNick(irc.network)
|
||||||
|
for target in msg.args[1].split(','):
|
||||||
|
if nick == target:
|
||||||
|
self._sendNick(irc, nick)
|
||||||
|
self.monitoring.remove(irc)
|
||||||
|
irc.unmonitor(nick)
|
||||||
|
break
|
||||||
NickCapture = internationalizeDocstring(NickCapture)
|
NickCapture = internationalizeDocstring(NickCapture)
|
||||||
|
|
||||||
Class = NickCapture
|
Class = NickCapture
|
||||||
|
@ -666,6 +666,7 @@ class Irc(IrcCommandDispatcher):
|
|||||||
self._setNonResettingVariables()
|
self._setNonResettingVariables()
|
||||||
self._queueConnectMessages()
|
self._queueConnectMessages()
|
||||||
self.startedSync = ircutils.IrcDict()
|
self.startedSync = ircutils.IrcDict()
|
||||||
|
self.monitoring = ircutils.IrcDict()
|
||||||
|
|
||||||
def isChannel(self, s):
|
def isChannel(self, s):
|
||||||
"""Helper function to check whether a given string is a channel on
|
"""Helper function to check whether a given string is a channel on
|
||||||
@ -965,7 +966,8 @@ class Irc(IrcCommandDispatcher):
|
|||||||
elif self.sasl_username and self.sasl_password:
|
elif self.sasl_username and self.sasl_password:
|
||||||
self.sasl = 'plain'
|
self.sasl = 'plain'
|
||||||
|
|
||||||
for cap in ('account-notify', 'extended-join', 'multi-prefix'):
|
for cap in ('account-notify', 'extended-join', 'multi-prefix',
|
||||||
|
'metadata-notify', 'account-tag'):
|
||||||
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('REQ', cap)))
|
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('REQ', cap)))
|
||||||
|
|
||||||
if self.sasl:
|
if self.sasl:
|
||||||
@ -1041,6 +1043,38 @@ class Irc(IrcCommandDispatcher):
|
|||||||
command='CAP',
|
command='CAP',
|
||||||
args=('END',)))
|
args=('END',)))
|
||||||
|
|
||||||
|
def monitor(self, targets):
|
||||||
|
"""Increment a counter of how many callbacks monitor each target;
|
||||||
|
and send a MONITOR + to the server if the target is not yet
|
||||||
|
monitored."""
|
||||||
|
if isinstance(targets, str):
|
||||||
|
targets = [targets]
|
||||||
|
not_yet_monitored = set()
|
||||||
|
for target in targets:
|
||||||
|
if target in self.monitoring:
|
||||||
|
self.monitoring[target] += 1
|
||||||
|
else:
|
||||||
|
not_yet_monitored.add(target)
|
||||||
|
self.monitoring[target] = 1
|
||||||
|
if not_yet_monitored:
|
||||||
|
self.queueMsg(ircmsgs.monitor('+', not_yet_monitored))
|
||||||
|
return not_yet_monitored
|
||||||
|
|
||||||
|
def unmonitor(self, targets):
|
||||||
|
"""Decrements a counter of how many callbacks monitor each target;
|
||||||
|
and send a MONITOR - to the server if the counter drops to 0."""
|
||||||
|
if isinstance(targets, str):
|
||||||
|
targets = [targets]
|
||||||
|
should_be_unmonitored = set()
|
||||||
|
for target in targets:
|
||||||
|
self.monitoring[target] -= 1
|
||||||
|
if self.monitoring[target] == 0:
|
||||||
|
del self.monitoring[target]
|
||||||
|
should_be_unmonitored.add(target)
|
||||||
|
if should_be_unmonitored:
|
||||||
|
self.queueMsg(ircmsgs.monitor('-', should_be_unmonitored))
|
||||||
|
return should_be_unmonitored
|
||||||
|
|
||||||
def do903(self, msg):
|
def do903(self, msg):
|
||||||
log.info('%s: SASL authentication successful', self.network)
|
log.info('%s: SASL authentication successful', self.network)
|
||||||
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',)))
|
self.queueMsg(ircmsgs.IrcMsg(command='CAP', args=('END',)))
|
||||||
|
@ -50,6 +50,37 @@ from .utils.iter import all
|
|||||||
class MalformedIrcMsg(ValueError):
|
class MalformedIrcMsg(ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# http://ircv3.net/specs/core/message-tags-3.2.html#escaping-values
|
||||||
|
SERVER_TAG_ESCAPE = [
|
||||||
|
('\\', '\\\\'), # \ -> \\
|
||||||
|
(' ', r'\s'),
|
||||||
|
(';', r'\:'),
|
||||||
|
('\r', r'\r'),
|
||||||
|
('\n', r'\n'),
|
||||||
|
]
|
||||||
|
escape_server_tag_value = utils.str.MultipleReplacer(
|
||||||
|
dict(SERVER_TAG_ESCAPE))
|
||||||
|
unescape_server_tag_value = utils.str.MultipleReplacer(
|
||||||
|
dict(map(lambda x:(x[1],x[0]), SERVER_TAG_ESCAPE)))
|
||||||
|
|
||||||
|
def parse_server_tags(s):
|
||||||
|
server_tags = {}
|
||||||
|
for tag in s.split(';'):
|
||||||
|
if '=' not in tag:
|
||||||
|
server_tags[tag] = None
|
||||||
|
else:
|
||||||
|
(key, value) = tag.split('=', 1)
|
||||||
|
server_tags[key] = unescape_server_tag_value(value)
|
||||||
|
return server_tags
|
||||||
|
def format_server_tags(server_tags):
|
||||||
|
parts = []
|
||||||
|
for (key, value) in server_tags.items():
|
||||||
|
if value is None:
|
||||||
|
parts.append(key)
|
||||||
|
else:
|
||||||
|
parts.append('%s=%s' % (key, escape_server_tag_value(value)))
|
||||||
|
return '@' + ';'.join(parts)
|
||||||
|
|
||||||
class IrcMsg(object):
|
class IrcMsg(object):
|
||||||
"""Class to represent an IRC message.
|
"""Class to represent an IRC message.
|
||||||
|
|
||||||
@ -81,7 +112,8 @@ class IrcMsg(object):
|
|||||||
# data. Goodbye, __slots__.
|
# data. Goodbye, __slots__.
|
||||||
# On second thought, let's use methods for tagging.
|
# On second thought, let's use methods for tagging.
|
||||||
__slots__ = ('args', 'command', 'host', 'nick', 'prefix', 'user',
|
__slots__ = ('args', 'command', 'host', 'nick', 'prefix', 'user',
|
||||||
'_hash', '_str', '_repr', '_len', 'tags', 'reply_env')
|
'_hash', '_str', '_repr', '_len', 'tags', 'reply_env',
|
||||||
|
'server_tags')
|
||||||
def __init__(self, s='', command='', args=(), prefix='', msg=None,
|
def __init__(self, s='', command='', args=(), prefix='', msg=None,
|
||||||
reply_env=None):
|
reply_env=None):
|
||||||
assert not (msg and s), 'IrcMsg.__init__ cannot accept both s and msg'
|
assert not (msg and s), 'IrcMsg.__init__ cannot accept both s and msg'
|
||||||
@ -99,6 +131,11 @@ class IrcMsg(object):
|
|||||||
if not s.endswith('\n'):
|
if not s.endswith('\n'):
|
||||||
s += '\n'
|
s += '\n'
|
||||||
self._str = s
|
self._str = s
|
||||||
|
if s[0] == '@':
|
||||||
|
(server_tags, s) = s.split(' ', 1)
|
||||||
|
self.server_tags = parse_server_tags(server_tags[1:])
|
||||||
|
else:
|
||||||
|
self.server_tags = {}
|
||||||
if s[0] == ':':
|
if s[0] == ':':
|
||||||
self.prefix, s = s[1:].split(None, 1)
|
self.prefix, s = s[1:].split(None, 1)
|
||||||
else:
|
else:
|
||||||
@ -818,6 +855,19 @@ def ison(nick, prefix='', msg=None):
|
|||||||
prefix = msg.prefix
|
prefix = msg.prefix
|
||||||
return IrcMsg(prefix=prefix, command='ISON', args=(nick,), msg=msg)
|
return IrcMsg(prefix=prefix, command='ISON', args=(nick,), msg=msg)
|
||||||
|
|
||||||
|
def monitor(subcommand, nicks=None, prefix='', msg=None):
|
||||||
|
if conf.supybot.protocols.irc.strictRfc():
|
||||||
|
assert isNick(nick), repr(nick)
|
||||||
|
assert subcommand in '+-CLS'
|
||||||
|
if subcommand in 'CLS':
|
||||||
|
assert nicks is None
|
||||||
|
if msg and not prefix:
|
||||||
|
prefix = msg.prefix
|
||||||
|
if not isinstance(nicks, str):
|
||||||
|
nicks = ','.join(nicks)
|
||||||
|
return IrcMsg(prefix=prefix, command='MONITOR', args=(subcommand, nicks),
|
||||||
|
msg=msg)
|
||||||
|
|
||||||
def error(s, msg=None):
|
def error(s, msg=None):
|
||||||
return IrcMsg(command='ERROR', args=(s,), msg=msg)
|
return IrcMsg(command='ERROR', args=(s,), msg=msg)
|
||||||
|
|
||||||
|
@ -391,6 +391,10 @@ class IrcTestCase(SupyTestCase):
|
|||||||
m = self.irc.takeMsg()
|
m = self.irc.takeMsg()
|
||||||
self.failUnless(m.command == 'CAP', 'Expected CAP, got %r.' % m)
|
self.failUnless(m.command == 'CAP', 'Expected CAP, got %r.' % m)
|
||||||
m = self.irc.takeMsg()
|
m = self.irc.takeMsg()
|
||||||
|
self.failUnless(m.command == 'CAP', 'Expected CAP, 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)
|
self.failUnless(m.command == 'USER', 'Expected USER, got %r.' % m)
|
||||||
|
|
||||||
def testPingResponse(self):
|
def testPingResponse(self):
|
||||||
@ -492,6 +496,8 @@ class IrcCallbackTestCase(SupyTestCase):
|
|||||||
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'account-notify')),
|
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'account-notify')),
|
||||||
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'extended-join')),
|
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'extended-join')),
|
||||||
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'multi-prefix')),
|
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'multi-prefix')),
|
||||||
|
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'metadata-notify')),
|
||||||
|
ircmsgs.IrcMsg(command='CAP', args=('REQ', 'account-tag')),
|
||||||
ircmsgs.IrcMsg(command='CAP', args=('END',)),
|
ircmsgs.IrcMsg(command='CAP', args=('END',)),
|
||||||
ircmsgs.user('limnoria', user)
|
ircmsgs.user('limnoria', user)
|
||||||
]
|
]
|
||||||
|
@ -128,6 +128,19 @@ class IrcMsgTestCase(SupyTestCase):
|
|||||||
m.tag('repliedTo', 12)
|
m.tag('repliedTo', 12)
|
||||||
self.assertEqual(m.repliedTo, 12)
|
self.assertEqual(m.repliedTo, 12)
|
||||||
|
|
||||||
|
def testServerTags(self):
|
||||||
|
s = '@aaa=b\\:bb;ccc;example.com/ddd=ee\\\\se ' \
|
||||||
|
':nick!ident@host.com PRIVMSG me :Hello'
|
||||||
|
m = ircmsgs.IrcMsg(s)
|
||||||
|
self.assertEqual(m.server_tags, {
|
||||||
|
'aaa': 'b;bb',
|
||||||
|
'ccc': None,
|
||||||
|
'example.com/ddd': 'ee\\se'})
|
||||||
|
self.assertEqual(m.prefix, 'nick!ident@host.com')
|
||||||
|
self.assertEqual(m.command, 'PRIVMSG')
|
||||||
|
self.assertEqual(m.args, ('me', 'Hello'))
|
||||||
|
self.assertEqual(str(m), s + '\n')
|
||||||
|
|
||||||
class FunctionsTestCase(SupyTestCase):
|
class FunctionsTestCase(SupyTestCase):
|
||||||
def testIsAction(self):
|
def testIsAction(self):
|
||||||
L = [':jemfinch!~jfincher@ts26-2.homenet.ohio-state.edu PRIVMSG'
|
L = [':jemfinch!~jfincher@ts26-2.homenet.ohio-state.edu PRIVMSG'
|
||||||
|
Loading…
Reference in New Issue
Block a user