diff --git a/plugins/Admin/config.py b/plugins/Admin/config.py index 49a018483..0a6f64211 100644 --- a/plugins/Admin/config.py +++ b/plugins/Admin/config.py @@ -41,10 +41,6 @@ def configure(advanced): from supybot.questions import expect, anything, something, yn conf.registerPlugin('Admin', True) - Admin = conf.registerPlugin('Admin') -# This is where your configuration variables (if any) should go. For example: -# conf.registerGlobalValue(Admin, 'someConfigVariableName', -# registry.Boolean(False, """Help for someConfigVariableName.""")) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Admin/plugin.py b/plugins/Admin/plugin.py index 44e5a437d..63489d4e2 100644 --- a/plugins/Admin/plugin.py +++ b/plugins/Admin/plugin.py @@ -231,34 +231,6 @@ class Admin(callbacks.Plugin): irc.reply(irc.nick) nick = wrap(nick, [additional('nick'), additional('something')]) - @internationalizeDocstring - def part(self, irc, msg, args, channel, reason): - """[] [] - - Tells the bot to part the list of channels you give it. is - only necessary if you want the bot to part a channel other than the - current channel. If is specified, use it as the part - message. - """ - if channel is None: - if irc.isChannel(msg.args[0]): - channel = msg.args[0] - else: - irc.error(Raise=True) - try: - network = conf.supybot.networks.get(irc.network) - network.channels().remove(channel) - except KeyError: - pass - if channel not in irc.state.channels: - irc.error(_('I\'m not in %s.') % channel, Raise=True) - irc.queueMsg(ircmsgs.part(channel, reason or msg.nick)) - if msg.nick in irc.state.channels[channel].users: - irc.noReply() - else: - irc.replySuccess() - part = wrap(part, [optional('validChannel'), additional('text')]) - class capability(callbacks.Commands): @internationalizeDocstring diff --git a/plugins/Admin/test.py b/plugins/Admin/test.py index 5f94faf6f..6c090daef 100644 --- a/plugins/Admin/test.py +++ b/plugins/Admin/test.py @@ -94,27 +94,6 @@ class AdminTestCase(PluginTestCase): self.assertEqual(m.args[0], '#foo') self.assertEqual(m.args[1], 'key') - def testPart(self): - def getAfterJoinMessages(): - m = self.irc.takeMsg() - self.assertEqual(m.command, 'MODE') - m = self.irc.takeMsg() - self.assertEqual(m.command, 'MODE') - m = self.irc.takeMsg() - self.assertEqual(m.command, 'WHO') - self.assertError('part #foo') - self.assertRegexp('part #foo', 'not in') - self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) - getAfterJoinMessages() - m = self.getMsg('part #foo') - self.assertEqual(m.command, 'PART') - self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) - getAfterJoinMessages() - m = self.getMsg('part #foo reason') - self.assertEqual(m.command, 'PART') - self.assertEqual(m.args[0], '#foo') - self.assertEqual(m.args[1], 'reason') - def testNick(self): original = conf.supybot.nick() try: diff --git a/plugins/Channel/config.py b/plugins/Channel/config.py index 19f7462be..169543ef0 100644 --- a/plugins/Channel/config.py +++ b/plugins/Channel/config.py @@ -51,6 +51,15 @@ conf.registerChannelValue(Channel, 'nicksInPrivate', registry.Boolean(True, _("""Determines whether the output of 'nicks' will be sent in private. This prevents mass-highlights of a channel's users, accidental or on purpose."""))) - +conf.registerChannelValue(Channel, 'rejoinDelay', + registry.NonNegativeInteger(0, _("""Determines how many seconds the bot will wait + before rejoining a channel if kicked and + supybot.plugins.Channel.alwaysRejoin is on."""))) +conf.registerChannelValue(Channel, 'partMsg', + registry.String('$version', _("""Determines what part message should be + used by default. If the part command is called without a part message, + this will be used. If this value is empty, then no part message will + be used (they are optional in the IRC protocol). The standard + substitutions ($version, $nick, etc.) are all handled appropriately."""))) # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Channel/plugin.py b/plugins/Channel/plugin.py index 75834daa2..a9b404aa4 100644 --- a/plugins/Channel/plugin.py +++ b/plugins/Channel/plugin.py @@ -30,6 +30,7 @@ import sys import fnmatch +import time import supybot.conf as conf import supybot.ircdb as ircdb @@ -46,6 +47,7 @@ class Channel(callbacks.Plugin): """This plugin provides various commands for channel management, such as setting modes and channel-wide bans/ignores/capabilities. This is a core Supybot plugin that should not be removed!""" + def __init__(self, irc): self.__parent = super(Channel, self) self.__parent.__init__(irc) @@ -55,10 +57,18 @@ class Channel(callbacks.Plugin): channel = msg.args[0] if msg.args[1] == irc.nick: if self.registryValue('alwaysRejoin', channel): - self.log.info('Kicked from %s by %s. Rejoining.' % - (channel, msg.prefix)) + delay = self.registryValue('rejoinDelay', channel) networkGroup = conf.supybot.networks.get(irc.network) - irc.sendMsg(networkGroup.channels.join(channel)) + 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) + else: + self.log.info('Kicked from %s by %s. Rejoining.', + channel, msg.prefix) + irc.sendMsg(networkGroup.channels.join(channel)) else: self.log.info('Kicked from %s by %s. Not auto-rejoining.' % (channel, msg.prefix)) @@ -258,17 +268,22 @@ class Channel(callbacks.Plugin): any('nickInChannel')]) @internationalizeDocstring - def cycle(self, irc, msg, args, channel): + def cycle(self, irc, msg, args, channel, reason): """[] If you have the #channel,op capability, this will cause the bot to "cycle", or PART and then JOIN the channel. is only necessary - if the message isn't sent in the channel itself. + if the message isn't sent in the channel itself. If is not + specified, the default part message specified in + 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. """ - self._sendMsg(irc, ircmsgs.part(channel, msg.nick)) + reason = (reason or self.registryValue("partMsg", channel)) + reason = ircutils.standardSubstitute(irc, msg, reason) + self._sendMsg(irc, ircmsgs.part(channel, reason)) networkGroup = conf.supybot.networks.get(irc.network) self._sendMsg(irc, networkGroup.channels.join(channel)) - cycle = wrap(cycle, ['op']) + cycle = wrap(cycle, ['op', additional('text')]) @internationalizeDocstring def kick(self, irc, msg, args, channel, nicks, reason): @@ -941,6 +956,41 @@ class Channel(callbacks.Plugin): self.alertOps(irc, channel, text, frm=msg.nick) alert = wrap(alert, ['inChannel', 'text']) + @internationalizeDocstring + def part(self, irc, msg, args, channel, reason): + """[] [] + + Tells the bot to part the list of channels you give it. is + only necessary if you want the bot to part a channel other than the + current channel. If is specified, use it as the part + message. Otherwise, the default part message specified in + 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) + capability = ircdb.makeChannelCapability(channel, 'op') + hostmask = irc.state.nickToHostmask(msg.nick) + if not ircdb.checkCapability(hostmask, capability): + irc.errorNoCapability(capability, Raise=True) + try: + network = conf.supybot.networks.get(irc.network) + network.channels().remove(channel) + except KeyError: + 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 = ircutils.standardSubstitute(irc, msg, reason) + irc.queueMsg(ircmsgs.part(channel, reason)) + if msg.nick in irc.state.channels[channel].users: + irc.noReply() + else: + irc.replySuccess() + part = wrap(part, [optional('validChannel'), additional('text')]) Class = Channel diff --git a/plugins/Channel/test.py b/plugins/Channel/test.py index 6a8e4568e..2ac9bc148 100644 --- a/plugins/Channel/test.py +++ b/plugins/Channel/test.py @@ -251,6 +251,27 @@ class ChannelTestCase(ChannelPluginTestCase): def testNicks(self): self.assertResponse('channel nicks', 'bar, foo, and test') self.assertResponse('channel nicks --count', '3') - + + def testPart(self): + def getAfterJoinMessages(): + m = self.irc.takeMsg() + self.assertEqual(m.command, 'MODE') + m = self.irc.takeMsg() + self.assertEqual(m.command, 'MODE') + m = self.irc.takeMsg() + self.assertEqual(m.command, 'WHO') + self.assertError('part #foo') + self.assertRegexp('part #foo', 'not in') + self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) + getAfterJoinMessages() + m = self.getMsg('part #foo') + self.assertEqual(m.command, 'PART') + self.irc.feedMsg(ircmsgs.join('#foo', prefix=self.prefix)) + getAfterJoinMessages() + m = self.getMsg('part #foo reason') + self.assertEqual(m.command, 'PART') + self.assertEqual(m.args[0], '#foo') + self.assertEqual(m.args[1], 'reason') + # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/plugins/Dict/local/dictclient.py b/plugins/Dict/local/dictclient.py index c6f48f4f6..a7e1f5798 100644 --- a/plugins/Dict/local/dictclient.py +++ b/plugins/Dict/local/dictclient.py @@ -111,7 +111,7 @@ class Connection: capstr, msgid = re.search('<(.*)> (<.*>)$', string).groups() self.capabilities = capstr.split('.') self.messageid = msgid - + def getcapabilities(self): """Returns a list of the capabilities advertised by the server.""" return self.capabilities @@ -126,7 +126,7 @@ class Connection: network traffic!""" if hasattr(self, 'dbdescs'): return self.dbdescs - + self.sendcommand("SHOW DB") self.dbdescs = self.get100dict() return self.dbdescs @@ -165,7 +165,7 @@ class Connection: def sendcommand(self, command): """Takes a command, without a newline character, and sends it to the server.""" - self.wfile.write(command.encode('ascii') + b"\n") + self.wfile.write(command.encode('utf-8') + b"\n") def define(self, database, word): """Returns a list of Definition objects for each matching @@ -182,7 +182,7 @@ class Connection: if database != '*' and database != '!' and \ not database in self.getdbdescs(): raise Exception("Invalid database '%s' specified" % database) - + self.sendcommand("DEFINE " + enquote(database) + " " + enquote(word)) code = self.getresultcode()[0] @@ -249,11 +249,11 @@ class Database: a database name.""" self.conn = dictconn self.name = dbname - + def getname(self): """Returns the short name for this database.""" return self.name - + def getdescription(self): if hasattr(self, 'description'): return self.description @@ -264,7 +264,7 @@ class Database: else: self.description = self.conn.getdbdescs()[self.getname()] return self.description - + def getinfo(self): """Returns a string of info describing this database.""" if hasattr(self, 'info'): diff --git a/plugins/Network/plugin.py b/plugins/Network/plugin.py index aeaaa8636..548039e95 100644 --- a/plugins/Network/plugin.py +++ b/plugins/Network/plugin.py @@ -243,8 +243,7 @@ class Network(callbacks.Plugin): L.append(format(_('is on %L'), normal)) else: if command == 'whois': - L = [_('isn\'t on any non-secret channels or is using a ' - 'channel-list hiding umode.')] + L = [_('isn\'t on any publicly visible channels')] else: L = [] channels = format('%L', L) diff --git a/plugins/Owner/config.py b/plugins/Owner/config.py index 25e5d9915..243e4ee07 100644 --- a/plugins/Owner/config.py +++ b/plugins/Owner/config.py @@ -46,10 +46,11 @@ conf.registerGlobalValue(Owner, 'public', registry.Boolean(True, """Determines whether this plugin is publicly visible.""")) conf.registerGlobalValue(Owner, 'quitMsg', - registry.String('', """Determines what quit message will be used by default. + registry.String('$version', """Determines what quit message will be used by default. If the quit command is called without a quit message, this will be used. If this value is empty, the nick of the person giving the quit command will be - used.""")) + used. The standard substitutions ($version, $nick, etc.) are all handled + appropriately.""")) conf.registerGroup(conf.supybot.commands, 'renames', orderAlphabetically=True) diff --git a/plugins/Owner/plugin.py b/plugins/Owner/plugin.py index 8f5afc245..dc8de8981 100644 --- a/plugins/Owner/plugin.py +++ b/plugins/Owner/plugin.py @@ -344,9 +344,11 @@ class Owner(callbacks.Plugin): Exits the bot with the QUIT message . If is not given, the default quit message (supybot.plugins.Owner.quitMsg) will be used. - If there is no default quitMsg set, your nick will be used. + If there is no default quitMsg set, your nick will be used. The standard + substitutions ($version, $nick, etc.) are all handled appropriately. """ text = text or self.registryValue('quitMsg') or msg.nick + text = ircutils.standardSubstitute(irc, msg, text) irc.noReply() m = ircmsgs.quit(text) world.upkeep() diff --git a/plugins/QuoteGrabs/plugin.py b/plugins/QuoteGrabs/plugin.py index 8eb43d968..00f444e6b 100644 --- a/plugins/QuoteGrabs/plugin.py +++ b/plugins/QuoteGrabs/plugin.py @@ -61,8 +61,11 @@ class QuoteGrabsRecord(dbi.Record): def __str__(self): grabber = plugins.getUserName(self.grabber) - return format(_('%s (Said by: %s; grabbed by %s at %t)'), - self.text, self.hostmask, grabber, self.at) + if self.at: + return format(_('%s (Said by: %s; grabbed by %s at %t)'), + self.text, self.hostmask, grabber, self.at) + else: + return format('%s', self.text) class SqliteQuoteGrabsDB(object): def __init__(self, filename): @@ -105,7 +108,7 @@ class SqliteQuoteGrabsDB(object): db.commit() return db - def get(self, channel, id): + def get(self, channel, id, quoteonly = 0): db = self._getDb(channel) cursor = db.cursor() cursor.execute("""SELECT id, nick, quote, hostmask, added_at, added_by @@ -114,8 +117,11 @@ class SqliteQuoteGrabsDB(object): if len(results) == 0: raise dbi.NoRecordError (id, by, quote, hostmask, at, grabber) = results[0] - return QuoteGrabsRecord(id, by=by, text=quote, hostmask=hostmask, - at=int(at), grabber=grabber) + if quoteonly is 0: + return QuoteGrabsRecord(id, by=by, text=quote, hostmask=hostmask, + at=int(at), grabber=grabber) + else: + return QuoteGrabsRecord(id, text=quote) def random(self, channel, nick): db = self._getDb(channel) @@ -359,6 +365,20 @@ class QuoteGrabs(callbacks.Plugin): 'grabbed quotes in the database?')) random = wrap(random, ['channeldb', additional('nick')]) + @internationalizeDocstring + def say(self, irc, msg, args, channel, id): + """[] + + Return the quotegrab with the given . is only necessary + if the message isn't sent in the channel itself. + """ + try: + irc.reply(self.db.get(channel, id, 1)) + except dbi.NoRecordError: + irc.error(_('No quotegrab for id %s') % utils.str.quoted(id), + Raise=True) + say = wrap(say, ['channeldb', 'id']) + @internationalizeDocstring def get(self, irc, msg, args, channel, id): """[] diff --git a/plugins/Seen/plugin.py b/plugins/Seen/plugin.py index 55e9c15c5..da762b728 100644 --- a/plugins/Seen/plugin.py +++ b/plugins/Seen/plugin.py @@ -225,6 +225,17 @@ class Seen(callbacks.Plugin): except KeyError: irc.reply(format(_('I have not seen %s.'), name)) + def _checkChannelPresence(self, irc, channel, target, you): + if channel not in irc.state.channels: + irc.error(_("I'm not in %s." % channel), Raise=True) + if target not in irc.state.channels[channel].users: + if you: + msg = format(_('You must be in %s to use this command.'), channel) + else: + msg = format(_('%s must be in %s to use this command.'), + target, channel) + irc.error(msg, Raise=True) + @internationalizeDocstring def seen(self, irc, msg, args, channel, name): """[] @@ -236,9 +247,7 @@ class Seen(callbacks.Plugin): if name and ircutils.strEqual(name, irc.nick): irc.reply(_("You've found me!")) return - if msg.nick not in irc.state.channels[channel].users: - irc.error(format('You must be in %s to use this command.', channel)) - return + self._checkChannelPresence(irc, channel, msg.nick, True) self._seen(irc, channel, name) seen = wrap(seen, ['channel', 'something']) @@ -256,9 +265,7 @@ class Seen(callbacks.Plugin): if name and ircutils.strEqual(name, irc.nick): irc.reply(_("You've found me!")) return - if msg.nick not in irc.state.channels[channel].users: - irc.error(format('You must be in %s to use this command.', channel)) - return + self._checkChannelPresence(irc, channel, msg.nick, True) if name and optlist: raise callbacks.ArgumentError elif name: @@ -295,9 +302,7 @@ class Seen(callbacks.Plugin): Returns the last thing said in . is only necessary if the message isn't sent in the channel itself. """ - if msg.nick not in irc.state.channels[channel].users: - irc.error(format('You must be in %s to use this command.', channel)) - return + self._checkChannelPresence(irc, channel, msg.nick, True) self._last(irc, channel) last = wrap(last, ['channel']) @@ -327,9 +332,7 @@ class Seen(callbacks.Plugin): is only necessary if the message isn't sent in the channel itself. """ - if msg.nick not in irc.state.channels[channel].users: - irc.error(format('You must be in %s to use this command.', channel)) - return + self._checkChannelPresence(irc, channel, msg.nick, True) self._user(irc, channel, user) user = wrap(user, ['channel', 'otherUser']) @@ -343,13 +346,10 @@ class Seen(callbacks.Plugin): """ if nick is None: nick = msg.nick - if channel not in irc.state.channels: - irc.error(_('I am not in %s.') % channel) - return - if nick not in irc.state.channels[channel].users: - irc.error(format(_('%s must be in %s to use this command.'), - ('You' if nick == msg.nick else nick), channel)) - return + you = True + else: + you = False + self._checkChannelPresence(irc, channel, nick, you) if nick is None: nick = msg.nick end = None # By default, up until the most recent message. diff --git a/plugins/ShrinkUrl/config.py b/plugins/ShrinkUrl/config.py index 08e651f96..11b7672d0 100644 --- a/plugins/ShrinkUrl/config.py +++ b/plugins/ShrinkUrl/config.py @@ -42,8 +42,8 @@ def configure(advanced): conf.supybot.plugins.ShrinkUrl.shrinkSnarfer.setValue(True) class ShrinkService(registry.OnlySomeStrings): - """Valid values include 'ln', 'tiny', 'goo', 'ur1', and 'x0'.""" - validStrings = ('ln', 'tiny', 'goo', 'ur1', 'x0') + """Valid values include 'tiny', 'goo', 'ur1', and 'x0'.""" + validStrings = ('tiny', 'goo', 'ur1', 'x0') class ShrinkCycle(registry.SpaceSeparatedListOfStrings): """Valid values include 'ln', 'tiny', 'goo', 'ur1', and 'x0'.""" @@ -71,7 +71,7 @@ conf.registerChannelValue(ShrinkUrl, 'shrinkSnarfer', shrink snarfer is enabled. This snarfer will watch for URLs in the channel, and if they're sufficiently long (as determined by supybot.plugins.ShrinkUrl.minimumLength) it will post a - smaller URL from either ln-s.net or tinyurl.com, as denoted in + smaller URL from tinyurl.com, as denoted in supybot.plugins.ShrinkUrl.default."""))) conf.registerChannelValue(ShrinkUrl.shrinkSnarfer, 'showDomain', registry.Boolean(True, _("""Determines whether the snarfer will show the diff --git a/plugins/ShrinkUrl/plugin.py b/plugins/ShrinkUrl/plugin.py index 0e6f76de4..16e38a08b 100644 --- a/plugins/ShrinkUrl/plugin.py +++ b/plugins/ShrinkUrl/plugin.py @@ -171,37 +171,6 @@ class ShrinkUrl(callbacks.PluginRegexp): shrinkSnarfer = urlSnarfer(shrinkSnarfer) shrinkSnarfer.__doc__ = utils.web._httpUrlRe - @retry - def _getLnUrl(self, url): - url = utils.web.urlquote(url) - try: - return self.db.get('ln', url) - except KeyError: - text = utils.web.getUrl('http://ln-s.net/home/api.jsp?url=' + url) - text = text.decode() - (code, text) = text.split(None, 1) - text = text.strip() - if code == '200': - self.db.set('ln', url, text) - return text - else: - raise ShrinkError(text) - - @internationalizeDocstring - def ln(self, irc, msg, args, url): - """ - - Returns an ln-s.net version of . - """ - try: - lnurl = self._getLnUrl(url) - m = irc.reply(lnurl) - if m is not None: - m.tag('shrunken') - except ShrinkError as e: - irc.error(str(e)) - ln = thread(wrap(ln, ['httpUrl'])) - @retry def _getTinyUrl(self, url): try: diff --git a/plugins/ShrinkUrl/test.py b/plugins/ShrinkUrl/test.py index b8df89d35..9003415ea 100644 --- a/plugins/ShrinkUrl/test.py +++ b/plugins/ShrinkUrl/test.py @@ -39,8 +39,6 @@ class ShrinkUrlTestCase(ChannelPluginTestCase): 'term=all+your+base+are+belong+to+us' tests = {'tiny': [(sfUrl, r'http://tinyurl.com/b7wyvfz'), (udUrl, r'http://tinyurl.com/u479')], - 'ln': [(sfUrl, r'http://ln-s.net/\+PE-'), - (udUrl, r'http://ln-s.net/2\$K')], 'goo': [(sfUrl, r'http://goo.gl/3c59N'), (udUrl, r'http://goo.gl/ocTga')], 'ur1': [(sfUrl, r'http://ur1.ca/9xl25'), @@ -62,16 +60,14 @@ class ShrinkUrlTestCase(ChannelPluginTestCase): origsnarfer = snarfer() try: self.assertNotError( - 'config plugins.ShrinkUrl.serviceRotation ln x0') + 'config plugins.ShrinkUrl.serviceRotation goo x0') self.assertError( - 'config plugins.ShrinkUrl.serviceRotation ln x1') + 'config plugins.ShrinkUrl.serviceRotation goo x1') snarfer.setValue(True) self.assertSnarfRegexp(self.udUrl, r'.*%s.* \(at' % - self.tests['ln'][1][1]) + self.tests['goo'][1][1]) self.assertSnarfRegexp(self.udUrl, r'.*%s.* \(at' % self.tests['x0'][1][1]) - self.assertSnarfRegexp(self.udUrl, r'.*%s.* \(at' % - self.tests['ln'][1][1]) finally: cycle.setValue(origcycle) snarfer.setValue(origsnarfer) @@ -93,9 +89,6 @@ class ShrinkUrlTestCase(ChannelPluginTestCase): def testTinysnarf(self): self._snarf('tiny') - def testLnsnarf(self): - self._snarf('ln') - def testGoosnarf(self): self._snarf('goo') diff --git a/scripts/supybot b/scripts/supybot index 00ebd9bf2..a658ea78a 100644 --- a/scripts/supybot +++ b/scripts/supybot @@ -69,6 +69,7 @@ import supybot.i18n as i18n import supybot.utils as utils import supybot.registry as registry import supybot.questions as questions +import supybot.ircutils as ircutils from supybot.version import version @@ -104,6 +105,7 @@ def main(): for irc in world.ircs: quitmsg = conf.supybot.plugins.Owner.quitMsg() or \ 'Ctrl-C at console.' + quitmsg = ircutils.standardSubstitute(irc, None, quitmsg) irc.queueMsg(ircmsgs.quit(quitmsg)) irc.die() except SystemExit as e: diff --git a/src/conf.py b/src/conf.py index 84d65bc52..92385713f 100644 --- a/src/conf.py +++ b/src/conf.py @@ -470,8 +470,7 @@ registerChannelValue(supybot.reply, 'withNotice', registerGlobalValue(supybot.reply, 'withNoticeWhenPrivate', registry.Boolean(True, _("""Determines whether the bot will reply with a notice when it is sending a private message, in order not to open a /query - window in clients. This can be overridden by individual users via the user - configuration variable reply.withNoticeWhenPrivate."""))) + window in clients."""))) registerChannelValue(supybot.reply, 'withNickPrefix', registry.Boolean(True, _("""Determines whether the bot will always prefix diff --git a/src/ircutils.py b/src/ircutils.py index 324c455bc..c7968954a 100644 --- a/src/ircutils.py +++ b/src/ircutils.py @@ -49,7 +49,7 @@ from cStringIO import StringIO as sio from . import utils from . import minisix - +from .version import version def debug(s, *args): """Prints a debug string. Most likely replaced by our logging debug.""" @@ -690,6 +690,7 @@ def standardSubstitute(irc, msg, text, env=None): 'm': localtime[4], 'min': localtime[4], 'minute': localtime[4], 's': localtime[5], 'sec': localtime[5], 'second': localtime[5], 'tz': time.strftime('%Z', localtime), + 'version': 'Supybot %s' % version, }) if irc: vars.update({