all plugins: Use msg.channel instead of msg.args[0] + give network name to self.registryValue.

This commit is contained in:
Valentin Lorentz 2019-08-24 17:50:05 +02:00
parent 9326331c60
commit c1ae3f5c81
42 changed files with 407 additions and 350 deletions

View File

@ -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.')

View File

@ -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)

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -90,11 +90,11 @@ class ChannelLogger(callbacks.Plugin):
self.log.exception('Odd exception:')
def logNameTimestamp(self, channel):
format = self.registryValue('filenameTimestamp', channel)
format = self.registryValue('filenameTimestamp', channel, irc.network)
return time.strftime(format)
def getLogName(self, channel):
if self.registryValue('rotateLogs', channel):
if self.registryValue('rotateLogs', channel, irc.network):
return '%s.%s.log' % (channel, self.logNameTimestamp(channel))
else:
return '%s.log' % channel
@ -118,7 +118,7 @@ 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):
if self.registryValue('rotateLogs', channel, irc.network):
name = self.getLogName(channel)
if name != os.path.basename(log.name):
log.close()
@ -156,26 +156,27 @@ 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')
log.write(s)
if self.registryValue('flushImmediately'):
if self.registryValue('flushImmediately', irc.network):
log.flush()
def doPrivmsg(self, irc, msg):
(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,
@ -217,7 +218,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)
@ -242,7 +243,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)
@ -268,7 +269,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)

View File

@ -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)

View File

@ -199,21 +199,22 @@ class Config(callbacks.Plugin):
search = wrap(search, ['lowered']) # XXX compose with withoutSpaces?
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=None)
network=network.network, channel=channel, check=False)
value = str(group) or ' '
if addGlobal and not irc.nested:
value = _(
'Global: %(global_value)s; '
'%(channel_name)s @ %(network_name)s: %(channel_value)s') % {
'global_value': global_value,
'channel_name': msg.args[0],
'channel_name': msg.channel,
'network_name': irc.network,
'channel_value': value,
}
if hasattr(group, 'value'):
if not group._private:
if hasattr(global_group, 'value'):
if not global_group._private:
return (value, None)
else:
capability = getCapability(irc, group._name)
@ -224,7 +225,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):
@ -304,7 +305,7 @@ class Config(callbacks.Plugin):
else:
(value, private) = self._getValue(
irc, msg, group, network=irc,
channel=msg.args[0] if irc.isChannel(msg.args[0]) else None,
channel=msg.channel,
addGlobal=group._channelValue)
irc.reply(value, private=private)
config = wrap(config, ['settableConfigVar', additional('text')])
@ -319,11 +320,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)') % \

View File

@ -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)

View File

@ -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])

View File

@ -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; '

View File

@ -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)

View File

@ -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)

View File

@ -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:

View File

@ -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',

View File

@ -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))

View File

@ -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'])

View File

@ -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

View File

@ -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

View File

@ -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] \

View File

@ -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:

View File

@ -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)

View File

@ -258,7 +258,8 @@ 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.error(str(e))

View File

@ -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'])

View File

@ -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:

View File

@ -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

View File

@ -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')])

View File

@ -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:

View File

@ -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:

View File

@ -76,8 +76,8 @@ class Services(callbacks.Plugin):
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])
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
@ -357,17 +357,17 @@ class Services(callbacks.Plugin):
return
chanserv = self.registryValue('ChanServ')
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)

View File

@ -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 = ''

View File

@ -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

View File

@ -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

View File

@ -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'])

View File

@ -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'])

View File

@ -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):

View File

@ -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,

View File

@ -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:

View File

@ -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)

View File

@ -170,11 +170,11 @@ def _makeReply(irc, msg, s,
# XXX This isn't entirely right. Consider to=#foo, private=True.
target = ircutils.replyTo(msg)
def isPublic(s):
return irc.isChannel(irc._stripChannelPrefix(s))
return irc.isChannel(irc.stripChannelPrefix(s))
if to is not None and isPublic(to):
target = to
if isPublic(target):
channel = irc._stripChannelPrefix(target)
channel = irc.stripChannelPrefix(target)
else:
channel = None
if notice is None:
@ -376,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
@ -1414,8 +1414,9 @@ class PluginMixin(BasePlugin, irclib.IrcCallback):
names = registry.split(name)
for name in names:
group = group.get(name)
if value:
if channel or network:
group = group.getSpecific(network=network, channel=channel)
if value:
return group()
else:
return group

View File

@ -1135,7 +1135,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.
@ -1145,13 +1145,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

View File

@ -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())
@ -882,18 +883,20 @@ class Irc(IrcCommandDispatcher, log.Firewalled):
msg.tag('receivedOn', self.network)
msg.tag('receivedAt', time.time())
# Check if the message is sent to a channel
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)
msg.channel = self.stripChannelPrefix(msg.channel)
if not self.isChannel(msg.channel):
msg.channel = None
else:
msg.channel = None
def _stripChannelPrefix(self, channel):
def stripChannelPrefix(self, channel):
statusmsg_chars = self.state.supported.get('statusmsg', '')
return channel.lstrip(statusmsg_chars)