Merge branch 'ircmsg-channel' into netconf-and-ircmsgs-channel

This commit is contained in:
Valentin Lorentz 2019-08-24 15:39:17 +02:00
commit 9326331c60
11 changed files with 216 additions and 108 deletions

View File

@ -261,7 +261,7 @@ class Owner(callbacks.Plugin):
tokens = callbacks.tokenize(s, channel=msg.args[0]) tokens = callbacks.tokenize(s, channel=msg.args[0])
self.Proxy(irc, msg, tokens) self.Proxy(irc, msg, tokens)
except SyntaxError as e: except SyntaxError as e:
irc.queueMsg(callbacks.error(msg, str(e))) irc.error(str(e))
def logmark(self, irc, msg, args, text): def logmark(self, irc, msg, args, text):
"""<text> """<text>

View File

@ -156,17 +156,25 @@ def canonicalName(command, preserve_spaces=False):
command = command[:-1] command = command[:-1]
return ''.join([x for x in command if x not in special]).lower() + reAppend return ''.join([x for x in command if x not in special]).lower() + reAppend
def reply(msg, s, prefixNick=None, private=None, def reply(*args, **kwargs):
warnings.warn('callbacks.reply is deprecated. Use irc.reply instead.',
DeprecationWarning)
return _makeReply(dynamic.irc, *args, **kwargs)
def _makeReply(irc, msg, s,
prefixNick=None, private=None,
notice=None, to=None, action=None, error=False, notice=None, to=None, action=None, error=False,
stripCtcp=True): stripCtcp=True):
msg.tag('repliedTo') msg.tag('repliedTo')
# Ok, let's make the target: # Ok, let's make the target:
# XXX This isn't entirely right. Consider to=#foo, private=True. # XXX This isn't entirely right. Consider to=#foo, private=True.
target = ircutils.replyTo(msg) target = ircutils.replyTo(msg)
if ircutils.isChannel(to): def isPublic(s):
return irc.isChannel(irc._stripChannelPrefix(s))
if to is not None and isPublic(to):
target = to target = to
if ircutils.isChannel(target): if isPublic(target):
channel = target channel = irc._stripChannelPrefix(target)
else: else:
channel = None channel = None
if notice is None: if notice is None:
@ -195,11 +203,11 @@ def reply(msg, s, prefixNick=None, private=None,
s = ircutils.safeArgument(s) s = ircutils.safeArgument(s)
if not s and not action: if not s and not action:
s = _('Error: I tried to send you an empty message.') s = _('Error: I tried to send you an empty message.')
if prefixNick and ircutils.isChannel(target): if prefixNick and isPublic(target):
# Let's may sure we don't do, "#channel: foo.". # Let's may sure we don't do, "#channel: foo.".
if not ircutils.isChannel(to): if not isPublic(to):
s = '%s: %s' % (to, s) s = '%s: %s' % (to, s)
if not ircutils.isChannel(target): if not isPublic(target):
if conf.supybot.reply.withNoticeWhenPrivate(): if conf.supybot.reply.withNoticeWhenPrivate():
notice = True notice = True
# And now, let's decide whether it's a PRIVMSG or a NOTICE. # And now, let's decide whether it's a PRIVMSG or a NOTICE.
@ -214,11 +222,16 @@ def reply(msg, s, prefixNick=None, private=None,
ret.tag('inReplyTo', msg) ret.tag('inReplyTo', msg)
return ret return ret
def error(msg, s, **kwargs): def error(*args, **kwargs):
warnings.warn('callbacks.error is deprecated. Use irc.error instead.',
DeprecationWarning)
return _makeErrorReply(dynamic.irc, *args, **kwargs)
def _makeErrorReply(irc, msg, s, **kwargs):
"""Makes an error reply to msg with the appropriate error payload.""" """Makes an error reply to msg with the appropriate error payload."""
kwargs['error'] = True kwargs['error'] = True
msg.tag('isError') msg.tag('isError')
return reply(msg, s, **kwargs) return _makeReply(irc, msg, s, **kwargs)
def getHelp(method, name=None, doc=None): def getHelp(method, name=None, doc=None):
if name is None: if name is None:
@ -400,8 +413,8 @@ def checkCommandCapability(msg, cb, commandName):
checkCapability(antiCommand) checkCapability(antiCommand)
checkAtEnd = [commandName] checkAtEnd = [commandName]
default = conf.supybot.capabilities.default() default = conf.supybot.capabilities.default()
if ircutils.isChannel(msg.args[0]): if msg.channel:
channel = msg.args[0] channel = msg.channel
checkCapability(ircdb.makeChannelCapability(channel, antiCommand)) checkCapability(ircdb.makeChannelCapability(channel, antiCommand))
chanCommand = ircdb.makeChannelCapability(channel, commandName) chanCommand = ircdb.makeChannelCapability(channel, commandName)
checkAtEnd += [chanCommand] checkAtEnd += [chanCommand]
@ -426,7 +439,7 @@ class RichReplyMethods(object):
return ircutils.standardSubstitute(self, self.msg, s) return ircutils.standardSubstitute(self, self.msg, s)
def _getConfig(self, wrapper): def _getConfig(self, wrapper):
return conf.get(wrapper, self.msg.args[0]) return conf.get(wrapper, self.msg.channel)
def replySuccess(self, s='', **kwargs): def replySuccess(self, s='', **kwargs):
v = self._getConfig(conf.supybot.replies.success) v = self._getConfig(conf.supybot.replies.success)
@ -599,7 +612,7 @@ class ReplyIrcProxy(RichReplyMethods):
raise ArgumentError raise ArgumentError
if msg is None: if msg is None:
msg = self.msg msg = self.msg
m = error(msg, s, **kwargs) m = _makeErrorReply(self, msg, s, **kwargs)
self.irc.queueMsg(m) self.irc.queueMsg(m)
return m return m
@ -609,7 +622,7 @@ class ReplyIrcProxy(RichReplyMethods):
assert not isinstance(s, ircmsgs.IrcMsg), \ assert not isinstance(s, ircmsgs.IrcMsg), \
'Old code alert: there is no longer a "msg" argument to reply.' 'Old code alert: there is no longer a "msg" argument to reply.'
kwargs.pop('noLengthCheck', None) kwargs.pop('noLengthCheck', None)
m = reply(msg, s, **kwargs) m = _makeReply(self, msg, s, **kwargs)
self.irc.queueMsg(m) self.irc.queueMsg(m)
return m return m
@ -665,9 +678,9 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
self.notice = None self.notice = None
self.private = None self.private = None
self.noLengthCheck = None self.noLengthCheck = None
if self.irc.isChannel(self.msg.args[0]): if self.msg.channel:
self.prefixNick = conf.get(conf.supybot.reply.withNickPrefix, self.prefixNick = conf.get(conf.supybot.reply.withNickPrefix,
self.msg.args[0]) self.msg.channel)
else: else:
self.prefixNick = conf.supybot.reply.withNickPrefix() self.prefixNick = conf.supybot.reply.withNickPrefix()
@ -894,7 +907,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
elif self.noLengthCheck: elif self.noLengthCheck:
# noLengthCheck only matters to NestedCommandsIrcProxy, so # noLengthCheck only matters to NestedCommandsIrcProxy, so
# it's not used here. Just in case you were wondering. # it's not used here. Just in case you were wondering.
m = reply(msg, s, to=self.to, m = _makeReply(self, msg, s, to=self.to,
notice=self.notice, notice=self.notice,
action=self.action, action=self.action,
private=self.private, private=self.private,
@ -930,7 +943,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
# action implies noLengthCheck, which has already been # action implies noLengthCheck, which has already been
# handled. Let's stick an assert in here just in case. # handled. Let's stick an assert in here just in case.
assert not self.action assert not self.action
m = reply(msg, s, to=self.to, m = _makeReply(self, msg, s, to=self.to,
notice=self.notice, notice=self.notice,
private=self.private, private=self.private,
prefixNick=self.prefixNick, prefixNick=self.prefixNick,
@ -946,7 +959,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
while instant > 1 and msgs: while instant > 1 and msgs:
instant -= 1 instant -= 1
response = msgs.pop() response = msgs.pop()
m = reply(msg, response, to=self.to, m = _makeReply(self, msg, response, to=self.to,
notice=self.notice, notice=self.notice,
private=self.private, private=self.private,
prefixNick=self.prefixNick, prefixNick=self.prefixNick,
@ -976,10 +989,10 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
pass # We'll leave it as it is. pass # We'll leave it as it is.
mask = prefix.split('!', 1)[1] mask = prefix.split('!', 1)[1]
self._mores[mask] = msgs self._mores[mask] = msgs
public = self.irc.isChannel(msg.args[0]) public = bool(self.msg.channel)
private = self.private or not public private = self.private or not public
self._mores[msg.nick] = (private, msgs) self._mores[msg.nick] = (private, msgs)
m = reply(msg, response, to=self.to, m = _makeReply(self, msg, response, to=self.to,
action=self.action, action=self.action,
notice=self.notice, notice=self.notice,
private=self.private, private=self.private,
@ -1035,7 +1048,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
if not isinstance(self.irc, irclib.Irc): if not isinstance(self.irc, irclib.Irc):
return self.irc.error(s, **kwargs) return self.irc.error(s, **kwargs)
else: else:
m = error(self.msg, s, **kwargs) m = _makeErrorReply(self, self.msg, s, **kwargs)
self.irc.queueMsg(m) self.irc.queueMsg(m)
return m return m
else: else:
@ -1346,7 +1359,7 @@ class Commands(BasePlugin, SynchronizedAndFirewalled):
help = getHelp help = getHelp
chan = None chan = None
if dynamic.msg is not None: if dynamic.msg is not None:
chan = dynamic.msg.args[0] chan = dynamic.msg.channel
if simpleSyntax is None: if simpleSyntax is None:
simpleSyntax = conf.get(conf.supybot.reply.showSimpleSyntax, chan) simpleSyntax = conf.get(conf.supybot.reply.showSimpleSyntax, chan)
if simpleSyntax: if simpleSyntax:
@ -1385,7 +1398,7 @@ class PluginMixin(BasePlugin, irclib.IrcCallback):
else: else:
noIgnore = self.noIgnore noIgnore = self.noIgnore
if noIgnore or \ if noIgnore or \
not ircdb.checkIgnored(msg.prefix, msg.args[0]) or \ not ircdb.checkIgnored(msg.prefix, msg.channel) or \
not ircutils.isUserHostmask(msg.prefix): # Some services impl. not ircutils.isUserHostmask(msg.prefix): # Some services impl.
self.__parent.__call__(irc, msg) self.__parent.__call__(irc, msg)
else: else:

View File

@ -205,9 +205,12 @@ def urlSnarfer(f):
"""Protects the snarfer from loops (with other bots) and whatnot.""" """Protects the snarfer from loops (with other bots) and whatnot."""
def newf(self, irc, msg, match, *L, **kwargs): def newf(self, irc, msg, match, *L, **kwargs):
url = match.group(0) url = match.group(0)
channel = msg.args[0] channel = msg.channel
if not irc.isChannel(channel) or (ircmsgs.isCtcp(msg) and not if not channel:
ircmsgs.isAction(msg)): # Don't snarf in private
return
if not (ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg)):
# Don't snarf CTCPs unless they are a /me
return return
if ircdb.channels.getChannel(channel).lobotomized: if ircdb.channels.getChannel(channel).lobotomized:
self.log.debug('Not snarfing in %s: lobotomized.', channel) self.log.debug('Not snarfing in %s: lobotomized.', channel)
@ -491,10 +494,11 @@ def getChannel(irc, msg, args, state):
return return
if args and irc.isChannel(args[0]): if args and irc.isChannel(args[0]):
channel = args.pop(0) channel = args.pop(0)
elif irc.isChannel(msg.args[0]): elif msg.channel:
channel = msg.args[0] channel = msg.channel
else: else:
state.log.debug('Raising ArgumentError because there is no channel.') state.log.debug('Raising ArgumentError because there is no channel.')
print(msg.channel, msg)
raise callbacks.ArgumentError raise callbacks.ArgumentError
state.channel = channel state.channel = channel
state.args.append(channel) state.args.append(channel)
@ -502,8 +506,8 @@ def getChannel(irc, msg, args, state):
def getChannels(irc, msg, args, state): def getChannels(irc, msg, args, state):
if args and all(map(irc.isChannel, args[0].split(','))): if args and all(map(irc.isChannel, args[0].split(','))):
channels = args.pop(0).split(',') channels = args.pop(0).split(',')
elif irc.isChannel(msg.args[0]): elif msg.channel:
channels = [msg.args[0]] channels = [msg.channel]
else: else:
state.log.debug('Raising ArgumentError because there is no channel.') state.log.debug('Raising ArgumentError because there is no channel.')
raise callbacks.ArgumentError raise callbacks.ArgumentError
@ -535,11 +539,11 @@ def inChannel(irc, msg, args, state):
state.error(_('I\'m not in %s.') % state.channel, Raise=True) state.error(_('I\'m not in %s.') % state.channel, Raise=True)
def onlyInChannel(irc, msg, args, state): def onlyInChannel(irc, msg, args, state):
if not (irc.isChannel(msg.args[0]) and msg.args[0] in irc.state.channels): if not (msg.channel and msg.channel in irc.state.channels):
state.error(_('This command may only be given in a channel that I am ' state.error(_('This command may only be given in a channel that I am '
'in.'), Raise=True) 'in.'), Raise=True)
else: else:
state.channel = msg.args[0] state.channel = msg.channel
state.args.append(state.channel) state.args.append(state.channel)
def callerInGivenChannel(irc, msg, args, state): def callerInGivenChannel(irc, msg, args, state):
@ -576,8 +580,8 @@ def getChannelOrGlobal(irc, msg, args, state):
elif args and irc.isChannel(args[0]): elif args and irc.isChannel(args[0]):
channel = args.pop(0) channel = args.pop(0)
state.channel = channel state.channel = channel
elif irc.isChannel(msg.args[0]): elif msg.channel:
channel = msg.args[0] channel = msg.channel
state.channel = channel state.channel = channel
else: else:
state.log.debug('Raising ArgumentError because there is no channel.') state.log.debug('Raising ArgumentError because there is no channel.')
@ -620,11 +624,11 @@ def getSomethingNoSpaces(irc, msg, args, state, *L):
getSomething(irc, msg, args, state, p=p, *L) getSomething(irc, msg, args, state, p=p, *L)
def private(irc, msg, args, state): def private(irc, msg, args, state):
if irc.isChannel(msg.args[0]): if msg.channel:
state.errorRequiresPrivacy(Raise=True) state.errorRequiresPrivacy(Raise=True)
def public(irc, msg, args, state, errmsg=None): def public(irc, msg, args, state, errmsg=None):
if not irc.isChannel(msg.args[0]): if not msg.channel:
if errmsg is None: if errmsg is None:
errmsg = _('This message must be sent in a channel.') errmsg = _('This message must be sent in a channel.')
state.error(errmsg, Raise=True) state.error(errmsg, Raise=True)

View File

@ -875,16 +875,34 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
else: else:
return None return None
_numericErrorCommandRe = re.compile(r'^[45][0-9][0-9]$') def _tagMsg(self, msg):
def feedMsg(self, msg): """Sets attribute on an incoming IRC message. Will usually only be
"""Called by the IrcDriver; feeds a message received.""" called by feedMsg, but may be useful in tests as well."""
msg.tag('receivedBy', self) msg.tag('receivedBy', self)
msg.tag('receivedOn', self.network) msg.tag('receivedOn', self.network)
msg.tag('receivedAt', time.time()) msg.tag('receivedAt', time.time())
if msg.args and self.isChannel(msg.args[0]):
channel = msg.args[0] # Check if the message is sent to a channel
if msg.args:
msg.channel = msg.args[0]
if msg.command in ('NOTICE', 'PRIVMSG') and \
not conf.supybot.protocols.irc.strictRfc():
msg.channel = self._stripChannelPrefix(msg.channel)
if not self.isChannel(msg.channel):
msg.channel = None
else: else:
channel = None msg.channel = None
def _stripChannelPrefix(self, channel):
statusmsg_chars = self.state.supported.get('statusmsg', '')
return channel.lstrip(statusmsg_chars)
_numericErrorCommandRe = re.compile(r'^[45][0-9][0-9]$')
def feedMsg(self, msg):
"""Called by the IrcDriver; feeds a message received."""
self._tagMsg(msg)
channel = msg.channel
preInFilter = str(msg).rstrip('\r\n') preInFilter = str(msg).rstrip('\r\n')
log.debug('Incoming message (%s): %s', self.network, preInFilter) log.debug('Incoming message (%s): %s', self.network, preInFilter)

View File

@ -116,7 +116,7 @@ class IrcMsg(object):
# 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', 'time') 'server_tags', 'time', 'channel')
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'

View File

@ -659,7 +659,10 @@ def safeArgument(s):
def replyTo(msg): def replyTo(msg):
"""Returns the appropriate target to send responses to msg.""" """Returns the appropriate target to send responses to msg."""
if isChannel(msg.args[0]): if msg.channel:
# if message was sent to +#channel, we want to reply to +#channel;
# or unvoiced channel users will see the bot reply without the
# origin query
return msg.args[0] return msg.args[0]
else: else:
return msg.nick return msg.nick
@ -867,10 +870,7 @@ def standardSubstitute(irc, msg, text, env=None):
vars.update(msg.reply_env) vars.update(msg.reply_env)
if irc and msg: if irc and msg:
if isChannel(msg.args[0]): channel = msg.channel or 'somewhere'
channel = msg.args[0]
else:
channel = 'somewhere'
def randNick(): def randNick():
if channel != 'somewhere': if channel != 'somewhere':
L = list(irc.state.channels[channel].users) L = list(irc.state.channels[channel].users)

View File

@ -175,6 +175,7 @@ class FunctionsTestCase(SupyTestCase):
self.assertEqual('foobar--', callbacks.canonicalName('foobar--')) self.assertEqual('foobar--', callbacks.canonicalName('foobar--'))
def testAddressed(self): def testAddressed(self):
irc = getTestIrc()
oldprefixchars = str(conf.supybot.reply.whenAddressedBy.chars) oldprefixchars = str(conf.supybot.reply.whenAddressedBy.chars)
nick = 'supybot' nick = 'supybot'
conf.supybot.reply.whenAddressedBy.chars.set('~!@') conf.supybot.reply.whenAddressedBy.chars.set('~!@')
@ -189,6 +190,7 @@ class FunctionsTestCase(SupyTestCase):
for msg in inChannel: for msg in inChannel:
self.assertEqual('foo', callbacks.addressed(nick, msg), msg) self.assertEqual('foo', callbacks.addressed(nick, msg), msg)
msg = ircmsgs.privmsg(nick, 'foo') msg = ircmsgs.privmsg(nick, 'foo')
irc._tagMsg(msg)
self.assertEqual('foo', callbacks.addressed(nick, msg)) self.assertEqual('foo', callbacks.addressed(nick, msg))
conf.supybot.reply.whenAddressedBy.chars.set(oldprefixchars) conf.supybot.reply.whenAddressedBy.chars.set(oldprefixchars)
msg = ircmsgs.privmsg('#foo', '%s::::: bar' % nick) msg = ircmsgs.privmsg('#foo', '%s::::: bar' % nick)
@ -216,52 +218,84 @@ class FunctionsTestCase(SupyTestCase):
conf.supybot.reply.whenNotAddressed.setValue(original) conf.supybot.reply.whenNotAddressed.setValue(original)
def testAddressedWithMultipleNicks(self): def testAddressedWithMultipleNicks(self):
irc = getTestIrc()
msg = ircmsgs.privmsg('#foo', 'bar: baz') msg = ircmsgs.privmsg('#foo', 'bar: baz')
irc._tagMsg(msg)
self.assertEqual(callbacks.addressed('bar', msg), 'baz') self.assertEqual(callbacks.addressed('bar', msg), 'baz')
# need to recreate the msg objects since the old ones have already # need to recreate the msg objects since the old ones have already
# been tagged # been tagged
msg = ircmsgs.privmsg('#foo', 'bar: baz') msg = ircmsgs.privmsg('#foo', 'bar: baz')
irc._tagMsg(msg)
self.assertEqual(callbacks.addressed('biff', msg, nicks=['bar']), self.assertEqual(callbacks.addressed('biff', msg, nicks=['bar']),
'baz') 'baz')
def testAddressedWithNickAtEnd(self): def testAddressedWithNickAtEnd(self):
irc = getTestIrc()
msg = ircmsgs.privmsg('#foo', 'baz, bar') msg = ircmsgs.privmsg('#foo', 'baz, bar')
irc._tagMsg(msg)
self.assertEqual(callbacks.addressed('bar', msg, self.assertEqual(callbacks.addressed('bar', msg,
whenAddressedByNickAtEnd=True), whenAddressedByNickAtEnd=True),
'baz') 'baz')
def testAddressedPrefixCharsTakePrecedenceOverNickAtEnd(self): def testAddressedPrefixCharsTakePrecedenceOverNickAtEnd(self):
irc = getTestIrc()
msg = ircmsgs.privmsg('#foo', '@echo foo') msg = ircmsgs.privmsg('#foo', '@echo foo')
irc._tagMsg(msg)
self.assertEqual(callbacks.addressed('foo', msg, self.assertEqual(callbacks.addressed('foo', msg,
whenAddressedByNickAtEnd=True, whenAddressedByNickAtEnd=True,
prefixChars='@'), prefixChars='@'),
'echo foo') 'echo foo')
def testReply(self): def testReply(self):
irc = getTestIrc()
prefix = 'foo!bar@baz' prefix = 'foo!bar@baz'
channelMsg = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix) channelMsg = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix)
nonChannelMsg = ircmsgs.privmsg('supybot', 'bar baz', prefix=prefix) nonChannelMsg = ircmsgs.privmsg('supybot', 'bar baz', prefix=prefix)
irc._tagMsg(channelMsg)
irc._tagMsg(nonChannelMsg)
self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'), self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'),
callbacks.reply(channelMsg, 'foo', private=True)) callbacks._makeReply(irc, channelMsg, 'foo',
private=True))
self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'), self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'),
callbacks.reply(nonChannelMsg, 'foo')) callbacks._makeReply(irc, nonChannelMsg, 'foo'))
self.assertEqual(ircmsgs.privmsg(channelMsg.args[0], self.assertEqual(ircmsgs.privmsg(channelMsg.args[0],
'%s: foo' % channelMsg.nick), '%s: foo' % channelMsg.nick),
callbacks.reply(channelMsg, 'foo')) callbacks._makeReply(irc, channelMsg, 'foo'))
self.assertEqual(ircmsgs.privmsg(channelMsg.args[0], self.assertEqual(ircmsgs.privmsg(channelMsg.args[0],
'foo'), 'foo'),
callbacks.reply(channelMsg, 'foo', prefixNick=False)) callbacks._makeReply(irc, channelMsg, 'foo',
prefixNick=False))
self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'), self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'),
callbacks.reply(channelMsg, 'foo', callbacks._makeReply(irc, channelMsg, 'foo',
notice=True, private=True)) notice=True, private=True))
def testReplyStatusmsg(self):
irc = getTestIrc()
prefix = 'foo!bar@baz'
msg = ircmsgs.privmsg('+#foo', 'bar baz', prefix=prefix)
irc._tagMsg(msg)
# No statusmsg set, so understood as being a private message, so
# private reply
self.assertEqual(ircmsgs.notice(msg.nick, 'foo'),
callbacks._makeReply(irc, msg, 'foo'))
irc.state.supported['statusmsg'] = '+'
msg = ircmsgs.privmsg('+#foo', 'bar baz', prefix=prefix)
irc._tagMsg(msg)
print(msg.channel)
self.assertEqual(ircmsgs.privmsg('+#foo', '%s: foo' % msg.nick),
callbacks._makeReply(irc, msg, 'foo'))
def testReplyTo(self): def testReplyTo(self):
irc = getTestIrc()
prefix = 'foo!bar@baz' prefix = 'foo!bar@baz'
msg = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix) msg = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix)
self.assertEqual(callbacks.reply(msg, 'blah', to='blah'), irc._tagMsg(msg)
self.assertEqual(callbacks._makeReply(irc, msg, 'blah', to='blah'),
ircmsgs.privmsg('#foo', 'blah: blah')) ircmsgs.privmsg('#foo', 'blah: blah'))
self.assertEqual(callbacks.reply(msg, 'blah', to='blah', private=True), self.assertEqual(callbacks._makeReply(irc, msg, 'blah', to='blah',
private=True),
ircmsgs.notice('blah', 'blah')) ircmsgs.notice('blah', 'blah'))
def testTokenize(self): def testTokenize(self):
@ -682,7 +716,9 @@ class WithPrivateNoticeTestCase(ChannelPluginTestCase):
class ProxyTestCase(SupyTestCase): class ProxyTestCase(SupyTestCase):
def testHashing(self): def testHashing(self):
irc = getTestIrc()
msg = ircmsgs.ping('0') msg = ircmsgs.ping('0')
irc._tagMsg(msg)
irc = irclib.Irc('test') irc = irclib.Irc('test')
proxy = callbacks.SimpleProxy(irc, msg) proxy = callbacks.SimpleProxy(irc, msg)
# First one way... # First one way...

