mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-01-23 10:34:19 +01:00
Moved Configurable out to its own module.
This commit is contained in:
parent
6925ecf760
commit
2aaca31709
@ -52,6 +52,7 @@ import ircutils
|
|||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
import structures
|
import structures
|
||||||
|
import configurable
|
||||||
|
|
||||||
dbfilename = os.path.join(conf.dataDir, 'Bugzilla.db')
|
dbfilename = os.path.join(conf.dataDir, 'Bugzilla.db')
|
||||||
def makeDb(filename):
|
def makeDb(filename):
|
||||||
@ -83,18 +84,18 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
|
|
||||||
replyNoBugzilla = 'I don\'t have a bugzilla %r'
|
replyNoBugzilla = 'I don\'t have a bugzilla %r'
|
||||||
|
|
||||||
class Bugzilla(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
class Bugzilla(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
||||||
"""Show a link to a bug report with a brief description"""
|
"""Show a link to a bug report with a brief description"""
|
||||||
threaded = True
|
threaded = True
|
||||||
regexps = ['bzSnarfer']
|
regexps = ['bzSnarfer']
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('bug-snarfer', plugins.ConfigurableBoolType, False,
|
[('bug-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the bug snarfer will be enabled, such that any
|
"""Determines whether the bug snarfer will be enabled, such that any
|
||||||
Bugzilla URLs seen in the channel will have their information reported
|
Bugzilla URLs seen in the channel will have their information reported
|
||||||
into the channel.""")]
|
into the channel.""")]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
self.entre = re.compile('&(\S*?);')
|
self.entre = re.compile('&(\S*?);')
|
||||||
# Schema: {name, [url, description]}
|
# Schema: {name, [url, description]}
|
||||||
@ -102,7 +103,7 @@ class Bugzilla(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
|||||||
self.shorthand = utils.abbrev(self.db.keys())
|
self.shorthand = utils.abbrev(self.db.keys())
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
self.db.close()
|
self.db.close()
|
||||||
del self.db
|
del self.db
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ import plugins
|
|||||||
import privmsgs
|
import privmsgs
|
||||||
import ircutils
|
import ircutils
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
smileys = (':)', ';)', ':]', ':-)', ':-D', ':D', ':P', ':p', '(=', '=)')
|
smileys = (':)', ';)', ':]', ':-)', ':-D', ':D', ':P', ':p', '(=', '=)')
|
||||||
frowns = (':|', ':-/', ':-\\', ':\\', ':/', ':(', ':-(', ':\'(')
|
frowns = (':|', ':-/', ':-\\', ':\\', ':/', ':(', ':-(', ':\'(')
|
||||||
@ -65,21 +66,21 @@ smileyre = re.compile('|'.join(imap(re.escape, smileys)))
|
|||||||
frownre = re.compile('|'.join(imap(re.escape, frowns)))
|
frownre = re.compile('|'.join(imap(re.escape, frowns)))
|
||||||
|
|
||||||
class ChannelDB(plugins.ChannelDBHandler,
|
class ChannelDB(plugins.ChannelDBHandler,
|
||||||
plugins.Configurable,
|
configurable.Mixin,
|
||||||
callbacks.Privmsg):
|
callbacks.Privmsg):
|
||||||
noIgnore = True
|
noIgnore = True
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('self-stats', plugins.ConfigurableBoolType, True,
|
[('self-stats', configurable.BoolType, True,
|
||||||
"""Determines whether the bot will keep channel statistics on itself,
|
"""Determines whether the bot will keep channel statistics on itself,
|
||||||
possibly skewing the channel stats (especially in cases where he's
|
possibly skewing the channel stats (especially in cases where he's
|
||||||
relaying between channels on a network."""),
|
relaying between channels on a network."""),
|
||||||
('wordstats-top-n', plugins.ConfigurableIntType, 3,
|
('wordstats-top-n', configurable.IntType, 3,
|
||||||
"""Determines the maximum number of top users to show for a given
|
"""Determines the maximum number of top users to show for a given
|
||||||
wordstat when you request the wordstats for a particular word.""")]
|
wordstat when you request the wordstats for a particular word.""")]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
plugins.ChannelDBHandler.__init__(self)
|
plugins.ChannelDBHandler.__init__(self)
|
||||||
self.lastmsg = None
|
self.lastmsg = None
|
||||||
self.laststate = None
|
self.laststate = None
|
||||||
@ -87,7 +88,7 @@ class ChannelDB(plugins.ChannelDBHandler,
|
|||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.Privmsg.die(self)
|
callbacks.Privmsg.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
plugins.ChannelDBHandler.die(self)
|
plugins.ChannelDBHandler.die(self)
|
||||||
|
|
||||||
def makeDb(self, filename):
|
def makeDb(self, filename):
|
||||||
|
@ -53,6 +53,7 @@ import conf
|
|||||||
import utils
|
import utils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -82,7 +83,7 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
onStart.append('disable file')
|
onStart.append('disable file')
|
||||||
|
|
||||||
class Debian(callbacks.Privmsg,
|
class Debian(callbacks.Privmsg,
|
||||||
plugins.Configurable,
|
configurable.Mixin,
|
||||||
plugins.PeriodicFileDownloader):
|
plugins.PeriodicFileDownloader):
|
||||||
threaded = True
|
threaded = True
|
||||||
periodicFiles = {
|
periodicFiles = {
|
||||||
@ -93,8 +94,8 @@ class Debian(callbacks.Privmsg,
|
|||||||
604800, None)
|
604800, None)
|
||||||
}
|
}
|
||||||
contents = os.path.join(conf.dataDir, 'Contents-i386.gz')
|
contents = os.path.join(conf.dataDir, 'Contents-i386.gz')
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('python-zegrep', plugins.ConfigurableBoolType, False,
|
[('python-zegrep', configurable.BoolType, False,
|
||||||
"""An advanced option, mostly just for testing; uses a Python-coded
|
"""An advanced option, mostly just for testing; uses a Python-coded
|
||||||
zegrep rather than the actual zegrep executable, generally resulting
|
zegrep rather than the actual zegrep executable, generally resulting
|
||||||
in a 50x slowdown. What would take 2 seconds will take 100 with this
|
in a 50x slowdown. What would take 2 seconds will take 100 with this
|
||||||
@ -102,12 +103,12 @@ class Debian(callbacks.Privmsg,
|
|||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
plugins.PeriodicFileDownloader.__init__(self)
|
plugins.PeriodicFileDownloader.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.Privmsg.die(self)
|
callbacks.Privmsg.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
|
|
||||||
def file(self, irc, msg, args):
|
def file(self, irc, msg, args):
|
||||||
"""[--{regexp,exact}=<value>] [<glob>]
|
"""[--{regexp,exact}=<value>] [<glob>]
|
||||||
|
@ -49,6 +49,7 @@ import plugins
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -64,20 +65,20 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
onStart.append('dict config server %s' % server)
|
onStart.append('dict config server %s' % server)
|
||||||
|
|
||||||
replyTimeout = 'Timeout on the dictd server.'
|
replyTimeout = 'Timeout on the dictd server.'
|
||||||
class Dict(callbacks.Privmsg, plugins.Configurable):
|
class Dict(callbacks.Privmsg, configurable.Mixin):
|
||||||
threaded = True
|
threaded = True
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('server', plugins.ConfigurableStrType, 'dict.org',
|
[('server', configurable.StrType, 'dict.org',
|
||||||
"""Determines what server the bot will connect to to receive
|
"""Determines what server the bot will connect to to receive
|
||||||
definitions from."""),]
|
definitions from."""),]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.Privmsg.die(self)
|
callbacks.Privmsg.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
|
|
||||||
def dictionaries(self, irc, msg, args):
|
def dictionaries(self, irc, msg, args):
|
||||||
"""takes no arguments.
|
"""takes no arguments.
|
||||||
|
@ -48,6 +48,7 @@ import plugins
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -67,24 +68,24 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
class EbayError(callbacks.Error):
|
class EbayError(callbacks.Error):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Ebay(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
class Ebay(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
||||||
"""
|
"""
|
||||||
Module for eBay stuff. Currently contains a URL snarfer and a command to
|
Module for eBay stuff. Currently contains a URL snarfer and a command to
|
||||||
get info about an auction.
|
get info about an auction.
|
||||||
"""
|
"""
|
||||||
threaded = True
|
threaded = True
|
||||||
regexps = ['ebaySnarfer']
|
regexps = ['ebaySnarfer']
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('auction-snarfer', plugins.ConfigurableBoolType, False,
|
[('auction-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will automatically 'snarf' Ebay auction
|
"""Determines whether the bot will automatically 'snarf' Ebay auction
|
||||||
URLs and print information about them.""")]
|
URLs and print information about them.""")]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
|
|
||||||
_reopts = re.I | re.S
|
_reopts = re.I | re.S
|
||||||
|
@ -45,6 +45,7 @@ import plugins
|
|||||||
import privmsgs
|
import privmsgs
|
||||||
import ircutils
|
import ircutils
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
from questions import expect, anything, something, yn
|
from questions import expect, anything, something, yn
|
||||||
@ -61,18 +62,18 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
# Enforcer: Enforces capabilities on JOIN, MODE, KICK, etc.
|
# Enforcer: Enforces capabilities on JOIN, MODE, KICK, etc.
|
||||||
###
|
###
|
||||||
_chanCap = ircdb.makeChannelCapability
|
_chanCap = ircdb.makeChannelCapability
|
||||||
class Enforcer(callbacks.Privmsg, plugins.Configurable):
|
class Enforcer(callbacks.Privmsg, configurable.Mixin):
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('auto-op', plugins.ConfigurableBoolType, False,
|
[('auto-op', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will automatically op people with
|
"""Determines whether the bot will automatically op people with
|
||||||
the <channel>.op capability when they join the channel."""),
|
the <channel>.op capability when they join the channel."""),
|
||||||
('auto-voice', plugins.ConfigurableBoolType, False,
|
('auto-voice', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will automatically voice people with
|
"""Determines whether the bot will automatically voice people with
|
||||||
the <channel>.voice capability when they join the channel."""),
|
the <channel>.voice capability when they join the channel."""),
|
||||||
('auto-halfop', plugins.ConfigurableBoolType, False,
|
('auto-halfop', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will automatically halfop people with
|
"""Determines whether the bot will automatically halfop people with
|
||||||
the <channel>.halfop capability when they join the channel."""),
|
the <channel>.halfop capability when they join the channel."""),
|
||||||
('revenge', plugins.ConfigurableBoolType, False,
|
('revenge', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will take revenge on people who do
|
"""Determines whether the bot will take revenge on people who do
|
||||||
things it doesn't like (somewhat like 'bitch mode' in other IRC
|
things it doesn't like (somewhat like 'bitch mode' in other IRC
|
||||||
bots)."""),]
|
bots)."""),]
|
||||||
@ -80,11 +81,11 @@ class Enforcer(callbacks.Privmsg, plugins.Configurable):
|
|||||||
started = False
|
started = False
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.Privmsg.die(self)
|
callbacks.Privmsg.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
|
|
||||||
def start(self, irc, msg, args):
|
def start(self, irc, msg, args):
|
||||||
"""[<CHANSERV>]
|
"""[<CHANSERV>]
|
||||||
|
@ -55,6 +55,7 @@ import ircmsgs
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
tableCreateStatements = {
|
tableCreateStatements = {
|
||||||
'larts': ("""CREATE TABLE larts (
|
'larts': ("""CREATE TABLE larts (
|
||||||
@ -79,26 +80,26 @@ tableCreateStatements = {
|
|||||||
)""",),
|
)""",),
|
||||||
}
|
}
|
||||||
|
|
||||||
class FunDB(callbacks.Privmsg, plugins.Configurable, plugins.ChannelDBHandler):
|
class FunDB(callbacks.Privmsg, configurable.Mixin, plugins.ChannelDBHandler):
|
||||||
"""
|
"""
|
||||||
Contains the 'fun' commands that require a database. Currently includes
|
Contains the 'fun' commands that require a database. Currently includes
|
||||||
database-backed commands for crossword puzzle solving, anagram searching,
|
database-backed commands for crossword puzzle solving, anagram searching,
|
||||||
larting, praising, excusing, and insulting.
|
larting, praising, excusing, and insulting.
|
||||||
"""
|
"""
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('show-ids', plugins.ConfigurableBoolType, False,
|
[('show-ids', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will show the id of an
|
"""Determines whether the bot will show the id of an
|
||||||
excuse/insult/praise/lart.""")]
|
excuse/insult/praise/lart.""")]
|
||||||
)
|
)
|
||||||
_tables = sets.Set(['lart', 'insult', 'excuse', 'praise'])
|
_tables = sets.Set(['lart', 'insult', 'excuse', 'praise'])
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
plugins.ChannelDBHandler.__init__(self)
|
plugins.ChannelDBHandler.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.Privmsg.die(self)
|
callbacks.Privmsg.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
plugins.ChannelDBHandler.die(self)
|
plugins.ChannelDBHandler.die(self)
|
||||||
|
|
||||||
def makeDb(self, dbfilename, replace=False):
|
def makeDb(self, dbfilename, replace=False):
|
||||||
|
@ -47,6 +47,7 @@ import plugins
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -69,15 +70,15 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
onStart.append('Gameknot toggle stat off')
|
onStart.append('Gameknot toggle stat off')
|
||||||
|
|
||||||
|
|
||||||
class Gameknot(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
class Gameknot(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
||||||
threaded = True
|
threaded = True
|
||||||
regexps = ['gameknotSnarfer', 'gameknotStatsSnarfer']
|
regexps = ['gameknotSnarfer', 'gameknotStatsSnarfer']
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('game-snarfer', plugins.ConfigurableBoolType, True,
|
[('game-snarfer', configurable.BoolType, True,
|
||||||
"""Determines whether the game URL snarfer is active; if so, the bot
|
"""Determines whether the game URL snarfer is active; if so, the bot
|
||||||
will reply to the channel with a summary of the game data when it
|
will reply to the channel with a summary of the game data when it
|
||||||
sees a Gameknot game on the channel."""),
|
sees a Gameknot game on the channel."""),
|
||||||
('stats-snarfer', plugins.ConfigurableBoolType, True,
|
('stats-snarfer', configurable.BoolType, True,
|
||||||
"""Determines whether the stats URL snarfer is active; if so, the bot
|
"""Determines whether the stats URL snarfer is active; if so, the bot
|
||||||
will reply to the channel with a summary of the stats of any player
|
will reply to the channel with a summary of the stats of any player
|
||||||
whose stats URL is seen on the channel.""")]
|
whose stats URL is seen on the channel.""")]
|
||||||
@ -89,11 +90,11 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
|||||||
_gkteam = re.compile(r'Team:(<.*?>)+(?P<name>.*?)</span>')
|
_gkteam = re.compile(r'Team:(<.*?>)+(?P<name>.*?)</span>')
|
||||||
_gkseen = re.compile(r'(seen on GK:\s+([^[]+ago)|.*?is hiding.*?)')
|
_gkseen = re.compile(r'(seen on GK:\s+([^[]+ago)|.*?is hiding.*?)')
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
|
|
||||||
def getStats(self, name):
|
def getStats(self, name):
|
||||||
|
@ -55,6 +55,7 @@ import ircutils
|
|||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
import structures
|
import structures
|
||||||
|
import configurable
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
from questions import expect, anything, something, yn
|
from questions import expect, anything, something, yn
|
||||||
@ -125,28 +126,28 @@ def search(log, *args, **kwargs):
|
|||||||
log.exception('Uncaught SOAP error:')
|
log.exception('Uncaught SOAP error:')
|
||||||
raise callbacks.Error, 'Invalid Google license key.'
|
raise callbacks.Error, 'Invalid Google license key.'
|
||||||
|
|
||||||
class Google(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
class Google(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
||||||
threaded = True
|
threaded = True
|
||||||
regexps = sets.Set(['googleSnarfer', 'googleGroups'])
|
regexps = sets.Set(['googleSnarfer', 'googleGroups'])
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('groups-snarfer', plugins.ConfigurableBoolType, False,
|
[('groups-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the groups snarfer is enabled. If so, URLs at
|
"""Determines whether the groups snarfer is enabled. If so, URLs at
|
||||||
groups.google.com will be snarfed and their group/title messaged to
|
groups.google.com will be snarfed and their group/title messaged to
|
||||||
the channel."""),
|
the channel."""),
|
||||||
('search-snarfer', plugins.ConfigurableBoolType, False,
|
('search-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the search snarfer is enabled. If so, messages
|
"""Determines whether the search snarfer is enabled. If so, messages
|
||||||
(even unaddressed ones) beginning with the word 'google' will result
|
(even unaddressed ones) beginning with the word 'google' will result
|
||||||
in the first URL Google returns being sent to the channel.""")]
|
in the first URL Google returns being sent to the channel.""")]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
self.total = 0
|
self.total = 0
|
||||||
self.totalTime = 0
|
self.totalTime = 0
|
||||||
self.last24hours = structures.queue()
|
self.last24hours = structures.queue()
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
|
|
||||||
def formatData(self, data):
|
def formatData(self, data):
|
||||||
|
@ -46,6 +46,7 @@ import utils
|
|||||||
import plugins
|
import plugins
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -57,23 +58,23 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
onStart.append('load Karma')
|
onStart.append('load Karma')
|
||||||
|
|
||||||
class Karma(callbacks.PrivmsgCommandAndRegexp,
|
class Karma(callbacks.PrivmsgCommandAndRegexp,
|
||||||
plugins.Configurable,
|
configurable.Mixin,
|
||||||
plugins.ChannelDBHandler):
|
plugins.ChannelDBHandler):
|
||||||
addressedRegexps = ['increaseKarma', 'decreaseKarma']
|
addressedRegexps = ['increaseKarma', 'decreaseKarma']
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('simple-output', plugins.ConfigurableBoolType, False,
|
[('simple-output', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will output shorter versions of the
|
"""Determines whether the bot will output shorter versions of the
|
||||||
karma output when requesting a single thing's karma. (example: 'foo:
|
karma output when requesting a single thing's karma. (example: 'foo:
|
||||||
1')""")]
|
1')""")]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
plugins.ChannelDBHandler.__init__(self)
|
plugins.ChannelDBHandler.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
plugins.ChannelDBHandler.die(self)
|
plugins.ChannelDBHandler.die(self)
|
||||||
|
|
||||||
def makeDb(self, filename):
|
def makeDb(self, filename):
|
||||||
|
@ -57,6 +57,7 @@ import webutils
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
L = [os.__file__]
|
L = [os.__file__]
|
||||||
if hasattr(math, '__file__'):
|
if hasattr(math, '__file__'):
|
||||||
@ -75,22 +76,22 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
Would you like to enable this snarfer?""") == 'y':
|
Would you like to enable this snarfer?""") == 'y':
|
||||||
onStart.append('python config aspn-snarfer on')
|
onStart.append('python config aspn-snarfer on')
|
||||||
|
|
||||||
class Python(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
class Python(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
||||||
modulechars = '%s%s%s' % (string.ascii_letters, string.digits, '_.')
|
modulechars = '%s%s%s' % (string.ascii_letters, string.digits, '_.')
|
||||||
regexps = ['aspnRecipes']
|
regexps = ['aspnRecipes']
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('aspn-snarfer', plugins.ConfigurableBoolType, False,
|
[('aspn-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the ASPN Python recipe snarfer is enabled. If
|
"""Determines whether the ASPN Python recipe snarfer is enabled. If
|
||||||
so, it will message the channel with the name of the recipe when it
|
so, it will message the channel with the name of the recipe when it
|
||||||
sees an ASPN Python recipe link on the channel.""")]
|
sees an ASPN Python recipe link on the channel.""")]
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
|
|
||||||
def pydoc(self, irc, msg, args):
|
def pydoc(self, irc, msg, args):
|
||||||
|
@ -54,6 +54,7 @@ import plugins
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -69,10 +70,10 @@ minRandomLength = 8
|
|||||||
minRandomWords = 3
|
minRandomWords = 3
|
||||||
|
|
||||||
class QuoteGrabs(plugins.ChannelDBHandler,
|
class QuoteGrabs(plugins.ChannelDBHandler,
|
||||||
plugins.Configurable,
|
configurable.Mixin,
|
||||||
callbacks.Privmsg):
|
callbacks.Privmsg):
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('random-grabber', plugins.ConfigurableBoolType, False,
|
[('random-grabber', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will randomly grab possibly-suitable
|
"""Determines whether the bot will randomly grab possibly-suitable
|
||||||
quotes for someone."""),]
|
quotes for someone."""),]
|
||||||
)
|
)
|
||||||
|
@ -51,6 +51,7 @@ import ircmsgs
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
import socket
|
import socket
|
||||||
@ -107,17 +108,17 @@ def reload(x=None):
|
|||||||
else:
|
else:
|
||||||
(ircs, ircstates, lastmsg, channels, abbreviations, originalIrc) = x
|
(ircs, ircstates, lastmsg, channels, abbreviations, originalIrc) = x
|
||||||
|
|
||||||
class Relay(callbacks.Privmsg, plugins.Configurable):
|
class Relay(callbacks.Privmsg, configurable.Mixin):
|
||||||
noIgnore = True
|
noIgnore = True
|
||||||
priority = sys.maxint
|
priority = sys.maxint
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('color', plugins.ConfigurableBoolType, True,
|
[('color', configurable.BoolType, True,
|
||||||
"""Determines whether the bot will color relayed PRIVMSGs so as to
|
"""Determines whether the bot will color relayed PRIVMSGs so as to
|
||||||
make the messages easier to read."""),]
|
make the messages easier to read."""),]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
self.ircs = ircs
|
self.ircs = ircs
|
||||||
self._color = 0
|
self._color = 0
|
||||||
self._whois = {}
|
self._whois = {}
|
||||||
@ -139,7 +140,7 @@ class Relay(callbacks.Privmsg, plugins.Configurable):
|
|||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.Privmsg.die(self)
|
callbacks.Privmsg.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
for irc in self.abbreviations:
|
for irc in self.abbreviations:
|
||||||
if irc != originalIrc:
|
if irc != originalIrc:
|
||||||
irc.callbacks[:] = []
|
irc.callbacks[:] = []
|
||||||
|
@ -47,6 +47,7 @@ import ircutils
|
|||||||
import privmsgs
|
import privmsgs
|
||||||
import webutils
|
import webutils
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
@ -94,7 +95,7 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
class TrackerError(Exception):
|
class TrackerError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Sourceforge(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
class Sourceforge(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
||||||
"""
|
"""
|
||||||
Module for Sourceforge stuff. Currently contains commands to query a
|
Module for Sourceforge stuff. Currently contains commands to query a
|
||||||
project's most recent bugs and rfes.
|
project's most recent bugs and rfes.
|
||||||
@ -114,21 +115,21 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp, plugins.Configurable):
|
|||||||
_status = re.compile(r'<b>(Status):</b> <a.+?<br>(.+?)</td>', _reopts)
|
_status = re.compile(r'<b>(Status):</b> <a.+?<br>(.+?)</td>', _reopts)
|
||||||
_res =(_resolution, _assigned, _submitted, _priority, _status)
|
_res =(_resolution, _assigned, _submitted, _priority, _status)
|
||||||
|
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('tracker-snarfer', plugins.ConfigurableBoolType, False,
|
[('tracker-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will reply to SF.net Tracker URLs in
|
"""Determines whether the bot will reply to SF.net Tracker URLs in
|
||||||
the channel with a nice summary of the tracker item."""),
|
the channel with a nice summary of the tracker item."""),
|
||||||
('default-project', plugins.ConfigurableStrType, '',
|
('default-project', configurable.StrType, '',
|
||||||
"""Sets the default project (used by the bugs/rfes commands in the
|
"""Sets the default project (used by the bugs/rfes commands in the
|
||||||
case that no explicit project is given).""")]
|
case that no explicit project is given).""")]
|
||||||
)
|
)
|
||||||
_projectURL = 'http://sourceforge.net/projects/'
|
_projectURL = 'http://sourceforge.net/projects/'
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
|
|
||||||
def _formatResp(self, text, num=''):
|
def _formatResp(self, text, num=''):
|
||||||
|
@ -47,25 +47,26 @@ import ircmsgs
|
|||||||
import plugins
|
import plugins
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
def ConfigurableTopicSeparator(s):
|
def ConfigurableTopicSeparator(s):
|
||||||
s = plugins.ConfigurableStrType(s)
|
s = configurable.StrType(s)
|
||||||
if s.lstrip() == s:
|
if s.lstrip() == s:
|
||||||
s = ' ' + s
|
s = ' ' + s
|
||||||
if s.rstrip() == s:
|
if s.rstrip() == s:
|
||||||
s += ' '
|
s += ' '
|
||||||
return s
|
return s
|
||||||
|
|
||||||
class Topic(callbacks.Privmsg, plugins.Configurable):
|
class Topic(callbacks.Privmsg, configurable.Mixin):
|
||||||
topicFormatter = '%s (%s)'
|
topicFormatter = '%s (%s)'
|
||||||
topicUnformatter = re.compile('(.*) \((\S+)\)')
|
topicUnformatter = re.compile('(.*) \((\S+)\)')
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('separator', plugins.ConfigurableStrType, ' || ',
|
[('separator', configurable.StrType, ' || ',
|
||||||
"The separator between individual topics in the channel topic.")]
|
"The separator between individual topics in the channel topic.")]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
|
|
||||||
def _splitTopic(self, topic, channel):
|
def _splitTopic(self, topic, channel):
|
||||||
separator = self.configurables.get('separator', channel)
|
separator = self.configurables.get('separator', channel)
|
||||||
|
@ -54,6 +54,7 @@ import ircmsgs
|
|||||||
import ircutils
|
import ircutils
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
|
import configurable
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
# This will be called by setup.py to configure this module. onStart and
|
# This will be called by setup.py to configure this module. onStart and
|
||||||
@ -82,26 +83,26 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
length that will trigger this snarfer?""")
|
length that will trigger this snarfer?""")
|
||||||
|
|
||||||
class URL(callbacks.PrivmsgCommandAndRegexp,
|
class URL(callbacks.PrivmsgCommandAndRegexp,
|
||||||
plugins.Configurable,
|
configurable.Mixin,
|
||||||
plugins.ChannelDBHandler):
|
plugins.ChannelDBHandler):
|
||||||
regexps = ['tinyurlSnarfer']
|
regexps = ['tinyurlSnarfer']
|
||||||
configurables = plugins.ConfigurableDictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('tinyurl-snarfer', plugins.ConfigurableBoolType, False,
|
[('tinyurl-snarfer', configurable.BoolType, False,
|
||||||
"""Determines whether the bot will output shorter versions of URLs
|
"""Determines whether the bot will output shorter versions of URLs
|
||||||
longer than the tinyurl-minimum-length config variable."""),
|
longer than the tinyurl-minimum-length config variable."""),
|
||||||
('tinyurl-minimum-length', plugins.ConfigurableIntType, 46,
|
('tinyurl-minimum-length', configurable.IntType, 46,
|
||||||
"""The minimum length a URL must be before the tinyurl-snarfer will
|
"""The minimum length a URL must be before the tinyurl-snarfer will
|
||||||
snarf it and offer a tinyurl replacement."""),]
|
snarf it and offer a tinyurl replacement."""),]
|
||||||
)
|
)
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.nextMsgs = {}
|
self.nextMsgs = {}
|
||||||
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
callbacks.PrivmsgCommandAndRegexp.__init__(self)
|
||||||
plugins.Configurable.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
plugins.ChannelDBHandler.__init__(self)
|
plugins.ChannelDBHandler.__init__(self)
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
callbacks.PrivmsgCommandAndRegexp.die(self)
|
callbacks.PrivmsgCommandAndRegexp.die(self)
|
||||||
plugins.Configurable.die(self)
|
configurable.Mixin.die(self)
|
||||||
plugins.ChannelDBHandler.die(self)
|
plugins.ChannelDBHandler.die(self)
|
||||||
|
|
||||||
def makeDb(self, filename):
|
def makeDb(self, filename):
|
||||||
|
212
src/configurable.py
Normal file
212
src/configurable.py
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
###
|
||||||
|
# Copyright (c) 2002, Jeremiah Fincher
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are met:
|
||||||
|
#
|
||||||
|
# * Redistributions of source code must retain the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer.
|
||||||
|
# * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
# this list of conditions, and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
# * Neither the name of the author of this software nor the name of
|
||||||
|
# contributors to this software may be used to endorse or promote products
|
||||||
|
# derived from this software without specific prior written consent.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
###
|
||||||
|
|
||||||
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
import conf
|
||||||
|
import utils
|
||||||
|
import ircdb
|
||||||
|
import ircutils
|
||||||
|
import privmsgs
|
||||||
|
import callbacks
|
||||||
|
|
||||||
|
class Dictionary(object):
|
||||||
|
"""This is a dictionary to handle configuration for individual channels,
|
||||||
|
including a default configuration for channels that haven't modified their
|
||||||
|
configuration from the default.
|
||||||
|
"""
|
||||||
|
def __init__(self, seq):
|
||||||
|
self.helps = {}
|
||||||
|
self.types = {}
|
||||||
|
self.defaults = {}
|
||||||
|
self.originalNames = {}
|
||||||
|
self.unparsedValues = {}
|
||||||
|
self.channels = ircutils.IrcDict()
|
||||||
|
for (name, type, default, help) in seq:
|
||||||
|
if ',' in name:
|
||||||
|
raise ValueError, 'There can be no commas in the name.'
|
||||||
|
original = name
|
||||||
|
name = callbacks.canonicalName(name)
|
||||||
|
self.originalNames[name] = original
|
||||||
|
self.helps[name] = utils.normalizeWhitespace(help)
|
||||||
|
self.types[name] = type
|
||||||
|
self.defaults[name] = default
|
||||||
|
|
||||||
|
def get(self, name, channel=None):
|
||||||
|
name = callbacks.canonicalName(name)
|
||||||
|
if channel is not None:
|
||||||
|
try:
|
||||||
|
return self.channels[channel][name]
|
||||||
|
except KeyError:
|
||||||
|
return self.defaults[name]
|
||||||
|
else:
|
||||||
|
return self.defaults[name]
|
||||||
|
|
||||||
|
def set(self, name, value, channel=None):
|
||||||
|
name = callbacks.canonicalName(name)
|
||||||
|
if name not in self.originalNames:
|
||||||
|
raise KeyError, name
|
||||||
|
if ',' in name:
|
||||||
|
raise ValueError, 'There can be no commas in the name.'
|
||||||
|
self.unparsedValues[(channel, name)] = value
|
||||||
|
if channel is not None:
|
||||||
|
d = self.channels.setdefault(channel, {})
|
||||||
|
d[name] = self.types[name](value)
|
||||||
|
else:
|
||||||
|
self.defaults[name] = self.types[name](value)
|
||||||
|
|
||||||
|
def help(self, name):
|
||||||
|
return self.helps[callbacks.canonicalName(name)]
|
||||||
|
|
||||||
|
def names(self):
|
||||||
|
L = self.originalNames.values()
|
||||||
|
L.sort()
|
||||||
|
return L
|
||||||
|
|
||||||
|
class Error(TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def BoolType(s):
|
||||||
|
s = s.lower()
|
||||||
|
if s in ('true', 'enable', 'on'):
|
||||||
|
return True
|
||||||
|
elif s in ('false', 'disable', 'off'):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
s = 'Value must be one of on/off/true/false/enable/disable.'
|
||||||
|
raise Error, s
|
||||||
|
|
||||||
|
def StrType(s):
|
||||||
|
if s and s[0] not in '\'"' and s[-1] not in '\'"':
|
||||||
|
s = repr(s)
|
||||||
|
try:
|
||||||
|
v = utils.safeEval(s)
|
||||||
|
if type(v) is not str:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError: # This catches the utils.safeEval(s) errors too.
|
||||||
|
raise Error, 'Value must be a string.'
|
||||||
|
return v
|
||||||
|
|
||||||
|
def IntType(s):
|
||||||
|
try:
|
||||||
|
return int(s)
|
||||||
|
except ValueError:
|
||||||
|
raise Error, 'Value must be an int.'
|
||||||
|
|
||||||
|
class Mixin(object):
|
||||||
|
"""A mixin class to provide a "config" command that can be consistent
|
||||||
|
across all plugins, in order to unify the configuration for each plugin.
|
||||||
|
|
||||||
|
Plugins subclassing this should have a "configurables" attribute which is
|
||||||
|
a ConfigurableDictionary initialized with a list of 4-tuples of
|
||||||
|
(name, type, default, help). Name is the string name of the config
|
||||||
|
variable; type is a function taking a string and returning some value of
|
||||||
|
the type the variable is supposed to be; default is the default value the
|
||||||
|
variable should take on; help is a string that'll be returned to describe
|
||||||
|
the purpose of the config variable.
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
className = self.__class__.__name__
|
||||||
|
self.filename = os.path.join(conf.confDir, '%s-configurable'%className)
|
||||||
|
if os.path.exists(self.filename):
|
||||||
|
fd = file(self.filename)
|
||||||
|
for line in fd:
|
||||||
|
line = line.rstrip()
|
||||||
|
(channel, name, value) = line.split(',', 2)
|
||||||
|
if channel == 'default':
|
||||||
|
channel = None
|
||||||
|
try:
|
||||||
|
# The eval here is to turn from "'foo'" to 'foo'.
|
||||||
|
self.configurables.set(name, eval(value), channel)
|
||||||
|
except Error, e:
|
||||||
|
s = 'Couldn\'t read configurable from file: %s'
|
||||||
|
self.log.warning(s, e)
|
||||||
|
except KeyError, e:
|
||||||
|
s = 'Configurable variable %s doesn\'t exist anymore.'
|
||||||
|
self.log.warning(s, name)
|
||||||
|
|
||||||
|
def die(self):
|
||||||
|
fd = file(self.filename, 'w')
|
||||||
|
L = self.configurables.unparsedValues.items()
|
||||||
|
L.sort()
|
||||||
|
for ((channel, name), value) in L:
|
||||||
|
if channel is None:
|
||||||
|
channel = 'default'
|
||||||
|
name = self.configurables.originalNames[name]
|
||||||
|
fd.write('%s,%s,%r\n' % (channel, name, value))
|
||||||
|
fd.close()
|
||||||
|
|
||||||
|
def config(self, irc, msg, args):
|
||||||
|
"""[<channel>] [<name>] [<value>]
|
||||||
|
|
||||||
|
Sets the value of config variable <name> to <value> on <channel>. If
|
||||||
|
<name> is given but <value> is not, returns the help and current value
|
||||||
|
for <name>. If neither <name> nor <value> is given, returns the valid
|
||||||
|
config variables for this plugin. <channel> is only necessary if the
|
||||||
|
message isn't sent in the channel itself.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
channel = privmsgs.getChannel(msg, args)
|
||||||
|
capability = ircdb.makeChannelCapability(channel, 'op')
|
||||||
|
except callbacks.ArgumentError:
|
||||||
|
raise
|
||||||
|
except callbacks.Error:
|
||||||
|
channel = None
|
||||||
|
capability = 'admin'
|
||||||
|
if not ircdb.checkCapability(msg.prefix, capability):
|
||||||
|
irc.error(msg, conf.replyNoCapability % capability)
|
||||||
|
return
|
||||||
|
(name, value) = privmsgs.getArgs(args, required=0, optional=2)
|
||||||
|
if not name:
|
||||||
|
irc.reply(msg, utils.commaAndify(self.configurables.names()))
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
if not value:
|
||||||
|
help = self.configurables.help(name)
|
||||||
|
value = self.configurables.get(name, channel=channel)
|
||||||
|
s = '%s: %s (Current value: %r)' % (name, help, value)
|
||||||
|
irc.reply(msg, s)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
self.configurables.set(name, value, channel)
|
||||||
|
irc.reply(msg, conf.replySuccess)
|
||||||
|
except Error, e:
|
||||||
|
irc.error(msg, str(e))
|
||||||
|
except KeyError:
|
||||||
|
irc.error(msg, 'There is no config variable %r' % name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
|
165
src/plugins.py
165
src/plugins.py
@ -241,171 +241,6 @@ class PeriodicFileDownloader(object):
|
|||||||
world.threadsSpawned += 1
|
world.threadsSpawned += 1
|
||||||
|
|
||||||
|
|
||||||
class ConfigurableDictionary(object):
|
|
||||||
"""This is a dictionary to handle configuration for individual channels,
|
|
||||||
including a default configuration for channels that haven't modified their
|
|
||||||
configuration from the default.
|
|
||||||
"""
|
|
||||||
def __init__(self, seq):
|
|
||||||
self.helps = {}
|
|
||||||
self.types = {}
|
|
||||||
self.defaults = {}
|
|
||||||
self.originalNames = {}
|
|
||||||
self.unparsedValues = {}
|
|
||||||
self.channels = ircutils.IrcDict()
|
|
||||||
for (name, type, default, help) in seq:
|
|
||||||
if ',' in name:
|
|
||||||
raise ValueError, 'There can be no commas in the name.'
|
|
||||||
original = name
|
|
||||||
name = callbacks.canonicalName(name)
|
|
||||||
self.originalNames[name] = original
|
|
||||||
self.helps[name] = utils.normalizeWhitespace(help)
|
|
||||||
self.types[name] = type
|
|
||||||
self.defaults[name] = default
|
|
||||||
|
|
||||||
def get(self, name, channel=None):
|
|
||||||
name = callbacks.canonicalName(name)
|
|
||||||
if channel is not None:
|
|
||||||
try:
|
|
||||||
return self.channels[channel][name]
|
|
||||||
except KeyError:
|
|
||||||
return self.defaults[name]
|
|
||||||
else:
|
|
||||||
return self.defaults[name]
|
|
||||||
|
|
||||||
def set(self, name, value, channel=None):
|
|
||||||
name = callbacks.canonicalName(name)
|
|
||||||
if name not in self.originalNames:
|
|
||||||
raise KeyError, name
|
|
||||||
if ',' in name:
|
|
||||||
raise ValueError, 'There can be no commas in the name.'
|
|
||||||
self.unparsedValues[(channel, name)] = value
|
|
||||||
if channel is not None:
|
|
||||||
d = self.channels.setdefault(channel, {})
|
|
||||||
d[name] = self.types[name](value)
|
|
||||||
else:
|
|
||||||
self.defaults[name] = self.types[name](value)
|
|
||||||
|
|
||||||
def help(self, name):
|
|
||||||
return self.helps[callbacks.canonicalName(name)]
|
|
||||||
|
|
||||||
def names(self):
|
|
||||||
L = self.originalNames.values()
|
|
||||||
L.sort()
|
|
||||||
return L
|
|
||||||
|
|
||||||
class ConfigurableTypeError(TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def ConfigurableBoolType(s):
|
|
||||||
s = s.lower()
|
|
||||||
if s in ('true', 'enable', 'on'):
|
|
||||||
return True
|
|
||||||
elif s in ('false', 'disable', 'off'):
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
s = 'Value must be one of on/off/true/false/enable/disable.'
|
|
||||||
raise ConfigurableTypeError, s
|
|
||||||
|
|
||||||
def ConfigurableStrType(s):
|
|
||||||
if s and s[0] not in '\'"' and s[-1] not in '\'"':
|
|
||||||
s = repr(s)
|
|
||||||
try:
|
|
||||||
v = utils.safeEval(s)
|
|
||||||
if type(v) is not str:
|
|
||||||
raise ValueError
|
|
||||||
except ValueError:
|
|
||||||
raise ConfigurableTypeError, 'Value must be a string.'
|
|
||||||
return v
|
|
||||||
|
|
||||||
def ConfigurableIntType(s):
|
|
||||||
try:
|
|
||||||
return int(s)
|
|
||||||
except ValueError:
|
|
||||||
raise ConfigurableTypeError, 'Value must be an int.'
|
|
||||||
|
|
||||||
class Configurable(object):
|
|
||||||
"""A mixin class to provide a "config" command that can be consistent
|
|
||||||
across all plugins, in order to unify the configuration for each plugin.
|
|
||||||
|
|
||||||
Plugins subclassing this should have a "configurables" attribute which is
|
|
||||||
a ConfigurableDictionary initialized with a list of 4-tuples of
|
|
||||||
(name, type, default, help). Name is the string name of the config
|
|
||||||
variable; type is a function taking a string and returning some value of
|
|
||||||
the type the variable is supposed to be; default is the default value the
|
|
||||||
variable should take on; help is a string that'll be returned to describe
|
|
||||||
the purpose of the config variable.
|
|
||||||
"""
|
|
||||||
def __init__(self):
|
|
||||||
className = self.__class__.__name__
|
|
||||||
self.filename = os.path.join(conf.confDir, '%s-configurable'%className)
|
|
||||||
if os.path.exists(self.filename):
|
|
||||||
fd = file(self.filename)
|
|
||||||
for line in fd:
|
|
||||||
line = line.rstrip()
|
|
||||||
(channel, name, value) = line.split(',', 2)
|
|
||||||
if channel == 'default':
|
|
||||||
channel = None
|
|
||||||
try:
|
|
||||||
self.configurables.set(name, eval(value), channel)
|
|
||||||
except ConfigurableTypeError, e:
|
|
||||||
s = 'Couldn\'t read configurable from file: %s'
|
|
||||||
self.log.warning(s, e)
|
|
||||||
except KeyError, e:
|
|
||||||
s = 'Configurable variable %s doesn\'t exist anymore.'
|
|
||||||
self.log.warning(s, name)
|
|
||||||
|
|
||||||
def die(self):
|
|
||||||
fd = file(self.filename, 'w')
|
|
||||||
L = self.configurables.unparsedValues.items()
|
|
||||||
L.sort()
|
|
||||||
for ((channel, name), value) in L:
|
|
||||||
if channel is None:
|
|
||||||
channel = 'default'
|
|
||||||
name = self.configurables.originalNames[name]
|
|
||||||
fd.write('%s,%s,%r\n' % (channel, name, value))
|
|
||||||
fd.close()
|
|
||||||
|
|
||||||
def config(self, irc, msg, args):
|
|
||||||
"""[<channel>] [<name>] [<value>]
|
|
||||||
|
|
||||||
Sets the value of config variable <name> to <value> on <channel>. If
|
|
||||||
<name> is given but <value> is not, returns the help and current value
|
|
||||||
for <name>. If neither <name> nor <value> is given, returns the valid
|
|
||||||
config variables for this plugin. <channel> is only necessary if the
|
|
||||||
message isn't sent in the channel itself.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
channel = privmsgs.getChannel(msg, args)
|
|
||||||
capability = ircdb.makeChannelCapability(channel, 'op')
|
|
||||||
except callbacks.ArgumentError:
|
|
||||||
raise
|
|
||||||
except callbacks.Error:
|
|
||||||
channel = None
|
|
||||||
capability = 'admin'
|
|
||||||
if not ircdb.checkCapability(msg.prefix, capability):
|
|
||||||
irc.error(msg, conf.replyNoCapability % capability)
|
|
||||||
return
|
|
||||||
(name, value) = privmsgs.getArgs(args, required=0, optional=2)
|
|
||||||
if not name:
|
|
||||||
irc.reply(msg, utils.commaAndify(self.configurables.names()))
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
if not value:
|
|
||||||
help = self.configurables.help(name)
|
|
||||||
value = self.configurables.get(name, channel=channel)
|
|
||||||
s = '%s: %s (Current value: %r)' % (name, help, value)
|
|
||||||
irc.reply(msg, s)
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
self.configurables.set(name, value, channel)
|
|
||||||
irc.reply(msg, conf.replySuccess)
|
|
||||||
except ConfigurableTypeError, e:
|
|
||||||
irc.error(msg, str(e))
|
|
||||||
except KeyError:
|
|
||||||
irc.error(msg, 'There is no config variable %r' % name)
|
|
||||||
|
|
||||||
|
|
||||||
_randomnickRe = re.compile(r'\$randomnick', re.I)
|
_randomnickRe = re.compile(r'\$randomnick', re.I)
|
||||||
_randomdateRe = re.compile(r'\$randomdate', re.I)
|
_randomdateRe = re.compile(r'\$randomdate', re.I)
|
||||||
_randomintRe = re.compile(r'\$randomint', re.I)
|
_randomintRe = re.compile(r'\$randomint', re.I)
|
||||||
|
Loading…
Reference in New Issue
Block a user