mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-14 14:49:21 +01:00
Merge branch 'netconf-and-ircmsgs-channel' into testing
This commit is contained in:
commit
573921c00f
@ -49,9 +49,9 @@ def getChannel(irc, msg, args):
|
||||
If the channel was given in args, args is modified (the channel is
|
||||
removed).
|
||||
"""
|
||||
if args and irc.isChannel(msg.args[0]):
|
||||
if args and msg.channel:
|
||||
if conf.supybot.reply.requireChannelCommandsToBeSentInChannel():
|
||||
if args[0] != msg.args[0]:
|
||||
if args[0] != msg.channel:
|
||||
s = 'Channel commands must be sent in the channel to which ' \
|
||||
'they apply; if this is not the behavior you desire, ' \
|
||||
'ask the bot\'s administrator to change the registry ' \
|
||||
@ -60,8 +60,8 @@ def getChannel(irc, msg, args):
|
||||
'to False.'
|
||||
raise callbacks.Error(s)
|
||||
return args.pop(0)
|
||||
elif irc.isChannel(msg.args[0]):
|
||||
return msg.args[0]
|
||||
elif msg.channel:
|
||||
return msg.channel
|
||||
else:
|
||||
raise callbacks.Error('Command must be sent in a channel or ' \
|
||||
'include a channel in its arguments.')
|
||||
|
@ -50,17 +50,20 @@ class Anonymous(callbacks.Plugin):
|
||||
supybot.plugins.Anonymous.requireRegistration.
|
||||
"""
|
||||
def _preCheck(self, irc, msg, target, action):
|
||||
if self.registryValue('requireRegistration', target):
|
||||
if self.registryValue('requireRegistration', target, irc.network):
|
||||
try:
|
||||
foo = ircdb.users.getUser(msg.prefix)
|
||||
except KeyError:
|
||||
irc.errorNotRegistered(Raise=True)
|
||||
capability = self.registryValue('requireCapability', target)
|
||||
capability = self.registryValue('requireCapability',
|
||||
target, irc.network)
|
||||
if capability:
|
||||
if not ircdb.checkCapability(msg.prefix, capability):
|
||||
irc.errorNoCapability(capability, Raise=True)
|
||||
if action != 'tell':
|
||||
if self.registryValue('requirePresenceInChannel', target) and \
|
||||
require_presence = self.registryValue('requirePresenceInChannel',
|
||||
target, irc.network)
|
||||
if require_presence and \
|
||||
msg.nick not in irc.state.channels[target].users:
|
||||
irc.error(format(_('You must be in %s to %q in there.'),
|
||||
target, action), Raise=True)
|
||||
|
@ -48,12 +48,13 @@ class AutoMode(callbacks.Plugin):
|
||||
"""This plugin, when configured, allows the bot to automatically set modes
|
||||
on users when they join."""
|
||||
def doJoin(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
network = irc.network
|
||||
if ircutils.strEqual(irc.nick, msg.nick):
|
||||
return
|
||||
if not self.registryValue('enable', channel):
|
||||
if not self.registryValue('enable', channel, network):
|
||||
return
|
||||
fallthrough = self.registryValue('fallthrough', channel)
|
||||
fallthrough = self.registryValue('fallthrough', channel, network)
|
||||
def do(type):
|
||||
cap = ircdb.makeChannelCapability(channel, type)
|
||||
cap_auto = ircdb.makeChannelCapability(channel, 'auto'+type)
|
||||
@ -63,7 +64,7 @@ class AutoMode(callbacks.Plugin):
|
||||
ignoreChannelOp=True, ignoreDefaultAllow=True)
|
||||
except KeyError:
|
||||
apply_mode = False
|
||||
if self.registryValue('alternativeCapabilities', channel):
|
||||
if self.registryValue('alternativeCapabilities', channel, network):
|
||||
try:
|
||||
override = ircdb.checkCapability(msg.prefix, cap_auto,
|
||||
ignoreOwner=not self.registryValue('owner'),
|
||||
@ -73,9 +74,9 @@ class AutoMode(callbacks.Plugin):
|
||||
else:
|
||||
override = False
|
||||
if apply_mode or override:
|
||||
if override or self.registryValue(type, channel):
|
||||
self.log.info('Scheduling auto-%s of %s in %s.',
|
||||
type, msg.prefix, channel)
|
||||
if override or self.registryValue(type, channel, network):
|
||||
self.log.info('Scheduling auto-%s of %s in %s @ %s.',
|
||||
type, msg.prefix, channel, network)
|
||||
def dismiss():
|
||||
"""Determines whether or not a mode has already
|
||||
been applied."""
|
||||
@ -87,8 +88,9 @@ class AutoMode(callbacks.Plugin):
|
||||
raise Continue # Even if fallthrough, let's only do one.
|
||||
elif not fallthrough:
|
||||
self.log.debug('%s has %s, but supybot.plugins.AutoMode.%s'
|
||||
' is not enabled in %s, refusing to fall '
|
||||
'through.', msg.prefix, cap, type, channel)
|
||||
' is not enabled in %s @ %s, refusing to '
|
||||
'fall through.',
|
||||
msg.prefix, cap, type, channel, network)
|
||||
raise Continue
|
||||
def schedule_msg(msg, dismiss):
|
||||
def f():
|
||||
@ -96,7 +98,7 @@ class AutoMode(callbacks.Plugin):
|
||||
irc.queueMsg(msg)
|
||||
else:
|
||||
self.log.info('Dismissing auto-mode for %s.', msg.args[2])
|
||||
delay = self.registryValue('delay', channel)
|
||||
delay = self.registryValue('delay', channel, network)
|
||||
if delay:
|
||||
schedule.addEvent(f, time.time() + delay)
|
||||
else:
|
||||
@ -107,7 +109,7 @@ class AutoMode(callbacks.Plugin):
|
||||
except KeyError:
|
||||
return
|
||||
pattern = re.compile('-|\+')
|
||||
for item in self.registryValue('extra', channel):
|
||||
for item in self.registryValue('extra', channel, network):
|
||||
try:
|
||||
username, modes = pattern.split(item, maxsplit=1)
|
||||
modes = item[len(username)] + modes
|
||||
@ -118,8 +120,8 @@ class AutoMode(callbacks.Plugin):
|
||||
if username != user.name:
|
||||
continue
|
||||
else:
|
||||
self.log.info('Scheduling auto-modes %s of %s in %s.',
|
||||
modes, msg.prefix, channel)
|
||||
self.log.info('Scheduling auto-modes %s of %s in %s @ %s.',
|
||||
modes, msg.prefix, channel, network)
|
||||
modes = [modes] + \
|
||||
([msg.nick]*len(pattern.sub('', modes)))
|
||||
schedule_msg(ircmsgs.mode(channel, modes), lambda :False)
|
||||
@ -133,8 +135,9 @@ class AutoMode(callbacks.Plugin):
|
||||
finally:
|
||||
extra_modes()
|
||||
c = ircdb.channels.getChannel(channel)
|
||||
if c.checkBan(msg.prefix) and self.registryValue('ban', channel):
|
||||
period = self.registryValue('ban.period', channel)
|
||||
if c.checkBan(msg.prefix) and self.registryValue('ban',
|
||||
channel, network):
|
||||
period = self.registryValue('ban.period', channel, network)
|
||||
if period:
|
||||
def unban():
|
||||
try:
|
||||
|
@ -72,10 +72,11 @@ class BadWords(callbacks.Privmsg):
|
||||
# We need to check for bad words here rather than in doPrivmsg because
|
||||
# messages don't get to doPrivmsg if the user is ignored.
|
||||
if msg.command == 'PRIVMSG' and self.words():
|
||||
channel = msg.args[0]
|
||||
self.updateRegexp(channel)
|
||||
channel = msg.channel
|
||||
self.updateRegexp(channel, irc.network)
|
||||
s = ircutils.stripFormatting(msg.args[1])
|
||||
if irc.isChannel(channel) and self.registryValue('kick', channel):
|
||||
if irc.isChannel(channel) \
|
||||
and self.registryValue('kick', channel, irc.network):
|
||||
if self.regexp.search(s):
|
||||
c = irc.state.channels[channel]
|
||||
cap = ircdb.makeChannelCapability(channel, 'op')
|
||||
@ -86,22 +87,23 @@ class BadWords(callbacks.Privmsg):
|
||||
"they are halfop+ or can't be "
|
||||
"kicked.", msg.nick, channel)
|
||||
else:
|
||||
message = self.registryValue('kick.message', channel)
|
||||
message = self.registryValue('kick.message',
|
||||
channel, irc.network)
|
||||
irc.queueMsg(ircmsgs.kick(channel, msg.nick, message))
|
||||
else:
|
||||
self.log.warning('Should kick %s from %s, but not opped.',
|
||||
msg.nick, channel)
|
||||
return msg
|
||||
|
||||
def updateRegexp(self, channel):
|
||||
def updateRegexp(self, channel, network):
|
||||
if self.lastModified < self.words.lastModified:
|
||||
self.makeRegexp(self.words(), channel)
|
||||
self.makeRegexp(self.words(), channel, network)
|
||||
self.lastModified = time.time()
|
||||
|
||||
def outFilter(self, irc, msg):
|
||||
if self.filtering and msg.command == 'PRIVMSG' and self.words():
|
||||
channel = msg.args[0]
|
||||
self.updateRegexp(channel)
|
||||
channel = msg.channel
|
||||
self.updateRegexp(channel, irc.network)
|
||||
s = msg.args[1]
|
||||
if self.registryValue('stripFormatting'):
|
||||
s = ircutils.stripFormatting(s)
|
||||
@ -110,9 +112,9 @@ class BadWords(callbacks.Privmsg):
|
||||
msg = ircmsgs.privmsg(msg.args[0], t, msg=msg)
|
||||
return msg
|
||||
|
||||
def makeRegexp(self, iterable, channel):
|
||||
def makeRegexp(self, iterable, channel, network):
|
||||
s = '(%s)' % '|'.join(map(re.escape, iterable))
|
||||
if self.registryValue('requireWordBoundaries', channel):
|
||||
if self.registryValue('requireWordBoundaries', channel, network):
|
||||
s = r'\b%s\b' % s
|
||||
self.regexp = re.compile(s, re.I)
|
||||
|
||||
|
@ -54,24 +54,26 @@ class Channel(callbacks.Plugin):
|
||||
self.invites = {}
|
||||
|
||||
def doKick(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
network = irc.network
|
||||
if msg.args[1] == irc.nick:
|
||||
if self.registryValue('alwaysRejoin', channel):
|
||||
delay = self.registryValue('rejoinDelay', channel)
|
||||
if self.registryValue('alwaysRejoin', channel, network):
|
||||
delay = self.registryValue('rejoinDelay', channel, network)
|
||||
networkGroup = conf.supybot.networks.get(irc.network)
|
||||
if delay:
|
||||
def f():
|
||||
irc.sendMsg(networkGroup.channels.join(channel))
|
||||
schedule.addEvent(f, time.time() + delay)
|
||||
self.log.info('Kicked from %s by %s. Rejoining after %s '
|
||||
'seconds.', channel, msg.prefix, delay)
|
||||
self.log.info('Kicked from %s @ %s by %s. '
|
||||
'Rejoining after %s seconds.',
|
||||
channel, network, msg.prefix, delay)
|
||||
else:
|
||||
self.log.info('Kicked from %s by %s. Rejoining.',
|
||||
channel, msg.prefix)
|
||||
self.log.info('Kicked from %s @ %s by %s. Rejoining.',
|
||||
channel, network, msg.prefix)
|
||||
irc.sendMsg(networkGroup.channels.join(channel))
|
||||
else:
|
||||
self.log.info('Kicked from %s by %s. Not auto-rejoining.',
|
||||
channel, msg.prefix)
|
||||
self.log.info('Kicked from %s @ %s by %s. Not auto-rejoining.',
|
||||
channel, network, msg.prefix)
|
||||
|
||||
def _sendMsg(self, irc, msg):
|
||||
irc.queueMsg(msg)
|
||||
@ -274,7 +276,7 @@ class Channel(callbacks.Plugin):
|
||||
supybot.plugins.Channel.partMsg will be used. No part message will be
|
||||
used if neither a cycle reason nor a default part message is given.
|
||||
"""
|
||||
reason = (reason or self.registryValue("partMsg", channel))
|
||||
reason = (reason or self.registryValue("partMsg", channel, irc.network))
|
||||
reason = ircutils.standardSubstitute(irc, msg, reason)
|
||||
self._sendMsg(irc, ircmsgs.part(channel, reason))
|
||||
networkGroup = conf.supybot.networks.get(irc.network)
|
||||
@ -907,12 +909,20 @@ class Channel(callbacks.Plugin):
|
||||
nicks if --count option is provided.
|
||||
"""
|
||||
# Make sure we don't elicit information about private channels to
|
||||
# people or channels that shouldn't know
|
||||
# people or channels that shouldn't know. Someone is allowed if
|
||||
# any of these are true:
|
||||
# * the channel is not secret (mode +s),
|
||||
# * the request is sent to the channel itself (FIXME: what about
|
||||
# channels without +n?),
|
||||
# * the requester is op,
|
||||
# * the request is not sent to a channel (or else everyone in the
|
||||
# channel would see the response) and the requester is in the
|
||||
# channel themselves
|
||||
capability = ircdb.makeChannelCapability(channel, 'op')
|
||||
if 's' in irc.state.channels[channel].modes and \
|
||||
msg.args[0] != channel and \
|
||||
msg.channel != channel and \
|
||||
not ircdb.checkCapability(msg.prefix, capability) and \
|
||||
(irc.isChannel(msg.args[0]) or \
|
||||
(msg.channel or \
|
||||
msg.nick not in irc.state.channels[channel].users):
|
||||
irc.error(_('You don\'t have access to that information.'),
|
||||
Raise=True)
|
||||
@ -920,7 +930,7 @@ class Channel(callbacks.Plugin):
|
||||
keys = [option for (option, arg) in optlist]
|
||||
if 'count' not in keys:
|
||||
utils.sortBy(str.lower, L)
|
||||
private = self.registryValue("nicksInPrivate", channel)
|
||||
private = self.registryValue("nicksInPrivate", channel, irc.network)
|
||||
irc.reply(utils.str.commaAndify(L), private=private)
|
||||
else:
|
||||
irc.reply(str(len(L)))
|
||||
@ -961,11 +971,9 @@ class Channel(callbacks.Plugin):
|
||||
supybot.plugins.Channel.partMsg will be used. No part message will be
|
||||
used if no default is configured.
|
||||
"""
|
||||
if channel is None:
|
||||
if irc.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
else:
|
||||
irc.error(Raise=True)
|
||||
channel = channel or msg.channel
|
||||
if not channel:
|
||||
irc.error(Raise=True)
|
||||
capability = ircdb.makeChannelCapability(channel, 'op')
|
||||
if not ircdb.checkCapabilities(msg.prefix, [capability, 'admin']):
|
||||
irc.errorNoCapability(capability, Raise=True)
|
||||
@ -976,7 +984,7 @@ class Channel(callbacks.Plugin):
|
||||
pass
|
||||
if channel not in irc.state.channels:
|
||||
irc.error(_('I\'m not in %s.') % channel, Raise=True)
|
||||
reason = (reason or self.registryValue("partMsg", channel))
|
||||
reason = (reason or self.registryValue("partMsg", channel, irc.network))
|
||||
reason = ircutils.standardSubstitute(irc, msg, reason)
|
||||
irc.queueMsg(ircmsgs.part(channel, reason))
|
||||
if msg.nick in irc.state.channels[channel].users:
|
||||
|
@ -90,13 +90,13 @@ class ChannelLogger(callbacks.Plugin):
|
||||
if e.args[0] != 'I/O operation on a closed file':
|
||||
self.log.exception('Odd exception:')
|
||||
|
||||
def logNameTimestamp(self, channel):
|
||||
format = self.registryValue('filenameTimestamp', channel)
|
||||
def logNameTimestamp(self, network, channel):
|
||||
format = self.registryValue('filenameTimestamp', channel, network)
|
||||
return time.strftime(format)
|
||||
|
||||
def getLogName(self, channel):
|
||||
if self.registryValue('rotateLogs', channel):
|
||||
name = '%s.%s.log' % (channel, self.logNameTimestamp(channel))
|
||||
def getLogName(self, network, channel):
|
||||
if self.registryValue('rotateLogs', channel, network):
|
||||
return '%s.%s.log' % (channel, self.logNameTimestamp(network, channel))
|
||||
else:
|
||||
name = '%s.log' % channel
|
||||
return utils.file.sanitizeName(name)
|
||||
@ -120,8 +120,8 @@ class ChannelLogger(callbacks.Plugin):
|
||||
def checkLogNames(self):
|
||||
for (irc, logs) in self.logs.items():
|
||||
for (channel, log) in list(logs.items()):
|
||||
if self.registryValue('rotateLogs', channel):
|
||||
name = self.getLogName(channel)
|
||||
if self.registryValue('rotateLogs', channel, irc.network):
|
||||
name = self.getLogName(irc.network, channel)
|
||||
if name != os.path.basename(log.name):
|
||||
log.close()
|
||||
del logs[channel]
|
||||
@ -137,7 +137,7 @@ class ChannelLogger(callbacks.Plugin):
|
||||
return logs[channel]
|
||||
else:
|
||||
try:
|
||||
name = self.getLogName(channel)
|
||||
name = self.getLogName(irc.network, channel)
|
||||
logDir = self.getLogDir(irc, channel)
|
||||
log = open(os.path.join(logDir, name), encoding='utf-8', mode='a')
|
||||
logs[channel] = log
|
||||
@ -158,14 +158,14 @@ class ChannelLogger(callbacks.Plugin):
|
||||
return ircutils.toLower(channel)
|
||||
|
||||
def doLog(self, irc, channel, s, *args):
|
||||
if not self.registryValue('enable', channel):
|
||||
if not self.registryValue('enable', channel, irc.network):
|
||||
return
|
||||
s = format(s, *args)
|
||||
channel = self.normalizeChannel(irc, channel)
|
||||
log = self.getLog(irc, channel)
|
||||
if self.registryValue('timestamp', channel):
|
||||
if self.registryValue('timestamp', channel, irc.network):
|
||||
self.timestamp(log)
|
||||
if self.registryValue('stripFormatting', channel):
|
||||
if self.registryValue('stripFormatting', channel, irc.network):
|
||||
s = ircutils.stripFormatting(s)
|
||||
if minisix.PY2:
|
||||
s = s.decode('utf8', 'ignore')
|
||||
@ -177,7 +177,8 @@ class ChannelLogger(callbacks.Plugin):
|
||||
(recipients, text) = msg.args
|
||||
for channel in recipients.split(','):
|
||||
if irc.isChannel(channel):
|
||||
noLogPrefix = self.registryValue('noLogPrefix', channel)
|
||||
noLogPrefix = self.registryValue('noLogPrefix',
|
||||
channel, irc.network)
|
||||
cap = ircdb.makeChannelCapability(channel, 'logChannelMessages')
|
||||
try:
|
||||
logChannelMessages = ircdb.checkCapability(msg.prefix, cap,
|
||||
@ -219,7 +220,7 @@ class ChannelLogger(callbacks.Plugin):
|
||||
|
||||
def doJoin(self, irc, msg):
|
||||
for channel in msg.args[0].split(','):
|
||||
if(self.registryValue('showJoinParts', channel)):
|
||||
if(self.registryValue('showJoinParts', channel, irc.network)):
|
||||
self.doLog(irc, channel,
|
||||
'*** %s <%s> has joined %s\n',
|
||||
msg.nick, msg.prefix, channel)
|
||||
@ -244,7 +245,7 @@ class ChannelLogger(callbacks.Plugin):
|
||||
else:
|
||||
reason = ""
|
||||
for channel in msg.args[0].split(','):
|
||||
if(self.registryValue('showJoinParts', channel)):
|
||||
if(self.registryValue('showJoinParts', channel, irc.network)):
|
||||
self.doLog(irc, channel,
|
||||
'*** %s <%s> has left %s%s\n',
|
||||
msg.nick, msg.prefix, channel, reason)
|
||||
@ -270,7 +271,7 @@ class ChannelLogger(callbacks.Plugin):
|
||||
else:
|
||||
reason = ""
|
||||
for channel in msg.tagged('channels'):
|
||||
if(self.registryValue('showJoinParts', channel)):
|
||||
if(self.registryValue('showJoinParts', channel, irc.network)):
|
||||
self.doLog(irc, channel,
|
||||
'*** %s <%s> has quit IRC%s\n',
|
||||
msg.nick, msg.prefix, reason)
|
||||
|
@ -142,8 +142,8 @@ class StatsDB(plugins.ChannelUserDB):
|
||||
return UserStat(*L)
|
||||
|
||||
def addMsg(self, irc, msg, id=None):
|
||||
if msg.args and irc.isChannel(msg.args[0]):
|
||||
channel = plugins.getChannel(msg.args[0])
|
||||
if msg.channel:
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
if (channel, 'channelStats') not in self:
|
||||
self[channel, 'channelStats'] = ChannelStat()
|
||||
self[channel, 'channelStats'].addMsg(msg)
|
||||
@ -186,8 +186,8 @@ class ChannelStats(callbacks.Plugin):
|
||||
|
||||
def outFilter(self, irc, msg):
|
||||
if msg.command == 'PRIVMSG':
|
||||
if irc.isChannel(msg.args[0]):
|
||||
if self.registryValue('selfStats', msg.args[0]):
|
||||
if msg.channel:
|
||||
if self.registryValue('selfStats', msg.channel, irc.network):
|
||||
try:
|
||||
self.outFiltering = True
|
||||
self.db.addMsg(irc, msg, 0)
|
||||
|
@ -151,10 +151,10 @@ class Config(callbacks.Plugin):
|
||||
def _list(self, irc, group):
|
||||
L = []
|
||||
for (vname, v) in group._children.items():
|
||||
if hasattr(group, 'channelValue') and group.channelValue and \
|
||||
if hasattr(group, '_channelValue') and group._channelValue and \
|
||||
irc.isChannel(vname) and not v._children:
|
||||
continue
|
||||
if hasattr(v, 'channelValue') and v.channelValue:
|
||||
if hasattr(v, '_channelValue') and v._channelValue:
|
||||
vname = '#' + vname
|
||||
if v._added and not all(irc.isChannel, v._added):
|
||||
vname = '@' + vname
|
||||
@ -198,13 +198,33 @@ class Config(callbacks.Plugin):
|
||||
irc.reply(_('There were no matching configuration variables.'))
|
||||
search = wrap(search, ['lowered']) # XXX compose with withoutSpaces?
|
||||
|
||||
def _getValue(self, irc, msg, group, addChannel=False):
|
||||
def _getValue(self, irc, msg, group, network=None, channel=None, addGlobal=False):
|
||||
global_group = group
|
||||
global_value = str(group) or ' '
|
||||
group = group.getSpecific(
|
||||
network=network.network, channel=channel, check=False)
|
||||
value = str(group) or ' '
|
||||
if addChannel and irc.isChannel(msg.args[0]) and not irc.nested:
|
||||
s = str(group.get(msg.args[0]))
|
||||
value = _('Global: %s; %s: %s') % (value, msg.args[0], s)
|
||||
if hasattr(group, 'value'):
|
||||
if not group._private:
|
||||
if addGlobal and not irc.nested:
|
||||
if global_group._channelValue and channel:
|
||||
# TODO: also show the network value when relevant
|
||||
value = _(
|
||||
'Global: %(global_value)s; '
|
||||
'%(channel_name)s @ %(network_name)s: %(channel_value)s') % {
|
||||
'global_value': global_value,
|
||||
'channel_name': msg.channel,
|
||||
'network_name': irc.network,
|
||||
'channel_value': value,
|
||||
}
|
||||
elif global_group._networkValue and network:
|
||||
value = _(
|
||||
'Global: %(global_value)s; '
|
||||
'%(network_name)s: %(network_value)s') % {
|
||||
'global_value': global_value,
|
||||
'network_name': irc.network,
|
||||
'network_value': value,
|
||||
}
|
||||
if hasattr(global_group, 'value'):
|
||||
if not global_group._private:
|
||||
return (value, None)
|
||||
else:
|
||||
capability = getCapability(irc, group._name)
|
||||
@ -215,7 +235,7 @@ class Config(callbacks.Plugin):
|
||||
else:
|
||||
irc.error(_('That registry variable has no value. Use the list '
|
||||
'command in this plugin to see what variables are '
|
||||
'available in this group.'))
|
||||
'available in this group.'), Raise=True)
|
||||
|
||||
def _setValue(self, irc, msg, group, value):
|
||||
if isReadOnly(group._name):
|
||||
@ -230,28 +250,44 @@ class Config(callbacks.Plugin):
|
||||
irc.errorNoCapability(capability, Raise=True)
|
||||
|
||||
@internationalizeDocstring
|
||||
def channel(self, irc, msg, args, channels, group, value):
|
||||
"""[<channel>] <name> [<value>]
|
||||
def channel(self, irc, msg, args, network, channels, group, value):
|
||||
"""[<network>] [<channel>] <name> [<value>]
|
||||
|
||||
If <value> is given, sets the channel configuration variable for <name>
|
||||
to <value> for <channel>. Otherwise, returns the current channel
|
||||
to <value> for <channel> on the <network>.
|
||||
Otherwise, returns the current channel
|
||||
configuration value of <name>. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself. More than one channel may
|
||||
be given at once by separating them with commas."""
|
||||
if not group.channelValue:
|
||||
be given at once by separating them with commas.
|
||||
<network> defaults to the current network."""
|
||||
if not group._channelValue:
|
||||
irc.error(_('That configuration variable is not a channel-specific '
|
||||
'configuration variable.'))
|
||||
return
|
||||
if value is not None:
|
||||
for channel in channels:
|
||||
assert irc.isChannel(channel)
|
||||
|
||||
# Sets the non-network-specific value, for forward
|
||||
# compatibility, ie. this will work even if the owner rolls
|
||||
# back Limnoria to an older version.
|
||||
# It's also an easy way to support plugins which are not
|
||||
# network-aware.
|
||||
self._setValue(irc, msg, group.get(channel), value)
|
||||
|
||||
if network != '*':
|
||||
# Set the network-specific value
|
||||
self._setValue(irc, msg, group.get(':' + network.network).get(channel), value)
|
||||
|
||||
irc.replySuccess()
|
||||
else:
|
||||
if network == '*':
|
||||
network = None
|
||||
values = []
|
||||
private = None
|
||||
for channel in channels:
|
||||
(value, private_value) = self._getValue(irc, msg, group.get(channel))
|
||||
(value, private_value) = \
|
||||
self._getValue(irc, msg, group, network, channel)
|
||||
values.append((channel, value))
|
||||
if private_value:
|
||||
private = True
|
||||
@ -261,7 +297,32 @@ class Config(callbacks.Plugin):
|
||||
private=private)
|
||||
else:
|
||||
irc.reply(values[0][1], private=private)
|
||||
channel = wrap(channel, ['channels', 'settableConfigVar',
|
||||
channel = wrap(channel, [optional(first(('literal', '*'), 'networkIrc')),
|
||||
'channels', 'settableConfigVar',
|
||||
additional('text')])
|
||||
|
||||
def network(self, irc, msg, args, network, group, value):
|
||||
"""[<network>] <name> [<value>]
|
||||
|
||||
If <value> is given, sets the network configuration variable for <name>
|
||||
to <value> for <network>.
|
||||
Otherwise, returns the current network configuration value of <name>.
|
||||
<network> defaults to the current network."""
|
||||
if not group._networkValue:
|
||||
irc.error(_('That configuration variable is not a network-specific '
|
||||
'configuration variable.'))
|
||||
return
|
||||
if value is not None:
|
||||
self._setValue(irc, msg, group.get(':' + network.network), value)
|
||||
|
||||
irc.replySuccess()
|
||||
else:
|
||||
values = []
|
||||
private = None
|
||||
(value, private) = \
|
||||
self._getValue(irc, msg, group, network)
|
||||
irc.reply(value, private=private)
|
||||
network = wrap(network, ['networkIrc', 'settableConfigVar',
|
||||
additional('text')])
|
||||
|
||||
@internationalizeDocstring
|
||||
@ -276,7 +337,10 @@ class Config(callbacks.Plugin):
|
||||
self._setValue(irc, msg, group, value)
|
||||
irc.replySuccess()
|
||||
else:
|
||||
(value, private) = self._getValue(irc, msg, group, addChannel=group.channelValue)
|
||||
(value, private) = self._getValue(
|
||||
irc, msg, group, network=irc,
|
||||
channel=msg.channel,
|
||||
addGlobal=group._channelValue or group._networkValue)
|
||||
irc.reply(value, private=private)
|
||||
config = wrap(config, ['settableConfigVar', additional('text')])
|
||||
|
||||
@ -290,11 +354,10 @@ class Config(callbacks.Plugin):
|
||||
s = group.help()
|
||||
if s:
|
||||
if hasattr(group, 'value') and not group._private:
|
||||
channel = msg.args[0]
|
||||
if irc.isChannel(channel) and \
|
||||
channel in group._children:
|
||||
if msg.channel and \
|
||||
msg.channel in group._children:
|
||||
globvalue = str(group)
|
||||
chanvalue = str(group.get(channel))
|
||||
chanvalue = str(group.get(msg.channel))
|
||||
if chanvalue != globvalue:
|
||||
s += _(' (Current global value: %s; '
|
||||
'current channel value: %s)') % \
|
||||
|
@ -133,13 +133,13 @@ class ConfigTestCase(ChannelPluginTestCase):
|
||||
'^Completely: Error: ',
|
||||
frm=self.prefix3)
|
||||
self.assertResponse('config plugins.Config.%s' % var_name,
|
||||
'Global: 0; #test: 0')
|
||||
'Global: 0; #test @ test: 0')
|
||||
|
||||
self.assertNotRegexp('config channel plugins.Config.%s 1' % var_name,
|
||||
'^Completely: Error: ',
|
||||
frm=self.prefix3)
|
||||
self.assertResponse('config plugins.Config.%s' % var_name,
|
||||
'Global: 0; #test: 1')
|
||||
'Global: 0; #test @ test: 1')
|
||||
|
||||
def testOpNonEditable(self):
|
||||
var_name = 'testOpNonEditable' + random_string()
|
||||
@ -154,18 +154,18 @@ class ConfigTestCase(ChannelPluginTestCase):
|
||||
'^Completely: Error: ',
|
||||
frm=self.prefix3)
|
||||
self.assertResponse('config plugins.Config.%s' % var_name,
|
||||
'Global: 0; #test: 0')
|
||||
'Global: 0; #test @ test: 0')
|
||||
|
||||
self.assertRegexp('config channel plugins.Config.%s 1' % var_name,
|
||||
'^Completely: Error: ',
|
||||
frm=self.prefix3)
|
||||
self.assertResponse('config plugins.Config.%s' % var_name,
|
||||
'Global: 0; #test: 0')
|
||||
'Global: 0; #test @ test: 0')
|
||||
|
||||
self.assertNotRegexp('config channel plugins.Config.%s 1' % var_name,
|
||||
'^Completely: Error: ')
|
||||
self.assertResponse('config plugins.Config.%s' % var_name,
|
||||
'Global: 0; #test: 1')
|
||||
'Global: 0; #test @ test: 1')
|
||||
|
||||
def testChannel(self):
|
||||
self.assertResponse('config reply.whenAddressedBy.strings ^',
|
||||
@ -181,6 +181,77 @@ class ConfigTestCase(ChannelPluginTestCase):
|
||||
self.assertResponse('config channel #testchan1 reply.whenAddressedBy.strings', '.')
|
||||
self.assertResponse('config channel #testchan2 reply.whenAddressedBy.strings', '.')
|
||||
|
||||
def testNetwork(self):
|
||||
getTestIrc('testnet1')
|
||||
getTestIrc('testnet2')
|
||||
self.assertResponse('config reply.whenAddressedBy.strings ^',
|
||||
'The operation succeeded.')
|
||||
self.assertResponse('config network reply.whenAddressedBy.strings @',
|
||||
'The operation succeeded.')
|
||||
self.assertResponse('config network reply.whenAddressedBy.strings', '@')
|
||||
self.assertNotError('config network reply.whenAddressedBy.strings $')
|
||||
self.assertResponse('config network testnet1 reply.whenAddressedBy.strings', '^')
|
||||
self.assertResponse('config network testnet2 reply.whenAddressedBy.strings', '^')
|
||||
self.assertResponse('config network reply.whenAddressedBy.strings', '$')
|
||||
self.assertResponse('config network testnet1 reply.whenAddressedBy.strings', '^')
|
||||
self.assertResponse('config network testnet2 reply.whenAddressedBy.strings', '^')
|
||||
|
||||
self.assertNotError('config network testnet1 reply.whenAddressedBy.strings =')
|
||||
self.assertResponse('config network testnet1 reply.whenAddressedBy.strings', '=')
|
||||
self.assertResponse('config network testnet2 reply.whenAddressedBy.strings', '^')
|
||||
|
||||
def testChannelNetwork(self):
|
||||
irc = self.irc
|
||||
irc1 = getTestIrc('testnet1')
|
||||
irc2 = getTestIrc('testnet2')
|
||||
irc3 = getTestIrc('testnet3')
|
||||
conf.supybot.reply.whenAddressedBy.strings.get('#test')._wasSet = False
|
||||
# 1. Set global
|
||||
self.assertResponse('config reply.whenAddressedBy.strings ^',
|
||||
'The operation succeeded.')
|
||||
|
||||
# 2. Set for current net + #testchan1
|
||||
self.assertResponse('config channel #testchan1 reply.whenAddressedBy.strings @',
|
||||
'The operation succeeded.')
|
||||
|
||||
# Exact match for #2:
|
||||
self.assertResponse('config channel #testchan1 reply.whenAddressedBy.strings', '@')
|
||||
|
||||
# 3: Set for #testchan1 for all nets:
|
||||
self.assertNotError('config channel * #testchan1 reply.whenAddressedBy.strings $')
|
||||
|
||||
# Still exact match for #2:
|
||||
self.assertResponse('config channel #testchan1 reply.whenAddressedBy.strings', '@')
|
||||
|
||||
# Inherit from *:
|
||||
self.assertResponse('config channel testnet1 #testchan1 reply.whenAddressedBy.strings', '$')
|
||||
self.assertResponse('config channel testnet2 #testchan1 reply.whenAddressedBy.strings', '$')
|
||||
|
||||
# 4: Set for testnet1 for #testchan1 and #testchan2:
|
||||
self.assertNotError('config channel testnet1 #testchan1,#testchan2 reply.whenAddressedBy.strings .')
|
||||
|
||||
# 5: Set for testnet2 for #testchan1:
|
||||
self.assertNotError('config channel testnet2 #testchan1 reply.whenAddressedBy.strings :')
|
||||
|
||||
# Inherit from global value (nothing was set of current net or current
|
||||
# chan):
|
||||
(old_channel, self.channel) = (self.channel, '#iejofjfozifk')
|
||||
try:
|
||||
self.assertResponse('config channel reply.whenAddressedBy.strings', '^')
|
||||
finally:
|
||||
self.channel = old_channel
|
||||
|
||||
# Still exact match for #2:
|
||||
self.assertResponse('config channel #testchan1 reply.whenAddressedBy.strings', '@')
|
||||
self.assertResponse('config channel %s #testchan1 reply.whenAddressedBy.strings' % irc.network, '@')
|
||||
|
||||
# Exact match for #4:
|
||||
self.assertResponse('config channel testnet1 #testchan1 reply.whenAddressedBy.strings', '.')
|
||||
self.assertResponse('config channel testnet1 #testchan2 reply.whenAddressedBy.strings', '.')
|
||||
|
||||
# Inherit from #5, which set for #testchan1 on all nets
|
||||
self.assertResponse('config channel testnet3 #testchan1 reply.whenAddressedBy.strings', ':')
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
||||
|
@ -93,13 +93,13 @@ class Dict(callbacks.Plugin):
|
||||
if words[0] in dbs:
|
||||
dictionary = words.pop(0)
|
||||
else:
|
||||
default = self.registryValue('default', msg.args[0])
|
||||
default = self.registryValue('default', msg.channel, irc.network)
|
||||
if default in dbs:
|
||||
dictionary = default
|
||||
else:
|
||||
if default:
|
||||
self.log.info('Default dict for %s is not a supported '
|
||||
'dictionary: %s.', msg.args[0], default)
|
||||
self.log.info('Default dict for %s @ %s is not a supported '
|
||||
'dictionary: %s.', msg.channel, irc.network, default)
|
||||
dictionary = '*'
|
||||
if not words:
|
||||
irc.error(_('You must give a word to define.'), Raise=True)
|
||||
@ -123,7 +123,7 @@ class Dict(callbacks.Plugin):
|
||||
L.append('%s: %s' % (db, s))
|
||||
utils.sortBy(len, L)
|
||||
if dictionary == '*' and len(dbs) > 1 and \
|
||||
self.registryValue("showDictName", msg.args[0]):
|
||||
self.registryValue("showDictName", msg.channel, irc.network):
|
||||
s = format(_('%L responded: %s'), list(dbs), '; '.join(L))
|
||||
else:
|
||||
s = '; '.join(L)
|
||||
|
@ -42,12 +42,12 @@ class Dunno(plugins.ChannelIdDatabasePlugin):
|
||||
|
||||
callAfter = ['MoobotFactoids', 'Factoids', 'Infobot']
|
||||
def invalidCommand(self, irc, msg, tokens):
|
||||
channel = msg.args[0]
|
||||
if irc.isChannel(channel):
|
||||
dunno = self.db.random(channel)
|
||||
if msg.channel:
|
||||
dunno = self.db.random(msg.channel)
|
||||
if dunno is not None:
|
||||
dunno = dunno.text
|
||||
prefixNick = self.registryValue('prefixNick', channel)
|
||||
prefixNick = self.registryValue('prefixNick',
|
||||
msg.channel, irc.network)
|
||||
env = {'command': tokens[0]}
|
||||
self.log.info('Issuing "dunno" answer, %s is not a command.',
|
||||
tokens[0])
|
||||
|
@ -53,7 +53,8 @@ from supybot.utils.seq import dameraulevenshtein
|
||||
def getFactoid(irc, msg, args, state):
|
||||
assert not state.channel
|
||||
callConverter('channel', irc, msg, args, state)
|
||||
separator = state.cb.registryValue('learnSeparator', state.channel)
|
||||
separator = state.cb.registryValue('learnSeparator',
|
||||
state.channel, irc.network)
|
||||
try:
|
||||
i = args.index(separator)
|
||||
except ValueError:
|
||||
@ -137,7 +138,8 @@ class FactoidsCallback(httpserver.SupyHTTPServerCallback):
|
||||
{'title': 'Factoids - not a channel',
|
||||
'error': 'This is not a channel'})
|
||||
return
|
||||
if not self._plugin.registryValue('web.channel', channel):
|
||||
if not self._plugin.registryValue('web.channel',
|
||||
channel, irc.network):
|
||||
self.send_response(403)
|
||||
self.send_header('Content-type', 'text/html; charset=utf-8')
|
||||
self.end_headers()
|
||||
@ -252,13 +254,16 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
method = self.getCommandMethod(command)
|
||||
if method.__func__.__name__ == 'learn':
|
||||
chan = None
|
||||
network = None
|
||||
if dynamic.msg is not None:
|
||||
chan = dynamic.msg.args[0]
|
||||
s = self.registryValue('learnSeparator', chan)
|
||||
chan = dynamic.msg.channel
|
||||
if dynamic.irc is not None:
|
||||
network = dynamic.irc.network
|
||||
s = self.registryValue('learnSeparator', chan, network)
|
||||
help = callbacks.getHelp
|
||||
if simpleSyntax is None:
|
||||
simpleSyntax = conf.get(conf.supybot.reply.showSimpleSyntax,
|
||||
chan)
|
||||
simpleSyntax = conf.supybot.reply.showSimpleSyntax.getSpecific(
|
||||
dynamic.irc.network, chan)()
|
||||
if simpleSyntax:
|
||||
help = callbacks.getSyntax
|
||||
return help(method,
|
||||
@ -276,7 +281,7 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
return (keyresults, factresults,)
|
||||
|
||||
def learn(self, irc, msg, args, channel, key, factoid):
|
||||
if self.registryValue('requireVoice', channel) and \
|
||||
if self.registryValue('requireVoice', channel, irc.network) and \
|
||||
not irc.state.channels[channel].isVoicePlus(msg.nick):
|
||||
irc.error(_('You have to be at least voiced to teach factoids.'), Raise=True)
|
||||
|
||||
@ -366,8 +371,8 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
|
||||
return []
|
||||
|
||||
def _updateRank(self, channel, factoids):
|
||||
if self.registryValue('keepRankInfo', channel):
|
||||
def _updateRank(self, network, channel, factoids):
|
||||
if self.registryValue('keepRankInfo', channel, network):
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
for (fact,factid,relationid) in factoids:
|
||||
@ -391,7 +396,7 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
if number:
|
||||
try:
|
||||
irc.reply(format_fact(factoids[number-1][0]))
|
||||
self._updateRank(channel, [factoids[number-1]])
|
||||
self._updateRank(irc.network, channel, [factoids[number-1]])
|
||||
except IndexError:
|
||||
irc.error(_('That\'s not a valid number for that key.'))
|
||||
return
|
||||
@ -399,7 +404,8 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
env = {'key': key}
|
||||
def prefixer(v):
|
||||
env['value'] = v
|
||||
formatter = self.registryValue('format', msg.args[0])
|
||||
formatter = self.registryValue('format',
|
||||
msg.channel, irc.network)
|
||||
return ircutils.standardSubstitute(irc, msg,
|
||||
formatter, env)
|
||||
if len(factoids) == 1:
|
||||
@ -413,7 +419,7 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
counter += 1
|
||||
irc.replies(factoidsS, prefixer=prefixer,
|
||||
joiner=', or ', onlyPrefixFirst=True)
|
||||
self._updateRank(channel, factoids)
|
||||
self._updateRank(irc.network, channel, factoids)
|
||||
elif error:
|
||||
irc.error(_('No factoid matches that key.'))
|
||||
|
||||
@ -429,9 +435,9 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
irc.error('No factoid matches that key.')
|
||||
|
||||
def invalidCommand(self, irc, msg, tokens):
|
||||
if irc.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
if self.registryValue('replyWhenInvalidCommand', channel):
|
||||
channel = msg.channel
|
||||
if channel:
|
||||
if self.registryValue('replyWhenInvalidCommand', channel, irc.network):
|
||||
key = ' '.join(tokens)
|
||||
factoids = self._lookupFactoid(channel, key)
|
||||
if factoids:
|
||||
@ -556,7 +562,7 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
itself.
|
||||
"""
|
||||
if not number:
|
||||
number = self.registryValue('rankListLength', channel)
|
||||
number = self.registryValue('rankListLength', channel, irc.network)
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""SELECT keys.key, relations.usage_count
|
||||
@ -655,7 +661,7 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
<channel> is only necessary if
|
||||
the message isn't sent in the channel itself.
|
||||
"""
|
||||
if self.registryValue('requireVoice', channel) and \
|
||||
if self.registryValue('requireVoice', channel, irc.network) and \
|
||||
not irc.state.channels[channel].isVoicePlus(msg.nick):
|
||||
irc.error(_('You have to be at least voiced to remove factoids.'), Raise=True)
|
||||
number = None
|
||||
@ -834,7 +840,8 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
if cursor.rowcount == 0:
|
||||
irc.reply(_('No keys matched that query.'))
|
||||
elif cursor.rowcount == 1 and \
|
||||
self.registryValue('showFactoidIfOnlyOneMatch', channel):
|
||||
self.registryValue('showFactoidIfOnlyOneMatch',
|
||||
channel, irc.network):
|
||||
self.whatis(irc, msg, [channel, cursor.fetchone()[0]])
|
||||
elif cursor.rowcount > 100:
|
||||
irc.reply(_('More than 100 keys matched that query; '
|
||||
@ -843,7 +850,8 @@ class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
if len(results) == 0:
|
||||
irc.reply(_('No keys matched that query.'))
|
||||
elif len(results) == 1 and \
|
||||
self.registryValue('showFactoidIfOnlyOneMatch', channel):
|
||||
self.registryValue('showFactoidIfOnlyOneMatch',
|
||||
channel, irc.network):
|
||||
self.whatis(irc, msg, [channel, results[0][0]])
|
||||
elif len(results) > 100:
|
||||
irc.reply(_('More than 100 keys matched that query; '
|
||||
|
@ -63,12 +63,12 @@ class Filter(callbacks.Plugin):
|
||||
|
||||
def outFilter(self, irc, msg):
|
||||
if msg.command in ('PRIVMSG', 'NOTICE'):
|
||||
if msg.args[0] in self.outFilters:
|
||||
if msg.channel in self.outFilters:
|
||||
if ircmsgs.isAction(msg):
|
||||
s = ircmsgs.unAction(msg)
|
||||
else:
|
||||
s = msg.args[1]
|
||||
methods = self.outFilters[msg.args[0]]
|
||||
methods = self.outFilters[msg.channel]
|
||||
for filtercommand in methods:
|
||||
myIrc = MyFilterProxy()
|
||||
filtercommand(myIrc, msg, [s])
|
||||
@ -651,7 +651,8 @@ class Filter(callbacks.Plugin):
|
||||
"internationalization" becomes "i18n").
|
||||
"""
|
||||
L = []
|
||||
minimum = self.registryValue('shrink.minimum', msg.args[0])
|
||||
minimum = self.registryValue('shrink.minimum',
|
||||
msg.channel, irc.network)
|
||||
r = re.compile(r'[A-Za-z]{%s,}' % minimum)
|
||||
def shrink(m):
|
||||
s = m.group(0)
|
||||
|
@ -130,7 +130,7 @@ class Games(callbacks.Plugin):
|
||||
self._rouletteBullet = random.randrange(0, 6)
|
||||
irc.reply(_('*SPIN* Are you feeling lucky?'), prefixNick=False)
|
||||
return
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
if self._rouletteChamber == self._rouletteBullet:
|
||||
self._rouletteBullet = random.randrange(0, 6)
|
||||
self._rouletteChamber = random.randrange(0, 6)
|
||||
|
@ -69,7 +69,7 @@ class Google(callbacks.PluginRegexp):
|
||||
_googleRe = re.compile(r'\b(google)\b', re.I)
|
||||
def outFilter(self, irc, msg):
|
||||
if msg.command == 'PRIVMSG' and \
|
||||
self.registryValue('colorfulFilter', msg.args[0]):
|
||||
self.registryValue('colorfulFilter', msg.channel, irc.network):
|
||||
s = msg.args[1]
|
||||
s = re.sub(self._googleRe, self._getColorGoogle, s)
|
||||
msg = ircmsgs.privmsg(msg.args[0], s, msg=msg)
|
||||
@ -88,7 +88,7 @@ class Google(callbacks.PluginRegexp):
|
||||
|
||||
|
||||
_gsearchUrl = 'https://www.google.com/search'
|
||||
def search(self, query, channel, options={}):
|
||||
def search(self, query, channel, network, options={}):
|
||||
"""search("search phrase", options={})
|
||||
|
||||
Valid options are:
|
||||
@ -121,11 +121,11 @@ class Google(callbacks.PluginRegexp):
|
||||
opts['safe'] = v
|
||||
elif k == 'language':
|
||||
opts['hl'] = v
|
||||
defLang = self.registryValue('defaultLanguage', channel)
|
||||
defLang = self.registryValue('defaultLanguage', channel, network)
|
||||
if 'hl' not in opts and defLang:
|
||||
opts['hl'] = defLang.strip('lang_')
|
||||
if 'safe' not in opts:
|
||||
opts['safe'] = self.registryValue('searchFilter', dynamic.channel)
|
||||
opts['safe'] = self.registryValue('searchFilter', channel, network)
|
||||
if 'rsz' not in opts:
|
||||
opts['rsz'] = 'large'
|
||||
|
||||
@ -169,7 +169,8 @@ class Google(callbacks.PluginRegexp):
|
||||
If option --snippet is given, returns also the page text snippet.
|
||||
"""
|
||||
opts = dict(opts)
|
||||
data = self.search(text, msg.args[0], {'smallsearch': True})
|
||||
data = self.search(text, msg.channel, irc.network,
|
||||
{'smallsearch': True})
|
||||
data = self.decode(data)
|
||||
if data:
|
||||
url = data[0]['url']
|
||||
@ -195,13 +196,13 @@ class Google(callbacks.PluginRegexp):
|
||||
if 'language' in optlist and optlist['language'].lower() not in \
|
||||
conf.supybot.plugins.Google.safesearch.validStrings:
|
||||
irc.errorInvalid('language')
|
||||
data = self.search(text, msg.args[0], dict(optlist))
|
||||
bold = self.registryValue('bold', msg.args[0])
|
||||
max = self.registryValue('maximumResults', msg.args[0])
|
||||
data = self.search(text, msg.channel, irc.network, dict(optlist))
|
||||
bold = self.registryValue('bold', msg.channel, irc.network)
|
||||
max = self.registryValue('maximumResults', msg.channel, irc.network)
|
||||
# We don't use supybot.reply.oneToOne here, because you generally
|
||||
# do not want @google to echo ~20 lines of results, even if you
|
||||
# have reply.oneToOne enabled.
|
||||
onetoone = self.registryValue('oneToOne', msg.args[0])
|
||||
onetoone = self.registryValue('oneToOne', msg.channel, irc.network)
|
||||
for result in self.formatData(data,
|
||||
bold=bold, max=max, onetoone=onetoone):
|
||||
irc.reply(result)
|
||||
@ -215,7 +216,7 @@ class Google(callbacks.PluginRegexp):
|
||||
|
||||
Returns a link to the cached version of <url> if it is available.
|
||||
"""
|
||||
data = self.search(url, msg.args[0], {'smallsearch': True})
|
||||
data = self.search(url, msg.channel, irc.network, {'smallsearch': True})
|
||||
if data:
|
||||
m = data[0]
|
||||
if m['cacheUrl']:
|
||||
@ -233,10 +234,11 @@ class Google(callbacks.PluginRegexp):
|
||||
Returns the results of each search, in order, from greatest number
|
||||
of results to least.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
network = irc.network
|
||||
results = []
|
||||
for arg in args:
|
||||
text = self.search(arg, channel, {'smallsearch': True})
|
||||
text = self.search(arg, channel, network, {'smallsearch': True})
|
||||
i = text.find('id="resultStats"')
|
||||
stats = utils.web.htmlToText(self._fight_re.search(text).group('stats'))
|
||||
if stats == '':
|
||||
@ -246,7 +248,7 @@ class Google(callbacks.PluginRegexp):
|
||||
results.append((int(count), arg))
|
||||
results.sort()
|
||||
results.reverse()
|
||||
if self.registryValue('bold', msg.args[0]):
|
||||
if self.registryValue('bold', channel, network):
|
||||
bold = ircutils.bold
|
||||
else:
|
||||
bold = repr
|
||||
@ -294,26 +296,26 @@ class Google(callbacks.PluginRegexp):
|
||||
codes (not language names), which are listed here:
|
||||
https://cloud.google.com/translate/docs/languages
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
(text, language) = self._translate(sourceLang, targetLang, text)
|
||||
irc.reply(text, language)
|
||||
translate = wrap(translate, ['something', 'to', 'something', 'text'])
|
||||
|
||||
def googleSnarfer(self, irc, msg, match):
|
||||
r"^google\s+(.*)$"
|
||||
if not self.registryValue('searchSnarfer', msg.args[0]):
|
||||
if not self.registryValue('searchSnarfer', msg.channel, irc.network):
|
||||
return
|
||||
searchString = match.group(1)
|
||||
data = self.search(searchString, msg.args[0], {'smallsearch': True})
|
||||
data = self.search(searchString, msg.channel, irc.network,
|
||||
{'smallsearch': True})
|
||||
if data['responseData']['results']:
|
||||
url = data['responseData']['results'][0]['unescapedUrl']
|
||||
irc.reply(url, prefixNick=False)
|
||||
googleSnarfer = urlSnarfer(googleSnarfer)
|
||||
|
||||
def _googleUrl(self, s, channel):
|
||||
def _googleUrl(self, s, channel, network):
|
||||
s = utils.web.urlquote_plus(s)
|
||||
url = r'http://%s/search?q=%s' % \
|
||||
(self.registryValue('baseUrl', channel), s)
|
||||
(self.registryValue('baseUrl', channel, network), s)
|
||||
return url
|
||||
|
||||
_calcRe1 = re.compile(r'<span class="cwcot".*?>(.*?)</span>', re.I)
|
||||
@ -325,10 +327,7 @@ class Google(callbacks.PluginRegexp):
|
||||
|
||||
Uses Google's calculator to calculate the value of <expression>.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
if not irc.isChannel(channel):
|
||||
channel = None
|
||||
url = self._googleUrl(expr, channel)
|
||||
url = self._googleUrl(expr, msg.channel, irc.network)
|
||||
h = {"User-Agent":"Mozilla/5.0 (Windows NT 6.2; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1667.0 Safari/537.36"}
|
||||
html = utils.web.getUrl(url, headers=h).decode('utf8')
|
||||
match = self._calcRe1.search(html)
|
||||
@ -359,10 +358,7 @@ class Google(callbacks.PluginRegexp):
|
||||
|
||||
Looks <phone number> up on Google.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
if not irc.isChannel(channel):
|
||||
channel = None
|
||||
url = self._googleUrl(phonenumber, channel)
|
||||
url = self._googleUrl(phonenumber, msg.channel, irc.network)
|
||||
html = utils.web.getUrl(url).decode('utf8')
|
||||
m = self._phoneRe.search(html)
|
||||
if m is not None:
|
||||
|
@ -92,7 +92,7 @@ class Herald(callbacks.Plugin):
|
||||
return # Recently split.
|
||||
channel = msg.args[0]
|
||||
irc = callbacks.SimpleProxy(irc, msg)
|
||||
if self.registryValue('heralding', channel):
|
||||
if self.registryValue('heralding', channel, irc.network):
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
if id in self.splitters:
|
||||
@ -100,22 +100,26 @@ class Herald(callbacks.Plugin):
|
||||
return
|
||||
herald = self.db[channel, id]
|
||||
except KeyError:
|
||||
default = self.registryValue('default', channel)
|
||||
default = self.registryValue('default', channel, irc.network)
|
||||
if default:
|
||||
default = ircutils.standardSubstitute(irc, msg, default)
|
||||
msgmaker = ircmsgs.privmsg
|
||||
if self.registryValue('default.notice', channel):
|
||||
if self.registryValue('default.notice',
|
||||
channel, irc.network):
|
||||
msgmaker = ircmsgs.notice
|
||||
target = msg.nick
|
||||
if self.registryValue('default.public', channel):
|
||||
if self.registryValue('default.public',
|
||||
channel, irc.network):
|
||||
target = channel
|
||||
irc.queueMsg(msgmaker(target, default))
|
||||
return
|
||||
now = time.time()
|
||||
throttle = self.registryValue('throttle', channel)
|
||||
throttle = self.registryValue('throttle',
|
||||
channel, irc.network)
|
||||
if now - self.lastHerald.get((channel, id), 0) > throttle:
|
||||
if (channel, id) in self.lastParts:
|
||||
i = self.registryValue('throttle.afterPart', channel)
|
||||
i = self.registryValue('throttle.afterPart',
|
||||
channel, irc.network)
|
||||
if now - self.lastParts[channel, id] < i:
|
||||
return
|
||||
self.lastHerald[channel, id] = now
|
||||
@ -160,7 +164,7 @@ class Herald(callbacks.Plugin):
|
||||
self.setRegistryValue('default', text, channel)
|
||||
irc.replySuccess()
|
||||
else:
|
||||
resp = self.registryValue('default', channel) or \
|
||||
resp = self.registryValue('default', channel, irc.network) or \
|
||||
_('I do not have a default herald set for %s.') % channel
|
||||
irc.reply(resp)
|
||||
default = wrap(default, ['channel',
|
||||
|
@ -243,16 +243,16 @@ class Karma(callbacks.Plugin):
|
||||
return thing
|
||||
|
||||
def _respond(self, irc, channel, thing, karma):
|
||||
if self.registryValue('response', channel):
|
||||
if self.registryValue('response', channel, irc.network):
|
||||
irc.reply(_('%(thing)s\'s karma is now %(karma)i') %
|
||||
{'thing': thing, 'karma': karma})
|
||||
else:
|
||||
irc.noReply()
|
||||
|
||||
def _doKarma(self, irc, msg, channel, thing):
|
||||
inc = self.registryValue('incrementChars', channel)
|
||||
dec = self.registryValue('decrementChars', channel)
|
||||
onlynicks = self.registryValue('onlyNicks', channel)
|
||||
inc = self.registryValue('incrementChars', channel, irc.network)
|
||||
dec = self.registryValue('decrementChars', channel, irc.network)
|
||||
onlynicks = self.registryValue('onlyNicks', channel, irc.network)
|
||||
karma = ''
|
||||
for s in inc:
|
||||
if thing.endswith(s):
|
||||
@ -262,7 +262,8 @@ class Karma(callbacks.Plugin):
|
||||
irc.state.channels[channel].users):
|
||||
return
|
||||
if ircutils.strEqual(thing, msg.nick) and \
|
||||
not self.registryValue('allowSelfRating', channel):
|
||||
not self.registryValue('allowSelfRating',
|
||||
channel, irc.network):
|
||||
irc.error(_('You\'re not allowed to adjust your own karma.'))
|
||||
return
|
||||
self.db.increment(channel, self._normalizeThing(thing))
|
||||
@ -274,7 +275,8 @@ class Karma(callbacks.Plugin):
|
||||
irc.state.channels[channel].users):
|
||||
return
|
||||
if ircutils.strEqual(thing, msg.nick) and \
|
||||
not self.registryValue('allowSelfRating', channel):
|
||||
not self.registryValue('allowSelfRating',
|
||||
channel, irc.network):
|
||||
irc.error(_('You\'re not allowed to adjust your own karma.'))
|
||||
return
|
||||
self.db.decrement(channel, self._normalizeThing(thing))
|
||||
@ -283,23 +285,22 @@ class Karma(callbacks.Plugin):
|
||||
self._respond(irc, channel, thing, karma[0]-karma[1])
|
||||
|
||||
def invalidCommand(self, irc, msg, tokens):
|
||||
channel = msg.args[0]
|
||||
if irc.isChannel(channel) and tokens:
|
||||
if msg.channel and tokens:
|
||||
thing = ' '.join(tokens)
|
||||
self._doKarma(irc, msg, channel, thing)
|
||||
self._doKarma(irc, msg, msg.channel, thing)
|
||||
|
||||
def doPrivmsg(self, irc, msg):
|
||||
# We don't handle this if we've been addressed because invalidCommand
|
||||
# will handle it for us. This prevents us from accessing the db twice
|
||||
# and therefore crashing.
|
||||
if not (msg.addressed or msg.repliedTo):
|
||||
channel = msg.args[0]
|
||||
if irc.isChannel(channel) and \
|
||||
if msg.channel and \
|
||||
not ircmsgs.isCtcp(msg) and \
|
||||
self.registryValue('allowUnaddressedKarma', channel):
|
||||
self.registryValue('allowUnaddressedKarma',
|
||||
msg.channel, irc.network):
|
||||
irc = callbacks.SimpleProxy(irc, msg)
|
||||
thing = msg.args[1].rstrip()
|
||||
self._doKarma(irc, msg, channel, thing)
|
||||
self._doKarma(irc, msg, msg.channel, thing)
|
||||
|
||||
@internationalizeDocstring
|
||||
def karma(self, irc, msg, args, channel, things):
|
||||
@ -320,7 +321,7 @@ class Karma(callbacks.Plugin):
|
||||
else:
|
||||
(added, subtracted) = t
|
||||
total = added - subtracted
|
||||
if self.registryValue('simpleOutput', channel):
|
||||
if self.registryValue('simpleOutput', channel, irc.network):
|
||||
s = format('%s: %i', name, total)
|
||||
else:
|
||||
s = format(_('Karma for %q has been increased %n and '
|
||||
@ -342,7 +343,7 @@ class Karma(callbacks.Plugin):
|
||||
irc.reply(_('I didn\'t know the karma for any of those '
|
||||
'things.'))
|
||||
else: # No name was given. Return the top/bottom N karmas.
|
||||
limit = self.registryValue('rankingDisplay', channel)
|
||||
limit = self.registryValue('rankingDisplay', channel, irc.network)
|
||||
highest = [format('%q (%s)', s, t)
|
||||
for (s, t) in self.db.top(channel, limit)]
|
||||
lowest = [format('%q (%s)', s, t)
|
||||
@ -372,7 +373,8 @@ class Karma(callbacks.Plugin):
|
||||
necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
L = self.db.most(channel, kind,
|
||||
self.registryValue('mostDisplay', channel))
|
||||
self.registryValue('mostDisplay',
|
||||
channel, irc.network))
|
||||
if L:
|
||||
L = [format('%q: %i', name, i) for (name, i) in L]
|
||||
irc.reply(format('%L', L))
|
||||
|
@ -85,7 +85,7 @@ class Lart(plugins.ChannelIdDatabasePlugin):
|
||||
text = text.replace('$who', target)
|
||||
if reason:
|
||||
text += _(' for ') + reason
|
||||
if self.registryValue('showIds', channel):
|
||||
if self.registryValue('showIds', channel, irc.network):
|
||||
text += format(' (#%i)', lart.id)
|
||||
irc.reply(text, action=True)
|
||||
lart = wrap(lart, ['channeldb', optional('id'), 'text'])
|
||||
|
@ -48,9 +48,9 @@ class Limiter(callbacks.Plugin):
|
||||
irc.noReply()
|
||||
|
||||
def _enforceLimit(self, irc, channel):
|
||||
if self.registryValue('enable', channel):
|
||||
maximum = self.registryValue('maximumExcess', channel)
|
||||
minimum = self.registryValue('minimumExcess', channel)
|
||||
if self.registryValue('enable', channel, irc.network):
|
||||
maximum = self.registryValue('maximumExcess', channel, irc.network)
|
||||
minimum = self.registryValue('minimumExcess', channel, irc.network)
|
||||
assert maximum > minimum
|
||||
currentUsers = len(irc.state.channels[channel].users)
|
||||
currentLimit = irc.state.channels[channel].modes.get('l', 0)
|
||||
@ -62,7 +62,7 @@ class Limiter(callbacks.Plugin):
|
||||
def doJoin(self, irc, msg):
|
||||
if not ircutils.strEqual(msg.nick, irc.nick):
|
||||
irc = callbacks.SimpleProxy(irc, msg)
|
||||
self._enforceLimit(irc, msg.args[0])
|
||||
self._enforceLimit(irc, msg.channel)
|
||||
doPart = doJoin
|
||||
doKick = doJoin
|
||||
|
||||
|
@ -115,9 +115,9 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
db.isolation_level = None
|
||||
return db
|
||||
|
||||
def _updateRank(self, channel, regexp):
|
||||
def _updateRank(self, network, channel, regexp):
|
||||
subfolder = None if channel == 'global' else channel
|
||||
if self.registryValue('keepRankInfo', subfolder):
|
||||
if self.registryValue('keepRankInfo', subfolder, network):
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""SELECT usage_count
|
||||
@ -153,10 +153,10 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
return True
|
||||
|
||||
def do_privmsg_notice(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
if not irc.isChannel(channel):
|
||||
channel = msg.channel
|
||||
if not channel:
|
||||
return
|
||||
if self.registryValue('enable', channel):
|
||||
if self.registryValue('enable', channel, irc.network):
|
||||
actions = []
|
||||
results = []
|
||||
for channel in set(map(plugins.getChannel, (channel, 'global'))):
|
||||
@ -168,12 +168,12 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
results.extend([(channel,)+x for x in cursor.fetchall()])
|
||||
if len(results) == 0:
|
||||
return
|
||||
max_triggers = self.registryValue('maxTriggers', channel)
|
||||
max_triggers = self.registryValue('maxTriggers', channel, irc.network)
|
||||
for (channel, regexp, action) in results:
|
||||
for match in re.finditer(regexp, msg.args[1]):
|
||||
if match is not None:
|
||||
thisaction = action
|
||||
self._updateRank(channel, regexp)
|
||||
self._updateRank(irc.network, channel, regexp)
|
||||
for (i, j) in enumerate(match.groups()):
|
||||
if match.group(i+1) is not None:
|
||||
thisaction = re.sub(r'\$' + str(i+1), match.group(i+1), thisaction)
|
||||
@ -192,7 +192,7 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
self.do_privmsg_notice(irc, msg)
|
||||
|
||||
def doNotice(self, irc, msg):
|
||||
if self.registryValue('enableForNotices', msg.args[0]):
|
||||
if self.registryValue('enableForNotices', msg.channel, irc.network):
|
||||
self.do_privmsg_notice(irc, msg)
|
||||
|
||||
@internationalizeDocstring
|
||||
@ -406,7 +406,7 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
return
|
||||
|
||||
s = [ "%s: %s" % (ircutils.bold('#'+str(regexp[1])), regexp[0]) for regexp in regexps ]
|
||||
separator = self.registryValue('listSeparator', channel)
|
||||
separator = self.registryValue('listSeparator', channel, irc.network)
|
||||
irc.reply(separator.join(s))
|
||||
list = wrap(list, ['channelOrGlobal'])
|
||||
|
||||
@ -419,7 +419,7 @@ class MessageParser(callbacks.Plugin, plugins.ChannelDBHandler):
|
||||
rankListLength registry value. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
numregexps = self.registryValue('rankListLength', channel)
|
||||
numregexps = self.registryValue('rankListLength', channel, irc.network)
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""SELECT regexp, usage_count
|
||||
|
@ -124,7 +124,7 @@ class Misc(callbacks.Plugin):
|
||||
utils.timeElapsed(punishment, seconds=False)))
|
||||
return
|
||||
# Now, for normal handling.
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
# Only bother with the invaildCommand flood handling if it's actually
|
||||
# enabled
|
||||
if conf.supybot.abuse.flood.command.invalid():
|
||||
@ -138,7 +138,8 @@ class Misc(callbacks.Plugin):
|
||||
msg.prefix != irc.prefix and \
|
||||
ircutils.isUserHostmask(msg.prefix):
|
||||
penalty = conf.supybot.abuse.flood.command.invalid.punishment()
|
||||
banmask = banmasker(msg.prefix, channel=None)
|
||||
banmask = banmasker(msg.prefix, channel=channel,
|
||||
network=irc.network)
|
||||
self.log.info('Ignoring %s for %s seconds due to an apparent '
|
||||
'invalid command flood.', banmask, penalty)
|
||||
if tokens and tokens[0] == 'Error:':
|
||||
@ -153,7 +154,8 @@ class Misc(callbacks.Plugin):
|
||||
utils.timeElapsed(penalty, seconds=False)))
|
||||
return
|
||||
# Now, for normal handling.
|
||||
if conf.get(conf.supybot.reply.whenNotCommand, channel):
|
||||
if conf.supybot.reply.whenNotCommand.getSpecific(
|
||||
channel, irc.network)():
|
||||
if len(tokens) >= 2:
|
||||
cb = irc.getCallback(tokens[0])
|
||||
if cb:
|
||||
@ -177,7 +179,7 @@ class Misc(callbacks.Plugin):
|
||||
if channel != irc.nick else _('private'))
|
||||
if irc.nested:
|
||||
bracketConfig = conf.supybot.commands.nested.brackets
|
||||
brackets = conf.get(bracketConfig, channel)
|
||||
brackets = bracketConfig.getSpecific(channel, irc.network)()
|
||||
if brackets:
|
||||
(left, right) = brackets
|
||||
irc.reply(left + ' '.join(tokens) + right)
|
||||
@ -386,7 +388,7 @@ class Misc(callbacks.Plugin):
|
||||
return
|
||||
try:
|
||||
L = irc._mores[userHostmask]
|
||||
number = self.registryValue('mores', msg.args[0])
|
||||
number = self.registryValue('mores', msg.channel, irc.network)
|
||||
chunks = [L.pop() for x in range(0, number)]
|
||||
if L:
|
||||
if len(L) < 2:
|
||||
@ -406,7 +408,7 @@ class Misc(callbacks.Plugin):
|
||||
def _validLastMsg(self, irc, msg):
|
||||
return msg.prefix and \
|
||||
msg.command == 'PRIVMSG' and \
|
||||
irc.isChannel(msg.args[0])
|
||||
msg.channel
|
||||
|
||||
@internationalizeDocstring
|
||||
def last(self, irc, msg, args, optlist):
|
||||
@ -423,9 +425,9 @@ class Misc(callbacks.Plugin):
|
||||
predicates = {}
|
||||
nolimit = False
|
||||
skipfirst = True
|
||||
if irc.isChannel(msg.args[0]):
|
||||
if msg.channel:
|
||||
predicates['in'] = lambda m: ircutils.strEqual(m.args[0],
|
||||
msg.args[0])
|
||||
msg.channel)
|
||||
else:
|
||||
skipfirst = False
|
||||
for (option, arg) in optlist:
|
||||
@ -437,7 +439,7 @@ class Misc(callbacks.Plugin):
|
||||
def f(m, arg=arg):
|
||||
return ircutils.strEqual(m.args[0], arg)
|
||||
predicates['in'] = f
|
||||
if arg != msg.args[0]:
|
||||
if arg != msg.channel:
|
||||
skipfirst = False
|
||||
elif option == 'on':
|
||||
def f(m, arg=arg):
|
||||
@ -484,6 +486,7 @@ class Misc(callbacks.Plugin):
|
||||
predicates.append(userInChannel)
|
||||
# Make sure the user can't get messages from a +s channel unless
|
||||
# they're calling the command from that channel or from a query
|
||||
# TODO: support statusmsg, but be careful about leaking scopes.
|
||||
def notSecretMsg(m):
|
||||
return not irc.isChannel(msg.args[0]) \
|
||||
or msg.args[0] == m.args[0] \
|
||||
|
@ -325,7 +325,7 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
else:
|
||||
key = ' '.join(tokens)
|
||||
key = self._sanitizeKey(key)
|
||||
channel = plugins.getChannel(msg.args[0])
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
fact = self.db.getFactoid(channel, key)
|
||||
if fact:
|
||||
self.db.updateRequest(channel, key, msg.prefix)
|
||||
@ -385,7 +385,7 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
|
||||
def addFactoid(self, irc, msg, tokens):
|
||||
# First, check and see if the entire message matches a factoid key
|
||||
channel = plugins.getChannel(msg.args[0])
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
id = self._getUserId(irc, msg.prefix)
|
||||
try:
|
||||
(key, fact) = self._getKeyAndFactoid(tokens)
|
||||
@ -401,7 +401,7 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
id = self._getUserId(irc, msg.prefix)
|
||||
(key, regexp) = list(map(' '.join,
|
||||
utils.iter.split('=~'.__eq__, tokens, maxsplit=1)))
|
||||
channel = plugins.getChannel(msg.args[0])
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
# Check and make sure it's in the DB
|
||||
fact = self._getFactoid(irc, channel, key)
|
||||
self._checkNotLocked(irc, channel, key)
|
||||
@ -422,7 +422,7 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
isAlso = pairs.index(['is', 'also'])
|
||||
key = ' '.join(tokens[:isAlso])
|
||||
new_text = ' '.join(tokens[isAlso+2:])
|
||||
channel = plugins.getChannel(msg.args[0])
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
fact = self._getFactoid(irc, channel, key)
|
||||
self._checkNotLocked(irc, channel, key)
|
||||
# It's fair game if we get to here
|
||||
@ -433,7 +433,7 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
|
||||
def replaceFactoid(self, irc, msg, tokens):
|
||||
# Must be registered!
|
||||
channel = plugins.getChannel(msg.args[0])
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
id = self._getUserId(irc, msg.prefix)
|
||||
del tokens[0] # remove the "no,"
|
||||
try:
|
||||
@ -576,7 +576,7 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
method = getattr(self, '_most%s' % method, None)
|
||||
if method is None:
|
||||
raise callbacks.ArgumentError
|
||||
limit = self.registryValue('mostCount', channel)
|
||||
limit = self.registryValue('mostCount', channel, irc.network)
|
||||
method(irc, channel, limit)
|
||||
most = wrap(most, ['channeldb',
|
||||
('literal', ('popular', 'authored', 'recent'))])
|
||||
@ -652,7 +652,8 @@ class MoobotFactoids(callbacks.Plugin):
|
||||
if not results:
|
||||
irc.reply(format(_('No keys matching %q found.'), search))
|
||||
elif len(results) == 1 and \
|
||||
self.registryValue('showFactoidIfOnlyOneMatch', channel):
|
||||
self.registryValue('showFactoidIfOnlyOneMatch',
|
||||
channel, irc.network):
|
||||
key = results[0][0]
|
||||
self.invalidCommand(irc, msg, [key])
|
||||
else:
|
||||
|
@ -186,7 +186,7 @@ class Note(callbacks.Plugin):
|
||||
specified by separating their names by commas.
|
||||
"""
|
||||
# Let's get the from user.
|
||||
public = irc.isChannel(msg.args[0])
|
||||
public = bool(msg.channel)
|
||||
sent = []
|
||||
for target in targets:
|
||||
id = self.db.send(user.id, target.id, public, text)
|
||||
@ -209,7 +209,7 @@ class Note(callbacks.Plugin):
|
||||
'that have been sent to you.', Raise=True)
|
||||
self.db.setRead(id)
|
||||
text += ' (in reply to #%s)' % id
|
||||
public = irc.isChannel(msg.args[0])
|
||||
public = bool(msg.channel)
|
||||
try:
|
||||
target = ircdb.users.getUser(note.frm)
|
||||
except KeyError:
|
||||
@ -271,7 +271,7 @@ class Note(callbacks.Plugin):
|
||||
note = wrap(note, ['user', ('id', 'note')])
|
||||
|
||||
def _formatNoteId(self, irc, msg, note, sent=False):
|
||||
if note.public or not irc.isChannel(msg.args[0]):
|
||||
if note.public or not msg.channel:
|
||||
if sent:
|
||||
sender = plugins.getUserName(note.to)
|
||||
return format('#%i to %s', note.id, sender)
|
||||
|
@ -258,10 +258,11 @@ class Owner(callbacks.Plugin):
|
||||
utils.timeElapsed(punishment, seconds=False)))
|
||||
return
|
||||
try:
|
||||
tokens = callbacks.tokenize(s, channel=msg.args[0])
|
||||
tokens = callbacks.tokenize(s, channel=msg.channel,
|
||||
network=irc.network)
|
||||
self.Proxy(irc, msg, tokens)
|
||||
except SyntaxError as e:
|
||||
irc.queueMsg(callbacks.error(msg, str(e)))
|
||||
irc.error(str(e))
|
||||
|
||||
def logmark(self, irc, msg, args, text):
|
||||
"""<text>
|
||||
|
@ -84,7 +84,7 @@ class Praise(plugins.ChannelIdDatabasePlugin):
|
||||
text = text.replace('$who', target)
|
||||
if reason:
|
||||
text += _(' for ') + reason
|
||||
if self.registryValue('showIds', channel):
|
||||
if self.registryValue('showIds', channel, irc.network):
|
||||
text += format(' (#%i)', praise.id)
|
||||
irc.reply(text, action=True)
|
||||
praise = wrap(praise, ['channeldb', optional('id'), 'text'])
|
||||
|
@ -45,7 +45,7 @@ class Protector(callbacks.Plugin):
|
||||
if ircutils.strEqual(msg.nick, irc.nick):
|
||||
self.log.debug('%q is immune, it\'s me.', msg)
|
||||
return True # It's the bot itself.
|
||||
if msg.nick in self.registryValue('immune', msg.args[0]):
|
||||
if msg.nick in self.registryValue('immune', msg.channel, irc.network):
|
||||
self.log.debug('%q is immune, it\'s configured to be immune.', msg)
|
||||
return True
|
||||
return False
|
||||
@ -78,18 +78,18 @@ class Protector(callbacks.Plugin):
|
||||
self.log.debug('Ignoring %q, %s.', msg, reason)
|
||||
if not msg.args:
|
||||
ignore('no msg.args')
|
||||
elif not irc.isChannel(msg.args[0]):
|
||||
elif not msg.channel:
|
||||
ignore('not on a channel')
|
||||
elif not self.registryValue('enable', msg.args[0]):
|
||||
elif not self.registryValue('enable', msg.channel, irc.network):
|
||||
ignore('supybot.plugins.Protector.enable is False.')
|
||||
elif msg.args[0] not in irc.state.channels:
|
||||
elif msg.channel not in irc.state.channels:
|
||||
# One has to wonder how this would happen, but just in case...
|
||||
ignore('bot isn\'t in channel')
|
||||
elif irc.nick not in irc.state.channels[msg.args[0]].ops:
|
||||
elif irc.nick not in irc.state.channels[msg.channel].ops:
|
||||
ignore('bot is not opped')
|
||||
elif msg.nick not in irc.state.channels[msg.args[0]].users:
|
||||
elif msg.nick not in irc.state.channels[msg.channel].users:
|
||||
ignore('sender is not in channel (ChanServ, maybe?)')
|
||||
elif msg.nick not in irc.state.channels[msg.args[0]].ops:
|
||||
elif msg.nick not in irc.state.channels[msg.channel].ops:
|
||||
ignore('sender is not an op in channel (IRCOP, maybe?)')
|
||||
elif self.isImmune(irc, msg):
|
||||
ignore('sender is immune')
|
||||
@ -97,7 +97,7 @@ class Protector(callbacks.Plugin):
|
||||
super(Protector, self).__call__(irc, msg)
|
||||
|
||||
def doMode(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
chanOp = ircdb.makeChannelCapability(channel, 'op')
|
||||
chanVoice = ircdb.makeChannelCapability(channel, 'voice')
|
||||
chanHalfOp = ircdb.makeChannelCapability(channel, 'halfop')
|
||||
@ -134,7 +134,7 @@ class Protector(callbacks.Plugin):
|
||||
# Handle bans.
|
||||
|
||||
def doKick(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
kicked = msg.args[1].split(',')
|
||||
protected = []
|
||||
for nick in kicked:
|
||||
|
@ -241,14 +241,17 @@ class QuoteGrabs(callbacks.Plugin):
|
||||
if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg):
|
||||
return
|
||||
irc = callbacks.SimpleProxy(irc, msg)
|
||||
if irc.isChannel(msg.args[0]):
|
||||
(chan, payload) = msg.args
|
||||
words = self.registryValue('randomGrabber.minimumWords', chan)
|
||||
length = self.registryValue('randomGrabber.minimumCharacters',chan)
|
||||
if msg.channel:
|
||||
payload = msg.args[1]
|
||||
words = self.registryValue('randomGrabber.minimumWords',
|
||||
msg.channel, irc.network)
|
||||
length = self.registryValue('randomGrabber.minimumCharacters',
|
||||
msg.channel, irc.network)
|
||||
grabTime = \
|
||||
self.registryValue('randomGrabber.averageTimeBetweenGrabs', chan)
|
||||
channel = plugins.getChannel(chan)
|
||||
if self.registryValue('randomGrabber', chan):
|
||||
self.registryValue('randomGrabber.averageTimeBetweenGrabs',
|
||||
msg.channel, irc.network)
|
||||
channel = plugins.getChannel(msg.channel)
|
||||
if self.registryValue('randomGrabber', msg.channel, irc.network):
|
||||
if len(payload) > length and len(payload.split()) > words:
|
||||
try:
|
||||
last = int(self.db.select(channel, msg.nick))
|
||||
@ -287,6 +290,8 @@ class QuoteGrabs(callbacks.Plugin):
|
||||
for m in reversed(irc.state.history):
|
||||
if m.command == 'PRIVMSG' and ircutils.nickEqual(m.nick, nick) \
|
||||
and ircutils.strEqual(m.args[0], chan):
|
||||
# TODO: strip statusmsg prefix for comparison? Must be careful
|
||||
# abouk leaks, though.
|
||||
self._grab(channel, irc, m, msg.prefix)
|
||||
irc.replySuccess()
|
||||
return
|
||||
|
@ -352,7 +352,7 @@ class RSS(callbacks.Plugin):
|
||||
announced_feeds = set()
|
||||
for irc in world.ircs:
|
||||
for channel in irc.state.channels:
|
||||
announced_feeds |= self.registryValue('announce', channel)
|
||||
announced_feeds |= self.registryValue('announce', channel, irc.network)
|
||||
for name in announced_feeds:
|
||||
feed = self.get_feed(name)
|
||||
if not feed:
|
||||
@ -385,14 +385,15 @@ class RSS(callbacks.Plugin):
|
||||
new_entries = sort_feed_items(new_entries, 'newestFirst')
|
||||
for irc in world.ircs:
|
||||
for channel in irc.state.channels:
|
||||
if feed.name not in self.registryValue('announce', channel):
|
||||
if feed.name not in self.registryValue('announce',
|
||||
channel, irc.network):
|
||||
continue
|
||||
if initial:
|
||||
max_entries = \
|
||||
self.registryValue('initialAnnounceHeadlines', channel)
|
||||
max_entries = self.registryValue(
|
||||
'initialAnnounceHeadlines', channel, irc.network)
|
||||
else:
|
||||
max_entries = \
|
||||
self.registryValue('maximumAnnounceHeadlines', channel)
|
||||
max_entries = self.registryValue(
|
||||
'maximumAnnounceHeadlines', channel, irc.network)
|
||||
announced_entries = new_entries[0:max_entries]
|
||||
announced_entries = sort_feed_items(announced_entries, order)
|
||||
for entry in announced_entries:
|
||||
@ -402,9 +403,9 @@ class RSS(callbacks.Plugin):
|
||||
#################
|
||||
# Entry rendering
|
||||
|
||||
def should_send_entry(self, channel, entry):
|
||||
whitelist = self.registryValue('keywordWhitelist', channel)
|
||||
blacklist = self.registryValue('keywordBlacklist', channel)
|
||||
def should_send_entry(self, network, channel, entry):
|
||||
whitelist = self.registryValue('keywordWhitelist', channel, network)
|
||||
blacklist = self.registryValue('keywordBlacklist', channel, network)
|
||||
|
||||
# fix shadowing by "from supybot.commands import *"
|
||||
try:
|
||||
@ -429,14 +430,15 @@ class RSS(callbacks.Plugin):
|
||||
|
||||
_normalize_entry = utils.str.multipleReplacer(
|
||||
{'\r': ' ', '\n': ' ', '\x00': ''})
|
||||
def format_entry(self, channel, feed, entry, is_announce):
|
||||
def format_entry(self, network, channel, feed, entry, is_announce):
|
||||
key_name = 'announceFormat' if is_announce else 'format'
|
||||
if feed.name in self.registryValue('feeds'):
|
||||
specific_key_name = registry.join(['feeds', feed.name, key_name])
|
||||
template = self.registryValue(specific_key_name, channel) or \
|
||||
self.registryValue(key_name, channel)
|
||||
template = self.registryValue(specific_key_name,
|
||||
channel, network) or \
|
||||
self.registryValue(key_name, channel, network)
|
||||
else:
|
||||
template = self.registryValue(key_name, channel)
|
||||
template = self.registryValue(key_name, channel, network)
|
||||
date = entry.get('published_parsed')
|
||||
date = utils.str.timestamp(date)
|
||||
s = string.Template(template).substitute(
|
||||
@ -446,9 +448,9 @@ class RSS(callbacks.Plugin):
|
||||
return self._normalize_entry(s)
|
||||
|
||||
def announce_entry(self, irc, channel, feed, entry):
|
||||
if self.should_send_entry(channel, entry):
|
||||
s = self.format_entry(channel, feed, entry, True)
|
||||
if self.registryValue('notice', channel):
|
||||
if self.should_send_entry(irc.network, channel, entry):
|
||||
s = self.format_entry(irc.network, channel, feed, entry, True)
|
||||
if self.registryValue('notice', channel, irc.network):
|
||||
m = ircmsgs.notice(channel, s)
|
||||
else:
|
||||
m = ircmsgs.privmsg(channel, s)
|
||||
@ -559,10 +561,7 @@ class RSS(callbacks.Plugin):
|
||||
feed = self.get_feed(url)
|
||||
if not feed:
|
||||
feed = Feed(url, url, True)
|
||||
if irc.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
else:
|
||||
channel = None
|
||||
channel = msg.channel
|
||||
self.update_feed_if_needed(feed)
|
||||
entries = feed.entries
|
||||
if not entries:
|
||||
@ -573,13 +572,13 @@ class RSS(callbacks.Plugin):
|
||||
s += str(feed.last_exception)
|
||||
irc.error(s)
|
||||
return
|
||||
n = n or self.registryValue('defaultNumberOfHeadlines', channel)
|
||||
entries = list(filter(lambda e:self.should_send_entry(channel, e),
|
||||
n = n or self.registryValue('defaultNumberOfHeadlines', channel, irc.network)
|
||||
entries = list(filter(lambda e:self.should_send_entry(irc.network, channel, e),
|
||||
feed.entries))
|
||||
entries = entries[:n]
|
||||
headlines = map(lambda e:self.format_entry(channel, feed, e, False),
|
||||
headlines = map(lambda e:self.format_entry(irc.network, channel, feed, e, False),
|
||||
entries)
|
||||
sep = self.registryValue('headlineSeparator', channel)
|
||||
sep = self.registryValue('headlineSeparator', channel, irc.network)
|
||||
irc.replies(headlines, joiner=sep)
|
||||
rss = wrap(rss, [first('url', 'feedName'), additional('int')])
|
||||
|
||||
|
@ -197,7 +197,7 @@ class Relay(callbacks.Plugin):
|
||||
do401 = do402
|
||||
|
||||
def _formatPrivmsg(self, nick, network, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
if self.registryValue('includeNetwork', channel):
|
||||
network = '@' + network
|
||||
else:
|
||||
@ -229,12 +229,12 @@ class Relay(callbacks.Plugin):
|
||||
assert msg.command in ('PRIVMSG', 'NOTICE', 'TOPIC')
|
||||
for otherIrc in world.ircs:
|
||||
if otherIrc != irc and not otherIrc.zombie:
|
||||
if msg.args[0] in otherIrc.state.channels:
|
||||
if msg.channel in otherIrc.state.channels:
|
||||
msg.tag('relayedMsg')
|
||||
otherIrc.queueMsg(msg)
|
||||
|
||||
def _checkRelayMsg(self, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
if channel in self.lastRelayMsgs:
|
||||
q = self.lastRelayMsgs[channel]
|
||||
unformatted = ircutils.stripFormatting(msg.args[1])
|
||||
@ -247,7 +247,7 @@ class Relay(callbacks.Plugin):
|
||||
def _punishRelayers(self, msg):
|
||||
assert self._checkRelayMsg(msg), 'Punishing without checking.'
|
||||
who = msg.prefix
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
def notPunishing(irc, s, *args):
|
||||
self.log.info('Not punishing %s in %s on %s: %s.',
|
||||
msg.prefix, channel, irc.network, s, *args)
|
||||
@ -268,12 +268,12 @@ class Relay(callbacks.Plugin):
|
||||
def doPrivmsg(self, irc, msg):
|
||||
if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg):
|
||||
return
|
||||
(channel, text) = msg.args
|
||||
if irc.isChannel(channel):
|
||||
text = msg.args[1]
|
||||
if msg.channel:
|
||||
irc = self._getRealIrc(irc)
|
||||
if channel not in self.registryValue('channels'):
|
||||
if msg.channel not in self.registryValue('channels'):
|
||||
return
|
||||
ignores = self.registryValue('ignores', channel)
|
||||
ignores = self.registryValue('ignores', msg.channel, irc.network)
|
||||
for ignore in ignores:
|
||||
if ircutils.hostmaskPatternEqual(ignore, msg.prefix):
|
||||
self.log.debug('Refusing to relay %s, ignored by %s.',
|
||||
@ -281,7 +281,8 @@ class Relay(callbacks.Plugin):
|
||||
return
|
||||
# Let's try to detect other relay bots.
|
||||
if self._checkRelayMsg(msg):
|
||||
if self.registryValue('punishOtherRelayBots', channel):
|
||||
if self.registryValue('punishOtherRelayBots',
|
||||
msg.channel, irc.network):
|
||||
self._punishRelayers(msg)
|
||||
# Either way, we don't relay the message.
|
||||
else:
|
||||
@ -291,13 +292,12 @@ class Relay(callbacks.Plugin):
|
||||
else:
|
||||
network = self._getIrcName(irc)
|
||||
s = self._formatPrivmsg(msg.nick, network, msg)
|
||||
m = self._msgmaker(channel, s)
|
||||
m = self._msgmaker(msg.channel, network, s)
|
||||
self._sendToOthers(irc, m)
|
||||
|
||||
def _msgmaker(self, target, s):
|
||||
def _msgmaker(self, target, network, s):
|
||||
msg = dynamic.msg
|
||||
channel = dynamic.channel
|
||||
if self.registryValue('noticeNonPrivmsgs', dynamic.channel) and \
|
||||
if self.registryValue('noticeNonPrivmsgs', target) and \
|
||||
msg.command != 'PRIVMSG':
|
||||
return ircmsgs.notice(target, s)
|
||||
else:
|
||||
@ -423,16 +423,15 @@ class Relay(callbacks.Plugin):
|
||||
if msg.relayedMsg:
|
||||
self._addRelayMsg(msg)
|
||||
else:
|
||||
channel = msg.args[0]
|
||||
if channel in self.registryValue('channels'):
|
||||
if msg.channel in self.registryValue('channels'):
|
||||
network = self._getIrcName(irc)
|
||||
s = self._formatPrivmsg(irc.nick, network, msg)
|
||||
relayMsg = self._msgmaker(channel, s)
|
||||
relayMsg = self._msgmaker(msg.args[0], s)
|
||||
self._sendToOthers(irc, relayMsg)
|
||||
return msg
|
||||
|
||||
def _addRelayMsg(self, msg):
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
if channel in self.lastRelayMsgs:
|
||||
q = self.lastRelayMsgs[channel]
|
||||
else:
|
||||
|
@ -125,8 +125,8 @@ class Seen(callbacks.Plugin):
|
||||
def doPrivmsg(self, irc, msg):
|
||||
if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg):
|
||||
return
|
||||
if irc.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
if msg.channel:
|
||||
channel = msg.channel
|
||||
said = ircmsgs.prettyPrint(msg)
|
||||
self.db.update(channel, msg.nick, said)
|
||||
self.anydb.update(channel, msg.nick, said)
|
||||
@ -184,7 +184,8 @@ class Seen(callbacks.Plugin):
|
||||
results = []
|
||||
if '*' in name:
|
||||
if (len(name.replace('*', '')) <
|
||||
self.registryValue('minimumNonWildcard', channel)):
|
||||
self.registryValue('minimumNonWildcard',
|
||||
channel, irc.network)):
|
||||
irc.error(_('Not enough non-wildcard characters.'),
|
||||
Raise=True)
|
||||
results = db.seenWildcard(channel, name)
|
||||
@ -196,7 +197,7 @@ class Seen(callbacks.Plugin):
|
||||
reply = format(_('%s was last seen in %s %s ago'),
|
||||
nick, channel,
|
||||
utils.timeElapsed(time.time()-when))
|
||||
if self.registryValue('showLastMessage', channel):
|
||||
if self.registryValue('showLastMessage', channel, irc.network):
|
||||
if minisix.PY2:
|
||||
said = said.decode('utf8')
|
||||
reply = _('%s: %s') % (reply, said)
|
||||
@ -277,7 +278,7 @@ class Seen(callbacks.Plugin):
|
||||
(when, said) = db.seen(channel, '<last>')
|
||||
reply = format(_('Someone was last seen in %s %s ago'),
|
||||
channel, utils.timeElapsed(time.time()-when))
|
||||
if self.registryValue('showLastMessage', channel):
|
||||
if self.registryValue('showLastMessage', channel, irc.network):
|
||||
reply = _('%s: %s') % (reply, said)
|
||||
irc.reply(reply)
|
||||
except KeyError:
|
||||
@ -304,7 +305,7 @@ class Seen(callbacks.Plugin):
|
||||
reply = format(_('%s was last seen in %s %s ago'),
|
||||
user.name, channel,
|
||||
utils.timeElapsed(time.time()-when))
|
||||
if self.registryValue('showLastMessage', channel):
|
||||
if self.registryValue('showLastMessage', channel, irc.network):
|
||||
reply = _('%s: %s') % (reply, said)
|
||||
irc.reply(reply)
|
||||
except KeyError:
|
||||
|
@ -38,8 +38,8 @@ def registerNick(nick, password=''):
|
||||
p = conf.supybot.plugins.Services.Nickserv.get('password')
|
||||
h = _('Determines what password the bot will use with NickServ when ' \
|
||||
'identifying as %s.') % nick
|
||||
v = conf.registerGlobalValue(p, nick,
|
||||
registry.String(password, h, private=True))
|
||||
v = conf.registerNetworkValue(p, nick,
|
||||
registry.String(password, h, private=True))
|
||||
if password:
|
||||
v.setValue(password)
|
||||
|
||||
@ -65,7 +65,7 @@ class ValidNickSet(conf.ValidNicks):
|
||||
List = ircutils.IrcSet
|
||||
|
||||
Services = conf.registerPlugin('Services')
|
||||
conf.registerGlobalValue(Services, 'nicks',
|
||||
conf.registerNetworkValue(Services, 'nicks',
|
||||
ValidNickSet([], _("""Determines what nicks the bot will use with
|
||||
services.""")))
|
||||
|
||||
@ -76,19 +76,19 @@ conf.registerGlobalValue(Services, 'disabledNetworks',
|
||||
Networks(_('QuakeNet').split(), _("""Determines what networks this plugin
|
||||
will be disabled on.""")))
|
||||
|
||||
conf.registerGlobalValue(Services, 'noJoinsUntilIdentified',
|
||||
conf.registerNetworkValue(Services, 'noJoinsUntilIdentified',
|
||||
registry.Boolean(False, _("""Determines whether the bot will not join any
|
||||
channels until it is identified. This may be useful, for instances, if
|
||||
you have a vhost that isn't set until you're identified, or if you're
|
||||
joining +r channels that won't allow you to join unless you identify.""")))
|
||||
conf.registerGlobalValue(Services, 'ghostDelay',
|
||||
conf.registerNetworkValue(Services, 'ghostDelay',
|
||||
registry.NonNegativeInteger(60, _("""Determines how many seconds the bot will
|
||||
wait between successive GHOST attempts. Set this to 0 to disable GHOST.""")))
|
||||
conf.registerGlobalValue(Services, 'NickServ',
|
||||
conf.registerNetworkValue(Services, 'NickServ',
|
||||
ValidNickOrEmptyString('NickServ', _("""Determines what nick the 'NickServ' service
|
||||
has.""")))
|
||||
conf.registerGroup(Services.NickServ, 'password')
|
||||
conf.registerGlobalValue(Services, 'ChanServ',
|
||||
conf.registerNetworkValue(Services, 'ChanServ',
|
||||
ValidNickOrEmptyString('ChanServ', _("""Determines what nick the 'ChanServ' service
|
||||
has.""")))
|
||||
conf.registerChannelValue(Services.ChanServ, 'password',
|
||||
|
@ -55,7 +55,7 @@ class Services(callbacks.Plugin):
|
||||
def __init__(self, irc):
|
||||
self.__parent = super(Services, self)
|
||||
self.__parent.__init__(irc)
|
||||
for nick in self.registryValue('nicks'):
|
||||
for nick in self.registryValue('nicks', network=irc.network):
|
||||
config.registerNick(nick)
|
||||
self.reset()
|
||||
|
||||
@ -75,9 +75,9 @@ class Services(callbacks.Plugin):
|
||||
def outFilter(self, irc, msg):
|
||||
if msg.command == 'JOIN' and not self.disabled(irc):
|
||||
if not self.identified:
|
||||
if self.registryValue('noJoinsUntilIdentified'):
|
||||
self.log.info('Holding JOIN to %s until identified.',
|
||||
msg.args[0])
|
||||
if self.registryValue('noJoinsUntilIdentified', network=irc.network):
|
||||
self.log.info('Holding JOIN to %s @ %s until identified.',
|
||||
msg.channel, irc.network)
|
||||
self.waitingJoins.setdefault(irc.network, [])
|
||||
self.waitingJoins[irc.network].append(msg)
|
||||
return None
|
||||
@ -90,25 +90,25 @@ class Services(callbacks.Plugin):
|
||||
else:
|
||||
return network_nick
|
||||
|
||||
def _getNickServPassword(self, nick):
|
||||
def _getNickServPassword(self, nick, network):
|
||||
# This should later be nick-specific.
|
||||
assert nick in self.registryValue('nicks')
|
||||
return self.registryValue('NickServ.password.%s' % nick)
|
||||
assert nick in self.registryValue('nicks', network=network)
|
||||
return self.registryValue('NickServ.password.%s' % nick, network=network)
|
||||
|
||||
def _setNickServPassword(self, nick, password):
|
||||
def _setNickServPassword(self, nick, password, network):
|
||||
# This also should be nick-specific.
|
||||
assert nick in self.registryValue('nicks')
|
||||
self.setRegistryValue('NickServ.password.%s' % nick, password)
|
||||
assert nick in self.registryValue('nicks', network=network)
|
||||
self.setRegistryValue('NickServ.password.%s' % nick, password, network=network)
|
||||
|
||||
def _doIdentify(self, irc, nick=None):
|
||||
if self.disabled(irc):
|
||||
return
|
||||
if nick is None:
|
||||
nick = self._getNick(irc.network)
|
||||
if nick not in self.registryValue('nicks'):
|
||||
if nick not in self.registryValue('nicks', network=irc.network):
|
||||
return
|
||||
nickserv = self.registryValue('NickServ')
|
||||
password = self._getNickServPassword(nick)
|
||||
nickserv = self.registryValue('NickServ', network=irc.network)
|
||||
password = self._getNickServPassword(nick, irc.network)
|
||||
if not nickserv or not password:
|
||||
s = 'Tried to identify without a NickServ or password set.'
|
||||
self.log.warning(s)
|
||||
@ -127,11 +127,11 @@ class Services(callbacks.Plugin):
|
||||
return
|
||||
if nick is None:
|
||||
nick = self._getNick(irc.network)
|
||||
if nick not in self.registryValue('nicks'):
|
||||
if nick not in self.registryValue('nicks', network=irc.network):
|
||||
return
|
||||
nickserv = self.registryValue('NickServ')
|
||||
password = self._getNickServPassword(nick)
|
||||
ghostDelay = self.registryValue('ghostDelay')
|
||||
nickserv = self.registryValue('NickServ', network=irc.network)
|
||||
password = self._getNickServPassword(nick, irc.network)
|
||||
ghostDelay = self.registryValue('ghostDelay', network=irc.network)
|
||||
if not ghostDelay:
|
||||
return
|
||||
if not nickserv or not password:
|
||||
@ -157,11 +157,11 @@ class Services(callbacks.Plugin):
|
||||
if self.disabled(irc):
|
||||
return
|
||||
nick = self._getNick(irc.network)
|
||||
if nick not in self.registryValue('nicks'):
|
||||
if nick not in self.registryValue('nicks', network=irc.network):
|
||||
return
|
||||
nickserv = self.registryValue('NickServ')
|
||||
password = self._getNickServPassword(nick)
|
||||
ghostDelay = self.registryValue('ghostDelay')
|
||||
nickserv = self.registryValue('NickServ', network=irc.network)
|
||||
password = self._getNickServPassword(nick, irc.network)
|
||||
ghostDelay = self.registryValue('ghostDelay', network=irc.network)
|
||||
if not ghostDelay:
|
||||
return
|
||||
if nick and nickserv and password and \
|
||||
@ -181,13 +181,13 @@ class Services(callbacks.Plugin):
|
||||
if self.disabled(irc):
|
||||
return
|
||||
nick = self._getNick(irc.network)
|
||||
if nick not in self.registryValue('nicks'):
|
||||
if nick not in self.registryValue('nicks', network=irc.network):
|
||||
return
|
||||
nickserv = self.registryValue('NickServ')
|
||||
nickserv = self.registryValue('NickServ', network=irc.network)
|
||||
if not nickserv:
|
||||
self.log.warning('NickServ is unset, cannot identify.')
|
||||
return
|
||||
password = self._getNickServPassword(nick)
|
||||
password = self._getNickServPassword(nick, irc.network)
|
||||
if not password:
|
||||
self.log.warning('Password for %s is unset, cannot identify.',nick)
|
||||
return
|
||||
@ -205,10 +205,10 @@ class Services(callbacks.Plugin):
|
||||
if self.disabled(irc):
|
||||
return
|
||||
nick = self._getNick(irc.network)
|
||||
if nick not in self.registryValue('nicks'):
|
||||
if nick not in self.registryValue('nicks', network=irc.network):
|
||||
return
|
||||
if nick and irc.afterConnect:
|
||||
password = self._getNickServPassword(nick)
|
||||
password = self._getNickServPassword(nick, irc.network)
|
||||
if not password:
|
||||
return
|
||||
self._doGhost(irc)
|
||||
@ -232,8 +232,8 @@ class Services(callbacks.Plugin):
|
||||
|
||||
def doNotice(self, irc, msg):
|
||||
if irc.afterConnect:
|
||||
nickserv = self.registryValue('NickServ')
|
||||
chanserv = self.registryValue('ChanServ')
|
||||
nickserv = self.registryValue('NickServ', network=irc.network)
|
||||
chanserv = self.registryValue('ChanServ', network=irc.network)
|
||||
if nickserv and ircutils.strEqual(msg.nick, nickserv):
|
||||
self.doNickservNotice(irc, msg)
|
||||
elif chanserv and ircutils.strEqual(msg.nick, chanserv):
|
||||
@ -298,7 +298,7 @@ class Services(callbacks.Plugin):
|
||||
'Resetting password to empty.' % on
|
||||
self.log.warning(log)
|
||||
self.sentGhost = time.time()
|
||||
self._setNickServPassword(nick, '')
|
||||
self._setNickServPassword(nick, '', irc.network)
|
||||
elif self._ghosted(irc, s):
|
||||
self.log.info('Received "GHOST succeeded" from NickServ %s.', on)
|
||||
self.sentGhost = None
|
||||
@ -355,19 +355,19 @@ class Services(callbacks.Plugin):
|
||||
def checkPrivileges(self, irc, channel):
|
||||
if self.disabled(irc):
|
||||
return
|
||||
chanserv = self.registryValue('ChanServ')
|
||||
chanserv = self.registryValue('ChanServ', network=irc.network)
|
||||
on = 'on %s' % irc.network
|
||||
if chanserv and self.registryValue('ChanServ.op', channel):
|
||||
if chanserv and self.registryValue('ChanServ.op', channel, irc.network):
|
||||
if irc.nick not in irc.state.channels[channel].ops:
|
||||
self.log.info('Requesting op from %s in %s %s.',
|
||||
chanserv, channel, on)
|
||||
irc.sendMsg(ircmsgs.privmsg(chanserv, 'op %s' % channel))
|
||||
if chanserv and self.registryValue('ChanServ.halfop', channel):
|
||||
if chanserv and self.registryValue('ChanServ.halfop', channel, irc.network):
|
||||
if irc.nick not in irc.state.channels[channel].halfops:
|
||||
self.log.info('Requesting halfop from %s in %s %s.',
|
||||
chanserv, channel, on)
|
||||
irc.sendMsg(ircmsgs.privmsg(chanserv, 'halfop %s' % channel))
|
||||
if chanserv and self.registryValue('ChanServ.voice', channel):
|
||||
if chanserv and self.registryValue('ChanServ.voice', channel, irc.network):
|
||||
if irc.nick not in irc.state.channels[channel].voices:
|
||||
self.log.info('Requesting voice from %s in %s %s.',
|
||||
chanserv, channel, on)
|
||||
@ -376,7 +376,7 @@ class Services(callbacks.Plugin):
|
||||
def doMode(self, irc, msg):
|
||||
if self.disabled(irc):
|
||||
return
|
||||
chanserv = self.registryValue('ChanServ')
|
||||
chanserv = self.registryValue('ChanServ', network=irc.network)
|
||||
on = 'on %s' % irc.network
|
||||
if ircutils.strEqual(msg.nick, chanserv):
|
||||
channel = msg.args[0]
|
||||
@ -406,7 +406,7 @@ class Services(callbacks.Plugin):
|
||||
self.__parent.callCommand(command, irc, msg, *args, **kwargs)
|
||||
|
||||
def _chanservCommand(self, irc, channel, command, log=False):
|
||||
chanserv = self.registryValue('ChanServ')
|
||||
chanserv = self.registryValue('ChanServ', network=irc.network)
|
||||
if chanserv:
|
||||
msg = ircmsgs.privmsg(chanserv,
|
||||
' '.join([command, channel]))
|
||||
@ -493,7 +493,8 @@ class Services(callbacks.Plugin):
|
||||
invite = wrap(invite, [('checkChannelCapability', 'op'), 'inChannel'])
|
||||
|
||||
def doInvite(self, irc, msg):
|
||||
if ircutils.strEqual(msg.nick, self.registryValue('ChanServ')):
|
||||
if ircutils.strEqual(
|
||||
msg.nick, self.registryValue('ChanServ', etwork=irc.network)):
|
||||
channel = msg.args[1]
|
||||
on = 'on %s' % irc.network
|
||||
networkGroup = conf.supybot.networks.get(irc.network)
|
||||
@ -506,8 +507,8 @@ class Services(callbacks.Plugin):
|
||||
|
||||
Identifies with NickServ using the current nick.
|
||||
"""
|
||||
if self.registryValue('NickServ'):
|
||||
if irc.nick in self.registryValue('nicks'):
|
||||
if self.registryValue('NickServ', network=irc.network):
|
||||
if irc.nick in self.registryValue('nicks', network=irc.network):
|
||||
self._doIdentify(irc, irc.nick)
|
||||
irc.replySuccess()
|
||||
else:
|
||||
@ -525,7 +526,7 @@ class Services(callbacks.Plugin):
|
||||
Ghosts the bot's given nick and takes it. If no nick is given,
|
||||
ghosts the bot's configured nick and takes it.
|
||||
"""
|
||||
if self.registryValue('NickServ'):
|
||||
if self.registryValue('NickServ', network=irc.network):
|
||||
if not nick:
|
||||
nick = self._getNick(irc.network)
|
||||
if ircutils.strEqual(nick, irc.nick):
|
||||
@ -547,13 +548,17 @@ class Services(callbacks.Plugin):
|
||||
"""
|
||||
if not password:
|
||||
try:
|
||||
self.registryValue('nicks').remove(nick)
|
||||
v = self.registryValue('nicks', network=irc.network).copy()
|
||||
v.remove(nick)
|
||||
self.setRegistryValue('nicks', value=v, network=irc.network)
|
||||
irc.replySuccess()
|
||||
except KeyError:
|
||||
irc.error(_('That nick was not configured with a password.'))
|
||||
return
|
||||
else:
|
||||
self.registryValue('nicks').add(nick)
|
||||
v = self.registryValue('nicks', network=irc.network).copy()
|
||||
v.add(nick)
|
||||
self.setRegistryValue('nicks', value=v, network=irc.network)
|
||||
config.registerNick(nick, password)
|
||||
irc.replySuccess()
|
||||
password = wrap(password, [('checkCapability', 'admin'),
|
||||
@ -566,7 +571,7 @@ class Services(callbacks.Plugin):
|
||||
Returns the nicks that this plugin is configured to identify and ghost
|
||||
with.
|
||||
"""
|
||||
L = list(self.registryValue('nicks'))
|
||||
L = list(self.registryValue('nicks', network=irc.network))
|
||||
if L:
|
||||
utils.sortBy(ircutils.toLower, L)
|
||||
irc.reply(format('%L', L))
|
||||
|
@ -30,7 +30,7 @@
|
||||
from supybot.test import *
|
||||
|
||||
class ServicesTestCase(PluginTestCase):
|
||||
plugins = ('Services',)
|
||||
plugins = ('Services', 'Config')
|
||||
config = {
|
||||
'plugins.Services.NickServ': 'NickServ',
|
||||
'plugins.Services.ChanServ': 'ChanServ',
|
||||
@ -48,6 +48,33 @@ class ServicesTestCase(PluginTestCase):
|
||||
self.failUnless(m.args[0] == 'NickServ')
|
||||
self.failUnless(m.args[1].lower() == 'identify biff')
|
||||
|
||||
def testPasswordConfg(self):
|
||||
self.assertNotError('config plugins.Services.nicks ""')
|
||||
self.assertNotError('config network plugins.Services.nicks ""')
|
||||
|
||||
self.assertNotError('services password %s bar' % self.nick)
|
||||
|
||||
self.assertResponse(
|
||||
'config plugins.Services.nicks',
|
||||
'Global: ; test: %s' % self.nick)
|
||||
self.assertResponse(
|
||||
'config plugins.Services.nickserv.password.%s' % self.nick,
|
||||
'Global: bar; test: bar')
|
||||
|
||||
self.assertNotError(
|
||||
'config network plugins.Services.nickserv.password.%s bar2'
|
||||
% self.nick)
|
||||
self.assertResponse(
|
||||
'config plugins.Services.nickserv.password.%s' % self.nick,
|
||||
'Global: bar; test: bar2')
|
||||
self.assertResponse(
|
||||
'config plugins.Services.nickserv.password.%s' % self.nick,
|
||||
'Global: bar; test: bar2')
|
||||
|
||||
m = self.assertNotError('services identify')
|
||||
self.failUnless(m.args[0] == 'NickServ')
|
||||
self.failUnless(m.args[1].lower() == 'identify bar2')
|
||||
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
||||
|
@ -105,15 +105,17 @@ class ShrinkUrl(callbacks.PluginRegexp):
|
||||
|
||||
def _outFilterThread(self, irc, msg):
|
||||
(channel, text) = msg.args
|
||||
network = irc.network
|
||||
for m in utils.web.httpUrlRe.finditer(text):
|
||||
url = m.group(1)
|
||||
if len(url) > self.registryValue('minimumLength', channel):
|
||||
if len(url) > self.registryValue('minimumLength', channel, network):
|
||||
try:
|
||||
cmd = self.registryValue('serviceRotation',
|
||||
channel, value=False)
|
||||
channel, network, value=False)
|
||||
cmd = cmd.getService().capitalize()
|
||||
except ValueError:
|
||||
cmd = self.registryValue('default', channel).capitalize()
|
||||
cmd = self.registryValue('default', channel, network) \
|
||||
.capitalize()
|
||||
try:
|
||||
shortUrl = getattr(self, '_get%sUrl' % cmd)(url)
|
||||
text = text.replace(url, shortUrl)
|
||||
@ -126,39 +128,41 @@ class ShrinkUrl(callbacks.PluginRegexp):
|
||||
def outFilter(self, irc, msg):
|
||||
if msg.command != 'PRIVMSG':
|
||||
return msg
|
||||
channel = msg.args[0]
|
||||
if irc.isChannel(channel):
|
||||
if msg.channel:
|
||||
if not msg.shrunken:
|
||||
if self.registryValue('outFilter', channel):
|
||||
if self.registryValue('outFilter', msg.channel, irc.network):
|
||||
if utils.web.httpUrlRe.search(msg.args[1]):
|
||||
self._outFilterThread(irc, msg)
|
||||
return None
|
||||
return msg
|
||||
|
||||
def shrinkSnarfer(self, irc, msg, match):
|
||||
channel = msg.args[0]
|
||||
if not irc.isChannel(channel):
|
||||
channel = msg.channel
|
||||
network = irc.network
|
||||
if not channel:
|
||||
return
|
||||
if self.registryValue('shrinkSnarfer', channel):
|
||||
if self.registryValue('shrinkSnarfer', channel, network):
|
||||
url = match.group(0)
|
||||
r = self.registryValue('nonSnarfingRegexp', channel)
|
||||
r = self.registryValue('nonSnarfingRegexp', channel, network)
|
||||
if r and r.search(url) is not None:
|
||||
self.log.debug('Matched nonSnarfingRegexp: %u', url)
|
||||
return
|
||||
minlen = self.registryValue('minimumLength', channel)
|
||||
minlen = self.registryValue('minimumLength', channel, network)
|
||||
try:
|
||||
cmd = self.registryValue('serviceRotation',
|
||||
channel, value=False)
|
||||
channel, network, value=False)
|
||||
cmd = cmd.getService().capitalize()
|
||||
except ValueError:
|
||||
cmd = self.registryValue('default', channel).capitalize()
|
||||
cmd = self.registryValue('default', channel, network) \
|
||||
.capitalize()
|
||||
if len(url) >= minlen:
|
||||
try:
|
||||
shorturl = getattr(self, '_get%sUrl' % cmd)(url)
|
||||
except (utils.web.Error, AttributeError, ShrinkError):
|
||||
self.log.info('Couldn\'t get shorturl for %u', url)
|
||||
return
|
||||
if self.registryValue('shrinkSnarfer.showDomain', channel):
|
||||
if self.registryValue('shrinkSnarfer.showDomain',
|
||||
channel, network):
|
||||
domain = ' (at %s)' % utils.web.getDomain(url)
|
||||
else:
|
||||
domain = ''
|
||||
|
@ -140,9 +140,9 @@ class Status(callbacks.Plugin):
|
||||
"""
|
||||
(user, system, childUser, childSystem, elapsed) = os.times()
|
||||
now = time.time()
|
||||
target = msg.args[0]
|
||||
target = (msg.channel, irc.network)
|
||||
timeRunning = now - world.startedAt
|
||||
if self.registryValue('cpu.children', target) and \
|
||||
if self.registryValue('cpu.children', *target) and \
|
||||
user+system < timeRunning+1: # Fudge for FPU inaccuracies.
|
||||
children = _('My children have taken %.2f seconds of user time '
|
||||
'and %.2f seconds of system time '
|
||||
@ -154,11 +154,11 @@ class Status(callbacks.Plugin):
|
||||
response = _('I have taken %.2f seconds of user time and %.2f seconds '
|
||||
'of system time, for a total of %.2f seconds of CPU '
|
||||
'time. %s') % (user, system, user + system, children)
|
||||
if self.registryValue('cpu.threads', target):
|
||||
if self.registryValue('cpu.threads', *target):
|
||||
response += format('I have spawned %n; I currently have %i still '
|
||||
'running.',
|
||||
(world.threadsSpawned, 'thread'), activeThreads)
|
||||
if self.registryValue('cpu.memory', target):
|
||||
if self.registryValue('cpu.memory', *target):
|
||||
mem = None
|
||||
pid = os.getpid()
|
||||
plat = sys.platform
|
||||
|
@ -50,7 +50,8 @@ class Success(plugins.ChannelIdDatabasePlugin):
|
||||
class MySuccessClass(self.originalClass):
|
||||
__slots__ = ()
|
||||
def __call__(self):
|
||||
ret = pluginSelf.db.random(dynamic.msg.args[0])
|
||||
msg = dynamic.msg
|
||||
ret = pluginSelf.db.random(msg.channel or msg.args[0])
|
||||
if ret is None:
|
||||
try:
|
||||
self.__class__ = pluginSelf.originalClass
|
||||
|
@ -175,7 +175,8 @@ class Time(callbacks.Plugin):
|
||||
<channel> is given without <format>, uses the format for <channel>.
|
||||
"""
|
||||
if not format:
|
||||
format = self.registryValue('format', channel or msg.args[0])
|
||||
format = self.registryValue('format', channel or msg.channel,
|
||||
irc.network)
|
||||
if tzlocal:
|
||||
irc.reply(datetime.fromtimestamp(seconds, tzlocal()).strftime(format))
|
||||
else:
|
||||
@ -209,7 +210,7 @@ class Time(callbacks.Plugin):
|
||||
timezone = pytz.timezone(timezone)
|
||||
except pytz.UnknownTimeZoneError:
|
||||
irc.error(_('Unknown timezone'), Raise=True)
|
||||
format = self.registryValue("format", msg.args[0])
|
||||
format = self.registryValue("format", msg.channel, irc.network)
|
||||
irc.reply(datetime.now(timezone).strftime(format))
|
||||
tztime = wrap(tztime, ['text'])
|
||||
|
||||
|
@ -64,16 +64,17 @@ def canChangeTopic(irc, msg, args, state):
|
||||
|
||||
|
||||
def getTopic(irc, msg, args, state, format=True):
|
||||
separator = state.cb.registryValue('separator', state.channel)
|
||||
separator = state.cb.registryValue('separator', state.channel, irc.network)
|
||||
if separator in args[0] and not \
|
||||
state.cb.registryValue('allowSeparatorinTopics', state.channel):
|
||||
state.cb.registryValue('allowSeparatorinTopics',
|
||||
state.channel, irc.network):
|
||||
state.errorInvalid('topic', args[0],
|
||||
format(_('The topic must not include %q.'),
|
||||
separator))
|
||||
topic = args.pop(0)
|
||||
if format:
|
||||
env = {'topic': topic}
|
||||
formatter = state.cb.registryValue('format', state.channel)
|
||||
formatter = state.cb.registryValue('format', state.channel, irc.network)
|
||||
topic = ircutils.standardSubstitute(irc, msg, formatter, env)
|
||||
state.args.append(topic)
|
||||
|
||||
@ -90,7 +91,7 @@ def getTopicNumber(irc, msg, args, state):
|
||||
if n > 0:
|
||||
n -= 1
|
||||
topic = irc.state.getTopic(state.channel)
|
||||
separator = state.cb.registryValue('separator', state.channel)
|
||||
separator = state.cb.registryValue('separator', state.channel, irc.network)
|
||||
topics = splitTopic(topic, separator)
|
||||
if not topics:
|
||||
state.error(format(_('There are no topics in %s.'), state.channel),
|
||||
@ -162,24 +163,25 @@ class Topic(callbacks.Plugin):
|
||||
except (IOError, shutil.Error) as e:
|
||||
self.log.warning('File error: %s', e)
|
||||
|
||||
def _splitTopic(self, topic, channel):
|
||||
separator = self.registryValue('separator', channel)
|
||||
def _splitTopic(self, irc, channel):
|
||||
topic = irc.state.getTopic(channel)
|
||||
separator = self.registryValue('separator', channel, irc.network)
|
||||
return splitTopic(topic, separator)
|
||||
|
||||
def _joinTopic(self, channel, topics):
|
||||
separator = self.registryValue('separator', channel)
|
||||
def _joinTopic(self, irc, channel, topics):
|
||||
separator = self.registryValue('separator', channel, irc.network)
|
||||
return separator.join(topics)
|
||||
|
||||
def _addUndo(self, channel, topics):
|
||||
def _addUndo(self, irc, channel, topics):
|
||||
stack = self.undos.setdefault(channel, [])
|
||||
stack.append(topics)
|
||||
maxLen = self.registryValue('undo.max', channel)
|
||||
maxLen = self.registryValue('undo.max', channel, irc.network)
|
||||
del stack[:len(stack) - maxLen]
|
||||
|
||||
def _addRedo(self, channel, topics):
|
||||
def _addRedo(self, irc, channel, topics):
|
||||
stack = self.redos.setdefault(channel, [])
|
||||
stack.append(topics)
|
||||
maxLen = self.registryValue('undo.max', channel)
|
||||
maxLen = self.registryValue('undo.max', channel, irc.network)
|
||||
del stack[:len(stack) - maxLen]
|
||||
|
||||
def _getUndo(self, channel):
|
||||
@ -197,16 +199,16 @@ class Topic(callbacks.Plugin):
|
||||
def _formatTopics(self, irc, channel, topics, fit=False):
|
||||
topics = [s for s in topics if s and not s.isspace()]
|
||||
self.lastTopics[channel] = topics
|
||||
newTopic = self._joinTopic(channel, topics)
|
||||
newTopic = self._joinTopic(irc, channel, topics)
|
||||
try:
|
||||
maxLen = irc.state.supported['topiclen']
|
||||
if fit:
|
||||
while len(newTopic) > maxLen:
|
||||
topics.pop(0)
|
||||
self.lastTopics[channel] = topics
|
||||
newTopic = self._joinTopic(channel, topics)
|
||||
newTopic = self._joinTopic(irc, channel, topics)
|
||||
elif len(newTopic) > maxLen:
|
||||
if self.registryValue('recognizeTopiclen', channel):
|
||||
if self.registryValue('recognizeTopiclen', channel, irc.network):
|
||||
irc.error(format(_('That topic is too long for this '
|
||||
'server (maximum length: %i; this topic: '
|
||||
'%i).'), maxLen, len(newTopic)),
|
||||
@ -219,7 +221,7 @@ class Topic(callbacks.Plugin):
|
||||
if isinstance(topics, list) or isinstance(topics, tuple):
|
||||
assert topics is not None
|
||||
topics = self._formatTopics(irc, channel, topics, fit)
|
||||
self._addUndo(channel, topics)
|
||||
self._addUndo(irc, channel, topics)
|
||||
if not isDo and channel in self.redos:
|
||||
del self.redos[channel]
|
||||
irc.queueMsg(ircmsgs.topic(channel, topics))
|
||||
@ -238,7 +240,8 @@ class Topic(callbacks.Plugin):
|
||||
c = irc.state.channels[channel]
|
||||
if msg.nick in c.ops or msg.nick in c.halfops or 't' not in c.modes:
|
||||
return True
|
||||
capabilities = self.registryValue('requireManageCapability', channel)
|
||||
capabilities = self.registryValue('requireManageCapability',
|
||||
channel, irc.network)
|
||||
if capabilities:
|
||||
for capability in re.split(r'\s*;\s*', capabilities):
|
||||
if capability.startswith('channel,'):
|
||||
@ -247,7 +250,7 @@ class Topic(callbacks.Plugin):
|
||||
if capability and ircdb.checkCapability(msg.prefix, capability):
|
||||
return
|
||||
capabilities = self.registryValue('requireManageCapability',
|
||||
channel)
|
||||
channel, irc.network)
|
||||
irc.errorNoCapability(capabilities, Raise=True)
|
||||
else:
|
||||
return
|
||||
@ -261,7 +264,7 @@ class Topic(callbacks.Plugin):
|
||||
# Try to restore the topic when not set yet.
|
||||
channel = msg.args[1]
|
||||
c = irc.state.channels.get(channel)
|
||||
if c is None or not self.registryValue('setOnJoin', channel):
|
||||
if c is None or not self.registryValue('setOnJoin', channel, irc.network):
|
||||
return
|
||||
if irc.nick not in c.ops and 't' in c.modes:
|
||||
self.log.debug('Not trying to restore topic in %s. I\'m not opped '
|
||||
@ -274,7 +277,8 @@ class Topic(callbacks.Plugin):
|
||||
else:
|
||||
newTopic = self._formatTopics(irc, channel, topics)
|
||||
if c.topic == '' or (c.topic != newTopic and
|
||||
self.registryValue('alwaysSetOnJoin', channel)):
|
||||
self.registryValue('alwaysSetOnJoin',
|
||||
channel, irc.network)):
|
||||
self._sendTopics(irc, channel, newTopic)
|
||||
|
||||
def do332(self, irc, msg):
|
||||
@ -282,7 +286,7 @@ class Topic(callbacks.Plugin):
|
||||
self.watchingFor332.remove(msg.args[1])
|
||||
# Store an undo for the topic when we join a channel. This allows
|
||||
# us to undo the first topic change that takes place in a channel.
|
||||
self._addUndo(msg.args[1], [msg.args[2]])
|
||||
self._addUndo(irc, msg.args[1], [msg.args[2]])
|
||||
|
||||
def topic(self, irc, msg, args, channel):
|
||||
"""[<channel>]
|
||||
@ -301,7 +305,7 @@ class Topic(callbacks.Plugin):
|
||||
if the message isn't sent in the channel itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
topics.append(topic)
|
||||
self._sendTopics(irc, channel, topics)
|
||||
add = wrap(add, ['canChangeTopic', rest('topic')])
|
||||
@ -315,7 +319,7 @@ class Topic(callbacks.Plugin):
|
||||
itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
topics.append(topic)
|
||||
self._sendTopics(irc, channel, topics, fit=True)
|
||||
fit = wrap(fit, ['canChangeTopic', rest('topic')])
|
||||
@ -326,7 +330,7 @@ class Topic(callbacks.Plugin):
|
||||
Replaces topic <number> with <topic>.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
topics[i] = topic
|
||||
self._sendTopics(irc, channel, topics)
|
||||
replace = wrap(replace, ['canChangeTopic', 'topicNumber', rest('topic')])
|
||||
@ -339,7 +343,7 @@ class Topic(callbacks.Plugin):
|
||||
isn't sent in the channel itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
topics.insert(0, topic)
|
||||
self._sendTopics(irc, channel, topics)
|
||||
insert = wrap(insert, ['canChangeTopic', rest('topic')])
|
||||
@ -351,7 +355,7 @@ class Topic(callbacks.Plugin):
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
if len(topics) == 0 or len(topics) == 1:
|
||||
irc.error(_('I can\'t shuffle 1 or fewer topics.'), Raise=True)
|
||||
elif len(topics) == 2:
|
||||
@ -372,7 +376,7 @@ class Topic(callbacks.Plugin):
|
||||
itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
num = len(topics)
|
||||
if num == 0 or num == 1:
|
||||
irc.error(_('I cannot reorder 1 or fewer topics.'), Raise=True)
|
||||
@ -392,7 +396,7 @@ class Topic(callbacks.Plugin):
|
||||
Mostly useful for topic reordering. <channel> is only necessary if the
|
||||
message isn't sent in the channel itself.
|
||||
"""
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
L = []
|
||||
for (i, t) in enumerate(topics):
|
||||
L.append(format(_('%i: %s'), i + 1, utils.str.ellipsisify(t, 30)))
|
||||
@ -407,7 +411,7 @@ class Topic(callbacks.Plugin):
|
||||
index into the topics. <channel> is only necessary if the message
|
||||
isn't sent in the channel itself.
|
||||
"""
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
irc.reply(topics[number])
|
||||
get = wrap(get, ['inChannel', 'topicNumber'])
|
||||
|
||||
@ -421,7 +425,7 @@ class Topic(callbacks.Plugin):
|
||||
isn't sent in the channel itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
topics[number] = replacer(topics[number])
|
||||
self._sendTopics(irc, channel, topics)
|
||||
change = wrap(change, ['canChangeTopic', 'topicNumber', 'regexpReplacer'])
|
||||
@ -435,7 +439,7 @@ class Topic(callbacks.Plugin):
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
if number is not None:
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
topics[number] = topic
|
||||
else:
|
||||
topics = [topic]
|
||||
@ -453,7 +457,7 @@ class Topic(callbacks.Plugin):
|
||||
necessary if the message isn't sent in the channel itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
numbers = set(numbers)
|
||||
for n in numbers:
|
||||
# Equivalent of marking the topic for deletion; there's no
|
||||
@ -534,7 +538,7 @@ class Topic(callbacks.Plugin):
|
||||
channel itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
self._addRedo(channel, self._getUndo(channel)) # current topic.
|
||||
self._addRedo(irc, channel, self._getUndo(channel)) # current topic.
|
||||
topics = self._getUndo(channel) # This is the topic list we want.
|
||||
if topics is not None:
|
||||
self._sendTopics(irc, channel, topics, isDo=True)
|
||||
@ -564,7 +568,7 @@ class Topic(callbacks.Plugin):
|
||||
itself.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
if first == second:
|
||||
irc.error(_('I refuse to swap the same topic with itself.'))
|
||||
return
|
||||
@ -598,7 +602,7 @@ class Topic(callbacks.Plugin):
|
||||
variable supybot.plugins.Topic.default.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topic = self.registryValue('default', channel)
|
||||
topic = self.registryValue('default', channel, irc.network)
|
||||
if topic:
|
||||
self._sendTopics(irc, channel, [topic])
|
||||
else:
|
||||
@ -613,7 +617,7 @@ class Topic(callbacks.Plugin):
|
||||
current topic appropriately.
|
||||
"""
|
||||
self._checkManageCapabilities(irc, msg, channel)
|
||||
topics = self._splitTopic(irc.state.getTopic(channel), channel)
|
||||
topics = self._splitTopic(irc, channel)
|
||||
self.setRegistryValue('separator', separator, channel)
|
||||
self._sendTopics(irc, channel, topics)
|
||||
separator = wrap(separator, ['canChangeTopic', 'something'])
|
||||
|
@ -73,19 +73,19 @@ class URL(callbacks.Plugin):
|
||||
def doPrivmsg(self, irc, msg):
|
||||
if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg):
|
||||
return
|
||||
channel = msg.args[0]
|
||||
if irc.isChannel(channel):
|
||||
if msg.channel:
|
||||
if ircmsgs.isAction(msg):
|
||||
text = ircmsgs.unAction(msg)
|
||||
else:
|
||||
text = msg.args[1]
|
||||
for url in utils.web.urlRe.findall(text):
|
||||
r = self.registryValue('nonSnarfingRegexp', channel)
|
||||
r = self.registryValue('nonSnarfingRegexp',
|
||||
msg.channel, irc.network)
|
||||
if r and r.search(url):
|
||||
self.log.debug('Skipping adding %u to db.', url)
|
||||
continue
|
||||
self.log.debug('Adding %u to db.', url)
|
||||
self.db.add(channel, url, msg)
|
||||
self.db.add(msg.channel, url, msg)
|
||||
|
||||
@internationalizeDocstring
|
||||
def stats(self, irc, msg, args, channel):
|
||||
|
@ -207,17 +207,18 @@ class Unix(callbacks.Plugin):
|
||||
|
||||
Returns a fortune from the *nix fortune program.
|
||||
"""
|
||||
channel = msg.args[0]
|
||||
channel = msg.channel
|
||||
network = irc.network
|
||||
fortuneCmd = self.registryValue('fortune.command')
|
||||
if fortuneCmd:
|
||||
args = [fortuneCmd]
|
||||
if self.registryValue('fortune.short', channel):
|
||||
if self.registryValue('fortune.short', channel, network):
|
||||
args.append('-s')
|
||||
if self.registryValue('fortune.equal', channel):
|
||||
if self.registryValue('fortune.equal', channel, network):
|
||||
args.append('-e')
|
||||
if self.registryValue('fortune.offensive', channel):
|
||||
if self.registryValue('fortune.offensive', channel, network):
|
||||
args.append('-a')
|
||||
args.extend(self.registryValue('fortune.files', channel))
|
||||
args.extend(self.registryValue('fortune.files', channel, network))
|
||||
try:
|
||||
with open(os.devnull) as null:
|
||||
inst = subprocess.Popen(args,
|
||||
|
@ -46,7 +46,7 @@ class User(callbacks.Plugin):
|
||||
authentication to the bot. This is a core Supybot plugin that should
|
||||
not be removed!"""
|
||||
def _checkNotChannel(self, irc, msg, password=' '):
|
||||
if password and irc.isChannel(msg.args[0]):
|
||||
if password and msg.channel:
|
||||
raise callbacks.Error(conf.supybot.replies.requiresPrivacy())
|
||||
|
||||
@internationalizeDocstring
|
||||
@ -88,7 +88,8 @@ class User(callbacks.Plugin):
|
||||
users.append(u.name)
|
||||
if users:
|
||||
utils.sortBy(str.lower, users)
|
||||
private = self.registryValue("listInPrivate", msg.args[0])
|
||||
private = self.registryValue("listInPrivate",
|
||||
msg.channel, irc.network)
|
||||
irc.reply(format('%L', users), private=private)
|
||||
else:
|
||||
if predicates:
|
||||
|
@ -144,7 +144,7 @@ class Web(callbacks.PluginRegexp):
|
||||
threaded = True
|
||||
|
||||
def noIgnore(self, irc, msg):
|
||||
return not self.registryValue('checkIgnored', msg.args[0])
|
||||
return not self.registryValue('checkIgnored', msg.channel, irc.network)
|
||||
|
||||
def getTitle(self, irc, url, raiseErrors):
|
||||
size = conf.supybot.protocols.http.peekSize()
|
||||
@ -184,16 +184,17 @@ class Web(callbacks.PluginRegexp):
|
||||
|
||||
@fetch_sandbox
|
||||
def titleSnarfer(self, irc, msg, match):
|
||||
channel = msg.args[0]
|
||||
if not irc.isChannel(channel):
|
||||
channel = msg.channel
|
||||
network = irc.network
|
||||
if not channel:
|
||||
return
|
||||
if callbacks.addressed(irc.nick, msg):
|
||||
return
|
||||
if self.registryValue('titleSnarfer', channel):
|
||||
if self.registryValue('titleSnarfer', channel, network):
|
||||
url = match.group(0)
|
||||
if not self._checkURLWhitelist(url):
|
||||
return
|
||||
r = self.registryValue('nonSnarfingRegexp', channel)
|
||||
r = self.registryValue('nonSnarfingRegexp', channel, network)
|
||||
if r and r.search(url):
|
||||
self.log.debug('Not titleSnarfing %q.', url)
|
||||
return
|
||||
@ -203,14 +204,15 @@ class Web(callbacks.PluginRegexp):
|
||||
(target, title) = r
|
||||
if title:
|
||||
domain = utils.web.getDomain(target
|
||||
if self.registryValue('snarferShowTargetDomain', channel)
|
||||
if self.registryValue('snarferShowTargetDomain',
|
||||
channel, network)
|
||||
else url)
|
||||
prefix = self.registryValue('snarferPrefix', channel)
|
||||
prefix = self.registryValue('snarferPrefix', channel, network)
|
||||
s = "%s %s" % (prefix, title)
|
||||
if self.registryValue('snarferShowDomain', channel):
|
||||
if self.registryValue('snarferShowDomain', channel, network):
|
||||
s += format(_(' (at %s)'), domain)
|
||||
irc.reply(s, prefixNick=False)
|
||||
if self.registryValue('snarfMultipleUrls', channel):
|
||||
if self.registryValue('snarfMultipleUrls', channel, network):
|
||||
# FIXME: hack
|
||||
msg.tag('repliedTo', False)
|
||||
titleSnarfer = urlSnarfer(titleSnarfer)
|
||||
|
@ -59,6 +59,9 @@ supybot.log.plugins.individualLogfiles: False
|
||||
supybot.protocols.irc.throttleTime: 0
|
||||
supybot.reply.whenAddressedBy.chars: @
|
||||
supybot.networks.test.server: should.not.need.this
|
||||
supybot.networks.testnet1.server: should.not.need.this
|
||||
supybot.networks.testnet2.server: should.not.need.this
|
||||
supybot.networks.testnet3.server: should.not.need.this
|
||||
supybot.nick: test
|
||||
supybot.databases.users.allowUnregistration: True
|
||||
""" % {'base_dir': os.getcwd()})
|
||||
|
136
src/callbacks.py
136
src/callbacks.py
@ -156,17 +156,25 @@ def canonicalName(command, preserve_spaces=False):
|
||||
command = command[:-1]
|
||||
return ''.join([x for x in command if x not in special]).lower() + reAppend
|
||||
|
||||
def reply(msg, s, prefixNick=None, private=None,
|
||||
notice=None, to=None, action=None, error=False,
|
||||
stripCtcp=True):
|
||||
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,
|
||||
stripCtcp=True):
|
||||
msg.tag('repliedTo')
|
||||
# Ok, let's make the target:
|
||||
# XXX This isn't entirely right. Consider to=#foo, private=True.
|
||||
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
|
||||
if ircutils.isChannel(target):
|
||||
channel = target
|
||||
if isPublic(target):
|
||||
channel = irc.stripChannelPrefix(target)
|
||||
else:
|
||||
channel = None
|
||||
if notice is None:
|
||||
@ -195,11 +203,11 @@ def reply(msg, s, prefixNick=None, private=None,
|
||||
s = ircutils.safeArgument(s)
|
||||
if not s and not action:
|
||||
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.".
|
||||
if not ircutils.isChannel(to):
|
||||
if not isPublic(to):
|
||||
s = '%s: %s' % (to, s)
|
||||
if not ircutils.isChannel(target):
|
||||
if not isPublic(target):
|
||||
if conf.supybot.reply.withNoticeWhenPrivate():
|
||||
notice = True
|
||||
# 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)
|
||||
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."""
|
||||
kwargs['error'] = True
|
||||
msg.tag('isError')
|
||||
return reply(msg, s, **kwargs)
|
||||
return _makeReply(irc, msg, s, **kwargs)
|
||||
|
||||
def getHelp(method, name=None, doc=None):
|
||||
if name is None:
|
||||
@ -363,16 +376,16 @@ class Tokenizer(object):
|
||||
args[-1].append(ends.pop())
|
||||
return args
|
||||
|
||||
def tokenize(s, channel=None):
|
||||
def tokenize(s, channel=None, network=None):
|
||||
"""A utility function to create a Tokenizer and tokenize a string."""
|
||||
pipe = False
|
||||
brackets = ''
|
||||
nested = conf.supybot.commands.nested
|
||||
if nested():
|
||||
brackets = conf.get(nested.brackets, channel)
|
||||
brackets = nested.brackets.getSpecific(network, channel)()
|
||||
if conf.get(nested.pipeSyntax, channel): # No nesting, no pipe.
|
||||
pipe = True
|
||||
quotes = conf.get(conf.supybot.commands.quotes, channel)
|
||||
quotes = conf.supybot.commands.quotes.getSpecific(network, channel)()
|
||||
try:
|
||||
ret = Tokenizer(brackets=brackets,pipe=pipe,quotes=quotes).tokenize(s)
|
||||
return ret
|
||||
@ -400,8 +413,8 @@ def checkCommandCapability(msg, cb, commandName):
|
||||
checkCapability(antiCommand)
|
||||
checkAtEnd = [commandName]
|
||||
default = conf.supybot.capabilities.default()
|
||||
if ircutils.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
if msg.channel:
|
||||
channel = msg.channel
|
||||
checkCapability(ircdb.makeChannelCapability(channel, antiCommand))
|
||||
chanCommand = ircdb.makeChannelCapability(channel, commandName)
|
||||
checkAtEnd += [chanCommand]
|
||||
@ -426,7 +439,7 @@ class RichReplyMethods(object):
|
||||
return ircutils.standardSubstitute(self, self.msg, s)
|
||||
|
||||
def _getConfig(self, wrapper):
|
||||
return conf.get(wrapper, self.msg.args[0])
|
||||
return conf.get(wrapper, self.msg.channel)
|
||||
|
||||
def replySuccess(self, s='', **kwargs):
|
||||
v = self._getConfig(conf.supybot.replies.success)
|
||||
@ -572,6 +585,7 @@ class ReplyIrcProxy(RichReplyMethods):
|
||||
def __init__(self, irc, msg):
|
||||
self.irc = irc
|
||||
self.msg = msg
|
||||
self.getRealIrc()._setMsgChannel(self.msg)
|
||||
|
||||
def getRealIrc(self):
|
||||
"""Returns the real irclib.Irc object underlying this proxy chain."""
|
||||
@ -599,7 +613,7 @@ class ReplyIrcProxy(RichReplyMethods):
|
||||
raise ArgumentError
|
||||
if msg is None:
|
||||
msg = self.msg
|
||||
m = error(msg, s, **kwargs)
|
||||
m = _makeErrorReply(self, msg, s, **kwargs)
|
||||
self.irc.queueMsg(m)
|
||||
return m
|
||||
|
||||
@ -609,7 +623,7 @@ class ReplyIrcProxy(RichReplyMethods):
|
||||
assert not isinstance(s, ircmsgs.IrcMsg), \
|
||||
'Old code alert: there is no longer a "msg" argument to reply.'
|
||||
kwargs.pop('noLengthCheck', None)
|
||||
m = reply(msg, s, **kwargs)
|
||||
m = _makeReply(self, msg, s, **kwargs)
|
||||
self.irc.queueMsg(m)
|
||||
return m
|
||||
|
||||
@ -623,8 +637,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
_mores = ircutils.IrcDict()
|
||||
def __init__(self, irc, msg, args, nested=0):
|
||||
assert isinstance(args, list), 'Args should be a list, not a string.'
|
||||
self.irc = irc
|
||||
self.msg = msg
|
||||
super(NestedCommandsIrcProxy, self).__init__(irc, msg)
|
||||
self.nested = nested
|
||||
self.repliedTo = False
|
||||
if not self.nested and isinstance(irc, self.__class__):
|
||||
@ -665,9 +678,9 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
self.notice = None
|
||||
self.private = 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.msg.args[0])
|
||||
self.msg.channel)
|
||||
else:
|
||||
self.prefixNick = conf.supybot.reply.withNickPrefix()
|
||||
|
||||
@ -894,12 +907,12 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
elif self.noLengthCheck:
|
||||
# noLengthCheck only matters to NestedCommandsIrcProxy, so
|
||||
# it's not used here. Just in case you were wondering.
|
||||
m = reply(msg, s, to=self.to,
|
||||
notice=self.notice,
|
||||
action=self.action,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
m = _makeReply(self, msg, s, to=self.to,
|
||||
notice=self.notice,
|
||||
action=self.action,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
sendMsg(m)
|
||||
return m
|
||||
else:
|
||||
@ -930,11 +943,11 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
# action implies noLengthCheck, which has already been
|
||||
# handled. Let's stick an assert in here just in case.
|
||||
assert not self.action
|
||||
m = reply(msg, s, to=self.to,
|
||||
notice=self.notice,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
m = _makeReply(self, msg, s, to=self.to,
|
||||
notice=self.notice,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
sendMsg(m)
|
||||
return m
|
||||
# The '(XX more messages)' may have not the same
|
||||
@ -946,11 +959,11 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
while instant > 1 and msgs:
|
||||
instant -= 1
|
||||
response = msgs.pop()
|
||||
m = reply(msg, response, to=self.to,
|
||||
notice=self.notice,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
m = _makeReply(self, msg, response, to=self.to,
|
||||
notice=self.notice,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
sendMsg(m)
|
||||
# XXX We should somehow allow these to be returned, but
|
||||
# until someone complains, we'll be fine :) We
|
||||
@ -976,15 +989,15 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
pass # We'll leave it as it is.
|
||||
mask = prefix.split('!', 1)[1]
|
||||
self._mores[mask] = msgs
|
||||
public = self.irc.isChannel(msg.args[0])
|
||||
public = bool(self.msg.channel)
|
||||
private = self.private or not public
|
||||
self._mores[msg.nick] = (private, msgs)
|
||||
m = reply(msg, response, to=self.to,
|
||||
action=self.action,
|
||||
notice=self.notice,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
m = _makeReply(self, msg, response, to=self.to,
|
||||
action=self.action,
|
||||
notice=self.notice,
|
||||
private=self.private,
|
||||
prefixNick=self.prefixNick,
|
||||
stripCtcp=stripCtcp)
|
||||
sendMsg(m)
|
||||
return m
|
||||
finally:
|
||||
@ -1035,7 +1048,7 @@ class NestedCommandsIrcProxy(ReplyIrcProxy):
|
||||
if not isinstance(self.irc, irclib.Irc):
|
||||
return self.irc.error(s, **kwargs)
|
||||
else:
|
||||
m = error(self.msg, s, **kwargs)
|
||||
m = _makeErrorReply(self, self.msg, s, **kwargs)
|
||||
self.irc.queueMsg(m)
|
||||
return m
|
||||
else:
|
||||
@ -1346,7 +1359,7 @@ class Commands(BasePlugin, SynchronizedAndFirewalled):
|
||||
help = getHelp
|
||||
chan = None
|
||||
if dynamic.msg is not None:
|
||||
chan = dynamic.msg.args[0]
|
||||
chan = dynamic.msg.channel
|
||||
if simpleSyntax is None:
|
||||
simpleSyntax = conf.get(conf.supybot.reply.showSimpleSyntax, chan)
|
||||
if simpleSyntax:
|
||||
@ -1385,39 +1398,40 @@ class PluginMixin(BasePlugin, irclib.IrcCallback):
|
||||
else:
|
||||
noIgnore = self.noIgnore
|
||||
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.
|
||||
self.__parent.__call__(irc, msg)
|
||||
else:
|
||||
self.__parent.__call__(irc, msg)
|
||||
|
||||
def registryValue(self, name, channel=None, value=True):
|
||||
def registryValue(self, name, channel=None, network=None, value=True):
|
||||
if isinstance(network, bool):
|
||||
# Network-unaware plugin that uses 'value' as a positional
|
||||
# argument.
|
||||
(network, value) = (value, network)
|
||||
plugin = self.name()
|
||||
group = conf.supybot.plugins.get(plugin)
|
||||
names = registry.split(name)
|
||||
for name in names:
|
||||
group = group.get(name)
|
||||
if channel is not None:
|
||||
if ircutils.isChannel(channel):
|
||||
group = group.get(channel)
|
||||
else:
|
||||
self.log.debug('%s: registryValue got channel=%r', plugin,
|
||||
channel)
|
||||
if channel or network:
|
||||
group = group.getSpecific(network=network, channel=channel)
|
||||
if value:
|
||||
return group()
|
||||
else:
|
||||
return group
|
||||
|
||||
def setRegistryValue(self, name, value, channel=None):
|
||||
def setRegistryValue(self, name, value, channel=None, network=None):
|
||||
plugin = self.name()
|
||||
group = conf.supybot.plugins.get(plugin)
|
||||
names = registry.split(name)
|
||||
for name in names:
|
||||
group = group.get(name)
|
||||
if channel is None:
|
||||
group.setValue(value)
|
||||
else:
|
||||
group.get(channel).setValue(value)
|
||||
if network:
|
||||
group = group.get(':' + network)
|
||||
if channel:
|
||||
group = group.get(channel)
|
||||
group.setValue(value)
|
||||
|
||||
def userValue(self, name, prefixOrName, default=None):
|
||||
try:
|
||||
|
@ -205,9 +205,12 @@ def urlSnarfer(f):
|
||||
"""Protects the snarfer from loops (with other bots) and whatnot."""
|
||||
def newf(self, irc, msg, match, *L, **kwargs):
|
||||
url = match.group(0)
|
||||
channel = msg.args[0]
|
||||
if not irc.isChannel(channel) or (ircmsgs.isCtcp(msg) and not
|
||||
ircmsgs.isAction(msg)):
|
||||
channel = msg.channel
|
||||
if not channel:
|
||||
# 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
|
||||
if ircdb.channels.getChannel(channel).lobotomized:
|
||||
self.log.debug('Not snarfing in %s: lobotomized.', channel)
|
||||
@ -491,10 +494,11 @@ def getChannel(irc, msg, args, state):
|
||||
return
|
||||
if args and irc.isChannel(args[0]):
|
||||
channel = args.pop(0)
|
||||
elif irc.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
elif msg.channel:
|
||||
channel = msg.channel
|
||||
else:
|
||||
state.log.debug('Raising ArgumentError because there is no channel.')
|
||||
print(msg.channel, msg)
|
||||
raise callbacks.ArgumentError
|
||||
state.channel = channel
|
||||
state.args.append(channel)
|
||||
@ -502,8 +506,8 @@ def getChannel(irc, msg, args, state):
|
||||
def getChannels(irc, msg, args, state):
|
||||
if args and all(map(irc.isChannel, args[0].split(','))):
|
||||
channels = args.pop(0).split(',')
|
||||
elif irc.isChannel(msg.args[0]):
|
||||
channels = [msg.args[0]]
|
||||
elif msg.channel:
|
||||
channels = [msg.channel]
|
||||
else:
|
||||
state.log.debug('Raising ArgumentError because there is no channel.')
|
||||
raise callbacks.ArgumentError
|
||||
@ -535,11 +539,11 @@ def inChannel(irc, msg, args, state):
|
||||
state.error(_('I\'m not in %s.') % state.channel, Raise=True)
|
||||
|
||||
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 '
|
||||
'in.'), Raise=True)
|
||||
else:
|
||||
state.channel = msg.args[0]
|
||||
state.channel = msg.channel
|
||||
state.args.append(state.channel)
|
||||
|
||||
def callerInGivenChannel(irc, msg, args, state):
|
||||
@ -576,8 +580,8 @@ def getChannelOrGlobal(irc, msg, args, state):
|
||||
elif args and irc.isChannel(args[0]):
|
||||
channel = args.pop(0)
|
||||
state.channel = channel
|
||||
elif irc.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
elif msg.channel:
|
||||
channel = msg.channel
|
||||
state.channel = channel
|
||||
else:
|
||||
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)
|
||||
|
||||
def private(irc, msg, args, state):
|
||||
if irc.isChannel(msg.args[0]):
|
||||
if msg.channel:
|
||||
state.errorRequiresPrivacy(Raise=True)
|
||||
|
||||
def public(irc, msg, args, state, errmsg=None):
|
||||
if not irc.isChannel(msg.args[0]):
|
||||
if not msg.channel:
|
||||
if errmsg is None:
|
||||
errmsg = _('This message must be sent in a channel.')
|
||||
state.error(errmsg, Raise=True)
|
||||
|
41
src/conf.py
41
src/conf.py
@ -83,13 +83,14 @@ def registerGroup(Group, name, group=None, **kwargs):
|
||||
return Group.register(name, group)
|
||||
|
||||
def registerGlobalValue(group, name, value):
|
||||
value.channelValue = False
|
||||
value._networkValue = False
|
||||
value._channelValue = False
|
||||
return group.register(name, value)
|
||||
|
||||
def registerChannelValue(group, name, value, opSettable=True):
|
||||
def registerNetworkValue(group, name, value):
|
||||
value._supplyDefault = True
|
||||
value.channelValue = True
|
||||
value._opSettable = opSettable
|
||||
value._networkValue = True
|
||||
value._channelValue = False
|
||||
g = group.register(name, value)
|
||||
gname = g._name.lower()
|
||||
for name in registry._cache.keys():
|
||||
@ -97,8 +98,30 @@ def registerChannelValue(group, name, value, opSettable=True):
|
||||
name = name[len(gname)+1:] # +1 for .
|
||||
parts = registry.split(name)
|
||||
if len(parts) == 1 and parts[0] and ircutils.isChannel(parts[0]):
|
||||
# This gets the channel values so they always persist.
|
||||
# This gets the network values so they always persist.
|
||||
g.get(parts[0])()
|
||||
return g
|
||||
|
||||
def registerChannelValue(group, name, value, opSettable=True):
|
||||
value._supplyDefault = True
|
||||
value._networkValue = True
|
||||
value._channelValue = True
|
||||
value._opSettable = opSettable
|
||||
g = group.register(name, value)
|
||||
gname = g._name.lower()
|
||||
for name in registry._cache.keys():
|
||||
if name.lower().startswith(gname) and len(gname) < len(name):
|
||||
name = name[len(gname)+1:] # +1 for .
|
||||
parts = registry.split(name)
|
||||
if len(parts) == 2 and parts[0] and parts[0].startswith(':') \
|
||||
and parts[1] and ircutils.isChannel(parts[1]):
|
||||
# This gets the network+channel values so they always persist.
|
||||
g.get(parts[0])()
|
||||
g.get(parts[0]).get(parts[1])()
|
||||
elif len(parts) == 1 and parts[0] and ircutils.isChannel(parts[0]):
|
||||
# Old-style variant of the above, without a network
|
||||
g.get(parts[0])()
|
||||
return g
|
||||
|
||||
def registerPlugin(name, currentValue=None, public=True):
|
||||
group = registerGlobalValue(supybot.plugins, name,
|
||||
@ -1128,7 +1151,7 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
|
||||
self.error()
|
||||
self.__parent.setValue(self.List(v))
|
||||
|
||||
def makeBanmask(self, hostmask, options=None, channel=None):
|
||||
def makeBanmask(self, hostmask, options=None, channel=None, network=None):
|
||||
"""Create a banmask from the given hostmask. If a style of banmask
|
||||
isn't specified via options, the value of
|
||||
conf.supybot.protocols.irc.banmask is used.
|
||||
@ -1138,13 +1161,15 @@ class Banmask(registry.SpaceSeparatedSetOfStrings):
|
||||
only the exact hostmask will be used."""
|
||||
if not channel:
|
||||
channel = dynamic.channel
|
||||
assert channel is None or ircutils.isChannel(channel)
|
||||
if not network:
|
||||
network = dynamic.irc.network
|
||||
(nick, user, host) = ircutils.splitHostmask(hostmask)
|
||||
bnick = '*'
|
||||
buser = '*'
|
||||
bhost = '*'
|
||||
if not options:
|
||||
options = get(supybot.protocols.irc.banmask, channel)
|
||||
options = supybot.protocols.irc.banmask.getSpecific(
|
||||
channel, network)()
|
||||
for option in options:
|
||||
if option == 'nick':
|
||||
bnick = nick
|
||||
|
@ -843,6 +843,7 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
|
||||
self.queueMsg(ircmsgs.ping(now))
|
||||
if msg:
|
||||
for callback in reversed(self.callbacks):
|
||||
self._setMsgChannel(msg)
|
||||
msg = callback.outFilter(self, msg)
|
||||
if msg is None:
|
||||
log.debug('%s.outFilter returned None.', callback.name())
|
||||
@ -875,16 +876,36 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
|
||||
else:
|
||||
return None
|
||||
|
||||
_numericErrorCommandRe = re.compile(r'^[45][0-9][0-9]$')
|
||||
def feedMsg(self, msg):
|
||||
"""Called by the IrcDriver; feeds a message received."""
|
||||
def _tagMsg(self, msg):
|
||||
"""Sets attribute on an incoming IRC message. Will usually only be
|
||||
called by feedMsg, but may be useful in tests as well."""
|
||||
msg.tag('receivedBy', self)
|
||||
msg.tag('receivedOn', self.network)
|
||||
msg.tag('receivedAt', time.time())
|
||||
if msg.args and self.isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
|
||||
self._setMsgChannel(msg)
|
||||
|
||||
def _setMsgChannel(self, msg):
|
||||
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:
|
||||
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')
|
||||
log.debug('Incoming message (%s): %s', self.network, preInFilter)
|
||||
|
||||
|
@ -121,7 +121,7 @@ class IrcMsg(object):
|
||||
# On second thought, let's use methods for tagging.
|
||||
__slots__ = ('args', 'command', 'host', 'nick', 'prefix', 'user',
|
||||
'_hash', '_str', '_repr', '_len', 'tags', 'reply_env',
|
||||
'server_tags', 'time')
|
||||
'server_tags', 'time', 'channel')
|
||||
def __init__(self, s='', command='', args=(), prefix='', msg=None,
|
||||
reply_env=None):
|
||||
assert not (msg and s), 'IrcMsg.__init__ cannot accept both s and msg'
|
||||
|
@ -659,7 +659,10 @@ def safeArgument(s):
|
||||
|
||||
def replyTo(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]
|
||||
else:
|
||||
return msg.nick
|
||||
@ -867,10 +870,7 @@ def standardSubstitute(irc, msg, text, env=None):
|
||||
vars.update(msg.reply_env)
|
||||
|
||||
if irc and msg:
|
||||
if isChannel(msg.args[0]):
|
||||
channel = msg.args[0]
|
||||
else:
|
||||
channel = 'somewhere'
|
||||
channel = msg.channel or 'somewhere'
|
||||
def randNick():
|
||||
if channel != 'somewhere':
|
||||
L = list(irc.state.channels[channel].users)
|
||||
|
100
src/registry.py
100
src/registry.py
@ -212,7 +212,7 @@ class Group(object):
|
||||
s = '%r is not a valid entry in %r' % (attr, self._name)
|
||||
raise NonExistentRegistryEntry(s)
|
||||
|
||||
def __makeChild(self, attr, s):
|
||||
def _makeChild(self, attr, s):
|
||||
v = self.__class__(self._default, self._help)
|
||||
v.set(s)
|
||||
v._wasSet = False
|
||||
@ -225,10 +225,13 @@ class Group(object):
|
||||
return attr in self._children
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr in self._children:
|
||||
if attr.startswith('_'):
|
||||
raise AttributeError('%s has no attribute %s' %
|
||||
(self.__class__.__name__, attr))
|
||||
elif attr in self._children:
|
||||
return self._children[attr]
|
||||
elif self._supplyDefault:
|
||||
return self.__makeChild(attr, str(self))
|
||||
return self._makeChild(attr, str(self))
|
||||
else:
|
||||
self.__nonExistentEntry(attr)
|
||||
|
||||
@ -253,7 +256,7 @@ class Group(object):
|
||||
parts = split(rest)
|
||||
if len(parts) == 1 and parts[0] == name:
|
||||
try:
|
||||
self.__makeChild(name, v)
|
||||
self._makeChild(name, v)
|
||||
except InvalidRegistryValue:
|
||||
# It's probably supposed to be registered later.
|
||||
pass
|
||||
@ -328,7 +331,7 @@ class Value(Group):
|
||||
"""Invalid registry value. If you're getting this message, report it,
|
||||
because we forgot to put a proper help string here."""
|
||||
__slots__ = ('__parent', '_default', '_showDefault', '_help', '_callbacks',
|
||||
'value', 'channelValue', '_opSettable')
|
||||
'value', '_networkValue', '_channelValue', '_opSettable')
|
||||
def __init__(self, default, help, setDefault=True,
|
||||
showDefault=True, **kwargs):
|
||||
self.__parent = super(Value, self)
|
||||
@ -337,9 +340,29 @@ class Value(Group):
|
||||
self._showDefault = showDefault
|
||||
self._help = utils.str.normalizeWhitespace(help.strip())
|
||||
self._callbacks = []
|
||||
self._networkValue = False
|
||||
self._channelValue = False
|
||||
if setDefault:
|
||||
self.setValue(default)
|
||||
|
||||
def _makeChild(self, attr, s):
|
||||
v = self.__class__(self._default, self._help)
|
||||
v.set(s)
|
||||
v._wasSet = False
|
||||
if self._networkValue and self._channelValue:
|
||||
# If this is both a network-specific and channel-specific value,
|
||||
# then the child is (only) channel-specific.
|
||||
v._networkValue = False
|
||||
v._channelValue = True
|
||||
v._supplyDefault = True
|
||||
else:
|
||||
# Otherwise, the child is neither network-specific or
|
||||
# channel-specific.
|
||||
v._supplyDefault = False
|
||||
v._help = '' # Clear this so it doesn't print a bazillion times.
|
||||
self.register(attr, v)
|
||||
return v
|
||||
|
||||
def error(self, value=_NoValueGiven):
|
||||
if hasattr(self, 'errormsg') and value is not _NoValueGiven:
|
||||
try:
|
||||
@ -356,6 +379,58 @@ class Value(Group):
|
||||
e.value = self
|
||||
raise e
|
||||
|
||||
def getSpecific(self, network=None, channel=None, check=True):
|
||||
"""Gets the network-specific and/or channel-specific value of this
|
||||
Value.
|
||||
If `check=True` (the default), this will raise an error if `network`
|
||||
(resp. `channel`) is provided but this Value is not network-specific
|
||||
(resp. channel-specific). If `check=False`, then `network` and/or
|
||||
`channel` may be silently ignored.
|
||||
"""
|
||||
if network and not self._networkValue:
|
||||
if check:
|
||||
raise NonExistentRegistryEntry('%s is not network-specific' %
|
||||
self._name)
|
||||
else:
|
||||
network = None
|
||||
if channel and not self._channelValue:
|
||||
if check:
|
||||
raise NonExistentRegistryEntry('%s is not channel-specific' %
|
||||
self._name)
|
||||
else:
|
||||
channel = None
|
||||
if network and channel:
|
||||
# The complicated case. We want a net+chan specific value,
|
||||
# which may come in three different ways:
|
||||
#
|
||||
# 1. it was set explicitely net+chan
|
||||
# 2. it's inherited from a net specific value (which may itself be
|
||||
# inherited from the base value)
|
||||
# 3. it's inherited from the chan specific value (which is not a
|
||||
# actually a parent in the registry tree, but we need this to
|
||||
# load configuration from old bots).
|
||||
#
|
||||
# The choice between 2 and 3 is done by checking which of the
|
||||
# net-specific and chan-specific values was set explicitely by
|
||||
# a user/admin. In case both were, the net-specific value is used
|
||||
# (there is no particular reason for this, I just think it makes
|
||||
# more sense).
|
||||
network_value = self.get(':' + network)
|
||||
network_channel_value = network_value.get(channel)
|
||||
channel_value = self.get(channel)
|
||||
if network_value._wasSet or network_channel_value._wasSet:
|
||||
# cases 1 and 2
|
||||
return network_channel_value
|
||||
else:
|
||||
# case 3
|
||||
return channel_value
|
||||
elif network:
|
||||
return self.get(':' + network)
|
||||
elif channel:
|
||||
return self.get(channel)
|
||||
else:
|
||||
return self
|
||||
|
||||
def setName(self, *args):
|
||||
if self._name == 'unset':
|
||||
self._lastModified = 0
|
||||
@ -374,16 +449,23 @@ class Value(Group):
|
||||
100) convert to an integer in set() and check that the integer is less
|
||||
than 100 in this method. You *must* call this parent method in your
|
||||
own setValue."""
|
||||
self._setValue(v, inherited=False)
|
||||
|
||||
def _setValue(self, v, inherited):
|
||||
"""Like setValue, but accepted an extra 'inherited' argument.
|
||||
inherited=True means the value is inherited from the parent, so if
|
||||
the parent gets a new value, this group will get the new value as
|
||||
well."""
|
||||
self._lastModified = time.time()
|
||||
self.value = v
|
||||
if self._supplyDefault:
|
||||
for (name, v) in list(self._children.items()):
|
||||
if not v._wasSet:
|
||||
self.unregister(name)
|
||||
for (name, child) in list(self._children.items()):
|
||||
if not child._wasSet:
|
||||
child._setValue(v, inherited=True)
|
||||
# We call the callback once everything is clean
|
||||
for callback, args, kwargs in self._callbacks:
|
||||
callback(*args, **kwargs)
|
||||
self._wasSet = True
|
||||
self._wasSet = not inherited
|
||||
|
||||
def context(self, value):
|
||||
"""Return a context manager object, which sets this variable to a
|
||||
|
@ -96,8 +96,8 @@ def retry(tries=3):
|
||||
return newf
|
||||
return decorator
|
||||
|
||||
def getTestIrc():
|
||||
irc = irclib.Irc('test')
|
||||
def getTestIrc(name='test'):
|
||||
irc = irclib.Irc(name)
|
||||
# Gotta clear the connect messages (USER, NICK, etc.)
|
||||
while irc.takeMsg():
|
||||
pass
|
||||
|
@ -175,6 +175,7 @@ class FunctionsTestCase(SupyTestCase):
|
||||
self.assertEqual('foobar--', callbacks.canonicalName('foobar--'))
|
||||
|
||||
def testAddressed(self):
|
||||
irc = getTestIrc()
|
||||
oldprefixchars = str(conf.supybot.reply.whenAddressedBy.chars)
|
||||
nick = 'supybot'
|
||||
conf.supybot.reply.whenAddressedBy.chars.set('~!@')
|
||||
@ -189,6 +190,7 @@ class FunctionsTestCase(SupyTestCase):
|
||||
for msg in inChannel:
|
||||
self.assertEqual('foo', callbacks.addressed(nick, msg), msg)
|
||||
msg = ircmsgs.privmsg(nick, 'foo')
|
||||
irc._tagMsg(msg)
|
||||
self.assertEqual('foo', callbacks.addressed(nick, msg))
|
||||
conf.supybot.reply.whenAddressedBy.chars.set(oldprefixchars)
|
||||
msg = ircmsgs.privmsg('#foo', '%s::::: bar' % nick)
|
||||
@ -216,52 +218,84 @@ class FunctionsTestCase(SupyTestCase):
|
||||
conf.supybot.reply.whenNotAddressed.setValue(original)
|
||||
|
||||
def testAddressedWithMultipleNicks(self):
|
||||
irc = getTestIrc()
|
||||
msg = ircmsgs.privmsg('#foo', 'bar: baz')
|
||||
irc._tagMsg(msg)
|
||||
self.assertEqual(callbacks.addressed('bar', msg), 'baz')
|
||||
# need to recreate the msg objects since the old ones have already
|
||||
# been tagged
|
||||
msg = ircmsgs.privmsg('#foo', 'bar: baz')
|
||||
irc._tagMsg(msg)
|
||||
self.assertEqual(callbacks.addressed('biff', msg, nicks=['bar']),
|
||||
'baz')
|
||||
|
||||
def testAddressedWithNickAtEnd(self):
|
||||
irc = getTestIrc()
|
||||
msg = ircmsgs.privmsg('#foo', 'baz, bar')
|
||||
irc._tagMsg(msg)
|
||||
self.assertEqual(callbacks.addressed('bar', msg,
|
||||
whenAddressedByNickAtEnd=True),
|
||||
'baz')
|
||||
|
||||
def testAddressedPrefixCharsTakePrecedenceOverNickAtEnd(self):
|
||||
irc = getTestIrc()
|
||||
msg = ircmsgs.privmsg('#foo', '@echo foo')
|
||||
irc._tagMsg(msg)
|
||||
self.assertEqual(callbacks.addressed('foo', msg,
|
||||
whenAddressedByNickAtEnd=True,
|
||||
prefixChars='@'),
|
||||
'echo foo')
|
||||
|
||||
|
||||
def testReply(self):
|
||||
irc = getTestIrc()
|
||||
prefix = 'foo!bar@baz'
|
||||
channelMsg = ircmsgs.privmsg('#foo', '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'),
|
||||
callbacks.reply(channelMsg, 'foo', private=True))
|
||||
callbacks._makeReply(irc, channelMsg, 'foo',
|
||||
private=True))
|
||||
self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'),
|
||||
callbacks.reply(nonChannelMsg, 'foo'))
|
||||
callbacks._makeReply(irc, nonChannelMsg, 'foo'))
|
||||
self.assertEqual(ircmsgs.privmsg(channelMsg.args[0],
|
||||
'%s: foo' % channelMsg.nick),
|
||||
callbacks.reply(channelMsg, 'foo'))
|
||||
callbacks._makeReply(irc, channelMsg, 'foo'))
|
||||
self.assertEqual(ircmsgs.privmsg(channelMsg.args[0],
|
||||
'foo'),
|
||||
callbacks.reply(channelMsg, 'foo', prefixNick=False))
|
||||
callbacks._makeReply(irc, channelMsg, 'foo',
|
||||
prefixNick=False))
|
||||
self.assertEqual(ircmsgs.notice(nonChannelMsg.nick, 'foo'),
|
||||
callbacks.reply(channelMsg, 'foo',
|
||||
notice=True, private=True))
|
||||
callbacks._makeReply(irc, channelMsg, 'foo',
|
||||
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):
|
||||
irc = getTestIrc()
|
||||
prefix = 'foo!bar@baz'
|
||||
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'))
|
||||
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'))
|
||||
|
||||
def testTokenize(self):
|
||||
@ -682,7 +716,9 @@ class WithPrivateNoticeTestCase(ChannelPluginTestCase):
|
||||
|
||||
class ProxyTestCase(SupyTestCase):
|
||||
def testHashing(self):
|
||||
irc = getTestIrc()
|
||||
msg = ircmsgs.ping('0')
|
||||
irc._tagMsg(msg)
|
||||
irc = irclib.Irc('test')
|
||||
proxy = callbacks.SimpleProxy(irc, msg)
|
||||
# First one way...
|
||||
|
@ -47,6 +47,7 @@ class CommandsTestCase(SupyTestCase):
|
||||
realIrc = getTestIrc()
|
||||
realIrc.nick = 'test'
|
||||
realIrc.state.supported['chantypes'] = '#'
|
||||
realIrc._tagMsg(msg)
|
||||
irc = callbacks.SimpleProxy(realIrc, msg)
|
||||
myspec = Spec(spec, **kwargs)
|
||||
state = myspec(irc, msg, given)
|
||||
|
@ -470,6 +470,42 @@ class IrcTestCase(SupyTestCase):
|
||||
self.irc.feedMsg(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):
|
||||
self.irc.reset()
|
||||
self.irc.feedMsg(ircmsgs.IrcMsg(':someuser JOIN #foo'))
|
||||
|
@ -281,12 +281,10 @@ class FunctionsTestCase(SupyTestCase):
|
||||
def testStandardSubstitute(self):
|
||||
# Stub out random msg and irc objects that provide what
|
||||
# standardSubstitute wants
|
||||
msg = ircmsgs.IrcMsg(':%s PRIVMSG #channel :stuff' % self.hostmask)
|
||||
class Irc(object):
|
||||
nick = 'bob'
|
||||
network = 'testnet'
|
||||
irc = getTestIrc()
|
||||
|
||||
irc = Irc()
|
||||
msg = ircmsgs.IrcMsg(':%s PRIVMSG #channel :stuff' % self.hostmask)
|
||||
irc._tagMsg(msg)
|
||||
|
||||
f = ircutils.standardSubstitute
|
||||
vars = {'foo': 'bar', 'b': 'c', 'i': 100,
|
||||
@ -344,9 +342,12 @@ class FunctionsTestCase(SupyTestCase):
|
||||
self.assertEqual('{}|^', ircutils.toLower('[]\\~'))
|
||||
|
||||
def testReplyTo(self):
|
||||
irc = getTestIrc()
|
||||
prefix = 'foo!bar@baz'
|
||||
channel = ircmsgs.privmsg('#foo', '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(private), private.nick)
|
||||
|
||||
|
@ -185,9 +185,17 @@ class ValuesTestCase(SupyTestCase):
|
||||
self.assertRaises(registry.InvalidRegistryValue,
|
||||
v.setValue, re.compile(r'foo'))
|
||||
|
||||
def testBackslashes(self):
|
||||
def testBackslashesKeys(self):
|
||||
conf.supybot.reply.whenAddressedBy.strings.get(':foo').set('=/*')
|
||||
filename = conf.supybot.directories.conf.dirize('backslashes1.conf')
|
||||
registry.close(conf.supybot, filename)
|
||||
registry.open_registry(filename)
|
||||
value = conf.supybot.reply.whenAddressedBy.strings.get(':foo')()
|
||||
self.assertEqual(value, set(['=/*']))
|
||||
|
||||
def testBackslashesValues(self):
|
||||
conf.supybot.reply.whenAddressedBy.chars.set('\\')
|
||||
filename = conf.supybot.directories.conf.dirize('backslashes.conf')
|
||||
filename = conf.supybot.directories.conf.dirize('backslashes2.conf')
|
||||
registry.close(conf.supybot, filename)
|
||||
registry.open_registry(filename)
|
||||
self.assertEqual(conf.supybot.reply.whenAddressedBy.chars(), '\\')
|
||||
@ -224,4 +232,34 @@ class SecurityTestCase(SupyTestCase):
|
||||
self.assertFalse(g._private)
|
||||
self.assertTrue(g.val._private)
|
||||
|
||||
|
||||
class InheritanceTestCase(SupyTestCase):
|
||||
def testChild(self):
|
||||
parent = registry.String('foo', 'help')
|
||||
parent._supplyDefault = True
|
||||
self.assertTrue(parent._wasSet)
|
||||
self.assertEqual(parent(), 'foo')
|
||||
|
||||
child = parent.get('child')
|
||||
self.assertFalse(child._wasSet)
|
||||
self.assertEqual(child(), 'foo')
|
||||
|
||||
parent.setValue('bar')
|
||||
self.assertTrue(parent._wasSet)
|
||||
self.assertEqual(parent(), 'bar')
|
||||
self.assertFalse(child._wasSet)
|
||||
self.assertEqual(child(), 'bar') # Takes the new parent value
|
||||
|
||||
child.setValue('baz')
|
||||
self.assertTrue(parent._wasSet)
|
||||
self.assertEqual(parent(), 'bar')
|
||||
self.assertTrue(child._wasSet)
|
||||
self.assertEqual(child(), 'baz')
|
||||
|
||||
parent.setValue('qux')
|
||||
self.assertTrue(parent._wasSet)
|
||||
self.assertEqual(parent(), 'qux')
|
||||
self.assertTrue(child._wasSet)
|
||||
self.assertEqual(child(), 'baz') # Keeps its own value
|
||||
|
||||
# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79:
|
||||
|
@ -37,54 +37,53 @@ class holder:
|
||||
users = set(map(str, range(1000)))
|
||||
|
||||
class FunctionsTestCase(SupyTestCase):
|
||||
class irc:
|
||||
class state:
|
||||
channels = {'#foo': holder()}
|
||||
nick = 'foobar'
|
||||
network = 'testnet'
|
||||
|
||||
@retry()
|
||||
def testStandardSubstitute(self):
|
||||
irc = getTestIrc()
|
||||
irc.state.channels = {'#foo': holder()}
|
||||
|
||||
f = ircutils.standardSubstitute
|
||||
msg = ircmsgs.privmsg('#foo', 'filler', prefix='biff!quux@xyzzy')
|
||||
s = f(self.irc, msg, '$rand')
|
||||
irc._tagMsg(msg)
|
||||
s = f(irc, msg, '$rand')
|
||||
try:
|
||||
int(s)
|
||||
except ValueError:
|
||||
self.fail('$rand wasn\'t an int.')
|
||||
s = f(self.irc, msg, '$randomInt')
|
||||
s = f(irc, msg, '$randomInt')
|
||||
try:
|
||||
int(s)
|
||||
except ValueError:
|
||||
self.fail('$randomint wasn\'t an int.')
|
||||
self.assertEqual(f(self.irc, msg, '$botnick'), self.irc.nick)
|
||||
self.assertEqual(f(self.irc, msg, '$who'), msg.nick)
|
||||
self.assertEqual(f(self.irc, msg, '$WHO'),
|
||||
self.assertEqual(f(irc, msg, '$botnick'), irc.nick)
|
||||
self.assertEqual(f(irc, msg, '$who'), msg.nick)
|
||||
self.assertEqual(f(irc, msg, '$WHO'),
|
||||
msg.nick, 'stand. sub. not case-insensitive.')
|
||||
self.assertEqual(f(self.irc, msg, '$nick'), msg.nick)
|
||||
self.assertNotEqual(f(self.irc, msg, '$randomdate'), '$randomdate')
|
||||
q = f(self.irc,msg,'$randomdate\t$randomdate')
|
||||
self.assertEqual(f(irc, msg, '$nick'), msg.nick)
|
||||
self.assertNotEqual(f(irc, msg, '$randomdate'), '$randomdate')
|
||||
q = f(irc,msg,'$randomdate\t$randomdate')
|
||||
dl = q.split('\t')
|
||||
if dl[0] == dl[1]:
|
||||
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')
|
||||
if dl[0] == dl[1]:
|
||||
self.fail ('Two $randomints in the same string were the same')
|
||||
self.assertNotEqual(f(self.irc, msg, '$today'), '$today')
|
||||
self.assertNotEqual(f(self.irc, msg, '$now'), '$now')
|
||||
n = f(self.irc, msg, '$randnick')
|
||||
self.failUnless(n in self.irc.state.channels['#foo'].users)
|
||||
n = f(self.irc, msg, '$randomnick')
|
||||
self.failUnless(n in self.irc.state.channels['#foo'].users)
|
||||
n = f(self.irc, msg, '$randomnick '*100)
|
||||
self.assertNotEqual(f(irc, msg, '$today'), '$today')
|
||||
self.assertNotEqual(f(irc, msg, '$now'), '$now')
|
||||
n = f(irc, msg, '$randnick')
|
||||
self.failUnless(n in irc.state.channels['#foo'].users)
|
||||
n = f(irc, msg, '$randomnick')
|
||||
self.failUnless(n in irc.state.channels['#foo'].users)
|
||||
n = f(irc, msg, '$randomnick '*100)
|
||||
L = n.split()
|
||||
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])
|
||||
|
||||
net = f(self.irc, msg, '$network')
|
||||
self.assertEqual(net, self.irc.network)
|
||||
net = f(irc, msg, '$network')
|
||||
self.assertEqual(net, irc.network)
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user