View File

@ -47,6 +47,7 @@ class CommandsTestCase(SupyTestCase):
realIrc = getTestIrc() realIrc = getTestIrc()
realIrc.nick = 'test' realIrc.nick = 'test'
realIrc.state.supported['chantypes'] = '#' realIrc.state.supported['chantypes'] = '#'
realIrc._tagMsg(msg)
irc = callbacks.SimpleProxy(realIrc, msg) irc = callbacks.SimpleProxy(realIrc, msg)
myspec = Spec(spec, **kwargs) myspec = Spec(spec, **kwargs)
state = myspec(irc, msg, given) state = myspec(irc, msg, given)

View File

@ -470,6 +470,42 @@ class IrcTestCase(SupyTestCase):
self.irc.feedMsg(msg2) self.irc.feedMsg(msg2)
self.assertEqual(list(self.irc.state.history), [msg1, msg2]) self.assertEqual(list(self.irc.state.history), [msg1, msg2])
def testMsgChannel(self):
self.irc.reset()
self.irc.state.supported['statusmsg'] = '@'
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG #linux :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux')
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG @#linux2 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux2')
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG +#linux3 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, None)
self.irc.state.supported['statusmsg'] = '+@'
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG #linux :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux')
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG @#linux2 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux2')
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG +#linux3 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux3')
del self.irc.state.supported['statusmsg']
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG #linux :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux')
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG @#linux2 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, None)
self.irc.feedMsg(ircmsgs.IrcMsg('PRIVMSG +#linux3 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, None)
# Test msg.channel is set only for PRIVMSG and NOTICE
self.irc.state.supported['statusmsg'] = '+@'
self.irc.feedMsg(ircmsgs.IrcMsg('NOTICE @#linux :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux')
self.irc.feedMsg(ircmsgs.IrcMsg('NOTICE @#linux2 :foo bar baz!'))
self.assertEqual(self.irc.state.history[-1].channel, '#linux2')
self.irc.feedMsg(ircmsgs.IrcMsg('MODE @#linux3 +v foo'))
self.assertEqual(self.irc.state.history[-1].channel, None)
def testQuit(self): def testQuit(self):
self.irc.reset() self.irc.reset()
self.irc.feedMsg(ircmsgs.IrcMsg(':someuser JOIN #foo')) self.irc.feedMsg(ircmsgs.IrcMsg(':someuser JOIN #foo'))

View File

@ -281,12 +281,10 @@ class FunctionsTestCase(SupyTestCase):
def testStandardSubstitute(self): def testStandardSubstitute(self):
# Stub out random msg and irc objects that provide what # Stub out random msg and irc objects that provide what
# standardSubstitute wants # standardSubstitute wants
msg = ircmsgs.IrcMsg(':%s PRIVMSG #channel :stuff' % self.hostmask) irc = getTestIrc()
class Irc(object):
nick = 'bob'
network = 'testnet'
irc = Irc() msg = ircmsgs.IrcMsg(':%s PRIVMSG #channel :stuff' % self.hostmask)
irc._tagMsg(msg)
f = ircutils.standardSubstitute f = ircutils.standardSubstitute
vars = {'foo': 'bar', 'b': 'c', 'i': 100, vars = {'foo': 'bar', 'b': 'c', 'i': 100,
@ -344,9 +342,12 @@ class FunctionsTestCase(SupyTestCase):
self.assertEqual('{}|^', ircutils.toLower('[]\\~')) self.assertEqual('{}|^', ircutils.toLower('[]\\~'))
def testReplyTo(self): def testReplyTo(self):
irc = getTestIrc()
prefix = 'foo!bar@baz' prefix = 'foo!bar@baz'
channel = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix) channel = ircmsgs.privmsg('#foo', 'bar baz', prefix=prefix)
private = ircmsgs.privmsg('jemfinch', 'bar baz', prefix=prefix) private = ircmsgs.privmsg('jemfinch', 'bar baz', prefix=prefix)
irc._tagMsg(channel)
irc._tagMsg(private)
self.assertEqual(ircutils.replyTo(channel), channel.args[0]) self.assertEqual(ircutils.replyTo(channel), channel.args[0])
self.assertEqual(ircutils.replyTo(private), private.nick) self.assertEqual(ircutils.replyTo(private), private.nick)

View File

@ -37,54 +37,53 @@ class holder:
users = set(map(str, range(1000))) users = set(map(str, range(1000)))
class FunctionsTestCase(SupyTestCase): class FunctionsTestCase(SupyTestCase):
class irc:
class state:
channels = {'#foo': holder()}
nick = 'foobar'
network = 'testnet'
@retry() @retry()
def testStandardSubstitute(self): def testStandardSubstitute(self):
irc = getTestIrc()
irc.state.channels = {'#foo': holder()}
f = ircutils.standardSubstitute f = ircutils.standardSubstitute
msg = ircmsgs.privmsg('#foo', 'filler', prefix='biff!quux@xyzzy') msg = ircmsgs.privmsg('#foo', 'filler', prefix='biff!quux@xyzzy')
s = f(self.irc, msg, '$rand') irc._tagMsg(msg)
s = f(irc, msg, '$rand')
try: try:
int(s) int(s)
except ValueError: except ValueError:
self.fail('$rand wasn\'t an int.') self.fail('$rand wasn\'t an int.')
s = f(self.irc, msg, '$randomInt') s = f(irc, msg, '$randomInt')
try: try:
int(s) int(s)
except ValueError: except ValueError:
self.fail('$randomint wasn\'t an int.') self.fail('$randomint wasn\'t an int.')
self.assertEqual(f(self.irc, msg, '$botnick'), self.irc.nick) self.assertEqual(f(irc, msg, '$botnick'), irc.nick)
self.assertEqual(f(self.irc, msg, '$who'), msg.nick) self.assertEqual(f(irc, msg, '$who'), msg.nick)
self.assertEqual(f(self.irc, msg, '$WHO'), self.assertEqual(f(irc, msg, '$WHO'),
msg.nick, 'stand. sub. not case-insensitive.') msg.nick, 'stand. sub. not case-insensitive.')
self.assertEqual(f(self.irc, msg, '$nick'), msg.nick) self.assertEqual(f(irc, msg, '$nick'), msg.nick)
self.assertNotEqual(f(self.irc, msg, '$randomdate'), '$randomdate') self.assertNotEqual(f(irc, msg, '$randomdate'), '$randomdate')
q = f(self.irc,msg,'$randomdate\t$randomdate') q = f(irc,msg,'$randomdate\t$randomdate')
dl = q.split('\t') dl = q.split('\t')
if dl[0] == dl[1]: if dl[0] == dl[1]:
self.fail ('Two $randomdates in the same string were the same') self.fail ('Two $randomdates in the same string were the same')
q = f(self.irc, msg, '$randomint\t$randomint') q = f(irc, msg, '$randomint\t$randomint')
dl = q.split('\t') dl = q.split('\t')
if dl[0] == dl[1]: if dl[0] == dl[1]:
self.fail ('Two $randomints in the same string were the same') self.fail ('Two $randomints in the same string were the same')
self.assertNotEqual(f(self.irc, msg, '$today'), '$today') self.assertNotEqual(f(irc, msg, '$today'), '$today')
self.assertNotEqual(f(self.irc, msg, '$now'), '$now') self.assertNotEqual(f(irc, msg, '$now'), '$now')
n = f(self.irc, msg, '$randnick') n = f(irc, msg, '$randnick')
self.failUnless(n in self.irc.state.channels['#foo'].users) self.failUnless(n in irc.state.channels['#foo'].users)
n = f(self.irc, msg, '$randomnick') n = f(irc, msg, '$randomnick')
self.failUnless(n in self.irc.state.channels['#foo'].users) self.failUnless(n in irc.state.channels['#foo'].users)
n = f(self.irc, msg, '$randomnick '*100) n = f(irc, msg, '$randomnick '*100)
L = n.split() L = n.split()
self.failIf(all(L[0].__eq__, L), 'all $randomnicks were the same') self.failIf(all(L[0].__eq__, L), 'all $randomnicks were the same')
c = f(self.irc, msg, '$channel') c = f(irc, msg, '$channel')
self.assertEqual(c, msg.args[0]) self.assertEqual(c, msg.args[0])
net = f(self.irc, msg, '$network') net = f(irc, msg, '$network')
self.assertEqual(net, self.irc.network) self.assertEqual(net, irc.network)