mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-02-17 06:00:42 +01:00
HUUUUUUUUGE Configuration change.
This commit is contained in:
parent
b18ad358ee
commit
6ca78924f3
@ -1,3 +1,6 @@
|
|||||||
|
* Removed Admin.setprefixchar, since it's unneeded with the new
|
||||||
|
configuration.
|
||||||
|
|
||||||
* Changed the reply method of the irc object given to plugins not
|
* Changed the reply method of the irc object given to plugins not
|
||||||
to require a msg object.
|
to require a msg object.
|
||||||
|
|
||||||
|
@ -40,5 +40,11 @@ othersDir = os.path.join(installDir, 'others')
|
|||||||
sys.path.insert(0, srcDir)
|
sys.path.insert(0, srcDir)
|
||||||
sys.path.insert(0, othersDir)
|
sys.path.insert(0, othersDir)
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
import registry
|
||||||
|
|
||||||
|
supybot = registry.Group()
|
||||||
|
supybot.setName('supybot')
|
||||||
|
supybot.registerGroup('plugins')
|
||||||
|
|
||||||
|
|
||||||
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -156,7 +156,7 @@ def makeNewAlias(name, alias):
|
|||||||
class Alias(callbacks.Privmsg):
|
class Alias(callbacks.Privmsg):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
filename = os.path.join(conf.dataDir, 'Aliases.db')
|
filename = os.path.join(conf.supybot.directories.data(), 'Aliases.db')
|
||||||
# Schema: {name: [alias, locked]}
|
# Schema: {name: [alias, locked]}
|
||||||
self.aliases = structures.PersistentDictionary(filename)
|
self.aliases = structures.PersistentDictionary(filename)
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ class Alias(callbacks.Privmsg):
|
|||||||
def addAlias(self, irc, name, alias, lock=False):
|
def addAlias(self, irc, name, alias, lock=False):
|
||||||
if self._invalidCharsRe.search(name):
|
if self._invalidCharsRe.search(name):
|
||||||
raise AliasError, 'Names cannot contain spaces or square brackets.'
|
raise AliasError, 'Names cannot contain spaces or square brackets.'
|
||||||
if conf.enablePipeSyntax and '|' in name:
|
if conf.supybot.pipeSyntax() and '|' in name:
|
||||||
raise AliasError, 'Names cannot contain pipes.'
|
raise AliasError, 'Names cannot contain pipes.'
|
||||||
realName = callbacks.canonicalName(name)
|
realName = callbacks.canonicalName(name)
|
||||||
if name != realName:
|
if name != realName:
|
||||||
|
@ -67,7 +67,7 @@ priorityKeys = ['p1', 'p2', 'p3', 'p4', 'p5', 'Low', 'Normal', 'High',
|
|||||||
severityKeys = ['enhancement', 'trivial', 'minor', 'normal', 'major',
|
severityKeys = ['enhancement', 'trivial', 'minor', 'normal', 'major',
|
||||||
'critical', 'blocker']
|
'critical', 'blocker']
|
||||||
|
|
||||||
dbfilename = os.path.join(conf.dataDir, 'Bugzilla.db')
|
dbfilename = os.path.join(conf.supybot.directories.data(), 'Bugzilla.db')
|
||||||
|
|
||||||
def makeDb(filename):
|
def makeDb(filename):
|
||||||
if os.path.exists(filename):
|
if os.path.exists(filename):
|
||||||
|
@ -91,7 +91,8 @@ class ChannelLogger(irclib.IrcCallback):
|
|||||||
return self.logs[channel]
|
return self.logs[channel]
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
log = file(os.path.join(conf.logDir, '%s.log' % channel), 'a')
|
logDir = conf.supybot.directories.log()
|
||||||
|
log = file(os.path.join(logDir, '%s.log' % channel), 'a')
|
||||||
self.logs[channel] = log
|
self.logs[channel] = log
|
||||||
return log
|
return log
|
||||||
except IOError:
|
except IOError:
|
||||||
@ -99,7 +100,7 @@ class ChannelLogger(irclib.IrcCallback):
|
|||||||
return StringIO()
|
return StringIO()
|
||||||
|
|
||||||
def timestamp(self, log):
|
def timestamp(self, log):
|
||||||
log.write(time.strftime(conf.logTimestampFormat))
|
log.write(time.strftime(conf.supybot.log.timestampFormat()))
|
||||||
log.write(' ')
|
log.write(' ')
|
||||||
|
|
||||||
def doPrivmsg(self, irc, msg):
|
def doPrivmsg(self, irc, msg):
|
||||||
|
@ -71,8 +71,8 @@ class DCC(callbacks.Privmsg):
|
|||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
sock.settimeout(60)
|
sock.settimeout(60)
|
||||||
host = ircutils.hostFromHostmask(irc.prefix)
|
host = ircutils.hostFromHostmask(irc.prefix)
|
||||||
if conf.externalIP is not None:
|
if conf.supybot.externalIP():
|
||||||
ip = conf.externalIP
|
ip = conf.supybot.externalIP()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
ip = socket.gethostbyname(host)
|
ip = socket.gethostbyname(host)
|
||||||
|
@ -93,7 +93,7 @@ class Debian(callbacks.Privmsg,
|
|||||||
'debian/dists/unstable/Contents-i386.gz',
|
'debian/dists/unstable/Contents-i386.gz',
|
||||||
604800, None)
|
604800, None)
|
||||||
}
|
}
|
||||||
contents = os.path.join(conf.dataDir, 'Contents-i386.gz')
|
contents = os.path.join(conf.supybot.directories.data(),'Contents-i386.gz')
|
||||||
configurables = configurable.Dictionary(
|
configurables = configurable.Dictionary(
|
||||||
[('python-zegrep', configurable.BoolType, 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
|
||||||
|
@ -51,7 +51,7 @@ except ImportError:
|
|||||||
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
||||||
'plugin. Download it at <http://pysqlite.sf.net/>'
|
'plugin. Download it at <http://pysqlite.sf.net/>'
|
||||||
|
|
||||||
dbfilename = os.path.join(conf.dataDir, 'Dunno.db')
|
dbfilename = os.path.join(conf.supybot.directories.data(), 'Dunno.db')
|
||||||
|
|
||||||
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
|
||||||
|
@ -172,7 +172,8 @@ class Ebay(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
|||||||
return '; '.join(resp)
|
return '; '.join(resp)
|
||||||
else:
|
else:
|
||||||
raise EbayError, 'That doesn\'t appear to be a proper eBay ' \
|
raise EbayError, 'That doesn\'t appear to be a proper eBay ' \
|
||||||
'auction page. (%s)' % conf.replyPossibleBug
|
'auction page. (%s)' % \
|
||||||
|
conf.supybot.replies.possibleBug()
|
||||||
|
|
||||||
Class = Ebay
|
Class = Ebay
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ class Enforcer(callbacks.Privmsg, configurable.Mixin):
|
|||||||
irc.queueMsg(ircmsgs.topic(channel, self.topics[channel]))
|
irc.queueMsg(ircmsgs.topic(channel, self.topics[channel]))
|
||||||
if self.configurables.get('revenge', channel):
|
if self.configurables.get('revenge', channel):
|
||||||
irc.queueMsg(ircmsgs.kick(channel, msg.nick,
|
irc.queueMsg(ircmsgs.kick(channel, msg.nick,
|
||||||
conf.replyNoCapability %
|
conf.supybot.replies.noCapability() %
|
||||||
_chanCap(channel, 'topic')))
|
_chanCap(channel, 'topic')))
|
||||||
else:
|
else:
|
||||||
self.topics[channel] = msg.args[1]
|
self.topics[channel] = msg.args[1]
|
||||||
|
@ -319,7 +319,7 @@ class Factoids(plugins.ChannelDBHandler,
|
|||||||
counter = 0
|
counter = 0
|
||||||
for (added_by, added_at) in factoids:
|
for (added_by, added_at) in factoids:
|
||||||
counter += 1
|
counter += 1
|
||||||
added_at = time.strftime(conf.humanTimestampFormat,
|
added_at = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(added_at)))
|
time.localtime(int(added_at)))
|
||||||
L.append('#%s was added by %s at %s' % (counter,added_by,added_at))
|
L.append('#%s was added by %s at %s' % (counter,added_by,added_at))
|
||||||
factoids = '; '.join(L)
|
factoids = '; '.join(L)
|
||||||
|
@ -159,7 +159,7 @@ class Gameknot(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
|||||||
raise callbacks.Error, 'No user %s exists.' % name
|
raise callbacks.Error, 'No user %s exists.' % name
|
||||||
else:
|
else:
|
||||||
raise callbacks.Error,'The format of the page was odd. %s' % \
|
raise callbacks.Error,'The format of the page was odd. %s' % \
|
||||||
conf.replyPossibleBug
|
conf.supybot.replies.possibleBug()
|
||||||
except urllib2.URLError:
|
except urllib2.URLError:
|
||||||
raise callbacks.Error, 'Couldn\'t connect to gameknot.com'
|
raise callbacks.Error, 'Couldn\'t connect to gameknot.com'
|
||||||
|
|
||||||
|
@ -63,11 +63,13 @@ class HeraldDB(object):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.heralds = {}
|
self.heralds = {}
|
||||||
self.open()
|
self.open()
|
||||||
|
dataDir = conf.supybot.directories.data()
|
||||||
|
self.filename = os.path.join(dataDir, 'Herald.db')
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
filename = os.path.join(conf.dataDir, 'Herald.db')
|
dataDir = conf.supybot.directories.data()
|
||||||
if os.path.exists(filename):
|
if os.path.exists(self.filename):
|
||||||
fd = file(filename)
|
fd = file(self.filename)
|
||||||
for line in fd:
|
for line in fd:
|
||||||
line = line.rstrip()
|
line = line.rstrip()
|
||||||
try:
|
try:
|
||||||
@ -81,7 +83,7 @@ class HeraldDB(object):
|
|||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
fd = file(os.path.join(conf.dataDir, 'Herald.db'), 'w')
|
fd = file(self.filename, 'w')
|
||||||
L = self.heralds.items()
|
L = self.heralds.items()
|
||||||
L.sort()
|
L.sort()
|
||||||
for ((id, channel), msg) in L:
|
for ((id, channel), msg) in L:
|
||||||
|
@ -52,7 +52,7 @@ except ImportError:
|
|||||||
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
||||||
'plugin. Download it at <http://pysqlite.sf.net/>'
|
'plugin. Download it at <http://pysqlite.sf.net/>'
|
||||||
|
|
||||||
dbfilename = os.path.join(conf.dataDir, 'Infobot.db')
|
dbfilename = os.path.join(conf.supybot.directories.data(), 'Infobot.db')
|
||||||
|
|
||||||
def configure(onStart, afterConnect, advanced):
|
def configure(onStart, afterConnect, advanced):
|
||||||
from questions import expect, anything, something, yn
|
from questions import expect, anything, something, yn
|
||||||
|
@ -64,13 +64,16 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
onStart.append('load Lookup')
|
onStart.append('load Lookup')
|
||||||
print 'This module allows you to define commands that do a simple key'
|
print 'This module allows you to define commands that do a simple key'
|
||||||
print 'lookup and return some simple value. It has a command "add"'
|
print 'lookup and return some simple value. It has a command "add"'
|
||||||
|
### TODO: fix conf.dataDir here. I'm waiting until we rewrite this with
|
||||||
|
### a proper question.py print statement.
|
||||||
print 'that takes a command name and a file in conf.dataDir and adds a'
|
print 'that takes a command name and a file in conf.dataDir and adds a'
|
||||||
print 'command with that name that responds with mapping from that file.'
|
print 'command with that name that responds with mapping from that file.'
|
||||||
print 'The file itself should be composed of lines of the form key:value.'
|
print 'The file itself should be composed of lines of the form key:value.'
|
||||||
while yn('Would you like to add a file?') == 'y':
|
while yn('Would you like to add a file?') == 'y':
|
||||||
filename = something('What\'s the filename?')
|
filename = something('What\'s the filename?')
|
||||||
try:
|
try:
|
||||||
fd = file(os.path.join(conf.dataDir, filename))
|
dataDir = conf.supybot.directories.data()
|
||||||
|
fd = file(os.path.join(dataDir, filename))
|
||||||
except EnvironmentError, e:
|
except EnvironmentError, e:
|
||||||
print 'I couldn\'t open that file: %s' % e
|
print 'I couldn\'t open that file: %s' % e
|
||||||
continue
|
continue
|
||||||
@ -97,7 +100,8 @@ class Lookup(callbacks.Privmsg):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
self.lookupDomains = sets.Set()
|
self.lookupDomains = sets.Set()
|
||||||
self.dbHandler = LookupDB(name=os.path.join(conf.dataDir, 'Lookup'))
|
dataDir = conf.supybot.directories.data()
|
||||||
|
self.dbHandler = LookupDB(name=os.path.join(dataDir, 'Lookup'))
|
||||||
|
|
||||||
def _shrink(self, s):
|
def _shrink(self, s):
|
||||||
return utils.ellipsisify(s, 50)
|
return utils.ellipsisify(s, 50)
|
||||||
@ -132,8 +136,8 @@ class Lookup(callbacks.Privmsg):
|
|||||||
|
|
||||||
Adds a lookup for <name> with the key/value pairs specified in the
|
Adds a lookup for <name> with the key/value pairs specified in the
|
||||||
colon-delimited file specified by <filename>. <filename> is searched
|
colon-delimited file specified by <filename>. <filename> is searched
|
||||||
for in conf.dataDir. If <name> is not singular, we try to make it
|
for in conf.supybot.directories.data. If <name> is not singular, we
|
||||||
singular before creating the command.
|
try to make it singular before creating the command.
|
||||||
"""
|
"""
|
||||||
(name, filename) = privmsgs.getArgs(args, required=2)
|
(name, filename) = privmsgs.getArgs(args, required=2)
|
||||||
name = utils.depluralize(name)
|
name = utils.depluralize(name)
|
||||||
@ -151,7 +155,8 @@ class Lookup(callbacks.Privmsg):
|
|||||||
except sqlite.DatabaseError:
|
except sqlite.DatabaseError:
|
||||||
# Good, there's no such database.
|
# Good, there's no such database.
|
||||||
try:
|
try:
|
||||||
filename = os.path.join(conf.dataDir, filename)
|
dataDir = conf.supybot.directories.data()
|
||||||
|
filename = os.path.join(dataDir, filename)
|
||||||
fd = file(filename)
|
fd = file(filename)
|
||||||
except EnvironmentError, e:
|
except EnvironmentError, e:
|
||||||
irc.error('Could not open %s: %s' % (filename, e.args[1]))
|
irc.error('Could not open %s: %s' % (filename, e.args[1]))
|
||||||
|
@ -65,7 +65,7 @@ except ImportError:
|
|||||||
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
||||||
'plugin. Download it at <http://pysqlite.sf.net/>'
|
'plugin. Download it at <http://pysqlite.sf.net/>'
|
||||||
|
|
||||||
dbfilename = os.path.join(conf.dataDir, 'MoobotFactoids')
|
dbfilename = os.path.join(conf.supybot.directories.data(), 'MoobotFactoids')
|
||||||
|
|
||||||
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
|
||||||
@ -421,19 +421,19 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
|||||||
# First, creation info.
|
# First, creation info.
|
||||||
# Map the integer created_by to the username
|
# Map the integer created_by to the username
|
||||||
creat_by = ircdb.users.getUser(created_by).name
|
creat_by = ircdb.users.getUser(created_by).name
|
||||||
creat_at = time.strftime(conf.humanTimestampFormat,
|
creat_at = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(created_at)))
|
time.localtime(int(created_at)))
|
||||||
s += "Created by %s on %s." % (creat_by, creat_at)
|
s += "Created by %s on %s." % (creat_by, creat_at)
|
||||||
# Next, modification info, if any.
|
# Next, modification info, if any.
|
||||||
if modified_by is not None:
|
if modified_by is not None:
|
||||||
mod_by = ircdb.users.getUser(modified_by).name
|
mod_by = ircdb.users.getUser(modified_by).name
|
||||||
mod_at = time.strftime(conf.humanTimestampFormat,
|
mod_at = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(modified_at)))
|
time.localtime(int(modified_at)))
|
||||||
s += " Last modified by %s on %s." % (mod_by, mod_at)
|
s += " Last modified by %s on %s." % (mod_by, mod_at)
|
||||||
# Next, last requested info, if any
|
# Next, last requested info, if any
|
||||||
if last_requested_by is not None:
|
if last_requested_by is not None:
|
||||||
last_by = last_requested_by # not an int user id
|
last_by = last_requested_by # not an int user id
|
||||||
last_at = time.strftime(conf.humanTimestampFormat,
|
last_at = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(last_requested_at)))
|
time.localtime(int(last_requested_at)))
|
||||||
req_count = requested_count
|
req_count = requested_count
|
||||||
times_str = utils.nItems('time', requested_count)
|
times_str = utils.nItems('time', requested_count)
|
||||||
@ -441,7 +441,7 @@ class MoobotFactoids(callbacks.PrivmsgCommandAndRegexp):
|
|||||||
(last_by, last_at, times_str)
|
(last_by, last_at, times_str)
|
||||||
# Last, locked info
|
# Last, locked info
|
||||||
if locked_at is not None:
|
if locked_at is not None:
|
||||||
lock_at = time.strftime(conf.humanTimestampFormat,
|
lock_at = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(locked_at)))
|
time.localtime(int(locked_at)))
|
||||||
lock_by = ircdb.users.getUser(locked_by).name
|
lock_by = ircdb.users.getUser(locked_by).name
|
||||||
s += " Locked by %s on %s." % (lock_by, lock_at)
|
s += " Locked by %s on %s." % (lock_by, lock_at)
|
||||||
|
@ -139,14 +139,14 @@ class News(plugins.ChannelDBHandler, callbacks.Privmsg):
|
|||||||
if int(expires_at) == 0:
|
if int(expires_at) == 0:
|
||||||
s = '%s (Subject: "%s", added by %s on %s)' % \
|
s = '%s (Subject: "%s", added by %s on %s)' % \
|
||||||
(item, subject, added_by,
|
(item, subject, added_by,
|
||||||
time.strftime(conf.humanTimestampFormat,
|
time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(added_at))))
|
time.localtime(int(added_at))))
|
||||||
else:
|
else:
|
||||||
s = '%s (Subject: "%s", added by %s on %s, expires at %s)' % \
|
s = '%s (Subject: "%s", added by %s on %s, expires at %s)' % \
|
||||||
(item, subject, added_by,
|
(item, subject, added_by,
|
||||||
time.strftime(conf.humanTimestampFormat,
|
time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(added_at))),
|
time.localtime(int(added_at))),
|
||||||
time.strftime(conf.humanTimestampFormat,
|
time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(expires_at))))
|
time.localtime(int(expires_at))))
|
||||||
irc.reply(s)
|
irc.reply(s)
|
||||||
|
|
||||||
|
@ -57,8 +57,6 @@ except ImportError:
|
|||||||
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
raise callbacks.Error, 'You need to have PySQLite installed to use this ' \
|
||||||
'plugin. Download it at <http://pysqlite.sf.net/>'
|
'plugin. Download it at <http://pysqlite.sf.net/>'
|
||||||
|
|
||||||
dbfilename = os.path.join(conf.dataDir, 'Notes.db')
|
|
||||||
|
|
||||||
class NoteDb(plugins.DBHandler):
|
class NoteDb(plugins.DBHandler):
|
||||||
def makeDb(self, filename):
|
def makeDb(self, filename):
|
||||||
"create Notes database and tables"
|
"create Notes database and tables"
|
||||||
@ -85,7 +83,8 @@ class NoteDb(plugins.DBHandler):
|
|||||||
class Note(callbacks.Privmsg):
|
class Note(callbacks.Privmsg):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
self.dbHandler = NoteDb(name=os.path.join(conf.dataDir, 'Notes'))
|
dataDir = conf.supybot.directories.data()
|
||||||
|
self.dbHandler = NoteDb(name=os.path.join(dataDir, 'Notes'))
|
||||||
|
|
||||||
def setAsRead(self, id):
|
def setAsRead(self, id):
|
||||||
db = self.dbHandler.getDb()
|
db = self.dbHandler.getDb()
|
||||||
|
@ -256,7 +256,7 @@ class QuoteGrabs(plugins.ChannelDBHandler,
|
|||||||
irc.error('No quotegrab for id %r' % id)
|
irc.error('No quotegrab for id %r' % id)
|
||||||
return
|
return
|
||||||
quote, hostmask, timestamp = cursor.fetchone()
|
quote, hostmask, timestamp = cursor.fetchone()
|
||||||
time_str = time.strftime(conf.humanTimestampFormat,
|
time_str = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(float(timestamp)))
|
time.localtime(float(timestamp)))
|
||||||
irc.reply('%s (Said by: %s on %s)' % (quote, hostmask, time_str))
|
irc.reply('%s (Said by: %s on %s)' % (quote, hostmask, time_str))
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ class Quotes(plugins.ChannelDBHandler, callbacks.Privmsg):
|
|||||||
cursor.execute("""SELECT * FROM quotes WHERE id=%s""", id)
|
cursor.execute("""SELECT * FROM quotes WHERE id=%s""", id)
|
||||||
if cursor.rowcount == 1:
|
if cursor.rowcount == 1:
|
||||||
(id, added_by, added_at, quote) = cursor.fetchone()
|
(id, added_by, added_at, quote) = cursor.fetchone()
|
||||||
timestamp = time.strftime(conf.humanTimestampFormat,
|
timestamp = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(added_at)))
|
time.localtime(int(added_at)))
|
||||||
irc.reply('Quote %r added by %s at %s.' %
|
irc.reply('Quote %r added by %s at %s.' %
|
||||||
(quote, added_by, timestamp))
|
(quote, added_by, timestamp))
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
###
|
###
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Logs raw IRC messages to a file, conf.dataDir/raw.log
|
Logs raw IRC messages to a file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
@ -47,7 +47,8 @@ import irclib
|
|||||||
###
|
###
|
||||||
class RawLogger(irclib.IrcCallback):
|
class RawLogger(irclib.IrcCallback):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.fd = file(os.path.join(conf.logDir, 'raw.log'), 'a')
|
logDir = conf.supybot.directories.log()
|
||||||
|
self.fd = file(os.path.join(logDir, 'raw.log'), 'a')
|
||||||
world.flushers.append(self.fd.flush)
|
world.flushers.append(self.fd.flush)
|
||||||
|
|
||||||
def inFilter(self, irc, msg):
|
def inFilter(self, irc, msg):
|
||||||
|
@ -452,7 +452,7 @@ class Relay(callbacks.Privmsg, configurable.Mixin):
|
|||||||
channels = utils.commaAndify(L)
|
channels = utils.commaAndify(L)
|
||||||
if '317' in d:
|
if '317' in d:
|
||||||
idle = utils.timeElapsed(d['317'].args[2])
|
idle = utils.timeElapsed(d['317'].args[2])
|
||||||
signon = time.strftime(conf.humanTimestampFormat,
|
signon = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(float(d['317'].args[3])))
|
time.localtime(float(d['317'].args[3])))
|
||||||
else:
|
else:
|
||||||
idle = '<unknown>'
|
idle = '<unknown>'
|
||||||
|
@ -170,7 +170,7 @@ class Sourceforge(callbacks.PrivmsgCommandAndRegexp, configurable.Mixin):
|
|||||||
resp = imap(lambda s: utils.ellipsisify(s, 50), resp)
|
resp = imap(lambda s: utils.ellipsisify(s, 50), resp)
|
||||||
return '%s' % utils.commaAndify(resp)
|
return '%s' % utils.commaAndify(resp)
|
||||||
raise callbacks.Error, 'No Trackers were found. (%s)' % \
|
raise callbacks.Error, 'No Trackers were found. (%s)' % \
|
||||||
conf.replyPossibleBug
|
conf.supybot.replies.possibleBug()
|
||||||
except webutils.WebError, e:
|
except webutils.WebError, e:
|
||||||
raise callbacks.Error, str(e)
|
raise callbacks.Error, str(e)
|
||||||
|
|
||||||
|
@ -61,7 +61,8 @@ def configure(onStart, afterConnect, advanced):
|
|||||||
|
|
||||||
class UptimeDB(object):
|
class UptimeDB(object):
|
||||||
def __init__(self, filename='uptimes'):
|
def __init__(self, filename='uptimes'):
|
||||||
self.filename = os.path.join(conf.dataDir, filename)
|
dataDir = conf.supybot.directories.data()
|
||||||
|
self.filename = os.path.join(dataDir, filename)
|
||||||
if os.path.exists(self.filename):
|
if os.path.exists(self.filename):
|
||||||
fd = file(self.filename)
|
fd = file(self.filename)
|
||||||
s = fd.read()
|
s = fd.read()
|
||||||
@ -137,9 +138,9 @@ class Status(callbacks.Privmsg):
|
|||||||
return
|
return
|
||||||
def format((started, ended)):
|
def format((started, ended)):
|
||||||
return '%s until %s; up for %s' % \
|
return '%s until %s; up for %s' % \
|
||||||
(time.strftime(conf.humanTimestampFormat,
|
(time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(started)),
|
time.localtime(started)),
|
||||||
time.strftime(conf.humanTimestampFormat,
|
time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(ended)),
|
time.localtime(ended)),
|
||||||
utils.timeElapsed(ended-started))
|
utils.timeElapsed(ended-started))
|
||||||
irc.reply(utils.commaAndify(imap(format, L)))
|
irc.reply(utils.commaAndify(imap(format, L)))
|
||||||
@ -186,7 +187,7 @@ class Status(callbacks.Privmsg):
|
|||||||
try:
|
try:
|
||||||
r = os.popen('ps -o rss -p %s' % pid)
|
r = os.popen('ps -o rss -p %s' % pid)
|
||||||
r.readline() # VSZ Header.
|
r.readline() # VSZ Header.
|
||||||
mem = r.readline().strip() + ' kB'
|
mem = r.readline().strip()
|
||||||
finally:
|
finally:
|
||||||
r.close()
|
r.close()
|
||||||
elif sys.platform.startswith('netbsd'):
|
elif sys.platform.startswith('netbsd'):
|
||||||
|
@ -87,7 +87,8 @@ class TodoDB(plugins.DBHandler):
|
|||||||
class Todo(callbacks.Privmsg):
|
class Todo(callbacks.Privmsg):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
self.dbHandler = TodoDB(os.path.join(conf.dataDir, 'Todo'))
|
dataDir = conf.supybot.directories.data()
|
||||||
|
self.dbHandler = TodoDB(os.path.join(dataDir, 'Todo'))
|
||||||
|
|
||||||
def die(self):
|
def die(self):
|
||||||
self.dbHandler.die()
|
self.dbHandler.die()
|
||||||
@ -170,7 +171,7 @@ class Todo(callbacks.Privmsg):
|
|||||||
active = 'Inactive'
|
active = 'Inactive'
|
||||||
if pri:
|
if pri:
|
||||||
task += ', priority: %s' % pri
|
task += ', priority: %s' % pri
|
||||||
added_at = time.strftime(conf.humanTimestampFormat,
|
added_at = time.strftime(conf.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(added_at)))
|
time.localtime(int(added_at)))
|
||||||
s = "%s todo for %s: %s (Added at %s)" % \
|
s = "%s todo for %s: %s (Added at %s)" % \
|
||||||
(active, name, task, added_at)
|
(active, name, task, added_at)
|
||||||
|
@ -260,7 +260,7 @@ class URL(callbacks.PrivmsgCommandAndRegexp,
|
|||||||
return (tinyurl, updateDb)
|
return (tinyurl, updateDb)
|
||||||
|
|
||||||
def _formatUrl(self, url, added, addedBy):
|
def _formatUrl(self, url, added, addedBy):
|
||||||
when = time.strftime(conf.humanTimestampFormat,
|
when = time.strftime(conf.supybot.supybot.humanTimestampFormat(),
|
||||||
time.localtime(int(added)))
|
time.localtime(int(added)))
|
||||||
return '<%s> (added by %s at %s)' % (url, addedBy, when)
|
return '<%s> (added by %s at %s)' % (url, addedBy, when)
|
||||||
|
|
||||||
|
@ -160,9 +160,10 @@ class Words(callbacks.Privmsg, configurable.Mixin):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
callbacks.Privmsg.__init__(self)
|
callbacks.Privmsg.__init__(self)
|
||||||
configurable.Mixin.__init__(self)
|
configurable.Mixin.__init__(self)
|
||||||
self.dbHandler = WordsDB(os.path.join(conf.dataDir, 'Words'))
|
dataDir = conf.supybot.directories.data()
|
||||||
|
self.dbHandler = WordsDB(os.path.join(dataDir, 'Words'))
|
||||||
try:
|
try:
|
||||||
dictfile = os.path.join(conf.dataDir, 'dict')
|
dictfile = os.path.join(dataDir, 'dict')
|
||||||
self.wordList = file(dictfile).readlines()
|
self.wordList = file(dictfile).readlines()
|
||||||
self.gotDictFile = True
|
self.gotDictFile = True
|
||||||
except IOError:
|
except IOError:
|
||||||
@ -367,31 +368,7 @@ class Words(callbacks.Privmsg, configurable.Mixin):
|
|||||||
|
|
||||||
Class = Words
|
Class = Words
|
||||||
|
|
||||||
|
### TODO: Write a script to make the database.
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys, log
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
fd = sys.stdin
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
fd = file(sys.argv[1])
|
|
||||||
except EnvironmentError, e:
|
|
||||||
sys.stderr.write(str(e) + '\n')
|
|
||||||
sys.exit(-1)
|
|
||||||
db = WordsDB(os.path.join(conf.dataDir, 'Words')).getDb()
|
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""PRAGMA cache_size=20000""")
|
|
||||||
lineno = 0
|
|
||||||
for line in fd:
|
|
||||||
lineno += 1
|
|
||||||
line = line.rstrip()
|
|
||||||
try:
|
|
||||||
addWord(db, line)
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
sys.exit(-1)
|
|
||||||
except Exception, e:
|
|
||||||
sys.stderr.write('Error on line %s: %s\n' % (lineno, e))
|
|
||||||
db.commit()
|
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -38,6 +38,7 @@ __revision__ = "$Id$"
|
|||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import atexit
|
||||||
|
|
||||||
if sys.version_info < (2, 3, 0):
|
if sys.version_info < (2, 3, 0):
|
||||||
sys.stderr.write('This program requires Python >= 2.3.0\n')
|
sys.stderr.write('This program requires Python >= 2.3.0\n')
|
||||||
@ -105,6 +106,10 @@ if __name__ == '__main__':
|
|||||||
parser.add_option('-p', '--password', action='store',
|
parser.add_option('-p', '--password', action='store',
|
||||||
dest='password', default='',
|
dest='password', default='',
|
||||||
help='server password the bot should use')
|
help='server password the bot should use')
|
||||||
|
parser.add_option('', '--enable-eval', action='store_true',
|
||||||
|
dest='allowEval',
|
||||||
|
help='Determines whether the bot will '
|
||||||
|
'allow the evaluation of arbitrary Python code.')
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
@ -128,12 +133,12 @@ if __name__ == '__main__':
|
|||||||
log.info('Finished writing registry file.')
|
log.info('Finished writing registry file.')
|
||||||
atexit.register(closeRegistry)
|
atexit.register(closeRegistry)
|
||||||
|
|
||||||
nick = options.nick or conf.supybot.nick.get()
|
nick = options.nick or conf.supybot.nick()
|
||||||
user = options.user or conf.supybot.user.get()
|
user = options.user or conf.supybot.user()
|
||||||
ident = options.ident or conf.supybot.ident.get()
|
ident = options.ident or conf.supybot.ident()
|
||||||
password = options.password or conf.supybot.password.get()
|
password = options.password or conf.supybot.password()
|
||||||
|
|
||||||
server = options.server or conf.supybot.server.get()
|
server = options.server or conf.supybot.server()
|
||||||
if ':' in server:
|
if ':' in server:
|
||||||
serverAndPort = server.split(':', 1)
|
serverAndPort = server.split(':', 1)
|
||||||
serverAndPort[1] = int(serverAndPort[1])
|
serverAndPort[1] = int(serverAndPort[1])
|
||||||
@ -150,12 +155,15 @@ if __name__ == '__main__':
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
log.warning('Psyco isn\'t installed, cannot -OO.')
|
log.warning('Psyco isn\'t installed, cannot -OO.')
|
||||||
|
|
||||||
if not os.path.exists(conf.supybot.directories.log.get()):
|
if options.allowEval:
|
||||||
os.mkdir(conf.supybot.directories.log.get())
|
conf.allowEval = True
|
||||||
if not os.path.exists(conf.supybot.directories.conf.get()):
|
|
||||||
os.mkdir(conf.supybot.directories.conf.get())
|
if not os.path.exists(conf.supybot.directories.log()):
|
||||||
if not os.path.exists(conf.supybot.directories.data.get()):
|
os.mkdir(conf.supybot.directories.log())
|
||||||
os.mkdir(conf.supybot.directories.data.get())
|
if not os.path.exists(conf.supybot.directories.conf()):
|
||||||
|
os.mkdir(conf.supybot.directories.conf())
|
||||||
|
if not os.path.exists(conf.supybot.directories.data()):
|
||||||
|
os.mkdir(conf.supybot.directories.data())
|
||||||
|
|
||||||
import irclib
|
import irclib
|
||||||
import ircmsgs
|
import ircmsgs
|
||||||
|
3
setup.py
3
setup.py
@ -89,7 +89,8 @@ setup(
|
|||||||
'supybot.others.unum': os.path.join('others', 'unum'),
|
'supybot.others.unum': os.path.join('others', 'unum'),
|
||||||
'supybot.others.unum.units':
|
'supybot.others.unum.units':
|
||||||
os.path.join(os.path.join('others', 'unum'), 'units')},
|
os.path.join(os.path.join('others', 'unum'), 'units')},
|
||||||
scripts=['scripts/supybot-wizard',
|
scripts=['scripts/supybot',
|
||||||
|
'scripts/supybot-wizard',
|
||||||
'scripts/supybot-adduser',
|
'scripts/supybot-adduser',
|
||||||
'scripts/supybot-newplugin']
|
'scripts/supybot-newplugin']
|
||||||
)
|
)
|
||||||
|
59
src/Admin.py
59
src/Admin.py
@ -60,6 +60,10 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
privmsgs.CapabilityCheckingPrivmsg.__init__(self)
|
privmsgs.CapabilityCheckingPrivmsg.__init__(self)
|
||||||
self.joins = {}
|
self.joins = {}
|
||||||
|
|
||||||
|
def do376(self, irc, msg):
|
||||||
|
irc.queueMsg(ircmsgs.joins(conf.supybot.channels()))
|
||||||
|
do422 = do377 = do376
|
||||||
|
|
||||||
def do471(self, irc, msg):
|
def do471(self, irc, msg):
|
||||||
try:
|
try:
|
||||||
@ -107,7 +111,7 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
|
|
||||||
def doInvite(self, irc, msg):
|
def doInvite(self, irc, msg):
|
||||||
if msg.args[1] not in irc.state.channels:
|
if msg.args[1] not in irc.state.channels:
|
||||||
if conf.alwaysJoinOnInvite:
|
if conf.supybot.alwaysJoinOnInvite():
|
||||||
irc.queueMsg(ircmsgs.join(msg.args[1]))
|
irc.queueMsg(ircmsgs.join(msg.args[1]))
|
||||||
else:
|
else:
|
||||||
if ircdb.checkCapability(msg.prefix, 'admin'):
|
if ircdb.checkCapability(msg.prefix, 'admin'):
|
||||||
@ -182,16 +186,14 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
if command in ('enable', 'identify'):
|
if command in ('enable', 'identify'):
|
||||||
irc.error('You can\'t disable %s!' % command)
|
irc.error('You can\'t disable %s!' % command)
|
||||||
else:
|
else:
|
||||||
# This has to know that defaultCapabilties gets turned into a
|
|
||||||
# dictionary.
|
|
||||||
try:
|
try:
|
||||||
capability = ircdb.makeAntiCapability(command)
|
capability = ircdb.makeAntiCapability(command)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
irc.error('%r is not a valid command.' % command)
|
irc.error('%r is not a valid command.' % command)
|
||||||
return
|
return
|
||||||
if command in conf.defaultCapabilities:
|
if command in conf.supybot.defaultCapabilities():
|
||||||
conf.defaultCapabilities.remove(command)
|
conf.supybot.defaultCapabilities().remove(command)
|
||||||
conf.defaultCapabilities.add(capability)
|
conf.supybot.defaultCapabilities().add(capability)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
|
|
||||||
def enable(self, irc, msg, args):
|
def enable(self, irc, msg, args):
|
||||||
@ -205,8 +207,8 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
irc.error('%r is not a valid command.' % command)
|
irc.error('%r is not a valid command.' % command)
|
||||||
return
|
return
|
||||||
if anticapability in conf.defaultCapabilities:
|
if anticapability in conf.supybot.defaultCapabilities():
|
||||||
conf.defaultCapabilities.remove(anticapability)
|
conf.supybot.defaultCapabilities().remove(anticapability)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
else:
|
else:
|
||||||
irc.error('That command wasn\'t disabled.')
|
irc.error('That command wasn\'t disabled.')
|
||||||
@ -228,14 +230,14 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
|
|
||||||
# Thus, the owner capability can't be given in the bot. Admin users
|
# Thus, the owner capability can't be given in the bot. Admin users
|
||||||
# can only give out capabilities they have themselves (which will
|
# can only give out capabilities they have themselves (which will
|
||||||
# depend on both conf.defaultAllow and conf.defaultCapabilities), but
|
# depend on both conf.supybot.defaultAllow and
|
||||||
# generally means they can't mess with channel capabilities.
|
# conf.supybot.defaultCapabilities), but generally means they can't
|
||||||
|
# mess with channel capabilities.
|
||||||
(name, capability) = privmsgs.getArgs(args, required=2)
|
(name, capability) = privmsgs.getArgs(args, required=2)
|
||||||
if capability == 'owner':
|
if capability == 'owner':
|
||||||
irc.error('The "owner" capability can\'t be added in the bot.'
|
irc.error('The "owner" capability can\'t be added in the bot. '
|
||||||
' Use the supybot-adduser program (or edit the '
|
'Use the supybot-adduser program (or edit the '
|
||||||
'users.conf file yourself) to add an owner '
|
'users.conf file yourself) to add an owner capability.')
|
||||||
'capability.')
|
|
||||||
return
|
return
|
||||||
if ircdb.checkCapability(msg.prefix, capability) or \
|
if ircdb.checkCapability(msg.prefix, capability) or \
|
||||||
'-' in capability:
|
'-' in capability:
|
||||||
@ -292,7 +294,7 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
irc.error('I can\'t find a hostmask for %s' % arg)
|
irc.error('I can\'t find a hostmask for %s' % arg)
|
||||||
return
|
return
|
||||||
conf.ignores.append(hostmask)
|
conf.supybot.ignores().append(hostmask)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
|
|
||||||
def unignore(self, irc, msg, args):
|
def unignore(self, irc, msg, args):
|
||||||
@ -311,38 +313,23 @@ class Admin(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
irc.error('I can\'t find a hostmask for %s' % arg)
|
irc.error('I can\'t find a hostmask for %s' % arg)
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
conf.ignores.remove(hostmask)
|
conf.supybot.ignores().remove(hostmask)
|
||||||
while hostmask in conf.ignores:
|
while hostmask in conf.supybot.ignores():
|
||||||
conf.ignores.remove(hostmask)
|
conf.supybot.ignores().remove(hostmask)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
except ValueError:
|
except ValueError:
|
||||||
irc.error('%s wasn\'t in conf.ignores.' % hostmask)
|
irc.error('%s wasn\'t in conf.supybot.ignores.' % hostmask)
|
||||||
|
|
||||||
def ignores(self, irc, msg, args):
|
def ignores(self, irc, msg, args):
|
||||||
"""takes no arguments
|
"""takes no arguments
|
||||||
|
|
||||||
Returns the hostmasks currently being globally ignored.
|
Returns the hostmasks currently being globally ignored.
|
||||||
"""
|
"""
|
||||||
if conf.ignores:
|
if conf.supybot.ignores():
|
||||||
irc.reply(utils.commaAndify(imap(repr, conf.ignores)))
|
irc.reply(utils.commaAndify(imap(repr, conf.supybot.ignores())))
|
||||||
else:
|
else:
|
||||||
irc.reply('I\'m not currently globally ignoring anyone.')
|
irc.reply('I\'m not currently globally ignoring anyone.')
|
||||||
|
|
||||||
def setprefixchar(self, irc, msg, args):
|
|
||||||
"""<prefixchars>
|
|
||||||
|
|
||||||
Sets the prefix chars by which the bot can be addressed.
|
|
||||||
"""
|
|
||||||
s = privmsgs.getArgs(args)
|
|
||||||
for c in s:
|
|
||||||
if c not in conf.validPrefixChars:
|
|
||||||
s = 'PrefixChars must be something in %r'%conf.validPrefixChars
|
|
||||||
irc.error(s)
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
conf.prefixChars = s
|
|
||||||
irc.replySuccess()
|
|
||||||
|
|
||||||
def reportbug(self, irc, msg, args):
|
def reportbug(self, irc, msg, args):
|
||||||
"""<description>
|
"""<description>
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ import plugins
|
|||||||
|
|
||||||
import conf
|
import conf
|
||||||
import utils
|
import utils
|
||||||
|
import ircdb
|
||||||
|
import ircutils
|
||||||
import registry
|
import registry
|
||||||
import privmsgs
|
import privmsgs
|
||||||
import callbacks
|
import callbacks
|
||||||
@ -50,7 +52,7 @@ class InvalidRegistryName(callbacks.Error):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def getWrapper(name):
|
def getWrapper(name):
|
||||||
parts = name.split()
|
parts = name.split('.')
|
||||||
if not parts or parts[0] != 'supybot':
|
if not parts or parts[0] != 'supybot':
|
||||||
raise InvalidRegistryName, name
|
raise InvalidRegistryName, name
|
||||||
group = conf.supybot
|
group = conf.supybot
|
||||||
@ -62,13 +64,25 @@ def getWrapper(name):
|
|||||||
raise InvalidRegistryName, name
|
raise InvalidRegistryName, name
|
||||||
return group
|
return group
|
||||||
|
|
||||||
|
def getCapability(name):
|
||||||
|
capability = 'owner' # Default to requiring the owner capability.
|
||||||
|
parts = name.split('.')
|
||||||
|
while parts:
|
||||||
|
part = parts.pop()
|
||||||
|
if ircutils.isChannel(part):
|
||||||
|
# If a registry value has a channel in it, it requires a channel.op
|
||||||
|
# capability, or so we assume. We'll see if we're proven wrong.
|
||||||
|
capability = ircdb.makeChannelCapability(part, 'op')
|
||||||
|
### Do more later, for specific capabilities/sections.
|
||||||
|
return capability
|
||||||
|
|
||||||
|
|
||||||
class Config(callbacks.Privmsg):
|
class Config(callbacks.Privmsg):
|
||||||
def callCommand(self, method, irc, msg, *L):
|
def callCommand(self, method, irc, msg, *L):
|
||||||
try:
|
try:
|
||||||
callbacks.Privmsg.callCommand(method, irc, msg, *L)
|
callbacks.Privmsg.callCommand(self, method, irc, msg, *L)
|
||||||
except InvalidRegistryName, e:
|
except InvalidRegistryName, e:
|
||||||
irc.error('%r is not a valid configuration variable.' % e)
|
irc.error('%r is not a valid configuration variable.' % e.args[0])
|
||||||
except registry.InvalidRegistryValue, e:
|
except registry.InvalidRegistryValue, e:
|
||||||
irc.error(str(e))
|
irc.error(str(e))
|
||||||
|
|
||||||
@ -81,8 +95,11 @@ class Config(callbacks.Privmsg):
|
|||||||
name = privmsgs.getArgs(args)
|
name = privmsgs.getArgs(args)
|
||||||
group = getWrapper(name)
|
group = getWrapper(name)
|
||||||
if hasattr(group, 'getValues'):
|
if hasattr(group, 'getValues'):
|
||||||
L = zip(*group.getValues())[0]
|
try:
|
||||||
irc.reply(utils.commaAndify(L))
|
L = zip(*group.getValues())[0]
|
||||||
|
irc.reply(utils.commaAndify(L))
|
||||||
|
except TypeError:
|
||||||
|
irc.error('There don\'t seem to be any values in %r' % name)
|
||||||
else:
|
else:
|
||||||
irc.error('%r is not a valid configuration group.' % name)
|
irc.error('%r is not a valid configuration group.' % name)
|
||||||
|
|
||||||
@ -101,9 +118,13 @@ class Config(callbacks.Privmsg):
|
|||||||
Sets the current value of the configuration variable <name> to <value>.
|
Sets the current value of the configuration variable <name> to <value>.
|
||||||
"""
|
"""
|
||||||
(name, value) = privmsgs.getArgs(args, required=2)
|
(name, value) = privmsgs.getArgs(args, required=2)
|
||||||
wrapper = getWrapper(name)
|
capability = getCapability(name)
|
||||||
wrapper.set(value)
|
if ircdb.checkCapability(msg.prefix, capability):
|
||||||
irc.replySuccess()
|
wrapper = getWrapper(name)
|
||||||
|
wrapper.set(value)
|
||||||
|
irc.replySuccess()
|
||||||
|
else:
|
||||||
|
irc.errorNoCapability(capability)
|
||||||
|
|
||||||
def help(self, irc, msg, args):
|
def help(self, irc, msg, args):
|
||||||
"""<name>
|
"""<name>
|
||||||
@ -112,7 +133,7 @@ class Config(callbacks.Privmsg):
|
|||||||
"""
|
"""
|
||||||
name = privmsgs.getArgs(args)
|
name = privmsgs.getArgs(args)
|
||||||
wrapper = getWrapper(name)
|
wrapper = getWrapper(name)
|
||||||
irc.reply(msg, wrapper.help)
|
irc.reply(wrapper.help)
|
||||||
|
|
||||||
def reset(self, irc, msg, args):
|
def reset(self, irc, msg, args):
|
||||||
"""<name>
|
"""<name>
|
||||||
@ -120,9 +141,13 @@ class Config(callbacks.Privmsg):
|
|||||||
Resets the configuration variable <name> to its original value.
|
Resets the configuration variable <name> to its original value.
|
||||||
"""
|
"""
|
||||||
name = privmsgs.getArgs(args)
|
name = privmsgs.getArgs(args)
|
||||||
wrapper = getWrapper(name)
|
capability = getCapability(name)
|
||||||
wrapper.reset()
|
if ircdb.checkCapability(msg.prefix, capability):
|
||||||
irc.replySuccess()
|
wrapper = getWrapper(name)
|
||||||
|
wrapper.reset()
|
||||||
|
irc.replySuccess()
|
||||||
|
else:
|
||||||
|
irc.errorNoCapability(capability)
|
||||||
|
|
||||||
def default(self, irc, msg, args):
|
def default(self, irc, msg, args):
|
||||||
"""<name>
|
"""<name>
|
||||||
|
18
src/Misc.py
18
src/Misc.py
@ -54,7 +54,7 @@ class Misc(callbacks.Privmsg):
|
|||||||
priority = sys.maxint
|
priority = sys.maxint
|
||||||
def invalidCommand(self, irc, msg, tokens):
|
def invalidCommand(self, irc, msg, tokens):
|
||||||
self.log.debug('Misc.invalidCommand called (tokens %s)', tokens)
|
self.log.debug('Misc.invalidCommand called (tokens %s)', tokens)
|
||||||
if conf.replyWhenNotCommand:
|
if conf.supybot.reply.whenNotCommand():
|
||||||
command = tokens and tokens[0] or ''
|
command = tokens and tokens[0] or ''
|
||||||
irc.error('%r is not a valid command.' % command)
|
irc.error('%r is not a valid command.' % command)
|
||||||
else:
|
else:
|
||||||
@ -146,7 +146,7 @@ class Misc(callbacks.Privmsg):
|
|||||||
cb = irc.getCallback(args[0])
|
cb = irc.getCallback(args[0])
|
||||||
if cb is not None:
|
if cb is not None:
|
||||||
command = callbacks.canonicalName(privmsgs.getArgs(args[1:]))
|
command = callbacks.canonicalName(privmsgs.getArgs(args[1:]))
|
||||||
command = command.lstrip(conf.prefixChars)
|
command = command.lstrip(conf.supybot.prefixChars())
|
||||||
name = ' '.join(args)
|
name = ' '.join(args)
|
||||||
if hasattr(cb, 'isCommand') and cb.isCommand(command):
|
if hasattr(cb, 'isCommand') and cb.isCommand(command):
|
||||||
method = getattr(cb, command)
|
method = getattr(cb, command)
|
||||||
@ -158,7 +158,7 @@ class Misc(callbacks.Privmsg):
|
|||||||
return
|
return
|
||||||
command = callbacks.canonicalName(privmsgs.getArgs(args))
|
command = callbacks.canonicalName(privmsgs.getArgs(args))
|
||||||
# Users might expect "@help @list" to work.
|
# Users might expect "@help @list" to work.
|
||||||
command = command.lstrip(conf.prefixChars)
|
command = command.lstrip(conf.supybot.prefixChars())
|
||||||
cbs = callbacks.findCallbackForCommand(irc, command)
|
cbs = callbacks.findCallbackForCommand(irc, command)
|
||||||
if len(cbs) > 1:
|
if len(cbs) > 1:
|
||||||
tokens = [command]
|
tokens = [command]
|
||||||
@ -235,7 +235,7 @@ class Misc(callbacks.Privmsg):
|
|||||||
except:
|
except:
|
||||||
self.log.exception('Couldn\'t get id string: %r', s)
|
self.log.exception('Couldn\'t get id string: %r', s)
|
||||||
names = {}
|
names = {}
|
||||||
dirs = map(os.path.abspath, conf.pluginDirs)
|
dirs = map(os.path.abspath, conf.supybot.directories.plugins())
|
||||||
for (name, module) in sys.modules.items(): # Don't use iteritems.
|
for (name, module) in sys.modules.items(): # Don't use iteritems.
|
||||||
if hasattr(module, '__revision__'):
|
if hasattr(module, '__revision__'):
|
||||||
if 'supybot' in module.__file__:
|
if 'supybot' in module.__file__:
|
||||||
@ -268,7 +268,8 @@ class Misc(callbacks.Privmsg):
|
|||||||
return
|
return
|
||||||
filenameArg = os.path.basename(filenameArg)
|
filenameArg = os.path.basename(filenameArg)
|
||||||
ret = []
|
ret = []
|
||||||
for (dirname, _, filenames) in os.walk(conf.logDir):
|
dirname = conf.supybot.directories.log()
|
||||||
|
for (dirname,_,filenames) in os.walk(dirname):
|
||||||
if filenameArg:
|
if filenameArg:
|
||||||
if filenameArg in filenames:
|
if filenameArg in filenames:
|
||||||
filename = os.path.join(dirname, filenameArg)
|
filename = os.path.join(dirname, filenameArg)
|
||||||
@ -284,13 +285,6 @@ class Misc(callbacks.Privmsg):
|
|||||||
else:
|
else:
|
||||||
irc.error('I couldn\'t find any logfiles.')
|
irc.error('I couldn\'t find any logfiles.')
|
||||||
|
|
||||||
def getprefixchar(self, irc, msg, args):
|
|
||||||
"""takes no arguments
|
|
||||||
|
|
||||||
Returns the prefix character(s) the bot is currently using.
|
|
||||||
"""
|
|
||||||
irc.reply(repr(conf.prefixChars))
|
|
||||||
|
|
||||||
def plugin(self, irc, msg, args):
|
def plugin(self, irc, msg, args):
|
||||||
"""<command>
|
"""<command>
|
||||||
|
|
||||||
|
123
src/Owner.py
123
src/Owner.py
@ -55,6 +55,7 @@ import irclib
|
|||||||
import ircmsgs
|
import ircmsgs
|
||||||
import drivers
|
import drivers
|
||||||
import privmsgs
|
import privmsgs
|
||||||
|
import registry
|
||||||
import callbacks
|
import callbacks
|
||||||
|
|
||||||
class Deprecated(ImportError):
|
class Deprecated(ImportError):
|
||||||
@ -63,7 +64,8 @@ class Deprecated(ImportError):
|
|||||||
def loadPluginModule(name, ignoreDeprecation=False):
|
def loadPluginModule(name, ignoreDeprecation=False):
|
||||||
"""Loads (and returns) the module for the plugin with the given name."""
|
"""Loads (and returns) the module for the plugin with the given name."""
|
||||||
files = []
|
files = []
|
||||||
for dir in conf.pluginDirs:
|
pluginDirs = conf.supybot.directories.plugins()
|
||||||
|
for dir in pluginDirs:
|
||||||
try:
|
try:
|
||||||
files.extend(os.listdir(dir))
|
files.extend(os.listdir(dir))
|
||||||
except EnvironmentError: # OSError, IOError superclass.
|
except EnvironmentError: # OSError, IOError superclass.
|
||||||
@ -74,7 +76,7 @@ def loadPluginModule(name, ignoreDeprecation=False):
|
|||||||
name = os.path.splitext(files[index])[0]
|
name = os.path.splitext(files[index])[0]
|
||||||
except ValueError: # We'd rather raise the ImportError, so we'll let go...
|
except ValueError: # We'd rather raise the ImportError, so we'll let go...
|
||||||
pass
|
pass
|
||||||
moduleInfo = imp.find_module(name, conf.pluginDirs)
|
moduleInfo = imp.find_module(name, pluginDirs)
|
||||||
module = imp.load_module(name, *moduleInfo)
|
module = imp.load_module(name, *moduleInfo)
|
||||||
if 'deprecated' in module.__dict__ and module.deprecated:
|
if 'deprecated' in module.__dict__ and module.deprecated:
|
||||||
if ignoreDeprecation:
|
if ignoreDeprecation:
|
||||||
@ -91,8 +93,14 @@ def loadPluginClass(irc, module):
|
|||||||
callback = module.Class()
|
callback = module.Class()
|
||||||
assert not irc.getCallback(callback.name())
|
assert not irc.getCallback(callback.name())
|
||||||
irc.addCallback(callback)
|
irc.addCallback(callback)
|
||||||
if hasattr(callback, 'configure'):
|
|
||||||
callback.configure(irc)
|
def registerPlugin(name, currentValue=None):
|
||||||
|
conf.supybot.plugins.registerGroup(name,
|
||||||
|
registry.GroupWithValue(registry.Boolean(False, """Determines
|
||||||
|
whether this plugin is loaded by default.""")))
|
||||||
|
if currentValue is not None:
|
||||||
|
conf.supybot.plugins.getChild(name).setValue(currentValue)
|
||||||
|
|
||||||
|
|
||||||
class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
||||||
# This plugin must be first; its priority must be lowest; otherwise odd
|
# This plugin must be first; its priority must be lowest; otherwise odd
|
||||||
@ -107,6 +115,27 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
'capabilities': 'User',
|
'capabilities': 'User',
|
||||||
'addcapability': 'Admin',
|
'addcapability': 'Admin',
|
||||||
'removecapability': 'Admin'}
|
'removecapability': 'Admin'}
|
||||||
|
for (name, s) in registry.cache.iteritems():
|
||||||
|
if name.startswith('supybot.plugins'):
|
||||||
|
try:
|
||||||
|
(_, _, name) = name.split('.')
|
||||||
|
except ValueError: #unpack list of wrong size.
|
||||||
|
continue
|
||||||
|
registerPlugin(name)
|
||||||
|
|
||||||
|
def do001(self, irc, msg):
|
||||||
|
self.log.info('Loading other src/ plugins.')
|
||||||
|
for s in ('Admin', 'Channel', 'Config', 'Misc', 'User'):
|
||||||
|
self.log.info('Loading %s.' % s)
|
||||||
|
m = loadPluginModule(s)
|
||||||
|
loadPluginClass(irc, m)
|
||||||
|
for (name, value) in conf.supybot.plugins.getValues():
|
||||||
|
if value():
|
||||||
|
s = rsplit(name, '.', 1)[-1]
|
||||||
|
if not irc.getCallback(s):
|
||||||
|
self.log.info('Loading %s.' % s)
|
||||||
|
m = loadPluginModule(s)
|
||||||
|
loadPluginClass(irc, m)
|
||||||
|
|
||||||
def disambiguate(self, irc, tokens, ambiguousCommands=None):
|
def disambiguate(self, irc, tokens, ambiguousCommands=None):
|
||||||
"""Disambiguates the given tokens based on the plugins loaded and
|
"""Disambiguates the given tokens based on the plugins loaded and
|
||||||
@ -227,7 +256,7 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
irc.reply(utils.exnToString(e))
|
irc.reply(utils.exnToString(e))
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyEvalNotAllowed)
|
irc.error('You must enable conf.allowEval for that to work.')
|
||||||
|
|
||||||
def _exec(self, irc, msg, args):
|
def _exec(self, irc, msg, args):
|
||||||
"""<statement>
|
"""<statement>
|
||||||
@ -242,77 +271,7 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
except Exception, e:
|
except Exception, e:
|
||||||
irc.reply(utils.exnToString(e))
|
irc.reply(utils.exnToString(e))
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyEvalNotAllowed)
|
irc.error('You must enable conf.allowEval for that to work.')
|
||||||
|
|
||||||
def setconf(self, irc, msg, args):
|
|
||||||
"""[<name> [<value>]]
|
|
||||||
|
|
||||||
Lists adjustable variables in the conf-module by default, shows the
|
|
||||||
variable type with only the <name> argument and sets the value of the
|
|
||||||
variable to <value> when both arguments are given.
|
|
||||||
"""
|
|
||||||
(name, value) = privmsgs.getArgs(args, required=0, optional=2)
|
|
||||||
if name and value:
|
|
||||||
if conf.allowEval:
|
|
||||||
try:
|
|
||||||
value = eval(value)
|
|
||||||
except Exception, e:
|
|
||||||
irc.error(utils.exnToString(e))
|
|
||||||
return
|
|
||||||
setattr(conf, name, value)
|
|
||||||
irc.replySuccess()
|
|
||||||
else:
|
|
||||||
if name == 'allowEval':
|
|
||||||
irc.error('You can\'t set the value of allowEval.')
|
|
||||||
return
|
|
||||||
elif name not in conf.types:
|
|
||||||
irc.error('I can\'t set that conf variable.')
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
converter = conf.types[name]
|
|
||||||
try:
|
|
||||||
value = converter(value)
|
|
||||||
except ValueError, e:
|
|
||||||
irc.error(str(e))
|
|
||||||
return
|
|
||||||
setattr(conf, name, value)
|
|
||||||
irc.replySuccess()
|
|
||||||
elif name:
|
|
||||||
typeNames = {conf.mystr: 'string',
|
|
||||||
conf.mybool: 'boolean',
|
|
||||||
float: 'float'}
|
|
||||||
try:
|
|
||||||
type = typeNames[conf.types[name]]
|
|
||||||
except KeyError:
|
|
||||||
irc.error('That configuration variable doesn\'t exist.')
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
value = getattr(conf, name)
|
|
||||||
irc.reply('%s is a %s (%s).' % (name, type, value))
|
|
||||||
except KeyError:
|
|
||||||
irc.error('%s is of an unknown type.' % name)
|
|
||||||
else:
|
|
||||||
options = conf.types.keys()
|
|
||||||
options.sort()
|
|
||||||
irc.reply(', '.join(options))
|
|
||||||
|
|
||||||
def setdefaultcapability(self, irc, msg, args):
|
|
||||||
"""<capability>
|
|
||||||
|
|
||||||
Sets the default capability to be allowed for any command.
|
|
||||||
"""
|
|
||||||
capability = callbacks.canonicalName(privmsgs.getArgs(args))
|
|
||||||
conf.defaultCapabilities.add(capability)
|
|
||||||
irc.replySuccess()
|
|
||||||
|
|
||||||
def unsetdefaultcapability(self, irc, msg, args):
|
|
||||||
"""<capability>
|
|
||||||
|
|
||||||
Unsets the default capability for any command.
|
|
||||||
"""
|
|
||||||
capability = callbacks.canonicalName(privmsgs.getArgs(args))
|
|
||||||
conf.defaultCapabilities.remove(capability)
|
|
||||||
irc.replySuccess()
|
|
||||||
|
|
||||||
def ircquote(self, irc, msg, args):
|
def ircquote(self, irc, msg, args):
|
||||||
"""<string to be sent to the server>
|
"""<string to be sent to the server>
|
||||||
@ -357,9 +316,9 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
"""[--deprecated] <plugin>
|
"""[--deprecated] <plugin>
|
||||||
|
|
||||||
Loads the plugin <plugin> from any of the directories in
|
Loads the plugin <plugin> from any of the directories in
|
||||||
conf.pluginDirs; usually this includes the main installed directory
|
conf.supybot.directories.plugins; usually this includes the main
|
||||||
and 'plugins' in the current directory. --deprecated is necessary
|
installed directory and 'plugins' in the current directory.
|
||||||
if you wish to load deprecated plugins.
|
--deprecated is necessary if you wish to load deprecated plugins.
|
||||||
"""
|
"""
|
||||||
(optlist, args) = getopt.getopt(args, '', ['deprecated'])
|
(optlist, args) = getopt.getopt(args, '', ['deprecated'])
|
||||||
ignoreDeprecation = False
|
ignoreDeprecation = False
|
||||||
@ -385,6 +344,7 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
irc.error(utils.exnToString(e))
|
irc.error(utils.exnToString(e))
|
||||||
return
|
return
|
||||||
loadPluginClass(irc, module)
|
loadPluginClass(irc, module)
|
||||||
|
registerPlugin(name, True)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
|
|
||||||
def reload(self, irc, msg, args):
|
def reload(self, irc, msg, args):
|
||||||
@ -429,6 +389,7 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
callback.die()
|
callback.die()
|
||||||
del callback
|
del callback
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
registerPlugin(name, False)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
else:
|
else:
|
||||||
irc.error('There was no callback %s' % name)
|
irc.error('There was no callback %s' % name)
|
||||||
@ -436,8 +397,8 @@ class Owner(privmsgs.CapabilityCheckingPrivmsg):
|
|||||||
def reconf(self, irc, msg, args):
|
def reconf(self, irc, msg, args):
|
||||||
"""takes no arguments
|
"""takes no arguments
|
||||||
|
|
||||||
Reloads the configuration files in conf.dataDir: conf/users.conf and
|
Reloads the configuration files for the user and channel databases:
|
||||||
conf/channels.conf, by default.
|
conf/users.conf and conf/channels.conf, by default.
|
||||||
"""
|
"""
|
||||||
ircdb.users.reload()
|
ircdb.users.reload()
|
||||||
ircdb.channels.reload()
|
ircdb.channels.reload()
|
||||||
|
14
src/User.py
14
src/User.py
@ -53,7 +53,7 @@ import callbacks
|
|||||||
class User(callbacks.Privmsg):
|
class User(callbacks.Privmsg):
|
||||||
def _checkNotChannel(self, irc, msg, password=' '):
|
def _checkNotChannel(self, irc, msg, password=' '):
|
||||||
if password and ircutils.isChannel(msg.args[0]):
|
if password and ircutils.isChannel(msg.args[0]):
|
||||||
raise callbacks.Error, conf.replyRequiresPrivacy
|
raise callbacks.Error, conf.supybot.replies.requiresPrivacy()
|
||||||
|
|
||||||
def list(self, irc, msg, args):
|
def list(self, irc, msg, args):
|
||||||
"""[<glob>]
|
"""[<glob>]
|
||||||
@ -136,7 +136,7 @@ class User(callbacks.Privmsg):
|
|||||||
ircdb.users.delUser(id)
|
ircdb.users.delUser(id)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyIncorrectAuth)
|
irc.error(conf.supybot.replies.incorrectAuthentication())
|
||||||
|
|
||||||
def changename(self, irc, msg, args):
|
def changename(self, irc, msg, args):
|
||||||
"""<name> <new name> [<password>]
|
"""<name> <new name> [<password>]
|
||||||
@ -201,7 +201,7 @@ class User(callbacks.Privmsg):
|
|||||||
ircdb.users.setUser(id, user)
|
ircdb.users.setUser(id, user)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyIncorrectAuth)
|
irc.error(conf.supybot.replies.incorrectAuthentication())
|
||||||
return
|
return
|
||||||
|
|
||||||
def removehostmask(self, irc, msg, args):
|
def removehostmask(self, irc, msg, args):
|
||||||
@ -229,7 +229,7 @@ class User(callbacks.Privmsg):
|
|||||||
ircdb.users.setUser(id, user)
|
ircdb.users.setUser(id, user)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyIncorrectAuth)
|
irc.error(conf.supybot.replies.incorrectAuthentication())
|
||||||
return
|
return
|
||||||
|
|
||||||
def setpassword(self, irc, msg, args):
|
def setpassword(self, irc, msg, args):
|
||||||
@ -258,7 +258,7 @@ class User(callbacks.Privmsg):
|
|||||||
ircdb.users.setUser(id, user)
|
ircdb.users.setUser(id, user)
|
||||||
irc.replySuccess()
|
irc.replySuccess()
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyIncorrectAuth)
|
irc.error(conf.supybot.replies.incorrectAuthentication())
|
||||||
|
|
||||||
def username(self, irc, msg, args):
|
def username(self, irc, msg, args):
|
||||||
"""<hostmask|nick>
|
"""<hostmask|nick>
|
||||||
@ -345,7 +345,7 @@ class User(callbacks.Privmsg):
|
|||||||
irc.error('Your secure flag is true and your hostmask '
|
irc.error('Your secure flag is true and your hostmask '
|
||||||
'doesn\'t match any of your known hostmasks.')
|
'doesn\'t match any of your known hostmasks.')
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyIncorrectAuth)
|
irc.error(conf.supybot.replies.incorrectAuthentication())
|
||||||
|
|
||||||
def unidentify(self, irc, msg, args):
|
def unidentify(self, irc, msg, args):
|
||||||
"""takes no arguments
|
"""takes no arguments
|
||||||
@ -403,7 +403,7 @@ class User(callbacks.Privmsg):
|
|||||||
ircdb.users.setUser(id, user)
|
ircdb.users.setUser(id, user)
|
||||||
irc.reply('Secure flag set to %s' % value)
|
irc.reply('Secure flag set to %s' % value)
|
||||||
else:
|
else:
|
||||||
irc.error(conf.replyIncorrectAuth)
|
irc.error(conf.supybot.replies.incorrectAuthentication())
|
||||||
|
|
||||||
|
|
||||||
Class = User
|
Class = User
|
||||||
|
@ -42,7 +42,6 @@ import asynchat
|
|||||||
|
|
||||||
import log
|
import log
|
||||||
import conf
|
import conf
|
||||||
import repl
|
|
||||||
import ircdb
|
import ircdb
|
||||||
import world
|
import world
|
||||||
import drivers
|
import drivers
|
||||||
@ -53,7 +52,7 @@ class AsyncoreRunnerDriver(drivers.IrcDriver):
|
|||||||
def run(self):
|
def run(self):
|
||||||
log.debug(repr(asyncore.socket_map))
|
log.debug(repr(asyncore.socket_map))
|
||||||
try:
|
try:
|
||||||
asyncore.poll(conf.poll)
|
asyncore.poll(conf.supybot.drivers.poll())
|
||||||
except:
|
except:
|
||||||
log.exception('Uncaught exception:')
|
log.exception('Uncaught exception:')
|
||||||
|
|
||||||
@ -75,7 +74,8 @@ class AsyncoreDriver(asynchat.async_chat, object):
|
|||||||
|
|
||||||
def scheduleReconnect(self):
|
def scheduleReconnect(self):
|
||||||
when = time.time() + 60
|
when = time.time() + 60
|
||||||
whenS = time.strftime(conf.logTimestampFormat, time.localtime(when))
|
whenS = time.strftime(conf.supybot.log.timestampFormat(),
|
||||||
|
time.localtime(when))
|
||||||
if not world.dying:
|
if not world.dying:
|
||||||
log.info('Scheduling reconnect to %s at %s', self.server, whenS)
|
log.info('Scheduling reconnect to %s at %s', self.server, whenS)
|
||||||
def makeNewDriver():
|
def makeNewDriver():
|
||||||
@ -121,116 +121,12 @@ class AsyncoreDriver(asynchat.async_chat, object):
|
|||||||
log.info('Driver for %s dying.', self.irc)
|
log.info('Driver for %s dying.', self.irc)
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
class ReplListener(asyncore.dispatcher, object):
|
|
||||||
def __init__(self, port=conf.telnetPort):
|
|
||||||
asyncore.dispatcher.__init__(self)
|
|
||||||
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.set_reuse_addr()
|
|
||||||
self.bind(('', port))
|
|
||||||
self.listen(5)
|
|
||||||
|
|
||||||
def handle_accept(self):
|
|
||||||
(sock, addr) = self.accept()
|
|
||||||
log.info('Connection made to telnet-REPL: %s', addr)
|
|
||||||
Repl((sock, addr))
|
|
||||||
|
|
||||||
|
|
||||||
class Repl(asynchat.async_chat, object):
|
|
||||||
filename = 'repl'
|
|
||||||
def __init__(self, (sock, addr)):
|
|
||||||
asynchat.async_chat.__init__(self, sock)
|
|
||||||
self.buffer = ''
|
|
||||||
self.prompt = """SupyBot version %s.
|
|
||||||
Python %s
|
|
||||||
Type disconnect() to disconnect.
|
|
||||||
Name: """ % (world.version, sys.version.translate(string.ascii, '\r\n'))
|
|
||||||
self.u = None
|
|
||||||
self.authed = False
|
|
||||||
self.set_terminator('\r\n')
|
|
||||||
self.repl = repl.Repl(addr[0])
|
|
||||||
self.repl.namespace['disconnect'] = self.close
|
|
||||||
self.push(self.prompt)
|
|
||||||
self.tries = 0
|
|
||||||
|
|
||||||
_re = re.compile(r'(?<!\r)\n')
|
|
||||||
def push(self, data):
|
|
||||||
asynchat.async_chat.push(self, self._re.sub('\r\n', data))
|
|
||||||
|
|
||||||
def collect_incoming_data(self, data):
|
|
||||||
if self.tries >= 3:
|
|
||||||
self.close()
|
|
||||||
self.buffer += data
|
|
||||||
if len(self.buffer) > 1024:
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def handle_close(self):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def handle_error(self):
|
|
||||||
self.close()
|
|
||||||
|
|
||||||
def found_terminator(self):
|
|
||||||
if self.u is None:
|
|
||||||
try:
|
|
||||||
name = self.buffer
|
|
||||||
self.buffer = ''
|
|
||||||
id = ircdb.users.getUserId(name)
|
|
||||||
self.u = ircdb.users.getUser(id)
|
|
||||||
self.prompt = 'Password: '
|
|
||||||
except KeyError:
|
|
||||||
self.push('Unknown user.\n')
|
|
||||||
self.tries += 1
|
|
||||||
self.prompt = 'Name: '
|
|
||||||
log.warning('Unknown user %s on telnet REPL.', name)
|
|
||||||
self.push(self.prompt)
|
|
||||||
elif self.u is not None and not self.authed:
|
|
||||||
password = self.buffer
|
|
||||||
self.buffer = ''
|
|
||||||
if self.u.checkPassword(password):
|
|
||||||
if self.u.checkCapability('owner'):
|
|
||||||
self.authed = True
|
|
||||||
self.prompt = '>>> '
|
|
||||||
else:
|
|
||||||
self.push('Only owners can use this feature.\n')
|
|
||||||
self.close()
|
|
||||||
msg = 'Attempted non-owner user %s on telnet REPL' % name
|
|
||||||
log.warning(msg)
|
|
||||||
else:
|
|
||||||
self.push('Incorrect Password.\n')
|
|
||||||
self.prompt = 'Name: '
|
|
||||||
self.u = None
|
|
||||||
msg = 'Invalid password for user %s on telnet REPL.' % name
|
|
||||||
log.warning(msg)
|
|
||||||
self.push(self.prompt)
|
|
||||||
elif self.authed:
|
|
||||||
log.info('Telnet REPL: %s', self.buffer)
|
|
||||||
ret = self.repl.addLine(self.buffer+'\r\n')
|
|
||||||
self.buffer = ''
|
|
||||||
if ret is not repl.NotYet:
|
|
||||||
if ret is not None:
|
|
||||||
s = self._re.sub('\r\n', str(ret))
|
|
||||||
self.push(s)
|
|
||||||
self.push('\r\n')
|
|
||||||
self.prompt = '>>> '
|
|
||||||
else:
|
|
||||||
self.prompt = '... '
|
|
||||||
self.push(self.prompt)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
ignore(poller)
|
ignore(poller)
|
||||||
except NameError:
|
except NameError:
|
||||||
poller = AsyncoreRunnerDriver()
|
poller = AsyncoreRunnerDriver()
|
||||||
|
|
||||||
if conf.telnetEnable and __name__ != '__main__':
|
|
||||||
try:
|
|
||||||
ignore(_listener)
|
|
||||||
except NameError:
|
|
||||||
_listener = ReplListener()
|
|
||||||
|
|
||||||
Driver = AsyncoreDriver
|
Driver = AsyncoreDriver
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
ReplListener()
|
|
||||||
asyncore.loop()
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -70,11 +70,11 @@ def addressed(nick, msg):
|
|||||||
"""
|
"""
|
||||||
nick = ircutils.toLower(nick)
|
nick = ircutils.toLower(nick)
|
||||||
if ircutils.nickEqual(msg.args[0], nick):
|
if ircutils.nickEqual(msg.args[0], nick):
|
||||||
if msg.args[1][0] in conf.prefixChars:
|
if msg.args[1][0] in conf.supybot.prefixChars():
|
||||||
return msg.args[1][1:].strip()
|
return msg.args[1][1:].strip()
|
||||||
else:
|
else:
|
||||||
return msg.args[1].strip()
|
return msg.args[1].strip()
|
||||||
elif conf.replyWhenAddressedByNick and \
|
elif conf.supybot.reply.whenAddressedByNick() and \
|
||||||
ircutils.toLower(msg.args[1]).startswith(nick):
|
ircutils.toLower(msg.args[1]).startswith(nick):
|
||||||
try:
|
try:
|
||||||
(maybeNick, rest) = msg.args[1].split(None, 1)
|
(maybeNick, rest) = msg.args[1].split(None, 1)
|
||||||
@ -86,9 +86,9 @@ def addressed(nick, msg):
|
|||||||
return ''
|
return ''
|
||||||
except ValueError: # split didn't work.
|
except ValueError: # split didn't work.
|
||||||
return ''
|
return ''
|
||||||
elif msg.args[1] and msg.args[1][0] in conf.prefixChars:
|
elif msg.args[1] and msg.args[1][0] in conf.supybot.prefixChars():
|
||||||
return msg.args[1][1:].strip()
|
return msg.args[1][1:].strip()
|
||||||
elif conf.replyWhenNotAddressed:
|
elif conf.supybot.reply.whenNotAddressed():
|
||||||
return msg.args[1]
|
return msg.args[1]
|
||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
@ -112,7 +112,7 @@ def reply(msg, s, prefixName=True, private=False, notice=False, to=None):
|
|||||||
s = ircutils.safeArgument(s)
|
s = ircutils.safeArgument(s)
|
||||||
to = to or msg.nick
|
to = to or msg.nick
|
||||||
if ircutils.isChannel(msg.args[0]) and not private:
|
if ircutils.isChannel(msg.args[0]) and not private:
|
||||||
if notice or conf.replyWithPrivateNotice:
|
if notice or conf.supybot.reply.withPrivateNotice():
|
||||||
m = ircmsgs.notice(to, s)
|
m = ircmsgs.notice(to, s)
|
||||||
elif prefixName:
|
elif prefixName:
|
||||||
m = ircmsgs.privmsg(msg.args[0], '%s: %s' % (to, s))
|
m = ircmsgs.privmsg(msg.args[0], '%s: %s' % (to, s))
|
||||||
@ -227,7 +227,7 @@ def tokenize(s):
|
|||||||
try:
|
try:
|
||||||
if s != _lastTokenized:
|
if s != _lastTokenized:
|
||||||
_lastTokenized = s
|
_lastTokenized = s
|
||||||
if conf.enablePipeSyntax:
|
if conf.supybot.pipeSyntax():
|
||||||
tokens = '|'
|
tokens = '|'
|
||||||
else:
|
else:
|
||||||
tokens = ''
|
tokens = ''
|
||||||
@ -263,7 +263,7 @@ def formatArgumentError(method, name=None):
|
|||||||
if name is None:
|
if name is None:
|
||||||
name = method.__name__
|
name = method.__name__
|
||||||
if hasattr(method, '__doc__') and method.__doc__:
|
if hasattr(method, '__doc__') and method.__doc__:
|
||||||
if conf.showOnlySyntax:
|
if conf.supybot.showSimpleSyntax():
|
||||||
return getSyntax(method, name=name)
|
return getSyntax(method, name=name)
|
||||||
else:
|
else:
|
||||||
return getHelp(method, name=name)
|
return getHelp(method, name=name)
|
||||||
@ -281,7 +281,7 @@ def checkCommandCapability(msg, cb, command):
|
|||||||
if ircdb.checkCapability(msg.prefix, antichancap):
|
if ircdb.checkCapability(msg.prefix, antichancap):
|
||||||
log.info('Preventing because of antichancap: %s', msg.prefix)
|
log.info('Preventing because of antichancap: %s', msg.prefix)
|
||||||
return False
|
return False
|
||||||
return conf.defaultAllow or \
|
return conf.supybot.defaultAllow() or \
|
||||||
ircdb.checkCapability(msg.prefix, command) or \
|
ircdb.checkCapability(msg.prefix, command) or \
|
||||||
ircdb.checkCapability(msg.prefix, chancap)
|
ircdb.checkCapability(msg.prefix, chancap)
|
||||||
|
|
||||||
@ -296,30 +296,38 @@ class RichReplyMethods(object):
|
|||||||
return s
|
return s
|
||||||
|
|
||||||
def replySuccess(self, s='', **kwargs):
|
def replySuccess(self, s='', **kwargs):
|
||||||
self.reply(self.__makeReply(conf.replySuccess, s), **kwargs)
|
self.reply(self.__makeReply(conf.supybot.replies.success(), s),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
def replyError(self, s='', **kwargs):
|
def replyError(self, s='', **kwargs):
|
||||||
self.reply(self.__makeReply(conf.replyError, s), **kwargs)
|
self.reply(self.__makeReply(conf.supybot.replies.error(), s),
|
||||||
|
**kwargs)
|
||||||
|
|
||||||
def errorNoCapability(self, capability, s='', **kwargs):
|
def errorNoCapability(self, capability, s='', **kwargs):
|
||||||
log.warning('Denying %s for lacking %r capability',
|
log.warning('Denying %s for lacking %r capability',
|
||||||
self.msg.prefix, capability)
|
self.msg.prefix, capability)
|
||||||
s = self.__makeReply(conf.replyNoCapability % capability, s)
|
noCapability = conf.supybot.replies.noCapability()
|
||||||
|
s = self.__makeReply(noCapability % capability, s)
|
||||||
self.error(s, **kwargs)
|
self.error(s, **kwargs)
|
||||||
|
|
||||||
def errorPossibleBug(self, s='', **kwargs):
|
def errorPossibleBug(self, s='', **kwargs):
|
||||||
if s:
|
if s:
|
||||||
s += ' (%s)' % conf.replyPossibleBug
|
s += ' (%s)' % conf.supybot.replies.possibleBug()
|
||||||
|
else:
|
||||||
|
s = conf.supybot.replies.possibleBug()
|
||||||
self.error(s, **kwargs)
|
self.error(s, **kwargs)
|
||||||
|
|
||||||
def errorNotRegistered(self, s='', **kwargs):
|
def errorNotRegistered(self, s='', **kwargs):
|
||||||
self.error(self.__makeReply(conf.replyNotRegistered, s), **kwargs)
|
notRegistered = conf.supybot.replies.notRegistered()
|
||||||
|
self.error(self.__makeReply(notRegistered, s), **kwargs)
|
||||||
|
|
||||||
def errorNoUser(self, s='', **kwargs):
|
def errorNoUser(self, s='', **kwargs):
|
||||||
self.error(self.__makeReply(conf.replyNoUser, s), **kwargs)
|
noUser = conf.supybot.replies.noUser()
|
||||||
|
self.error(self.__makeReply(noUser, s), **kwargs)
|
||||||
|
|
||||||
def errorRequiresPrivacy(self, s='', **kwargs):
|
def errorRequiresPrivacy(self, s='', **kwargs):
|
||||||
self.error(self.__makeReply(conf.replyRequiresPrivacy, s), **kwargs)
|
requiresPrivacy = conf.supybot.replies.requiresPrivacy()
|
||||||
|
self.error(self.__makeReply(requiresPrivacy, s), **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class IrcObjectProxy(RichReplyMethods):
|
class IrcObjectProxy(RichReplyMethods):
|
||||||
@ -337,7 +345,7 @@ class IrcObjectProxy(RichReplyMethods):
|
|||||||
self.notice = False
|
self.notice = False
|
||||||
self.private = False
|
self.private = False
|
||||||
self.finished = False
|
self.finished = False
|
||||||
self.prefixName = conf.replyWithNickPrefix
|
self.prefixName = conf.supybot.reply.withNickPrefix()
|
||||||
self.noLengthCheck = False
|
self.noLengthCheck = False
|
||||||
if not args:
|
if not args:
|
||||||
self.finalEvaled = True
|
self.finalEvaled = True
|
||||||
@ -462,18 +470,18 @@ class IrcObjectProxy(RichReplyMethods):
|
|||||||
to=<nick|channel>: The nick or channel the reply should go to.
|
to=<nick|channel>: The nick or channel the reply should go to.
|
||||||
Defaults to msg.args[0] (or msg.nick if private)
|
Defaults to msg.args[0] (or msg.nick if private)
|
||||||
"""
|
"""
|
||||||
# These use |= or &= based on whether or not they default to True or
|
# These use and or or based on whether or not they default to True or
|
||||||
# False. Those that default to True use &=; those that default to
|
# False. Those that default to True use and; those that default to
|
||||||
# False use |=.
|
# False use or.
|
||||||
assert not isinstance(s, ircmsgs.IrcMsg), \
|
assert not isinstance(s, ircmsgs.IrcMsg), \
|
||||||
'Old code alert: there is no longer a "msg" argument to reply.'
|
'Old code alert: there is no longer a "msg" argument to reply.'
|
||||||
msg = self.msg
|
msg = self.msg
|
||||||
self.action |= action
|
self.action = action or self.action
|
||||||
self.notice |= notice
|
self.notice = notice or self.notice
|
||||||
self.private |= private
|
self.private = private or self.private
|
||||||
self.to = to or self.to
|
self.to = to or self.to
|
||||||
self.prefixName &= prefixName
|
self.prefixName = prefixName or self.prefixName
|
||||||
self.noLengthCheck |= noLengthCheck
|
self.noLengthCheck = noLengthCheck or self.noLengthCheck
|
||||||
if self.finalEvaled:
|
if self.finalEvaled:
|
||||||
if isinstance(self.irc, self.__class__):
|
if isinstance(self.irc, self.__class__):
|
||||||
self.irc.reply(s, self.noLengthCheck, self.prefixName,
|
self.irc.reply(s, self.noLengthCheck, self.prefixName,
|
||||||
@ -532,7 +540,7 @@ class IrcObjectProxy(RichReplyMethods):
|
|||||||
self.irc.error(s, private)
|
self.irc.error(s, private)
|
||||||
else:
|
else:
|
||||||
s = 'Error: ' + s
|
s = 'Error: ' + s
|
||||||
if private or conf.errorReplyPrivate:
|
if private or conf.supybot.reply.errorInPrivate():
|
||||||
self.irc.queueMsg(ircmsgs.privmsg(self.msg.nick, s))
|
self.irc.queueMsg(ircmsgs.privmsg(self.msg.nick, s))
|
||||||
else:
|
else:
|
||||||
self.irc.queueMsg(reply(self.msg, s))
|
self.irc.queueMsg(reply(self.msg, s))
|
||||||
@ -655,22 +663,6 @@ class Privmsg(irclib.IrcCallback):
|
|||||||
dispatcher.__doc__ = docstring
|
dispatcher.__doc__ = docstring
|
||||||
setattr(self.__class__, canonicalname, dispatcher)
|
setattr(self.__class__, canonicalname, dispatcher)
|
||||||
|
|
||||||
def configure(self, irc):
|
|
||||||
fakeIrc = ConfigIrcProxy(irc)
|
|
||||||
for args in conf.commandsOnStart:
|
|
||||||
args = args[:]
|
|
||||||
command = canonicalName(args.pop(0))
|
|
||||||
if self.isCommand(command):
|
|
||||||
self.log.debug('%s: %r', command, args)
|
|
||||||
method = getattr(self, command)
|
|
||||||
line = '%s %s' % (command, ' '.join(imap(utils.dqrepr, args)))
|
|
||||||
msg = ircmsgs.privmsg(fakeIrc.nick, line, fakeIrc.prefix)
|
|
||||||
try:
|
|
||||||
world.startup = True
|
|
||||||
method(fakeIrc, msg, args)
|
|
||||||
finally:
|
|
||||||
world.startup = False
|
|
||||||
|
|
||||||
def __call__(self, irc, msg):
|
def __call__(self, irc, msg):
|
||||||
if msg.command == 'PRIVMSG':
|
if msg.command == 'PRIVMSG':
|
||||||
if self.noIgnore or not ircdb.checkIgnored(msg.prefix,msg.args[0]):
|
if self.noIgnore or not ircdb.checkIgnored(msg.prefix,msg.args[0]):
|
||||||
|
630
src/conf.py
630
src/conf.py
@ -35,307 +35,308 @@ import fix
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import string
|
||||||
|
|
||||||
import sets
|
import utils
|
||||||
import os.path
|
import registry
|
||||||
import logging
|
import ircutils
|
||||||
|
|
||||||
###
|
|
||||||
# Directions:
|
|
||||||
#
|
|
||||||
# Boolean values should be either True or False.
|
|
||||||
###
|
|
||||||
|
|
||||||
###
|
|
||||||
# Directories.
|
|
||||||
###
|
|
||||||
logDir = 'logs'
|
|
||||||
confDir = 'conf'
|
|
||||||
dataDir = 'data'
|
|
||||||
installDir = os.path.dirname(os.path.dirname(sys.modules[__name__].__file__))
|
installDir = os.path.dirname(os.path.dirname(sys.modules[__name__].__file__))
|
||||||
pluginDirs = [os.path.join(installDir, s) for s in ('src', 'plugins')]
|
_srcDir = os.path.join(installDir, 'src')
|
||||||
|
_pluginsDir = os.path.join(installDir, 'plugins')
|
||||||
###
|
|
||||||
# Files.
|
|
||||||
###
|
|
||||||
userfile = 'users.conf'
|
|
||||||
channelfile = 'channels.conf'
|
|
||||||
|
|
||||||
###
|
|
||||||
# minimumLogPriority: The minimum priority that will be logged. Defaults to
|
|
||||||
# logging.INFO, which is probably a good value. Can also
|
|
||||||
# be usefully set to logging.{DEBUG,WARNING,ERROR,CRITICAL}
|
|
||||||
###
|
|
||||||
minimumLogPriority = logging.INFO
|
|
||||||
|
|
||||||
###
|
|
||||||
# stdoutLogging: Determines whether or not the bot logs to stdout.
|
|
||||||
###
|
|
||||||
stdoutLogging = True
|
|
||||||
|
|
||||||
###
|
|
||||||
# colorizedStdoutLogging: Determines whether or not the bot logs colored logs
|
|
||||||
# to stdout.
|
|
||||||
###
|
|
||||||
colorizedStdoutLogging = True
|
|
||||||
|
|
||||||
###
|
|
||||||
# logTimestampFormat: A format string defining how timestamps should be. Check
|
|
||||||
# the Python library reference for the "time" module to see
|
|
||||||
# what the various format specifiers mean.
|
|
||||||
###
|
|
||||||
logTimestampFormat = '[%d-%b-%Y %H:%M:%S]'
|
|
||||||
|
|
||||||
###
|
|
||||||
# humanTimestampFormat: A format string defining how timestamps should be
|
|
||||||
# formatted for human consumption. Check the Python
|
|
||||||
# library reference for the "time" module to see what the
|
|
||||||
# various format specifiers mean.
|
|
||||||
###
|
|
||||||
humanTimestampFormat = '%I:%M %p, %B %d, %Y'
|
|
||||||
|
|
||||||
###
|
|
||||||
# externalIP: A string that is the external IP of the bot. If this is None,
|
|
||||||
# the bot will attempt to find out its IP dynamically (though
|
|
||||||
# sometimes this doesn't work.)
|
|
||||||
###
|
|
||||||
externalIP = None
|
|
||||||
|
|
||||||
###
|
|
||||||
# throttleTime: A floating point number of seconds to throttle queued messages.
|
|
||||||
# (i.e., messages will not be sent faster than once per
|
|
||||||
# throttleTime units.)
|
|
||||||
###
|
|
||||||
throttleTime = 1.0
|
|
||||||
|
|
||||||
###
|
|
||||||
# snarfThrottle: A floating point number of seconds to throttle snarfed URLs,
|
|
||||||
# in order to prevent loops between two bots.
|
|
||||||
###
|
|
||||||
snarfThrottle = 10.0
|
|
||||||
|
|
||||||
###
|
###
|
||||||
# allowEval: True if the owner (and only the owner) should be able to eval
|
# allowEval: True if the owner (and only the owner) should be able to eval
|
||||||
# arbitrary Python code.
|
# arbitrary Python code. This is specifically *not* a registry
|
||||||
|
# variable because it shouldn't be modifiable in the bot.
|
||||||
###
|
###
|
||||||
allowEval = False
|
allowEval = False
|
||||||
|
|
||||||
###
|
|
||||||
# replyWhenNotCommand: True if you want the bot reply when someone apparently
|
supybot = registry.Group()
|
||||||
# addresses him but there is no command. Otherwise he'll
|
supybot.setName('supybot')
|
||||||
# just remain silent.
|
supybot.registerGroup('plugins') # This will be used by plugins, but not here.
|
||||||
###
|
|
||||||
replyWhenNotCommand = True
|
class ValidNick(registry.String):
|
||||||
|
def set(self, s):
|
||||||
|
original = getattr(self, 'value', self.default)
|
||||||
|
registry.String.set(self, s)
|
||||||
|
if not ircutils.isNick(self.value):
|
||||||
|
self.value = original
|
||||||
|
raise registry.InvalidRegistryValue, 'Value must be a valid nick.'
|
||||||
|
|
||||||
|
supybot.register('nick', ValidNick('supybot',
|
||||||
|
"""Determines the bot's nick."""))
|
||||||
|
|
||||||
|
supybot.register('ident', ValidNick('supybot',
|
||||||
|
"""Determines the bot's ident."""))
|
||||||
|
|
||||||
|
supybot.register('user', registry.String('supybot', """Determines the user
|
||||||
|
the bot sends to the server."""))
|
||||||
|
|
||||||
|
supybot.register('password', registry.String('', """Determines the password to
|
||||||
|
be sent to the server if it requires one."""))
|
||||||
|
|
||||||
|
# TODO: Make this check for validity.
|
||||||
|
supybot.register('server', registry.String('irc.freenode.net', """Determines
|
||||||
|
what server the bot connects to."""))
|
||||||
|
|
||||||
|
supybot.register('channels', registry.CommaSeparatedListOfStrings('#supybot',
|
||||||
|
"""Determines what channels the bot will join when it connects to the server.
|
||||||
|
"""))
|
||||||
|
|
||||||
|
supybot.registerGroup('databases')
|
||||||
|
supybot.databases.registerGroup('users')
|
||||||
|
supybot.databases.registerGroup('channels')
|
||||||
|
supybot.databases.users.register('filename', registry.String('users.conf', """
|
||||||
|
Determines what filename will be used for the users database. This file will
|
||||||
|
go into the directory specified by the supybot.directories.conf
|
||||||
|
variable."""))
|
||||||
|
supybot.databases.channels.register('filename',registry.String('channels.conf',
|
||||||
|
"""Determines what filename will be used for the channels database. This file
|
||||||
|
will go into the directory specified by the supybot.directories.conf
|
||||||
|
variable."""))
|
||||||
|
|
||||||
|
supybot.registerGroup('directories')
|
||||||
|
supybot.directories.register('conf', registry.String('conf', """
|
||||||
|
Determines what directory configuration data is put into."""))
|
||||||
|
supybot.directories.register('data', registry.String('data', """
|
||||||
|
Determines what directory data is put into."""))
|
||||||
|
supybot.directories.register('plugins',
|
||||||
|
registry.CommaSeparatedListOfStrings(['plugins',_srcDir,_pluginsDir],
|
||||||
|
"""Determines what directories the bot will look for plugins in."""))
|
||||||
|
|
||||||
|
supybot.register('humanTimestampFormat', registry.String('%I:%M %p, %B %d, %Y',
|
||||||
|
"""Determines how timestamps printed for human reading should be formatted.
|
||||||
|
Refer to the Python documentation for the time module to see valid formatting
|
||||||
|
characteres for time formats."""))
|
||||||
|
|
||||||
|
class IP(registry.String):
|
||||||
|
def set(self, s):
|
||||||
|
original = getattr(self, 'value', self.default)
|
||||||
|
registry.String.set(self, s)
|
||||||
|
if self.value: # Empty string is alright.
|
||||||
|
if not (utils.isIP(self.value) or utils.isIPV6(self.value)):
|
||||||
|
raise registry.InvalidRegistryValue, \
|
||||||
|
'Value must be a valid IP.'
|
||||||
|
|
||||||
|
supybot.register('externalIP', IP('', """A string that is the external IP of
|
||||||
|
the bot. If this is the empty string, the bot will attempt to find out its IP
|
||||||
|
dynamically (though sometimes that doesn't work, hence this variable)."""))
|
||||||
|
|
||||||
|
# XXX Should this (and a few others) be made into a group 'network' or
|
||||||
|
# 'server' or something?
|
||||||
|
supybot.register('throttleTime', registry.Float(1.0, """A floating point
|
||||||
|
number of seconds to throttle queued messages -- that is, messages will not
|
||||||
|
be sent faster than once per throttleTime seconds."""))
|
||||||
|
|
||||||
|
supybot.register('snarfThrottle', registry.Float(10.0, """A floating point
|
||||||
|
number of seconds to throttle snarfed URLs, in order to prevent loops between
|
||||||
|
two bots snarfing the same URLs and having the snarfed URL in the output of
|
||||||
|
the snarf message."""))
|
||||||
|
|
||||||
###
|
###
|
||||||
# replyWithPrivateNotice: True if replies to a user in a channel should be
|
# Reply/error tweaking.
|
||||||
# noticed to that user instead of sent to the channel
|
|
||||||
# itself.
|
|
||||||
###
|
###
|
||||||
replyWithPrivateNotice = False
|
|
||||||
|
# TODO: These should probably all be channel-specific.
|
||||||
|
supybot.registerGroup('reply')
|
||||||
|
supybot.reply.register('errorInPrivate', registry.Boolean(False, """
|
||||||
|
Determines whether the bot will send error messages to users in private."""))
|
||||||
|
|
||||||
|
supybot.reply.register('whenNotCommand', registry.Boolean(True, """
|
||||||
|
Determines whether the bot will reply with an error message when it is
|
||||||
|
addressed but not given a valid command. If this value is False, the bot
|
||||||
|
will remain silent."""))
|
||||||
|
|
||||||
|
supybot.reply.register('withPrivateNotice', registry.Boolean(False, """
|
||||||
|
Determines whether the bot will reply with a private notice to users rather
|
||||||
|
than sending a message to a channel. Private notices are particularly nice
|
||||||
|
because they don't generally cause IRC clients to open a new query window."""))
|
||||||
|
|
||||||
|
supybot.reply.register('withNickPrefix', registry.Boolean(True, """
|
||||||
|
Determines whether the bot will always prefix the user's nick to its reply to
|
||||||
|
that user's command."""))
|
||||||
|
|
||||||
|
supybot.reply.register('whenAddressedByNick', registry.Boolean(True, """
|
||||||
|
Determines whether the bot will reply when people address it by its nick,
|
||||||
|
rather than with a prefix character."""))
|
||||||
|
|
||||||
|
supybot.reply.register('whenNotAddressed', registry.Boolean(False, """
|
||||||
|
Determines whether the bot should attempt to reply to all messages even if they
|
||||||
|
don't address it (either via its nick or a prefix character). If you set this
|
||||||
|
to True, you almost certainly want to set supybot.reply.whenNotCommand to
|
||||||
|
False."""))
|
||||||
|
|
||||||
|
# XXX: Removed requireRegistration: it wasn't being used.
|
||||||
|
|
||||||
|
supybot.reply.register('requireChannelCommandsToBeSentInChannel',
|
||||||
|
registry.Boolean(False, """Determines whether the bot will allow you to send
|
||||||
|
channel-related commands outside of that channel. Sometimes people find it
|
||||||
|
confusing if a channel-related command (like Filter.outfilter) changes the
|
||||||
|
behavior of the channel but was sent outside the channel itself."""))
|
||||||
|
|
||||||
|
supybot.register('followIdentificationThroughNickChanges',
|
||||||
|
registry.Boolean(False, """Determines whether the bot will unidentify someone
|
||||||
|
when that person changes his or her nick. Setting this to True will cause the
|
||||||
|
bot to track such changes. It defaults to false for a little greater security.
|
||||||
|
"""))
|
||||||
|
|
||||||
|
supybot.register('alwaysJoinOnInvite', registry.Boolean(False, """Determines
|
||||||
|
whether the bot will always join a channel when it's invited. If this value
|
||||||
|
is False, the bot will only join a channel if the user inviting it has the
|
||||||
|
'admin' capability (or if it's explicitly told to join the channel using the
|
||||||
|
Admin.join command)"""))
|
||||||
|
|
||||||
|
supybot.register('pipeSyntax', registry.Boolean(False, """Supybot allows
|
||||||
|
nested commands; generally, commands are nested via square brackets. Supybot
|
||||||
|
can also provide a syntax more similar to UNIX pipes. The square bracket
|
||||||
|
nesting syntax is always enabled, but when this value is True, users can also
|
||||||
|
nest commands by saying 'bot: foo | bar' instead of 'bot: bar [foo]'."""))
|
||||||
|
|
||||||
|
supybot.register('showSimpleSyntax', registry.Boolean(False, """Supybot
|
||||||
|
normally replies with the full help whenever a user misuses a command. If this
|
||||||
|
value is set to True, the bot will only reply with the syntax of the command
|
||||||
|
(the first line of the docstring) rather than the full help."""))
|
||||||
|
|
||||||
|
supybot.register('defaultCapabilities',
|
||||||
|
registry.CommaSeparatedSetOfStrings(['-owner', '-admin', '-trusted'], """
|
||||||
|
These are the capabilities that are given to everyone by default. If they are
|
||||||
|
normal capabilities, then the user will have to have the appropriate
|
||||||
|
anti-capability if you want to override these capabilities; if they are
|
||||||
|
anti-capabilities, then the user will have to have the actual capability to
|
||||||
|
override these capabilities. See docs/CAPABILITIES if you don't understand
|
||||||
|
why these default to what they do."""))
|
||||||
|
|
||||||
###
|
###
|
||||||
# replyWithNickPrefix: True if the bot should always prefix the nick of the
|
# Replies
|
||||||
# person giving the command to its reply.
|
|
||||||
###
|
###
|
||||||
replyWithNickPrefix = True
|
# TODO: These should be channel-specific.
|
||||||
|
supybot.registerGroup('replies')
|
||||||
|
|
||||||
|
supybot.replies.register('error', registry.NormalizedString("""An error has
|
||||||
|
occurred and has been logged. Please contact this bot's administrator for more
|
||||||
|
information.""", """Determines what error message the bot gives when it wants
|
||||||
|
to be ambiguous."""))
|
||||||
|
|
||||||
|
supybot.replies.register('noCapability', registry.NormalizedString("""You
|
||||||
|
don\'t have the %r capability. If you think that you should have this
|
||||||
|
capability, be sure that you are identified before trying again. The 'whoami'
|
||||||
|
command can tell you if you're identified.""", """Determines what error message
|
||||||
|
is given when the bot is telling someone they aren't cool enough to use the
|
||||||
|
command they tried to use."""))
|
||||||
|
|
||||||
|
supybot.replies.register('success', registry.NormalizedString("""The operation
|
||||||
|
succeeded.""", """Determines what message the bot replies with when a command
|
||||||
|
succeeded."""))
|
||||||
|
|
||||||
|
supybot.replies.register('incorrectAuthentication',
|
||||||
|
registry.NormalizedString("""Your hostmask doesn't match or your password is
|
||||||
|
wrong.""", """Determines what message the bot replies wiwth when someone tries
|
||||||
|
to use a command that requires being identified or having a password and
|
||||||
|
neither credential is correct."""))
|
||||||
|
|
||||||
|
supybot.replies.register('noUser', registry.NormalizedString("""I can't find
|
||||||
|
that user in my user database.""", """Determines what error message the bot
|
||||||
|
replies with when someone tries to accessing some information on a user the
|
||||||
|
bot doesn't know about."""))
|
||||||
|
|
||||||
|
supybot.replies.register('notRegistered', registry.NormalizedString("""
|
||||||
|
You must be registered to use this command. If you are already registered, you
|
||||||
|
must either identify (using the identify command) or add a hostmask matching
|
||||||
|
your current hostmask (using the addhostmask command).""", """Determines what
|
||||||
|
error message the bot replies with when someone tries to do something that
|
||||||
|
requires them to be registered but they're not currently recognized."""))
|
||||||
|
|
||||||
|
# XXX: removed replyInvalidArgument.
|
||||||
|
|
||||||
|
supybot.replies.register('requiresPrivacy', registry.NormalizedString("""
|
||||||
|
That operation cannot be done in a channel.""", """Determines what error
|
||||||
|
messages the bot sends to people who try to do things in a channel that really
|
||||||
|
should be done in private."""))
|
||||||
|
supybot.replies.register('possibleBug', registry.NormalizedString("""This may
|
||||||
|
be a bug. If you think it is, please file a bug report at
|
||||||
|
<http://sourceforge.net/tracker/?func=add&group_id=58965&atid=489447>.""",
|
||||||
|
"""Determines what message the bot sends when it thinks you've encountered a
|
||||||
|
bug that the developers don't know about."""))
|
||||||
|
|
||||||
|
supybot.register('pingServer', registry.Boolean(True, """Determines whether
|
||||||
|
the bot will send PINGs to the server it's connected to in order to keep the
|
||||||
|
connection alive and discover earlier when it breaks. Really, this option
|
||||||
|
only exists for debugging purposes: you always should make it True unless
|
||||||
|
you're testing some strange server issues."""))
|
||||||
|
|
||||||
|
supybot.register('pingInterval', registry.Integer(120, """Determines the
|
||||||
|
number of seconds between sending pings to the server, if pings are being sent
|
||||||
|
to the server."""))
|
||||||
|
|
||||||
|
supybot.register('maxHistoryLength', registry.Integer(1000, """Determines
|
||||||
|
how many old messages the bot will keep around in its history. Changing this
|
||||||
|
variable will not take effect until the bot is restarted."""))
|
||||||
|
|
||||||
|
supybot.register('nickmods', registry.CommaSeparatedListOfStrings(
|
||||||
|
'__%s__,%s^,%s`,%s_,%s__,_%s,__%s,[%s]'.split(','),
|
||||||
|
"""A list of modifications to be made to a nick when the nick the bot tries
|
||||||
|
to get from the server is in use. There should be one %s in each string;
|
||||||
|
this will get replaced with the original nick."""))
|
||||||
|
|
||||||
|
supybot.register('defaultAllow', registry.Boolean(True, """Determines whether
|
||||||
|
the bot by default will allow users to run commands. If this is disabled, a
|
||||||
|
user will have to have the capability for whatever command he wishes to run.
|
||||||
|
"""))
|
||||||
|
|
||||||
|
supybot.register('defaultIgnore', registry.Boolean(False, """Determines
|
||||||
|
whether the bot will ignore unregistered users by default. Of course, that'll
|
||||||
|
make it particularly hard for those users to register with the bot, but that's
|
||||||
|
your problem to solve."""))
|
||||||
|
|
||||||
|
supybot.register('ignores', registry.CommaSeparatedListOfStrings('', """
|
||||||
|
A list of hostmasks ignored by the bot. Add people you don't like to here.
|
||||||
|
"""))
|
||||||
|
|
||||||
|
class ValidPrefixChars(registry.String):
|
||||||
|
def set(self, s):
|
||||||
|
registry.String.set(self, s)
|
||||||
|
if self.value.translate(string.ascii,
|
||||||
|
'`~!@#$%^&*()_-+=[{}]\\|\'";:,<.>/?'):
|
||||||
|
raise registry.InvalidRegistryValue, \
|
||||||
|
'Value must contain only ~!@#$%^&*()_-+=[{}]\\|\'";:,<.>/?'
|
||||||
|
|
||||||
|
supybot.register('prefixChars', ValidPrefixChars('@', """Determines what prefix
|
||||||
|
characters the bot will reply to. A prefix character is a single character
|
||||||
|
that the bot will use to determine what messages are addressed to it; when
|
||||||
|
there are no prefix characters set, it just uses its nick."""))
|
||||||
|
|
||||||
###
|
###
|
||||||
# replyWhenAddressedByNick: True if the bot should reply to messages of the
|
# Driver stuff.
|
||||||
# form "botnick: foo" where "botnick" is the bot's
|
|
||||||
# nick.
|
|
||||||
###
|
###
|
||||||
replyWhenAddressedByNick = True
|
supybot.registerGroup('drivers')
|
||||||
|
supybot.drivers.register('poll', registry.Float(1.0, """Determines the default
|
||||||
|
length of time a driver should block waiting for input."""))
|
||||||
|
|
||||||
###
|
class ValidDriverModule(registry.String):
|
||||||
# replyWhenNotAddressed: True if the bot should reply to messages even if they
|
def set(self, s):
|
||||||
# don't address it at all. If you have this on, you'll
|
original = getattr(self, 'value', self.default)
|
||||||
# almost certainly want to make sure replyWhenNotCommand
|
registry.String.set(self, s)
|
||||||
# is turned off.
|
if self.value not in ('socketDrivers',
|
||||||
###
|
'twistedDrivers',
|
||||||
replyWhenNotAddressed = False
|
'asyncoreDrivers'):
|
||||||
|
self.value = original
|
||||||
|
raise registry.InvalidRegistryValue, \
|
||||||
|
'Value must be one of "socketDrivers", "asyncoreDrivers", ' \
|
||||||
|
'or twistedDrivers.'
|
||||||
|
else:
|
||||||
|
# TODO: check to make sure Twisted is available if it's set to
|
||||||
|
# twistedDrivers.
|
||||||
|
pass
|
||||||
|
|
||||||
###
|
supybot.drivers.register('module', ValidDriverModule('socketDrivers', """
|
||||||
# requireRegistration: Oftentimes a plugin will want to record who added or
|
Determines what driver module the bot will use. socketDrivers, a simple
|
||||||
# changed or messed with it last. Supybot's user database
|
driver based on timeout sockets, is used by default because it's simple and
|
||||||
# is an excellent way to determine who exactly someone is.
|
stable. asyncoreDrivers is a bit older (and less well-maintained) but allows
|
||||||
# You may, however, want something a little less
|
you to integrate with asyncore-based applications. twistedDrivers is very
|
||||||
# "intrustive," so you can set this variable to False to
|
stable and simple, and if you've got Twisted installed, is probably your best
|
||||||
# tell such plugins that they should use the hostmask when
|
bet."""))
|
||||||
# the user isn't registered with the user database.
|
|
||||||
###
|
|
||||||
requireRegistration = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# requireChannelCommandsToBeSentInChannel: Normally, you can send channel
|
|
||||||
# related commands in private or in
|
|
||||||
# another channel. Sometimes this
|
|
||||||
# can be confusing, though, if the
|
|
||||||
# command changes the behavior of
|
|
||||||
# the bot in the channel. Set this
|
|
||||||
# variable to True if you want to
|
|
||||||
# require such commands to be sent
|
|
||||||
# in the channel to which they apply.
|
|
||||||
###
|
|
||||||
requireChannelCommandsToBeSentInChannel = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# followIdentificationThroughNickChanges: By default the bot will simply
|
|
||||||
# unidentify someone when he changes
|
|
||||||
# his nick. Setting this to True will
|
|
||||||
# cause the bot to track such changes.
|
|
||||||
###
|
|
||||||
followIdentificationThroughNickChanges = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# alwaysJoinOnInvite: Causes the bot to always join a channel when it's
|
|
||||||
# invited. Defaults to False, in which case the bot will
|
|
||||||
# only join if the user inviting it has the 'admin'
|
|
||||||
# capability.
|
|
||||||
###
|
|
||||||
alwaysJoinOnInvite = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# enablePipeSyntax: Supybot allows nested commands; generally, commands are
|
|
||||||
# nested via [square brackets]. Supybot can also use a
|
|
||||||
# syntax more similar to Unix pipes. What would be (and
|
|
||||||
# still can be; the pipe syntax doesn't disable the bracket
|
|
||||||
# syntax) "bot: bar [foo]" can now by "bot: foo | bar"
|
|
||||||
# This variable enables such syntax.
|
|
||||||
###
|
|
||||||
enablePipeSyntax = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# showOnlySyntax : Supybot normally returns the full help whenever a user
|
|
||||||
# misuses a command. If this option is set to True, the bot
|
|
||||||
# will only return the syntax of the command (the first line
|
|
||||||
# of the docstring) rather than the full help.
|
|
||||||
###
|
|
||||||
showOnlySyntax = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# defaultCapabilities: Capabilities allowed to everyone by default. You almost
|
|
||||||
# certainly want to have !owner and !admin in here.
|
|
||||||
###
|
|
||||||
defaultCapabilities = sets.Set(['-owner', '-admin', '-trusted'])
|
|
||||||
|
|
||||||
###
|
|
||||||
# reply%s: Stock replies for various reasons.
|
|
||||||
###
|
|
||||||
replyError = 'An error has occurred and has been logged. ' \
|
|
||||||
'Please contact this bot\'s administrator for more information.'
|
|
||||||
replyNoCapability = 'You don\'t have the "%s" capability. If you think ' \
|
|
||||||
'that you should have this capability, be sure that ' \
|
|
||||||
'you are identified via the "whoami" command.'
|
|
||||||
replySuccess = 'The operation succeeded.'
|
|
||||||
replyIncorrectAuth = 'Your hostmask doesn\'t match or your password is wrong.'
|
|
||||||
replyNoUser = 'I can\'t find that user in my database.'
|
|
||||||
replyNotRegistered = 'You must be registered to use this command. ' \
|
|
||||||
'If you are already registered, you must either ' \
|
|
||||||
'identify (using the identify command) or add a ' \
|
|
||||||
'hostmask matching your current hostmask (using ' \
|
|
||||||
'the addhostmask command).'
|
|
||||||
replyInvalidArgument = 'I can\'t send \\r, \\n, or \\0 (\\x00).'
|
|
||||||
replyRequiresPrivacy = 'That can\'t be done in a channel.'
|
|
||||||
replyEvalNotAllowed = 'You must enable conf.allowEval for that to work.'
|
|
||||||
replyPossibleBug = 'This may be a bug. If you think it is, please file a bug '\
|
|
||||||
'report at <http://sourceforge.net/tracker/?' \
|
|
||||||
'func=add&group_id=58965&atid=489447>'
|
|
||||||
|
|
||||||
###
|
|
||||||
# errorReplyPrivate: True if errors should be reported privately so as not to
|
|
||||||
# bother the channel.
|
|
||||||
###
|
|
||||||
errorReplyPrivate = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# telnetEnable: A boolean saying whether or not to enable the telnet REPL.
|
|
||||||
# This will allow a user with the 'owner' capability to telnet
|
|
||||||
# into the bot and see how it's working internally. A lifesaver
|
|
||||||
# for development.
|
|
||||||
###
|
|
||||||
telnetEnable = False
|
|
||||||
telnetPort = 31337
|
|
||||||
|
|
||||||
###
|
|
||||||
# poll: the length of a polling term.
|
|
||||||
# If asyncore drivers are all you're using, feel free to make
|
|
||||||
# this arbitrarily large -- be warned, however, that all other
|
|
||||||
# drivers are just sitting around while asyncore waits during
|
|
||||||
# this poll period (including the schedule). It'll take more
|
|
||||||
# CPU, but you probably don't want to set this more than 0.01
|
|
||||||
# when you've got non-asyncore drivers to worry about.
|
|
||||||
###
|
|
||||||
poll = 1
|
|
||||||
|
|
||||||
###
|
|
||||||
# pingServer: Determines whether the bot will send PINGs to the server it's
|
|
||||||
# connected to in order to keep the connection alive. Sometimes
|
|
||||||
# this seems to result in instability.
|
|
||||||
###
|
|
||||||
pingServer = True
|
|
||||||
|
|
||||||
###
|
|
||||||
# maxHistory: Maximum number of messages kept in an Irc object's state.
|
|
||||||
###
|
|
||||||
maxHistory = 1000
|
|
||||||
|
|
||||||
###
|
|
||||||
# pingInterval: Number of seconds between PINGs to the server.
|
|
||||||
# 0 means not to ping the server.
|
|
||||||
###
|
|
||||||
pingInterval = 120
|
|
||||||
|
|
||||||
###
|
|
||||||
# nickmods: List of ways to 'spice up' a nick so the bot doesn't run out of
|
|
||||||
# nicks if all his normal ones are taken.
|
|
||||||
###
|
|
||||||
nickmods = ['%s^', '^%s^', '__%s__', '%s_', '%s__', '__%s', '^^%s^^', '{%s}',
|
|
||||||
'[%s]', '][%s][', '}{%s}{', '}{}%s', '^_^%s', '%s^_^', '^_^%s^_^']
|
|
||||||
|
|
||||||
###
|
|
||||||
# defaultAllow: Are commands allowed by default?
|
|
||||||
###
|
|
||||||
defaultAllow = True
|
|
||||||
|
|
||||||
###
|
|
||||||
# defaultIgnore: True if users should be ignored by default.
|
|
||||||
# It's a really easy way to make sure that people who want to
|
|
||||||
# talk to the bot register first. (Of course, they can't
|
|
||||||
# register if they're ignored. We'll work on that.)
|
|
||||||
###
|
|
||||||
defaultIgnore = False
|
|
||||||
|
|
||||||
###
|
|
||||||
# ignores: Hostmasks to ignore.
|
|
||||||
###
|
|
||||||
ignores = []
|
|
||||||
|
|
||||||
###
|
|
||||||
# prefixChars: A string of chars that are valid prefixes to address the bot.
|
|
||||||
###
|
|
||||||
prefixChars = '@'
|
|
||||||
|
|
||||||
###
|
|
||||||
# validPrefixChars: A string of chars that are allowed to be used as
|
|
||||||
# prefixChars.
|
|
||||||
###
|
|
||||||
validPrefixChars = '`~!@#$%^&*()_-+=[{}]\\|\'";:,<.>/?'
|
|
||||||
|
|
||||||
###
|
|
||||||
# detailedTracebacks: A boolean describing whether or not the bot will give
|
|
||||||
# *extremely* detailed tracebacks. Be cautioned, this eats
|
|
||||||
# a lot of log file space.
|
|
||||||
###
|
|
||||||
detailedTracebacks = True
|
|
||||||
|
|
||||||
###
|
|
||||||
# driverModule: A string that is the module where the default driver for the
|
|
||||||
# bot will be found.
|
|
||||||
###
|
|
||||||
driverModule = 'socketDrivers'
|
|
||||||
#driverModule = 'asyncoreDrivers'
|
|
||||||
#driverModule = 'twistedDrivers'
|
|
||||||
|
|
||||||
###############################
|
###############################
|
||||||
###############################
|
###############################
|
||||||
@ -346,71 +347,4 @@ driverModule = 'socketDrivers'
|
|||||||
###############################
|
###############################
|
||||||
version ='0.76.1'
|
version ='0.76.1'
|
||||||
|
|
||||||
commandsOnStart = []
|
|
||||||
|
|
||||||
# This is a dictionary mapping names to converter functions for use in the
|
|
||||||
# Owner.setconf command.
|
|
||||||
def mybool(s):
|
|
||||||
"""Converts a string read from the user into a bool, fuzzily."""
|
|
||||||
if s.capitalize() == 'False' or s == '0':
|
|
||||||
return False
|
|
||||||
elif s.capitalize() == 'True' or s == '1':
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
raise ValueError, 'invalid literal for mybool()'
|
|
||||||
|
|
||||||
def mystr(s):
|
|
||||||
"""Converts a string read from the user into a real string."""
|
|
||||||
while s and s[0] in "'\"" and s[0] == s[-1]:
|
|
||||||
s = s[1:-1]
|
|
||||||
return s
|
|
||||||
|
|
||||||
types = {
|
|
||||||
'logDir': mystr,
|
|
||||||
'confDir': mystr,
|
|
||||||
'dataDir': mystr,
|
|
||||||
#'pluginDirs': (list, str),
|
|
||||||
'userfile': mystr,
|
|
||||||
'channelfile': mystr,
|
|
||||||
'logTimestampFormat': mystr,
|
|
||||||
'humanTimestampFormat': mystr,
|
|
||||||
'throttleTime': float,
|
|
||||||
'snarfThrottle': float,
|
|
||||||
#'allowEval': mybool,
|
|
||||||
'replyWhenNotCommand': mybool,
|
|
||||||
'replyWithPrivateNotice': mybool,
|
|
||||||
'replyWithNickPrefix': mybool,
|
|
||||||
'replyWhenAddressedByNick': mybool,
|
|
||||||
'requireRegistration': mybool,
|
|
||||||
'enablePipeSyntax': mybool,
|
|
||||||
'replyError': mystr,
|
|
||||||
'replyNoCapability': mystr,
|
|
||||||
'replySuccess': mystr,
|
|
||||||
'replyIncorrectAuth': mystr,
|
|
||||||
'replyNoUser': mystr,
|
|
||||||
'replyNotRegistered': mystr,
|
|
||||||
'replyInvalidArgument': mystr,
|
|
||||||
'replyRequiresPrivacy': mystr,
|
|
||||||
'replyEvalNotAllowed': mystr,
|
|
||||||
'errorReplyPrivate': mybool,
|
|
||||||
#'telnetEnable': mybool,
|
|
||||||
#'telnetPort': int,
|
|
||||||
'poll': float,
|
|
||||||
#'maxHistory': int,
|
|
||||||
'pingInterval': float,
|
|
||||||
#'nickmods': (list, str),
|
|
||||||
'defaultAllow': mybool,
|
|
||||||
'defaultIgnore': mybool,
|
|
||||||
#'ignores': (list, str),
|
|
||||||
'prefixChars': mystr,
|
|
||||||
'detailedTracebacks': mybool,
|
|
||||||
'driverModule': mystr,
|
|
||||||
'showOnlySyntax': mybool,
|
|
||||||
'pingServer': mybool,
|
|
||||||
'followIdentificationThroughNickChanges': mybool
|
|
||||||
}
|
|
||||||
|
|
||||||
if os.name == 'nt':
|
|
||||||
colorizedStdoutLogging = False
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -210,7 +210,8 @@ class Mixin(object):
|
|||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
className = self.__class__.__name__
|
className = self.__class__.__name__
|
||||||
self.filename = os.path.join(conf.confDir, '%s-configurable'%className)
|
self.filename = os.path.join(conf.supybot.directories.conf(),
|
||||||
|
'%s-configurable'%className)
|
||||||
if os.path.exists(self.filename):
|
if os.path.exists(self.filename):
|
||||||
fd = file(self.filename)
|
fd = file(self.filename)
|
||||||
for line in fd:
|
for line in fd:
|
||||||
@ -258,7 +259,7 @@ class Mixin(object):
|
|||||||
flushDictionary(self.configurables)
|
flushDictionary(self.configurables)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
def config(self, irc, msg, args):
|
def configurableishnessify(self, irc, msg, args):
|
||||||
"""[<channel>] [<name>] [<value>]
|
"""[<channel>] [<name>] [<value>]
|
||||||
|
|
||||||
Sets the value of config variable <name> to <value> on <channel>. If
|
Sets the value of config variable <name> to <value> on <channel>. If
|
||||||
|
@ -148,8 +148,11 @@ def run():
|
|||||||
del _drivers[name]
|
del _drivers[name]
|
||||||
_drivers[name] = driver
|
_drivers[name] = driver
|
||||||
|
|
||||||
def newDriver(server, irc, moduleName=conf.driverModule):
|
def newDriver(server, irc, moduleName=None):
|
||||||
"""Returns a new driver for the given server using conf.driverModule."""
|
"""Returns a new driver for the given server using the irc given and using
|
||||||
|
conf.supybot.driverModule to determine what driver to pick."""
|
||||||
|
if moduleName is None:
|
||||||
|
moduleName = conf.supybot.drivers.module()
|
||||||
driver = __import__(moduleName).Driver(server, irc)
|
driver = __import__(moduleName).Driver(server, irc)
|
||||||
irc.driver = driver
|
irc.driver = driver
|
||||||
return driver
|
return driver
|
||||||
|
31
src/ircdb.py
31
src/ircdb.py
@ -556,8 +556,11 @@ class ChannelsDictionary(utils.IterableMap):
|
|||||||
###
|
###
|
||||||
# Later, I might add some special handling for botnet.
|
# Later, I might add some special handling for botnet.
|
||||||
###
|
###
|
||||||
users = UsersDB(os.path.join(conf.confDir, conf.userfile))
|
confDir = conf.supybot.directories.conf()
|
||||||
channels = ChannelsDictionary(os.path.join(conf.confDir, conf.channelfile))
|
users = UsersDB(os.path.join(confDir,
|
||||||
|
conf.supybot.databases.users.filename()))
|
||||||
|
channels = ChannelsDictionary(os.path.join(confDir,
|
||||||
|
conf.supybot.databases.channels.filename()))
|
||||||
|
|
||||||
###
|
###
|
||||||
# Useful functions for checking credentials.
|
# Useful functions for checking credentials.
|
||||||
@ -567,9 +570,9 @@ def checkIgnored(hostmask, recipient='', users=users, channels=channels):
|
|||||||
|
|
||||||
Checks if the user is ignored by the recipient of the message.
|
Checks if the user is ignored by the recipient of the message.
|
||||||
"""
|
"""
|
||||||
for ignore in conf.ignores:
|
for ignore in conf.supybot.ignores():
|
||||||
if ircutils.hostmaskPatternEqual(ignore, hostmask):
|
if ircutils.hostmaskPatternEqual(ignore, hostmask):
|
||||||
log.info('Ignoring %s due to conf.ignores.', hostmask)
|
log.info('Ignoring %s due to conf.supybot.ignores.', hostmask)
|
||||||
return True
|
return True
|
||||||
try:
|
try:
|
||||||
id = users.getUserId(hostmask)
|
id = users.getUserId(hostmask)
|
||||||
@ -584,8 +587,9 @@ def checkIgnored(hostmask, recipient='', users=users, channels=channels):
|
|||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
if conf.defaultIgnore:
|
if conf.supybot.defaultIgnore():
|
||||||
log.info('Ignoring %s due to conf.defaultIgnore', hostmask)
|
log.info('Ignoring %s due to conf.supybot.defaultIgnore',
|
||||||
|
hostmask)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@ -625,17 +629,17 @@ def _checkCapabilityForUnknownUser(capability, users=users, channels=channels):
|
|||||||
return _x(capability, c.defaultAllow)
|
return _x(capability, c.defaultAllow)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
if capability in conf.defaultCapabilities:
|
if capability in conf.supybot.defaultCapabilities():
|
||||||
return True
|
return True
|
||||||
elif invertCapability(capability) in conf.defaultCapabilities:
|
elif invertCapability(capability) in conf.supybot.defaultCapabilities():
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return _x(capability, conf.defaultAllow)
|
return _x(capability, conf.supybot.defaultAllow())
|
||||||
|
|
||||||
def checkCapability(hostmask, capability, users=users, channels=channels):
|
def checkCapability(hostmask, capability, users=users, channels=channels):
|
||||||
"""Checks that the user specified by name/hostmask has the capabilty given.
|
"""Checks that the user specified by name/hostmask has the capabilty given.
|
||||||
"""
|
"""
|
||||||
if world.startup:
|
if world.testing:
|
||||||
return _x(capability, True)
|
return _x(capability, True)
|
||||||
try:
|
try:
|
||||||
u = users.getUser(hostmask)
|
u = users.getUser(hostmask)
|
||||||
@ -666,12 +670,13 @@ def checkCapability(hostmask, capability, users=users, channels=channels):
|
|||||||
return c.checkCapability(capability)
|
return c.checkCapability(capability)
|
||||||
else:
|
else:
|
||||||
return _x(capability, c.defaultAllow)
|
return _x(capability, c.defaultAllow)
|
||||||
if capability in conf.defaultCapabilities:
|
defaultCapabilities = conf.supybot.defaultCapabilities()
|
||||||
|
if capability in defaultCapabilities:
|
||||||
return True
|
return True
|
||||||
elif invertCapability(capability) in conf.defaultCapabilities:
|
elif invertCapability(capability) in defaultCapabilities:
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
return _x(capability, conf.defaultAllow)
|
return _x(capability, conf.supybot.defaultAllow())
|
||||||
|
|
||||||
|
|
||||||
def checkCapabilities(hostmask, capabilities, requireAll=False):
|
def checkCapabilities(hostmask, capabilities, requireAll=False):
|
||||||
|
@ -148,8 +148,7 @@ class IrcMsgQueue(object):
|
|||||||
def enqueue(self, msg):
|
def enqueue(self, msg):
|
||||||
"""Enqueues a given message."""
|
"""Enqueues a given message."""
|
||||||
if msg in self.msgs:
|
if msg in self.msgs:
|
||||||
if not world.startup:
|
log.info('Not adding msg %s to queue' % msg)
|
||||||
log.info('Not adding msg %s to queue' % msg)
|
|
||||||
else:
|
else:
|
||||||
self.msgs.add(msg)
|
self.msgs.add(msg)
|
||||||
if msg.command in _high:
|
if msg.command in _high:
|
||||||
@ -257,7 +256,7 @@ class IrcState(IrcCommandDispatcher):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ('history', 'nicksToHostmasks', 'channels')
|
__slots__ = ('history', 'nicksToHostmasks', 'channels')
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.history = RingBuffer(conf.maxHistory)
|
self.history = RingBuffer(conf.supybot.maxHistoryLength())
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
@ -407,7 +406,7 @@ class Irc(IrcCommandDispatcher):
|
|||||||
world.ircs.append(self)
|
world.ircs.append(self)
|
||||||
self.originalNick = intern(nick)
|
self.originalNick = intern(nick)
|
||||||
self.nick = self.originalNick
|
self.nick = self.originalNick
|
||||||
self.nickmods = cycle(conf.nickmods)
|
self.nickmods = cycle(conf.supybot.nickmods())
|
||||||
self.password = password
|
self.password = password
|
||||||
self.user = intern(user or nick) # Default to nick
|
self.user = intern(user or nick) # Default to nick
|
||||||
self.ident = intern(ident or nick) # Ditto.
|
self.ident = intern(ident or nick) # Ditto.
|
||||||
@ -486,13 +485,15 @@ class Irc(IrcCommandDispatcher):
|
|||||||
if self.fastqueue:
|
if self.fastqueue:
|
||||||
msg = self.fastqueue.dequeue()
|
msg = self.fastqueue.dequeue()
|
||||||
elif self.queue:
|
elif self.queue:
|
||||||
if not world.testing and now - self.lastTake <= conf.throttleTime:
|
if not world.testing and now - self.lastTake <= \
|
||||||
|
conf.supybot.throttleTime():
|
||||||
log.debug('Irc.takeMsg throttling.')
|
log.debug('Irc.takeMsg throttling.')
|
||||||
else:
|
else:
|
||||||
self.lastTake = now
|
self.lastTake = now
|
||||||
msg = self.queue.dequeue()
|
msg = self.queue.dequeue()
|
||||||
elif conf.pingServer and \
|
elif conf.supybot.pingServer() and \
|
||||||
now > (self.lastping + conf.pingInterval) and self.afterConnect:
|
now > (self.lastping + conf.supybot.pingInterval()) and \
|
||||||
|
self.afterConnect:
|
||||||
if self.outstandingPing:
|
if self.outstandingPing:
|
||||||
s = 'Reconnecting to %s, ping not replied to.' % self.server
|
s = 'Reconnecting to %s, ping not replied to.' % self.server
|
||||||
log.warning(s)
|
log.warning(s)
|
||||||
@ -525,16 +526,6 @@ class Irc(IrcCommandDispatcher):
|
|||||||
msg._len = len(str(msg))
|
msg._len = len(str(msg))
|
||||||
self.state.addMsg(self, msg)
|
self.state.addMsg(self, msg)
|
||||||
log.debug('Outgoing message: ' + str(msg).rstrip('\r\n'))
|
log.debug('Outgoing message: ' + str(msg).rstrip('\r\n'))
|
||||||
if msg.command == 'NICK':
|
|
||||||
# We don't want a race condition where the server's NICK
|
|
||||||
# back to us is lost and someone else steals our nick and uses
|
|
||||||
# it to abuse our 'owner' power we give to ourselves. Ergo, on
|
|
||||||
# outgoing messages that change our nick, we pre-emptively
|
|
||||||
# delete the 'owner' user we setup for ourselves.
|
|
||||||
user = ircdb.users.getUser(0)
|
|
||||||
user.unsetAuth()
|
|
||||||
user.hostmasks = []
|
|
||||||
ircdb.users.setUser(0, user)
|
|
||||||
return msg
|
return msg
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
@ -542,7 +533,6 @@ class Irc(IrcCommandDispatcher):
|
|||||||
def do001(self, msg):
|
def do001(self, msg):
|
||||||
"""Does some logging."""
|
"""Does some logging."""
|
||||||
log.info('Received 001 from the server.')
|
log.info('Received 001 from the server.')
|
||||||
log.info('Hostmasks of user 0: %r', ircdb.users.getUser(0).hostmasks)
|
|
||||||
|
|
||||||
def do002(self, msg):
|
def do002(self, msg):
|
||||||
"""Logs the ircd version."""
|
"""Logs the ircd version."""
|
||||||
@ -577,21 +567,11 @@ class Irc(IrcCommandDispatcher):
|
|||||||
"""Handles NICK messages."""
|
"""Handles NICK messages."""
|
||||||
if msg.nick == self.nick:
|
if msg.nick == self.nick:
|
||||||
newNick = intern(msg.args[0])
|
newNick = intern(msg.args[0])
|
||||||
user = ircdb.users.getUser(0)
|
|
||||||
user.unsetAuth()
|
|
||||||
user.hostmasks = []
|
|
||||||
try:
|
|
||||||
ircdb.users.getUser(newNick)
|
|
||||||
log.error('User already registered with name %s' % newNick)
|
|
||||||
except KeyError:
|
|
||||||
user.name = newNick
|
|
||||||
ircdb.users.setUser(0, user)
|
|
||||||
self.nick = newNick
|
self.nick = newNick
|
||||||
(nick, user, domain) = ircutils.splitHostmask(msg.prefix)
|
(nick, user, domain) = ircutils.splitHostmask(msg.prefix)
|
||||||
self.prefix = ircutils.joinHostmask(self.nick, user, domain)
|
self.prefix = ircutils.joinHostmask(self.nick, user, domain)
|
||||||
self.prefix = intern(self.prefix)
|
self.prefix = intern(self.prefix)
|
||||||
log.info('Changing user 0 hostmask to %r' % self.prefix)
|
elif conf.supybot.followIdentificationThroughNickChanges():
|
||||||
elif conf.followIdentificationThroughNickChanges:
|
|
||||||
# We use elif here because this means it's someone else's nick
|
# We use elif here because this means it's someone else's nick
|
||||||
# change, not our own.
|
# change, not our own.
|
||||||
try:
|
try:
|
||||||
@ -620,13 +600,7 @@ class Irc(IrcCommandDispatcher):
|
|||||||
# This catches cases where we know our own nick (from sending it to the
|
# This catches cases where we know our own nick (from sending it to the
|
||||||
# server) but we don't yet know our prefix.
|
# server) but we don't yet know our prefix.
|
||||||
if msg.nick == self.nick and self.prefix != msg.prefix:
|
if msg.nick == self.nick and self.prefix != msg.prefix:
|
||||||
log.info('Updating user 0 prefix: %r' % msg.prefix)
|
|
||||||
self.prefix = msg.prefix
|
self.prefix = msg.prefix
|
||||||
user = ircdb.users.getUser(0)
|
|
||||||
user.hostmasks = []
|
|
||||||
user.name = self.nick
|
|
||||||
user.addHostmask(msg.prefix)
|
|
||||||
ircdb.users.setUser(0, user)
|
|
||||||
|
|
||||||
# This keeps our nick and server attributes updated.
|
# This keeps our nick and server attributes updated.
|
||||||
if msg.command in self._nickSetters:
|
if msg.command in self._nickSetters:
|
||||||
|
67
src/log.py
67
src/log.py
@ -42,13 +42,57 @@ import logging
|
|||||||
|
|
||||||
import ansi
|
import ansi
|
||||||
import conf
|
import conf
|
||||||
|
import registry
|
||||||
|
|
||||||
|
class LogLevel(registry.Value):
|
||||||
|
def set(self, s):
|
||||||
|
s = s.upper()
|
||||||
|
try:
|
||||||
|
self.value = getattr(logging, s)
|
||||||
|
except AttributeError:
|
||||||
|
s = 'Invalid log level: should be one of ' \
|
||||||
|
'DEBUG, INFO, WARNING, ERROR, or CRITICAL.'
|
||||||
|
raise registry.InvalidRegistryValue, s
|
||||||
|
def __str__(self):
|
||||||
|
return logging.getLevelName(self.value)
|
||||||
|
|
||||||
|
conf.supybot.directories.register('log', registry.String('logs', """Determines
|
||||||
|
what directory the bot will store its logfiles in."""))
|
||||||
|
|
||||||
|
conf.supybot.registerGroup('log')
|
||||||
|
conf.supybot.log.register('minimumPriority', LogLevel(logging.INFO,
|
||||||
|
"""Determines what the minimum priority logged will be. Valid values are
|
||||||
|
DEBUG, INFO, WARNING, ERROR, and CRITICAL, in order of increasing
|
||||||
|
priority."""))
|
||||||
|
conf.supybot.log.register('timestampFormat',
|
||||||
|
registry.String('[%d-%b-%Y %H:%M:%S]',
|
||||||
|
"""Determines the format string for timestamps in logfiles. Refer to the
|
||||||
|
Python documentation for the time module to see what formats are accepted."""))
|
||||||
|
conf.supybot.log.register('detailedTracebacks', registry.Boolean(True, """
|
||||||
|
Determines whether highly detailed tracebacks will be logged. While more
|
||||||
|
informative (and thus more useful for debugging) they also take a significantly
|
||||||
|
greater amount of space in the logs. Hopefully, however, such uncaught
|
||||||
|
exceptions aren't very common."""))
|
||||||
|
conf.supybot.log.registerGroup('stdout',
|
||||||
|
registry.GroupWithValue(registry.Boolean(True, """Determines whether the bot
|
||||||
|
will log to stdout.""")))
|
||||||
|
|
||||||
|
class BooleanRequiredFalseOnWindows(registry.Boolean):
|
||||||
|
def set(self, s):
|
||||||
|
registry.Boolean.set(self, s)
|
||||||
|
if self.value and os.name == 'nt':
|
||||||
|
raise InvalidRegistryValue, 'Value cannot be true on Windows.'
|
||||||
|
|
||||||
|
conf.supybot.log.stdout.register('colorized',
|
||||||
|
BooleanRequiredFalseOnWindows(False, """Determines whether the bot's logs to
|
||||||
|
stdout (if enabled) will be colorized with ANSI color."""))
|
||||||
|
|
||||||
deadlyExceptions = [KeyboardInterrupt, SystemExit]
|
deadlyExceptions = [KeyboardInterrupt, SystemExit]
|
||||||
|
|
||||||
if not os.path.exists(conf.logDir):
|
if not os.path.exists(conf.supybot.directories.log()):
|
||||||
os.mkdir(conf.logDir, 0755)
|
os.mkdir(conf.supybot.directories.log(), 0755)
|
||||||
|
|
||||||
pluginLogDir = os.path.join(conf.logDir, 'plugins')
|
pluginLogDir = os.path.join(conf.supybot.directories.log(), 'plugins')
|
||||||
|
|
||||||
if not os.path.exists(pluginLogDir):
|
if not os.path.exists(pluginLogDir):
|
||||||
os.mkdir(pluginLogDir, 0755)
|
os.mkdir(pluginLogDir, 0755)
|
||||||
@ -56,14 +100,14 @@ if not os.path.exists(pluginLogDir):
|
|||||||
class Formatter(logging.Formatter):
|
class Formatter(logging.Formatter):
|
||||||
def formatTime(self, record, datefmt=None):
|
def formatTime(self, record, datefmt=None):
|
||||||
if datefmt is None:
|
if datefmt is None:
|
||||||
datefmt = conf.logTimestampFormat
|
datefmt = conf.supybot.log.timestampFormat()
|
||||||
return logging.Formatter.formatTime(self, record, datefmt)
|
return logging.Formatter.formatTime(self, record, datefmt)
|
||||||
|
|
||||||
def formatException(self, (E, e, tb)):
|
def formatException(self, (E, e, tb)):
|
||||||
for exn in deadlyExceptions:
|
for exn in deadlyExceptions:
|
||||||
if issubclass(e.__class__, exn):
|
if issubclass(e.__class__, exn):
|
||||||
raise
|
raise
|
||||||
if conf.detailedTracebacks:
|
if conf.supybot.log.detailedTracebacks():
|
||||||
try:
|
try:
|
||||||
return cgitb.text((E, e, tb)).rstrip('\r\n')
|
return cgitb.text((E, e, tb)).rstrip('\r\n')
|
||||||
except:
|
except:
|
||||||
@ -120,7 +164,7 @@ class DailyRotatingHandler(BetterFileHandler):
|
|||||||
|
|
||||||
class ColorizedFormatter(Formatter):
|
class ColorizedFormatter(Formatter):
|
||||||
def formatException(self, (E, e, tb)):
|
def formatException(self, (E, e, tb)):
|
||||||
if conf.colorizedStdoutLogging:
|
if conf.supybot.log.stdout.colorized():
|
||||||
return ''.join([ansi.BOLD, ansi.RED,
|
return ''.join([ansi.BOLD, ansi.RED,
|
||||||
Formatter.formatException(self, (E, e, tb)),
|
Formatter.formatException(self, (E, e, tb)),
|
||||||
ansi.RESET])
|
ansi.RESET])
|
||||||
@ -128,7 +172,7 @@ class ColorizedFormatter(Formatter):
|
|||||||
return Formatter.formatException(self, (E, e, tb))
|
return Formatter.formatException(self, (E, e, tb))
|
||||||
|
|
||||||
def format(self, record, *args, **kwargs):
|
def format(self, record, *args, **kwargs):
|
||||||
if conf.colorizedStdoutLogging:
|
if conf.supybot.log.stdout.colorized():
|
||||||
color = ''
|
color = ''
|
||||||
if record.levelno == logging.CRITICAL:
|
if record.levelno == logging.CRITICAL:
|
||||||
color = ansi.WHITE + ansi.BOLD
|
color = ansi.WHITE + ansi.BOLD
|
||||||
@ -148,13 +192,14 @@ pluginFormatter = Formatter('%(levelname)s %(asctime)s %(name)s %(message)s')
|
|||||||
|
|
||||||
# These are not.
|
# These are not.
|
||||||
_logger = logging.getLogger('supybot')
|
_logger = logging.getLogger('supybot')
|
||||||
_handler = BetterFileHandler(os.path.join(conf.logDir, 'misc.log'))
|
_handler = BetterFileHandler(os.path.join(conf.supybot.directories.log(),
|
||||||
|
'misc.log'))
|
||||||
_handler.setFormatter(formatter)
|
_handler.setFormatter(formatter)
|
||||||
_handler.setLevel(-1)
|
_handler.setLevel(-1)
|
||||||
_logger.addHandler(_handler)
|
_logger.addHandler(_handler)
|
||||||
_logger.setLevel(conf.minimumLogPriority)
|
_logger.setLevel(conf.supybot.log.minimumPriority())
|
||||||
|
|
||||||
if conf.stdoutLogging:
|
if conf.supybot.log.stdout():
|
||||||
_stdoutHandler = BetterStreamHandler(sys.stdout)
|
_stdoutHandler = BetterStreamHandler(sys.stdout)
|
||||||
_formatString = '%(name)s: %(levelname)s %(message)s'
|
_formatString = '%(name)s: %(levelname)s %(message)s'
|
||||||
_stdoutFormatter = ColorizedFormatter(_formatString)
|
_stdoutFormatter = ColorizedFormatter(_formatString)
|
||||||
@ -178,7 +223,7 @@ def getPluginLogger(name):
|
|||||||
if not log.handlers:
|
if not log.handlers:
|
||||||
filename = os.path.join(pluginLogDir, '%s.log' % name)
|
filename = os.path.join(pluginLogDir, '%s.log' % name)
|
||||||
handler = BetterFileHandler(filename)
|
handler = BetterFileHandler(filename)
|
||||||
handler.setLevel(conf.minimumLogPriority)
|
handler.setLevel(conf.supybot.log.minimumPriority())
|
||||||
handler.setFormatter(pluginFormatter)
|
handler.setFormatter(pluginFormatter)
|
||||||
log.addHandler(handler)
|
log.addHandler(handler)
|
||||||
return log
|
return log
|
||||||
|
@ -118,7 +118,7 @@ class ChannelDBHandler(object):
|
|||||||
"""Override this to specialize the filenames of your databases."""
|
"""Override this to specialize the filenames of your databases."""
|
||||||
channel = ircutils.toLower(channel)
|
channel = ircutils.toLower(channel)
|
||||||
prefix = '%s-%s%s' % (channel, self.__class__.__name__, self.suffix)
|
prefix = '%s-%s%s' % (channel, self.__class__.__name__, self.suffix)
|
||||||
return os.path.join(conf.dataDir, prefix)
|
return os.path.join(conf.supybot.directories.data(), prefix)
|
||||||
|
|
||||||
def makeDb(self, filename):
|
def makeDb(self, filename):
|
||||||
"""Override this to create your databases."""
|
"""Override this to create your databases."""
|
||||||
@ -174,7 +174,7 @@ class PeriodicFileDownloader(object):
|
|||||||
you want with this; you may want to build a database, take some stats,
|
you want with this; you may want to build a database, take some stats,
|
||||||
or simply rename the file. You can pass None as your function and the
|
or simply rename the file. You can pass None as your function and the
|
||||||
file with automatically be renamed to match the filename you have it listed
|
file with automatically be renamed to match the filename you have it listed
|
||||||
under. It'll be in conf.dataDir, of course.
|
under. It'll be in conf.supybot.directories.data, of course.
|
||||||
|
|
||||||
Aside from that dictionary, simply use self.getFile(filename) in any method
|
Aside from that dictionary, simply use self.getFile(filename) in any method
|
||||||
that makes use of a periodically downloaded file, and you'll be set.
|
that makes use of a periodically downloaded file, and you'll be set.
|
||||||
@ -187,7 +187,8 @@ class PeriodicFileDownloader(object):
|
|||||||
self.downloadedCounter = {}
|
self.downloadedCounter = {}
|
||||||
for filename in self.periodicFiles:
|
for filename in self.periodicFiles:
|
||||||
if self.periodicFiles[filename][-1] is None:
|
if self.periodicFiles[filename][-1] is None:
|
||||||
fullname = os.path.join(conf.dataDir, filename)
|
fullname = os.path.join(conf.supybot.directories.data(),
|
||||||
|
filename)
|
||||||
if os.path.exists(fullname):
|
if os.path.exists(fullname):
|
||||||
self.lastDownloaded[filename] = os.stat(fullname).st_ctime
|
self.lastDownloaded[filename] = os.stat(fullname).st_ctime
|
||||||
else:
|
else:
|
||||||
@ -206,7 +207,8 @@ class PeriodicFileDownloader(object):
|
|||||||
self.log.warning('Error downloading %s', url)
|
self.log.warning('Error downloading %s', url)
|
||||||
self.log.exception('Exception:')
|
self.log.exception('Exception:')
|
||||||
return
|
return
|
||||||
newFilename = os.path.join(conf.dataDir, utils.mktemp())
|
confDir = conf.supybot.directories.data()
|
||||||
|
newFilename = os.path.join(confDir, utils.mktemp())
|
||||||
outfd = file(newFilename, 'wb')
|
outfd = file(newFilename, 'wb')
|
||||||
start = time.time()
|
start = time.time()
|
||||||
s = infd.read(4096)
|
s = infd.read(4096)
|
||||||
@ -220,7 +222,7 @@ class PeriodicFileDownloader(object):
|
|||||||
self.downloadedCounter[filename] += 1
|
self.downloadedCounter[filename] += 1
|
||||||
self.lastDownloaded[filename] = time.time()
|
self.lastDownloaded[filename] = time.time()
|
||||||
if f is None:
|
if f is None:
|
||||||
toFilename = os.path.join(conf.dataDir, filename)
|
toFilename = os.path.join(confDir, filename)
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
# Windows, grrr...
|
# Windows, grrr...
|
||||||
if os.path.exists(toFilename):
|
if os.path.exists(toFilename):
|
||||||
|
@ -57,7 +57,7 @@ def getChannel(msg, args):
|
|||||||
removed).
|
removed).
|
||||||
"""
|
"""
|
||||||
if args and ircutils.isChannel(args[0]):
|
if args and ircutils.isChannel(args[0]):
|
||||||
if conf.requireChannelCommandsToBeSentInChannel:
|
if conf.supybot.reply.requireChannelCommandsToBeSentInChannel():
|
||||||
if args[0] != msg.args[0]:
|
if args[0] != msg.args[0]:
|
||||||
s = 'Channel commands must be sent in the channel to which ' \
|
s = 'Channel commands must be sent in the channel to which ' \
|
||||||
'they apply.'
|
'they apply.'
|
||||||
@ -145,22 +145,6 @@ def thread(f):
|
|||||||
t.start()
|
t.start()
|
||||||
return utils.changeFunctionName(newf, f.func_name, f.__doc__)
|
return utils.changeFunctionName(newf, f.func_name, f.__doc__)
|
||||||
|
|
||||||
def name(f):
|
|
||||||
"""Makes sure a name is available based on conf.requireRegistration."""
|
|
||||||
def newf(self, irc, msg, args, *L):
|
|
||||||
try:
|
|
||||||
name = ircdb.users.getUser(msg.prefix).name
|
|
||||||
except KeyError:
|
|
||||||
if conf.requireRegistration:
|
|
||||||
irc.errorNotRegistered()
|
|
||||||
return
|
|
||||||
else:
|
|
||||||
name = msg.prefix
|
|
||||||
L = (name,) + L
|
|
||||||
ff = types.MethodType(f, self, self.__class__)
|
|
||||||
ff(irc, msg, args, *L)
|
|
||||||
return utils.changeFunctionName(newf, f.func_name, f.__doc__)
|
|
||||||
|
|
||||||
def channel(f):
|
def channel(f):
|
||||||
"""Gives the command an extra channel arg as if it had called getChannel"""
|
"""Gives the command an extra channel arg as if it had called getChannel"""
|
||||||
def newf(self, irc, msg, args, *L):
|
def newf(self, irc, msg, args, *L):
|
||||||
@ -175,7 +159,7 @@ def urlSnarfer(f):
|
|||||||
f = _threadedWrapMethod(f)
|
f = _threadedWrapMethod(f)
|
||||||
def newf(self, irc, msg, match, *L):
|
def newf(self, irc, msg, match, *L):
|
||||||
now = time.time()
|
now = time.time()
|
||||||
cutoff = now - conf.snarfThrottle
|
cutoff = now - conf.supybot.snarfThrottle()
|
||||||
q = getattr(self, '_snarfedUrls', None)
|
q = getattr(self, '_snarfedUrls', None)
|
||||||
if q is None:
|
if q is None:
|
||||||
q = structures.smallqueue()
|
q = structures.smallqueue()
|
||||||
|
219
src/registry.py
219
src/registry.py
@ -32,13 +32,17 @@
|
|||||||
__revision__ = "$Id$"
|
__revision__ = "$Id$"
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
import sets
|
||||||
|
import types
|
||||||
|
|
||||||
import utils
|
import utils
|
||||||
|
|
||||||
|
|
||||||
class RegistryException(Exception):
|
class RegistryException(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class InvalidRegistryFile(RegistryException):
|
||||||
|
pass
|
||||||
|
|
||||||
class InvalidRegistryValue(RegistryException):
|
class InvalidRegistryValue(RegistryException):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -50,43 +54,47 @@ def open(filename):
|
|||||||
"""Initializes the module by loading the registry file into memory."""
|
"""Initializes the module by loading the registry file into memory."""
|
||||||
cache.clear()
|
cache.clear()
|
||||||
fd = utils.nonCommentNonEmptyLines(file(filename))
|
fd = utils.nonCommentNonEmptyLines(file(filename))
|
||||||
for line in fd:
|
for (i, line) in enumerate(fd):
|
||||||
line = line.rstrip()
|
line = line.rstrip('\r\n')
|
||||||
(key, value) = line.split(': ', 1)
|
try:
|
||||||
cache[key] = value
|
(key, value) = line.split(': ', 1)
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidRegistryFile, 'Error unpacking line #%s' % (i+1)
|
||||||
|
cache[key.lower()] = value
|
||||||
|
|
||||||
def close(registry, filename):
|
def close(registry, filename):
|
||||||
fd = file(filename, 'w')
|
fd = file(filename, 'w')
|
||||||
for (name, value) in registry.getValues(askChildren=True):
|
for (name, value) in registry.getValues(getChildren=True):
|
||||||
fd.write('%s: %s\n' % (name, value))
|
fd.write('%s: %s\n' % (name, value))
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
|
|
||||||
class Value(object):
|
class Value(object):
|
||||||
def __init__(self, default, help):
|
def __init__(self, default, help):
|
||||||
self.help = utils.normalizeWhitespace(help)
|
self.default = default
|
||||||
self.value = self.default = default
|
self.help = utils.normalizeWhitespace(help.strip())
|
||||||
|
self.setValue(default)
|
||||||
|
self.set(str(self)) # This is needed.
|
||||||
|
|
||||||
def set(self, s):
|
def set(self, s):
|
||||||
"""Override this with a function to convert a string to whatever type
|
"""Override this with a function to convert a string to whatever type
|
||||||
you want, and set it to .value."""
|
you want, and set it to .value."""
|
||||||
# self.value = value
|
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
def setValue(self, v):
|
||||||
|
self.value = v
|
||||||
|
|
||||||
def get(self):
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
def default(self):
|
|
||||||
return self.default
|
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.value = self.default
|
self.setValue(self.default)
|
||||||
|
|
||||||
def help(self):
|
|
||||||
return self.help
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return repr(self.value)
|
return repr(self.value)
|
||||||
|
|
||||||
|
# This is simply prettier than naming this function get(self)
|
||||||
|
def __call__(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
|
||||||
class Boolean(Value):
|
class Boolean(Value):
|
||||||
def set(self, s):
|
def set(self, s):
|
||||||
s = s.lower()
|
s = s.lower()
|
||||||
@ -94,6 +102,8 @@ class Boolean(Value):
|
|||||||
self.value = True
|
self.value = True
|
||||||
elif s in ('false', 'off', 'disabled'):
|
elif s in ('false', 'off', 'disabled'):
|
||||||
self.value = False
|
self.value = False
|
||||||
|
elif s == 'toggle':
|
||||||
|
self.value = not self.value
|
||||||
else:
|
else:
|
||||||
raise InvalidRegistryValue, 'Value must be True or False.'
|
raise InvalidRegistryValue, 'Value must be True or False.'
|
||||||
|
|
||||||
@ -104,9 +114,16 @@ class Integer(Value):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
raise InvalidRegistryValue, 'Value must be an integer.'
|
raise InvalidRegistryValue, 'Value must be an integer.'
|
||||||
|
|
||||||
|
class Float(Value):
|
||||||
|
def set(self, s):
|
||||||
|
try:
|
||||||
|
self.value = float(s)
|
||||||
|
except ValueError:
|
||||||
|
raise InvalidRegistryValue, 'Value must be a float.'
|
||||||
|
|
||||||
class String(Value):
|
class String(Value):
|
||||||
def set(self, s):
|
def set(self, s):
|
||||||
if s and s[0] not in '\'"' and s[-1] not in '\'"':
|
if not s or (s[0] not in '\'"' and s[-1] not in '\'"'):
|
||||||
s = repr(s)
|
s = repr(s)
|
||||||
try:
|
try:
|
||||||
v = utils.safeEval(s)
|
v = utils.safeEval(s)
|
||||||
@ -116,6 +133,11 @@ class String(Value):
|
|||||||
except ValueError: # This catches utils.safeEval(s) errors too.
|
except ValueError: # This catches utils.safeEval(s) errors too.
|
||||||
raise InvalidRegistryValue, 'Value must be a string.'
|
raise InvalidRegistryValue, 'Value must be a string.'
|
||||||
|
|
||||||
|
class NormalizedString(String):
|
||||||
|
def set(self, s):
|
||||||
|
s = utils.normalizeWhitespace(s.strip())
|
||||||
|
String.set(self, s)
|
||||||
|
|
||||||
class StringSurroundedBySpaces(String):
|
class StringSurroundedBySpaces(String):
|
||||||
def set(self, s):
|
def set(self, s):
|
||||||
String.set(self, s)
|
String.set(self, s)
|
||||||
@ -124,13 +146,25 @@ class StringSurroundedBySpaces(String):
|
|||||||
if self.value.rstrip() == self.value:
|
if self.value.rstrip() == self.value:
|
||||||
self.value += ' '
|
self.value += ' '
|
||||||
|
|
||||||
|
class CommaSeparatedListOfStrings(String):
|
||||||
|
def set(self, s):
|
||||||
|
String.set(self, s)
|
||||||
|
self.value = map(str.strip, self.value.split(','))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ','.join(self.value)
|
||||||
|
|
||||||
|
class CommaSeparatedSetOfStrings(CommaSeparatedListOfStrings):
|
||||||
|
def set(self, s):
|
||||||
|
CommaSeparatedListOfStrings.set(self, s)
|
||||||
|
self.value = sets.Set(self.value)
|
||||||
|
|
||||||
class Group(object):
|
class Group(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__dict__['name'] = 'unset'
|
self.name = 'unset'
|
||||||
self.__dict__['values'] = {}
|
self.values = {}
|
||||||
self.__dict__['children'] = {}
|
self.children = {}
|
||||||
self.__dict__['originals'] = {}
|
self.originals = {}
|
||||||
|
|
||||||
def __nonExistentEntry(self, attr):
|
def __nonExistentEntry(self, attr):
|
||||||
s = '%s is not a valid entry in %s' % (attr, self.name)
|
s = '%s is not a valid entry in %s' % (attr, self.name)
|
||||||
@ -140,56 +174,24 @@ class Group(object):
|
|||||||
original = attr
|
original = attr
|
||||||
attr = attr.lower()
|
attr = attr.lower()
|
||||||
if attr in self.values:
|
if attr in self.values:
|
||||||
return self.values[attr].get()
|
return self.values[attr]
|
||||||
elif attr in self.children:
|
elif attr in self.children:
|
||||||
return self.children[attr]
|
return self.children[attr]
|
||||||
else:
|
else:
|
||||||
self.__nonExistentEntry(original)
|
self.__nonExistentEntry(original)
|
||||||
|
|
||||||
def __setattr__(self, attr, s):
|
def getChild(self, attr):
|
||||||
original = attr
|
return self.children[attr.lower()]
|
||||||
attr = attr.lower()
|
|
||||||
if attr in self.values:
|
|
||||||
self.values[attr].set(s)
|
|
||||||
elif attr in self.children and hasattr(self.children[attr], 'set'):
|
|
||||||
self.children[attr].set(s)
|
|
||||||
else:
|
|
||||||
self.__nonExistentEntry(original)
|
|
||||||
|
|
||||||
def get(self, attr):
|
|
||||||
return self.__getattr__(attr)
|
|
||||||
|
|
||||||
def help(self, attr):
|
|
||||||
original = attr
|
|
||||||
attr = attr.lower()
|
|
||||||
if attr in self.values:
|
|
||||||
return self.values[attr].help
|
|
||||||
elif attr in self.children and hasattr(self.children[attr], 'help'):
|
|
||||||
return self.children[attr].help
|
|
||||||
else:
|
|
||||||
self.__nonExistentEntry(original)
|
|
||||||
|
|
||||||
def default(self, attr):
|
|
||||||
original = attr
|
|
||||||
attr = attr.lower()
|
|
||||||
if attr in self.values:
|
|
||||||
return self.values[attr].default
|
|
||||||
elif attr in self.children and hasattr(self.children[attr], 'default'):
|
|
||||||
return self.children[attr].default
|
|
||||||
else:
|
|
||||||
self.__nonExistentEntry(original)
|
|
||||||
|
|
||||||
def setName(self, name):
|
def setName(self, name):
|
||||||
self.__dict__['name'] = name
|
self.name = name
|
||||||
|
|
||||||
def getName(self):
|
def getName(self):
|
||||||
return self.__dict__['name']
|
return self.name
|
||||||
|
|
||||||
def register(self, name, value):
|
def register(self, name, value):
|
||||||
original = name
|
original = name
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
if name in self.values:
|
|
||||||
value.set(str(self.values[name]))
|
|
||||||
self.values[name] = value
|
self.values[name] = value
|
||||||
self.originals[name] = original
|
self.originals[name] = original
|
||||||
if cache:
|
if cache:
|
||||||
@ -200,11 +202,10 @@ class Group(object):
|
|||||||
def registerGroup(self, name, group=None):
|
def registerGroup(self, name, group=None):
|
||||||
original = name
|
original = name
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
|
if name in self.children:
|
||||||
|
return # Ignore redundant group inserts.
|
||||||
if group is None:
|
if group is None:
|
||||||
group = Group()
|
group = Group()
|
||||||
if name in self.children:
|
|
||||||
group.__dict__['values'] = self.children[name].values
|
|
||||||
group.__dict__['children'] = self.children[name].children
|
|
||||||
self.children[name] = group
|
self.children[name] = group
|
||||||
self.originals[name] = original
|
self.originals[name] = original
|
||||||
fullname = '%s.%s' % (self.name, name)
|
fullname = '%s.%s' % (self.name, name)
|
||||||
@ -212,25 +213,52 @@ class Group(object):
|
|||||||
if cache and fullname in cache:
|
if cache and fullname in cache:
|
||||||
group.set(cache[fullname])
|
group.set(cache[fullname])
|
||||||
|
|
||||||
def getValues(self, askChildren=False):
|
def getValues(self, getChildren=False):
|
||||||
L = []
|
L = []
|
||||||
items = self.values.items()
|
items = self.values.items()
|
||||||
utils.sortBy(lambda (k, _): (k.lower(), len(k), k), items)
|
for (name, child) in self.children.items():
|
||||||
|
if hasattr(child, 'value'):
|
||||||
|
items.append((name, child))
|
||||||
|
utils.sortBy(lambda (k, _): (len(k), k.lower(), k), items)
|
||||||
for (name, value) in items:
|
for (name, value) in items:
|
||||||
L.append(('%s.%s' % (self.getName(), name), str(value)))
|
L.append(('%s.%s' % (self.getName(), self.originals[name]), value))
|
||||||
if askChildren:
|
if getChildren:
|
||||||
items = self.children.items()
|
items = self.children.items()
|
||||||
utils.sortBy(lambda (k, _): (k.lower(), len(k), k), items)
|
utils.sortBy(lambda (k, _): (k.lower(), len(k), k), items)
|
||||||
for (_, child) in items:
|
for (_, child) in items:
|
||||||
L.extend(child.getValues(askChildren))
|
L.extend(child.getValues(getChildren))
|
||||||
return L
|
return L
|
||||||
|
|
||||||
|
|
||||||
class GroupWithDefault(Group):
|
class GroupWithValue(Group):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
Group.__init__(self)
|
Group.__init__(self)
|
||||||
self.__dict__['help'] = value.help
|
self.value = value
|
||||||
self.__dict__['value'] = self.__dict__['default'] = value
|
self.help = value.help
|
||||||
|
|
||||||
|
def set(self, s):
|
||||||
|
self.value.set(s)
|
||||||
|
|
||||||
|
def setValue(self, v):
|
||||||
|
self.value.setValue(v)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.value.reset()
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
return self.value()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
## def getValues(self, getChildren=False):
|
||||||
|
## L = Group.getValues(self, getChildren=False)
|
||||||
|
## L.insert(0, (self.getName(), str(self.value)))
|
||||||
|
## return L
|
||||||
|
|
||||||
|
class GroupWithDefault(GroupWithValue):
|
||||||
|
def __init__(self, value):
|
||||||
|
GroupWithValue.__init__(self, value)
|
||||||
|
|
||||||
def __makeChild(self, attr, s):
|
def __makeChild(self, attr, s):
|
||||||
v = copy.copy(self.value)
|
v = copy.copy(self.value)
|
||||||
@ -241,13 +269,7 @@ class GroupWithDefault(Group):
|
|||||||
try:
|
try:
|
||||||
return Group.__getattr__(self, attr)
|
return Group.__getattr__(self, attr)
|
||||||
except NonExistentRegistryEntry:
|
except NonExistentRegistryEntry:
|
||||||
return self.value.get()
|
return self.value
|
||||||
|
|
||||||
def __setattr__(self, attr, s):
|
|
||||||
try:
|
|
||||||
Group.__setattr__(self, attr, s)
|
|
||||||
except NonExistentRegistryEntry:
|
|
||||||
self.__makeChild(attr, s)
|
|
||||||
|
|
||||||
def setName(self, name):
|
def setName(self, name):
|
||||||
Group.setName(self, name)
|
Group.setName(self, name)
|
||||||
@ -256,25 +278,16 @@ class GroupWithDefault(Group):
|
|||||||
(_, group) = rsplit(k, '.', 1)
|
(_, group) = rsplit(k, '.', 1)
|
||||||
self.__makeChild(group, v)
|
self.__makeChild(group, v)
|
||||||
|
|
||||||
def set(self, *args):
|
def setChild(self, attr, s):
|
||||||
if len(args) == 1:
|
self.__setattr__(attr, s)
|
||||||
self.value.set(args[0])
|
|
||||||
else:
|
|
||||||
assert len(args) == 2
|
|
||||||
(attr, s) = args
|
|
||||||
self.__setattr__(attr, s)
|
|
||||||
|
|
||||||
def getValues(self, askChildren=False):
|
|
||||||
L = Group.getValues(self, askChildren)
|
|
||||||
L.insert(0, (self.getName(), str(self.value)))
|
|
||||||
return L
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
import sys
|
||||||
|
sys.setrecursionlimit(40)
|
||||||
supybot = Group()
|
supybot = Group()
|
||||||
supybot.setName('supybot')
|
supybot.setName('supybot')
|
||||||
supybot.register('throttleTime', Integer(1, """Determines the minimum
|
supybot.register('throttleTime', Float(1, """Determines the minimum
|
||||||
number of seconds the bot will wait between sending messages to the server.
|
number of seconds the bot will wait between sending messages to the server.
|
||||||
"""))
|
"""))
|
||||||
supybot.registerGroup('plugins')
|
supybot.registerGroup('plugins')
|
||||||
@ -282,9 +295,19 @@ if __name__ == '__main__':
|
|||||||
supybot.plugins.topic.registerGroup('separator',
|
supybot.plugins.topic.registerGroup('separator',
|
||||||
GroupWithDefault(StringSurroundedBySpaces(' || ',
|
GroupWithDefault(StringSurroundedBySpaces(' || ',
|
||||||
'Determines what separator the bot uses to separate topic entries.')))
|
'Determines what separator the bot uses to separate topic entries.')))
|
||||||
supybot.plugins.topic.separator.set('#supybot', ' |||| ')
|
supybot.plugins.topic.separator.setChild('#supybot', ' |||| ')
|
||||||
supybot.plugins.topic.separator.set(' <> ')
|
supybot.plugins.topic.separator.set(' <> ')
|
||||||
|
|
||||||
|
supybot.throttleTime.set(10)
|
||||||
|
|
||||||
|
supybot.registerGroup('log')
|
||||||
|
supybot.log.registerGroup('stdout',
|
||||||
|
GroupWithValue(Boolean(False,
|
||||||
|
"""Help for stdout.""")))
|
||||||
|
supybot.log.stdout.register('colorized', Boolean(False,
|
||||||
|
'Help colorized'))
|
||||||
|
supybot.log.stdout.setValue(True)
|
||||||
|
|
||||||
for (k, v) in supybot.getValues():
|
for (k, v) in supybot.getValues():
|
||||||
print '%s: %s' % (k, v)
|
print '%s: %s' % (k, v)
|
||||||
|
|
||||||
@ -292,11 +315,11 @@ if __name__ == '__main__':
|
|||||||
print 'Asking children'
|
print 'Asking children'
|
||||||
print
|
print
|
||||||
|
|
||||||
for (k, v) in supybot.getValues(askChildren=True):
|
for (k, v) in supybot.getValues(getChildren=True):
|
||||||
print '%s: %s' % (k, v)
|
print '%s: %s' % (k, v)
|
||||||
|
|
||||||
print supybot.help('throttleTime')
|
print supybot.throttleTime.help
|
||||||
print supybot.plugins.topic.help('separator')
|
print supybot.plugins.topic.separator.help
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -40,6 +40,7 @@ __revision__ ="$Id$"
|
|||||||
import fix
|
import fix
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
import atexit
|
||||||
import socket
|
import socket
|
||||||
from itertools import imap
|
from itertools import imap
|
||||||
|
|
||||||
@ -51,13 +52,17 @@ import ircmsgs
|
|||||||
import schedule
|
import schedule
|
||||||
|
|
||||||
instances = 0
|
instances = 0
|
||||||
originalPoll = conf.poll
|
originalPoll = conf.supybot.drivers.poll()
|
||||||
|
def resetPoll():
|
||||||
|
log.info('Resetting supybot.drivers.poll to %s', originalPoll)
|
||||||
|
conf.supybot.drivers.poll.setValue(originalPoll)
|
||||||
|
atexit.register(resetPoll)
|
||||||
|
|
||||||
class SocketDriver(drivers.IrcDriver):
|
class SocketDriver(drivers.IrcDriver):
|
||||||
def __init__(self, (server, port), irc, reconnectWaits=(0, 60, 300)):
|
def __init__(self, (server, port), irc, reconnectWaits=(0, 60, 300)):
|
||||||
global instances
|
global instances
|
||||||
instances += 1
|
instances += 1
|
||||||
conf.poll = originalPoll / instances
|
conf.supybot.drivers.poll.setValue(originalPoll / instances)
|
||||||
self.server = (server, port)
|
self.server = (server, port)
|
||||||
drivers.IrcDriver.__init__(self) # Must come after server is set.
|
drivers.IrcDriver.__init__(self) # Must come after server is set.
|
||||||
self.irc = irc
|
self.irc = irc
|
||||||
@ -88,7 +93,9 @@ class SocketDriver(drivers.IrcDriver):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
time.sleep(conf.poll) # Otherwise we might spin.
|
# We sleep here because otherwise, if we're the only driver, we'll
|
||||||
|
# spin at 100% CPU while we're disconnected.
|
||||||
|
time.sleep(conf.supybot.drivers.poll())
|
||||||
return
|
return
|
||||||
self._sendIfMsgs()
|
self._sendIfMsgs()
|
||||||
try:
|
try:
|
||||||
@ -124,12 +131,13 @@ class SocketDriver(drivers.IrcDriver):
|
|||||||
return
|
return
|
||||||
self.irc.reset()
|
self.irc.reset()
|
||||||
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.conn.settimeout(conf.poll*10) # Allow more time for connect.
|
# We allow more time for the connect here, since it might take longer.
|
||||||
|
self.conn.settimeout(conf.supybot.drivers.poll()*10)
|
||||||
if self.reconnectWaitsIndex < len(self.reconnectWaits)-1:
|
if self.reconnectWaitsIndex < len(self.reconnectWaits)-1:
|
||||||
self.reconnectWaitsIndex += 1
|
self.reconnectWaitsIndex += 1
|
||||||
try:
|
try:
|
||||||
self.conn.connect(self.server)
|
self.conn.connect(self.server)
|
||||||
self.conn.settimeout(conf.poll)
|
self.conn.settimeout(conf.supybot.drivers.poll())
|
||||||
except socket.error, e:
|
except socket.error, e:
|
||||||
if e.args[0] != 115:
|
if e.args[0] != 115:
|
||||||
log.warning('Error connecting to %s: %s', self.server, e)
|
log.warning('Error connecting to %s: %s', self.server, e)
|
||||||
@ -144,7 +152,8 @@ class SocketDriver(drivers.IrcDriver):
|
|||||||
|
|
||||||
def _scheduleReconnect(self):
|
def _scheduleReconnect(self):
|
||||||
when = time.time() + self.reconnectWaits[self.reconnectWaitsIndex]
|
when = time.time() + self.reconnectWaits[self.reconnectWaitsIndex]
|
||||||
whenS = time.strftime(conf.logTimestampFormat, time.localtime(when))
|
whenS = time.strftime(conf.supybot.log.timestampFormat(),
|
||||||
|
time.localtime(when))
|
||||||
if not world.dying:
|
if not world.dying:
|
||||||
log.info('Scheduling reconnect to %s at %s', self.server, whenS)
|
log.info('Scheduling reconnect to %s at %s', self.server, whenS)
|
||||||
schedule.addEvent(self.reconnect, when)
|
schedule.addEvent(self.reconnect, when)
|
||||||
|
@ -42,14 +42,13 @@ import drivers
|
|||||||
import ircmsgs
|
import ircmsgs
|
||||||
|
|
||||||
from twisted.internet import reactor
|
from twisted.internet import reactor
|
||||||
from twisted.manhole.telnet import Shell, ShellFactory
|
|
||||||
from twisted.protocols.basic import LineReceiver
|
from twisted.protocols.basic import LineReceiver
|
||||||
from twisted.internet.protocol import ReconnectingClientFactory
|
from twisted.internet.protocol import ReconnectingClientFactory
|
||||||
|
|
||||||
class TwistedRunnerDriver(drivers.IrcDriver):
|
class TwistedRunnerDriver(drivers.IrcDriver):
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
reactor.iterate(conf.poll)
|
reactor.iterate(conf.supybot.drivers.poll())
|
||||||
except:
|
except:
|
||||||
log.exception('Uncaught exception outside reactor:')
|
log.exception('Uncaught exception outside reactor:')
|
||||||
|
|
||||||
@ -104,26 +103,6 @@ class SupyReconnectingFactory(ReconnectingClientFactory):
|
|||||||
def die(self):
|
def die(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class MyShell(Shell):
|
|
||||||
def checkUserAndPass(self, username, password):
|
|
||||||
try:
|
|
||||||
id = ircdb.users.getUserId(username)
|
|
||||||
u = ircdb.users.getUser(id)
|
|
||||||
if u.checkPassword(password) and u.checkCapability('owner'):
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
except KeyError:
|
|
||||||
return False
|
|
||||||
|
|
||||||
class MyShellFactory(ShellFactory):
|
|
||||||
protocol = MyShell
|
|
||||||
|
|
||||||
if conf.telnetEnable and __name__ != '__main__':
|
|
||||||
reactor.listenTCP(conf.telnetPort, MyShellFactory())
|
|
||||||
|
|
||||||
|
|
||||||
Driver = SupyReconnectingFactory
|
Driver = SupyReconnectingFactory
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -92,7 +92,8 @@ def upkeep():
|
|||||||
log.debug('Pattern cache size: %s'%len(ircutils._patternCache))
|
log.debug('Pattern cache size: %s'%len(ircutils._patternCache))
|
||||||
log.debug('HostmaskPatternEqual cache size: %s' %
|
log.debug('HostmaskPatternEqual cache size: %s' %
|
||||||
len(ircutils._hostmaskPatternEqualCache))
|
len(ircutils._hostmaskPatternEqualCache))
|
||||||
log.info('%s upkeep ran.', time.strftime(conf.logTimestampFormat))
|
log.info('%s upkeep ran.',
|
||||||
|
time.strftime(conf.supybot.log.timestampFormat()))
|
||||||
return collected
|
return collected
|
||||||
|
|
||||||
def makeDriversDie():
|
def makeDriversDie():
|
||||||
@ -129,7 +130,6 @@ atexit.register(startDying)
|
|||||||
##################################################
|
##################################################
|
||||||
##################################################
|
##################################################
|
||||||
##################################################
|
##################################################
|
||||||
startup = False
|
|
||||||
testing = False
|
testing = False
|
||||||
dying = False
|
dying = False
|
||||||
|
|
||||||
|
44
test/test.py
44
test/test.py
@ -29,17 +29,30 @@
|
|||||||
# POSSIBILITY OF SUCH DAMAGE.
|
# POSSIBILITY OF SUCH DAMAGE.
|
||||||
###
|
###
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
import supybot
|
import supybot
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
registryFilename = os.path.join('test-conf', 'test.conf')
|
||||||
|
fd = file(registryFilename, 'w')
|
||||||
|
fd.write("""
|
||||||
|
supybot.directories.data: test-data
|
||||||
|
supybot.directories.conf: test-conf
|
||||||
|
supybot.directories.log: test-log
|
||||||
|
supybot.reply.whenNotCommand: False
|
||||||
|
supybot.log.stdout: False
|
||||||
|
supybot.log.minimumPriority: DEBUG
|
||||||
|
supybot.log.detailedTracebacks: False
|
||||||
|
supybot.throttleTime: 0
|
||||||
|
""")
|
||||||
|
fd.close()
|
||||||
|
|
||||||
|
import registry
|
||||||
|
registry.open(registryFilename)
|
||||||
|
|
||||||
|
import log
|
||||||
import conf
|
import conf
|
||||||
conf.dataDir = 'test-data'
|
|
||||||
conf.confDir = 'test-conf'
|
|
||||||
conf.logDir = 'test-log'
|
|
||||||
conf.replyWhenNotCommand = False
|
|
||||||
conf.stdoutLogging = False
|
|
||||||
conf.minimumLogPriority = logging.DEBUG
|
|
||||||
conf.detailedTracebacks = False # Bugs in cgitb can be bad.
|
|
||||||
|
|
||||||
import fix
|
import fix
|
||||||
|
|
||||||
@ -62,16 +75,19 @@ if __name__ == '__main__':
|
|||||||
import testsupport
|
import testsupport
|
||||||
import optparse
|
import optparse
|
||||||
|
|
||||||
if not os.path.exists(conf.dataDir):
|
if not os.path.exists(conf.supybot.directories.data()):
|
||||||
os.mkdir(conf.dataDir)
|
os.mkdir(conf.supybot.directories.data())
|
||||||
|
|
||||||
if not os.path.exists(conf.confDir):
|
if not os.path.exists(conf.supybot.directories.conf()):
|
||||||
os.mkdir(conf.confDir)
|
os.mkdir(conf.supybot.directories.conf())
|
||||||
|
|
||||||
if not os.path.exists(conf.logDir):
|
if not os.path.exists(conf.supybot.directories.log()):
|
||||||
os.mkdir(conf.logDir)
|
os.mkdir(conf.supybot.directories.log())
|
||||||
|
|
||||||
pluginLogDir = os.path.join(conf.logDir, 'plugins')
|
pluginLogDir = os.path.join(conf.supybot.directories.log(), 'plugins')
|
||||||
|
if not os.path.exists(pluginLogDir):
|
||||||
|
os.mkdir(pluginLogDir)
|
||||||
|
|
||||||
for filename in os.listdir(pluginLogDir):
|
for filename in os.listdir(pluginLogDir):
|
||||||
os.remove(os.path.join(pluginLogDir, filename))
|
os.remove(os.path.join(pluginLogDir, filename))
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class AdminTestCase(PluginTestCase, PluginDocumentation):
|
|||||||
self.assertNotError('admin unignore foo!bar@baz')
|
self.assertNotError('admin unignore foo!bar@baz')
|
||||||
self.assertError('admin unignore foo!bar@baz')
|
self.assertError('admin unignore foo!bar@baz')
|
||||||
finally:
|
finally:
|
||||||
conf.ignores = []
|
conf.supybot.ignores.set('')
|
||||||
|
|
||||||
def testIgnores(self):
|
def testIgnores(self):
|
||||||
try:
|
try:
|
||||||
@ -61,13 +61,7 @@ class AdminTestCase(PluginTestCase, PluginDocumentation):
|
|||||||
self.assertNotError('admin ignore foo!bar@baz')
|
self.assertNotError('admin ignore foo!bar@baz')
|
||||||
self.assertNotError('admin ignores')
|
self.assertNotError('admin ignores')
|
||||||
finally:
|
finally:
|
||||||
conf.ignores = []
|
conf.supybot.ignores.set('')
|
||||||
|
|
||||||
def testSetprefixchar(self):
|
|
||||||
self.assertNotError('setprefixchar $')
|
|
||||||
self.assertResponse('getprefixchar', "'$'")
|
|
||||||
self.assertError('setprefixchar p')
|
|
||||||
self.assertNoResponse(' ', 2) # make sure we return
|
|
||||||
|
|
||||||
def testAddcapability(self):
|
def testAddcapability(self):
|
||||||
self.assertError('addcapability sdlkfj foo')
|
self.assertError('addcapability sdlkfj foo')
|
||||||
|
@ -107,12 +107,12 @@ class AliasTestCase(ChannelPluginTestCase, PluginDocumentation):
|
|||||||
self.assertError('alias add [] foo')
|
self.assertError('alias add [] foo')
|
||||||
self.assertError('alias add "foo bar" foo')
|
self.assertError('alias add "foo bar" foo')
|
||||||
try:
|
try:
|
||||||
conf.enablePipeSyntax = True
|
conf.supybot.pipeSyntax.setValue(True)
|
||||||
self.assertError('alias add "foo|bar" foo')
|
self.assertError('alias add "foo|bar" foo')
|
||||||
conf.enablePipeSyntax = False
|
conf.supybot.pipeSyntax.setValue(False)
|
||||||
self.assertNotError('alias add "foo|bar" foo')
|
self.assertNotError('alias add "foo|bar" foo')
|
||||||
finally:
|
finally:
|
||||||
conf.enablePipeSyntax = False
|
conf.supybot.pipeSyntax.setValue(False)
|
||||||
|
|
||||||
def testNotCannotNestRaised(self):
|
def testNotCannotNestRaised(self):
|
||||||
self.assertNotError('alias add mytell "tell $channel $1"')
|
self.assertNotError('alias add mytell "tell $channel $1"')
|
||||||
|
@ -44,13 +44,14 @@ if network:
|
|||||||
def setUp(self, nick='test'):
|
def setUp(self, nick='test'):
|
||||||
PluginTestCase.setUp(self)
|
PluginTestCase.setUp(self)
|
||||||
try:
|
try:
|
||||||
if os.path.exists(os.path.join(conf.dataDir,
|
dataDir = conf.supybot.directories.data()
|
||||||
|
if os.path.exists(os.path.join(dataDir,
|
||||||
'Contents-i386.gz')):
|
'Contents-i386.gz')):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
print
|
print
|
||||||
print "Downloading files, this may take awhile"
|
print "Downloading files, this may take awhile"
|
||||||
filename = os.path.join(conf.dataDir, 'Contents-i386.gz')
|
filename = os.path.join(dataDir, 'Contents-i386.gz')
|
||||||
while not os.path.exists(filename):
|
while not os.path.exists(filename):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
print "Download complete"
|
print "Download complete"
|
||||||
|
@ -42,29 +42,32 @@ class MiscTestCase(ChannelPluginTestCase, PluginDocumentation):
|
|||||||
|
|
||||||
def testReplyWhenNotCommand(self):
|
def testReplyWhenNotCommand(self):
|
||||||
try:
|
try:
|
||||||
conf.replyWhenNotCommand = True
|
original = str(conf.supybot.reply.whenNotCommand)
|
||||||
|
conf.supybot.reply.whenNotCommand.set('True')
|
||||||
self.prefix = 'somethingElse!user@host.domain.tld'
|
self.prefix = 'somethingElse!user@host.domain.tld'
|
||||||
self.assertRegexp('foo bar baz', 'not.*command')
|
self.assertRegexp('foo bar baz', 'not.*command')
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotCommand = False
|
conf.supybot.reply.whenNotCommand.set(original)
|
||||||
|
|
||||||
if network:
|
if network:
|
||||||
def testNotReplyWhenRegexpsMatch(self):
|
def testNotReplyWhenRegexpsMatch(self):
|
||||||
try:
|
try:
|
||||||
conf.replyWhenNotCommand = True
|
original = str(conf.supybot.reply.whenNotCommand)
|
||||||
|
conf.supybot.reply.whenNotCommand.set('True')
|
||||||
self.prefix = 'somethingElse!user@host.domain.tld'
|
self.prefix = 'somethingElse!user@host.domain.tld'
|
||||||
self.assertNotError('http://gameknot.com/chess.pl?bd=1019508')
|
self.assertNotError('http://gameknot.com/chess.pl?bd=1019508')
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotCommand = False
|
conf.supybot.reply.whenNotCommand.set(original)
|
||||||
|
|
||||||
def testNotReplyWhenNotCanonicalName(self):
|
def testNotReplyWhenNotCanonicalName(self):
|
||||||
try:
|
try:
|
||||||
conf.replyWhenNotCommand = True
|
original = str(conf.supybot.reply.whenNotCommand)
|
||||||
|
conf.supybot.reply.whenNotCommand.set('True')
|
||||||
self.prefix = 'somethingElse!user@host.domain.tld'
|
self.prefix = 'somethingElse!user@host.domain.tld'
|
||||||
self.assertNotRegexp('STrLeN foobar', 'command')
|
self.assertNotRegexp('STrLeN foobar', 'command')
|
||||||
self.assertResponse('StRlEn foobar', '6')
|
self.assertResponse('StRlEn foobar', '6')
|
||||||
finally:
|
finally:
|
||||||
conf.repylWhenNotCommand = False
|
conf.supybot.reply.whenNotCommand.set(original)
|
||||||
|
|
||||||
def testHelp(self):
|
def testHelp(self):
|
||||||
self.assertHelp('help list')
|
self.assertHelp('help list')
|
||||||
@ -78,11 +81,11 @@ class MiscTestCase(ChannelPluginTestCase, PluginDocumentation):
|
|||||||
|
|
||||||
def testHelpStripsPrefixChars(self):
|
def testHelpStripsPrefixChars(self):
|
||||||
try:
|
try:
|
||||||
original = conf.prefixChars
|
original = str(conf.supybot.prefixChars)
|
||||||
conf.prefixChars = '@'
|
conf.supybot.prefixChars.set('@')
|
||||||
self.assertHelp('help @list')
|
self.assertHelp('help @list')
|
||||||
finally:
|
finally:
|
||||||
conf.prefixChars = original
|
conf.supybot.prefixChars.set(original)
|
||||||
|
|
||||||
def testHelpIsCaseInsensitive(self):
|
def testHelpIsCaseInsensitive(self):
|
||||||
self.assertHelp('help LIST')
|
self.assertHelp('help LIST')
|
||||||
@ -122,9 +125,6 @@ class MiscTestCase(ChannelPluginTestCase, PluginDocumentation):
|
|||||||
self.assertNotError('upkeep')
|
self.assertNotError('upkeep')
|
||||||
self.assertNotError('logfilesize')
|
self.assertNotError('logfilesize')
|
||||||
|
|
||||||
def testGetprefixchar(self):
|
|
||||||
self.assertNotError('getprefixchar')
|
|
||||||
|
|
||||||
def testPlugin(self):
|
def testPlugin(self):
|
||||||
self.assertResponse('plugin plugin', 'Misc')
|
self.assertResponse('plugin plugin', 'Misc')
|
||||||
|
|
||||||
|
@ -103,43 +103,6 @@ class OwnerTestCase(PluginTestCase, PluginDocumentation):
|
|||||||
self.assertNotError('load ALIAS')
|
self.assertNotError('load ALIAS')
|
||||||
self.assertNotError('unload ALIAS')
|
self.assertNotError('unload ALIAS')
|
||||||
|
|
||||||
def testSetconf(self):
|
|
||||||
self.assertRegexp('setconf', 'confDir')
|
|
||||||
self.assertNotRegexp('setconf', 'allowEval')
|
|
||||||
self.assertResponse('setconf confDir',
|
|
||||||
'confDir is a string (%s).' % conf.confDir)
|
|
||||||
self.assertError('setconf whackyConfOption')
|
|
||||||
try:
|
|
||||||
originalConfAllowEval = conf.allowEval
|
|
||||||
conf.allowEval = False
|
|
||||||
self.assertError('setconf alsdkfj 100')
|
|
||||||
self.assertError('setconf poll "foo"')
|
|
||||||
try:
|
|
||||||
originalReplySuccess = conf.replySuccess
|
|
||||||
self.assertResponse('setconf replySuccess foo', 'foo')
|
|
||||||
self.assertResponse('setconf replySuccess "foo"', 'foo')
|
|
||||||
self.assertResponse('setconf replySuccess \'foo\'', 'foo')
|
|
||||||
finally:
|
|
||||||
conf.replySuccess = originalReplySuccess
|
|
||||||
try:
|
|
||||||
originalReplyWhenNotCommand = conf.replyWhenNotCommand
|
|
||||||
self.assertNotError('setconf replyWhenNotCommand True')
|
|
||||||
self.failUnless(conf.replyWhenNotCommand)
|
|
||||||
self.assertNotError('setconf replyWhenNotCommand False')
|
|
||||||
self.failIf(conf.replyWhenNotCommand)
|
|
||||||
self.assertNotError('setconf replyWhenNotCommand true')
|
|
||||||
self.failUnless(conf.replyWhenNotCommand)
|
|
||||||
self.assertNotError('setconf replyWhenNotCommand false')
|
|
||||||
self.failIf(conf.replyWhenNotCommand)
|
|
||||||
self.assertNotError('setconf replyWhenNotCommand 1')
|
|
||||||
self.failUnless(conf.replyWhenNotCommand)
|
|
||||||
self.assertNotError('setconf replyWhenNotCommand 0')
|
|
||||||
self.failIf(conf.replyWhenNotCommand)
|
|
||||||
finally:
|
|
||||||
conf.replyWhenNotCommand = originalReplyWhenNotCommand
|
|
||||||
finally:
|
|
||||||
conf.allowEval = originalConfAllowEval
|
|
||||||
|
|
||||||
|
|
||||||
class FunctionsTestCase(unittest.TestCase):
|
class FunctionsTestCase(unittest.TestCase):
|
||||||
def testLoadPluginModule(self):
|
def testLoadPluginModule(self):
|
||||||
|
@ -48,6 +48,7 @@ class StatusTestCase(PluginTestCase, PluginDocumentation):
|
|||||||
|
|
||||||
def testCpustats(self):
|
def testCpustats(self):
|
||||||
m = self.assertNotError('status cpu')
|
m = self.assertNotError('status cpu')
|
||||||
|
self.failIf('kB kB' in m.args[1])
|
||||||
self.failIf('None' in m.args[1], 'None in cpu output: %r.' % m)
|
self.failIf('None' in m.args[1], 'None in cpu output: %r.' % m)
|
||||||
for s in ['linux', 'freebsd', 'openbsd', 'netbsd', 'darwin']:
|
for s in ['linux', 'freebsd', 'openbsd', 'netbsd', 'darwin']:
|
||||||
if sys.platform.startswith(s):
|
if sys.platform.startswith(s):
|
||||||
|
@ -86,7 +86,7 @@ class TokenizerTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def testPipe(self):
|
def testPipe(self):
|
||||||
try:
|
try:
|
||||||
conf.enablePipeSyntax = True
|
conf.supybot.pipeSyntax.set('True')
|
||||||
self.assertRaises(SyntaxError, tokenize, '| foo')
|
self.assertRaises(SyntaxError, tokenize, '| foo')
|
||||||
self.assertRaises(SyntaxError, tokenize, 'foo ||bar')
|
self.assertRaises(SyntaxError, tokenize, 'foo ||bar')
|
||||||
self.assertRaises(SyntaxError, tokenize, 'bar |')
|
self.assertRaises(SyntaxError, tokenize, 'bar |')
|
||||||
@ -100,7 +100,7 @@ class TokenizerTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(tokenize('foo bar | baz quux'),
|
self.assertEqual(tokenize('foo bar | baz quux'),
|
||||||
['baz', 'quux', ['foo', 'bar']])
|
['baz', 'quux', ['foo', 'bar']])
|
||||||
finally:
|
finally:
|
||||||
conf.enablePipeSyntax = False
|
conf.supybot.pipeSyntax.set('False')
|
||||||
|
|
||||||
def testBold(self):
|
def testBold(self):
|
||||||
s = '\x02foo\x02'
|
s = '\x02foo\x02'
|
||||||
@ -127,9 +127,9 @@ class FunctionsTestCase(unittest.TestCase):
|
|||||||
self.assertEqual('foobar--', callbacks.canonicalName('foobar--'))
|
self.assertEqual('foobar--', callbacks.canonicalName('foobar--'))
|
||||||
|
|
||||||
def testAddressed(self):
|
def testAddressed(self):
|
||||||
oldprefixchars = conf.prefixChars
|
oldprefixchars = str(conf.supybot.prefixChars)
|
||||||
nick = 'supybot'
|
nick = 'supybot'
|
||||||
conf.prefixChars = '~!@'
|
conf.supybot.prefixChars.set('~!@')
|
||||||
inChannel = ['~foo', '@foo', '!foo',
|
inChannel = ['~foo', '@foo', '!foo',
|
||||||
'%s: foo' % nick, '%s foo' % nick,
|
'%s: foo' % nick, '%s foo' % nick,
|
||||||
'%s: foo' % nick.capitalize(), '%s: foo' % nick.upper()]
|
'%s: foo' % nick.capitalize(), '%s: foo' % nick.upper()]
|
||||||
@ -142,7 +142,7 @@ class FunctionsTestCase(unittest.TestCase):
|
|||||||
self.assertEqual('foo', callbacks.addressed(nick, msg), msg)
|
self.assertEqual('foo', callbacks.addressed(nick, msg), msg)
|
||||||
msg = ircmsgs.privmsg(nick, 'foo')
|
msg = ircmsgs.privmsg(nick, 'foo')
|
||||||
self.assertEqual('foo', callbacks.addressed(nick, msg))
|
self.assertEqual('foo', callbacks.addressed(nick, msg))
|
||||||
conf.prefixChars = oldprefixchars
|
conf.supybot.prefixChars.set(oldprefixchars)
|
||||||
msg = ircmsgs.privmsg('#foo', '%s::::: bar' % nick)
|
msg = ircmsgs.privmsg('#foo', '%s::::: bar' % nick)
|
||||||
self.assertEqual('bar', callbacks.addressed(nick, msg))
|
self.assertEqual('bar', callbacks.addressed(nick, msg))
|
||||||
msg = ircmsgs.privmsg('#foo', '%s: foo' % nick.upper())
|
msg = ircmsgs.privmsg('#foo', '%s: foo' % nick.upper())
|
||||||
@ -155,12 +155,12 @@ class FunctionsTestCase(unittest.TestCase):
|
|||||||
msg2 = ircmsgs.privmsg('#foo', 'bar')
|
msg2 = ircmsgs.privmsg('#foo', 'bar')
|
||||||
self.assertEqual(callbacks.addressed('blah', msg1), 'bar')
|
self.assertEqual(callbacks.addressed('blah', msg1), 'bar')
|
||||||
try:
|
try:
|
||||||
original = conf.replyWhenNotAddressed
|
original = str(conf.supybot.reply.whenNotAddressed)
|
||||||
conf.replyWhenNotAddressed = True
|
conf.supybot.reply.whenNotAddressed.set('True')
|
||||||
self.assertEqual(callbacks.addressed('blah', msg1), 'bar')
|
self.assertEqual(callbacks.addressed('blah', msg1), 'bar')
|
||||||
self.assertEqual(callbacks.addressed('blah', msg2), 'bar')
|
self.assertEqual(callbacks.addressed('blah', msg2), 'bar')
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotAddressed = original
|
conf.supybot.reply.whenNotAddressed.set(original)
|
||||||
|
|
||||||
def testReply(self):
|
def testReply(self):
|
||||||
prefix = 'foo!bar@baz'
|
prefix = 'foo!bar@baz'
|
||||||
@ -220,17 +220,17 @@ class PrivmsgTestCase(ChannelPluginTestCase):
|
|||||||
|
|
||||||
def testErrorPrivateKwarg(self):
|
def testErrorPrivateKwarg(self):
|
||||||
try:
|
try:
|
||||||
originalConfErrorReplyPrivate = conf.errorReplyPrivate
|
original = str(conf.supybot.reply.errorInPrivate)
|
||||||
conf.errorReplyPrivate = False
|
conf.supybot.reply.errorInPrivate.set('False')
|
||||||
m = self.getMsg("eval irc.error('foo', private=True)")
|
m = self.getMsg("eval irc.error('foo', private=True)")
|
||||||
self.failIf(ircutils.isChannel(m.args[0]))
|
self.failIf(ircutils.isChannel(m.args[0]))
|
||||||
finally:
|
finally:
|
||||||
conf.errorReplyPrivate = originalConfErrorReplyPrivate
|
conf.supybot.reply.errorInPrivate.set(original)
|
||||||
|
|
||||||
def testErrorReplyPrivate(self):
|
def testErrorReplyPrivate(self):
|
||||||
try:
|
try:
|
||||||
originalConfErrorReplyPrivate = conf.errorReplyPrivate
|
original = str(conf.supybot.reply.errorInPrivate)
|
||||||
conf.errorReplyPrivate = False
|
conf.supybot.reply.errorInPrivate.set('False')
|
||||||
# If this doesn't raise an error, we've got a problem, so the next
|
# If this doesn't raise an error, we've got a problem, so the next
|
||||||
# two assertions shouldn't run. So we first check that what we
|
# two assertions shouldn't run. So we first check that what we
|
||||||
# expect to error actually does so we don't go on a wild goose
|
# expect to error actually does so we don't go on a wild goose
|
||||||
@ -239,11 +239,11 @@ class PrivmsgTestCase(ChannelPluginTestCase):
|
|||||||
self.assertError(s)
|
self.assertError(s)
|
||||||
m = self.getMsg(s)
|
m = self.getMsg(s)
|
||||||
self.failUnless(ircutils.isChannel(m.args[0]))
|
self.failUnless(ircutils.isChannel(m.args[0]))
|
||||||
conf.errorReplyPrivate = True
|
conf.supybot.reply.errorInPrivate.set('True')
|
||||||
m = self.getMsg(s)
|
m = self.getMsg(s)
|
||||||
self.failIf(ircutils.isChannel(m.args[0]))
|
self.failIf(ircutils.isChannel(m.args[0]))
|
||||||
finally:
|
finally:
|
||||||
conf.errorReplyPrivate = originalConfErrorReplyPrivate
|
conf.supybot.reply.errorInPrivate.set(original)
|
||||||
|
|
||||||
# Now for stuff not based on the plugins.
|
# Now for stuff not based on the plugins.
|
||||||
class First(callbacks.Privmsg):
|
class First(callbacks.Privmsg):
|
||||||
@ -300,12 +300,12 @@ class PrivmsgTestCase(ChannelPluginTestCase):
|
|||||||
|
|
||||||
def testEmptyNest(self):
|
def testEmptyNest(self):
|
||||||
try:
|
try:
|
||||||
conf.replyWhenNotCommand = True
|
conf.supybot.reply.whenNotCommand.set('True')
|
||||||
self.assertError('echo []')
|
self.assertError('echo []')
|
||||||
conf.replyWhenNotCommand = False
|
conf.supybot.reply.whenNotCommand.set('False')
|
||||||
self.assertResponse('echo []', '[]')
|
self.assertResponse('echo []', '[]')
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotCommand = False
|
conf.supybot.reply.whenNotCommand.set('False')
|
||||||
|
|
||||||
def testDispatcherHelp(self):
|
def testDispatcherHelp(self):
|
||||||
self.assertNotRegexp('help first', r'\(dispatcher')
|
self.assertNotRegexp('help first', r'\(dispatcher')
|
||||||
@ -317,18 +317,6 @@ class PrivmsgTestCase(ChannelPluginTestCase):
|
|||||||
self.assertError('first blah')
|
self.assertError('first blah')
|
||||||
self.assertResponse('third foo bar baz', 'foo bar baz')
|
self.assertResponse('third foo bar baz', 'foo bar baz')
|
||||||
|
|
||||||
def testConfigureHandlesNonCanonicalCommands(self):
|
|
||||||
# Note that this also ends up testing that the FakeIrc object in
|
|
||||||
# callbacks actually works.
|
|
||||||
try:
|
|
||||||
original = conf.commandsOnStart
|
|
||||||
tokens = callbacks.tokenize('Admin setprefixchar $')
|
|
||||||
conf.commandsOnStart = [tokens]
|
|
||||||
self.assertNotError('load Admin')
|
|
||||||
self.assertEqual(conf.prefixChars, '$')
|
|
||||||
finally:
|
|
||||||
conf.commandsOnStart = original
|
|
||||||
|
|
||||||
def testSyntaxErrorNotEscaping(self):
|
def testSyntaxErrorNotEscaping(self):
|
||||||
self.assertError('load [foo')
|
self.assertError('load [foo')
|
||||||
self.assertError('load foo]')
|
self.assertError('load foo]')
|
||||||
@ -342,14 +330,14 @@ class PrivmsgTestCase(ChannelPluginTestCase):
|
|||||||
|
|
||||||
def testInvalidCommandOneReplyOnly(self):
|
def testInvalidCommandOneReplyOnly(self):
|
||||||
try:
|
try:
|
||||||
original = conf.replyWhenNotCommand
|
original = str(conf.supybot.reply.whenNotCommand)
|
||||||
conf.replyWhenNotCommand = True
|
conf.supybot.reply.whenNotCommand.set('True')
|
||||||
self.assertRegexp('asdfjkl', 'not a valid command')
|
self.assertRegexp('asdfjkl', 'not a valid command')
|
||||||
self.irc.addCallback(self.InvalidCommand())
|
self.irc.addCallback(self.InvalidCommand())
|
||||||
self.assertResponse('asdfjkl', 'foo')
|
self.assertResponse('asdfjkl', 'foo')
|
||||||
self.assertNoResponse(' ', 2)
|
self.assertNoResponse(' ', 2)
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotCommand = original
|
conf.supybot.reply.whenNotCommand.set(original)
|
||||||
|
|
||||||
class BadInvalidCommand(callbacks.Privmsg):
|
class BadInvalidCommand(callbacks.Privmsg):
|
||||||
def invalidCommand(self, irc, msg, tokens):
|
def invalidCommand(self, irc, msg, tokens):
|
||||||
@ -358,12 +346,12 @@ class PrivmsgTestCase(ChannelPluginTestCase):
|
|||||||
|
|
||||||
def testBadInvalidCommandDoesNotKillAll(self):
|
def testBadInvalidCommandDoesNotKillAll(self):
|
||||||
try:
|
try:
|
||||||
original = conf.replyWhenNotCommand
|
original = str(conf.supybot.reply.whenNotCommand)
|
||||||
conf.replyWhenNotCommand = True
|
conf.supybot.reply.whenNotCommand.set('True')
|
||||||
self.irc.addCallback(self.BadInvalidCommand())
|
self.irc.addCallback(self.BadInvalidCommand())
|
||||||
self.assertRegexp('asdfjkl', 'not a valid command')
|
self.assertRegexp('asdfjkl', 'not a valid command')
|
||||||
finally:
|
finally:
|
||||||
conf.replyWhenNotCommand = original
|
conf.supybot.reply.whenNotCommand.set(original)
|
||||||
|
|
||||||
|
|
||||||
class PrivmsgCommandAndRegexpTestCase(PluginTestCase):
|
class PrivmsgCommandAndRegexpTestCase(PluginTestCase):
|
||||||
|
@ -35,10 +35,20 @@ import os
|
|||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import conf
|
import conf
|
||||||
|
import world
|
||||||
import ircdb
|
import ircdb
|
||||||
import ircutils
|
import ircutils
|
||||||
|
|
||||||
class FunctionsTestCase(unittest.TestCase):
|
class IrcdbTestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
world.testing = False
|
||||||
|
unittest.TestCase.setUp(self)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
world.testing = True
|
||||||
|
unittest.TestCase.tearDown(self)
|
||||||
|
|
||||||
|
class FunctionsTestCase(IrcdbTestCase):
|
||||||
def testIsAntiCapability(self):
|
def testIsAntiCapability(self):
|
||||||
self.failIf(ircdb.isAntiCapability('foo'))
|
self.failIf(ircdb.isAntiCapability('foo'))
|
||||||
self.failIf(ircdb.isAntiCapability('#foo.bar'))
|
self.failIf(ircdb.isAntiCapability('#foo.bar'))
|
||||||
@ -188,7 +198,7 @@ class UserCapabilitySetTestCase(unittest.TestCase):
|
|||||||
## self.failUnless(s.check('owner'))
|
## self.failUnless(s.check('owner'))
|
||||||
|
|
||||||
|
|
||||||
class IrcUserTestCase(unittest.TestCase):
|
class IrcUserTestCase(IrcdbTestCase):
|
||||||
def testCapabilities(self):
|
def testCapabilities(self):
|
||||||
u = ircdb.IrcUser()
|
u = ircdb.IrcUser()
|
||||||
u.addCapability('foo')
|
u.addCapability('foo')
|
||||||
@ -259,7 +269,7 @@ class IrcUserTestCase(unittest.TestCase):
|
|||||||
u = ircdb.IrcUser(capabilities=('foo',))
|
u = ircdb.IrcUser(capabilities=('foo',))
|
||||||
self.assertRaises(KeyError, u.removeCapability, 'bar')
|
self.assertRaises(KeyError, u.removeCapability, 'bar')
|
||||||
|
|
||||||
class IrcChannelTestCase(unittest.TestCase):
|
class IrcChannelTestCase(IrcdbTestCase):
|
||||||
def testInit(self):
|
def testInit(self):
|
||||||
c = ircdb.IrcChannel()
|
c = ircdb.IrcChannel()
|
||||||
self.failIf(c.checkCapability('op'))
|
self.failIf(c.checkCapability('op'))
|
||||||
@ -302,8 +312,9 @@ class IrcChannelTestCase(unittest.TestCase):
|
|||||||
c.removeBan(banmask)
|
c.removeBan(banmask)
|
||||||
self.failIf(c.checkIgnored(prefix))
|
self.failIf(c.checkIgnored(prefix))
|
||||||
|
|
||||||
class UsersDBTestCase(unittest.TestCase):
|
class UsersDBTestCase(IrcdbTestCase):
|
||||||
filename = os.path.join(conf.confDir, 'UsersDBTestCase.conf')
|
filename = os.path.join(conf.supybot.directories.conf(),
|
||||||
|
'UsersDBTestCase.conf')
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
try:
|
try:
|
||||||
os.remove(self.filename)
|
os.remove(self.filename)
|
||||||
@ -352,8 +363,9 @@ class UsersDBTestCase(unittest.TestCase):
|
|||||||
self.assertRaises(ValueError, self.users.setUser, id, u2)
|
self.assertRaises(ValueError, self.users.setUser, id, u2)
|
||||||
|
|
||||||
|
|
||||||
class CheckCapabilityTestCase(unittest.TestCase):
|
class CheckCapabilityTestCase(IrcdbTestCase):
|
||||||
filename = os.path.join(conf.confDir, 'CheckCapabilityTestCase.conf')
|
filename = os.path.join(conf.supybot.directories.conf(),
|
||||||
|
'CheckCapabilityTestCase.conf')
|
||||||
owner = 'owner!owner@owner'
|
owner = 'owner!owner@owner'
|
||||||
nothing = 'nothing!nothing@nothing'
|
nothing = 'nothing!nothing@nothing'
|
||||||
justfoo = 'justfoo!justfoo@justfoo'
|
justfoo = 'justfoo!justfoo@justfoo'
|
||||||
@ -455,9 +467,9 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def testNothing(self):
|
def testNothing(self):
|
||||||
self.assertEqual(self.checkCapability(self.nothing, self.cap),
|
self.assertEqual(self.checkCapability(self.nothing, self.cap),
|
||||||
conf.defaultAllow)
|
conf.supybot.defaultAllow())
|
||||||
self.assertEqual(self.checkCapability(self.nothing, self.anticap),
|
self.assertEqual(self.checkCapability(self.nothing, self.anticap),
|
||||||
not conf.defaultAllow)
|
not conf.supybot.defaultAllow())
|
||||||
|
|
||||||
def testJustFoo(self):
|
def testJustFoo(self):
|
||||||
self.failUnless(self.checkCapability(self.justfoo, self.cap))
|
self.failUnless(self.checkCapability(self.justfoo, self.cap))
|
||||||
@ -503,11 +515,11 @@ class CheckCapabilityTestCase(unittest.TestCase):
|
|||||||
u.setAuth(self.securefoo)
|
u.setAuth(self.securefoo)
|
||||||
self.users.setUser(id, u)
|
self.users.setUser(id, u)
|
||||||
try:
|
try:
|
||||||
originalConfDefaultAllow = conf.defaultAllow
|
originalConfDefaultAllow = conf.supybot.defaultAllow()
|
||||||
conf.defaultAllow = False
|
conf.supybot.defaultAllow.set('False')
|
||||||
self.failIf(self.checkCapability('a' + self.securefoo, self.cap))
|
self.failIf(self.checkCapability('a' + self.securefoo, self.cap))
|
||||||
finally:
|
finally:
|
||||||
conf.defaultAllow = originalConfDefaultAllow
|
conf.supybot.defaultAllow.set(str(originalConfDefaultAllow))
|
||||||
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
@ -208,18 +208,20 @@ class IrcStateTestCase(unittest.TestCase):
|
|||||||
prefix = 'nick!user@host'
|
prefix = 'nick!user@host'
|
||||||
irc = FakeIrc()
|
irc = FakeIrc()
|
||||||
def testHistory(self):
|
def testHistory(self):
|
||||||
oldconfmaxhistory = conf.maxHistory
|
oldconfmaxhistory = str(conf.supybot.maxHistoryLength)
|
||||||
conf.maxHistory = 10
|
conf.supybot.maxHistoryLength.set('10')
|
||||||
state = irclib.IrcState()
|
state = irclib.IrcState()
|
||||||
for msg in msgs:
|
for msg in msgs:
|
||||||
try:
|
try:
|
||||||
state.addMsg(self.irc, msg)
|
state.addMsg(self.irc, msg)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
self.failIf(len(state.history) > conf.maxHistory)
|
self.failIf(len(state.history)>conf.supybot.maxHistoryLength())
|
||||||
self.assertEqual(len(state.history), conf.maxHistory)
|
self.assertEqual(len(state.history),
|
||||||
self.assertEqual(list(state.history), msgs[len(msgs)-conf.maxHistory:])
|
conf.supybot.maxHistoryLength())
|
||||||
conf.maxHistory = oldconfmaxhistory
|
self.assertEqual(list(state.history),
|
||||||
|
msgs[len(msgs)-conf.supybot.maxHistoryLength():])
|
||||||
|
conf.supybot.maxHistoryLength.set(oldconfmaxhistory)
|
||||||
|
|
||||||
def testEmptyTopic(self):
|
def testEmptyTopic(self):
|
||||||
state = irclib.IrcState()
|
state = irclib.IrcState()
|
||||||
@ -392,8 +394,6 @@ class IrcCallbackTestCase(unittest.TestCase):
|
|||||||
self.assertEqual(doCommandCatcher.L, commands)
|
self.assertEqual(doCommandCatcher.L, commands)
|
||||||
|
|
||||||
def testFirstCommands(self):
|
def testFirstCommands(self):
|
||||||
oldconfthrottle = conf.throttleTime
|
|
||||||
conf.throttleTime = 0
|
|
||||||
nick = 'nick'
|
nick = 'nick'
|
||||||
user = 'user any user'
|
user = 'user any user'
|
||||||
password = 'password'
|
password = 'password'
|
||||||
@ -411,7 +411,6 @@ class IrcCallbackTestCase(unittest.TestCase):
|
|||||||
msgs.pop()
|
msgs.pop()
|
||||||
expected.insert(0, ircmsgs.password(password))
|
expected.insert(0, ircmsgs.password(password))
|
||||||
self.assertEqual(msgs, expected)
|
self.assertEqual(msgs, expected)
|
||||||
conf.throttleTime = oldconfthrottle
|
|
||||||
|
|
||||||
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:
|
||||||
|
|
||||||
|
@ -112,15 +112,17 @@ class PluginTestCase(unittest.TestCase):
|
|||||||
if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
|
if self.__class__ in (PluginTestCase, ChannelPluginTestCase):
|
||||||
# Necessary because there's a test in here that shouldn\'t run.
|
# Necessary because there's a test in here that shouldn\'t run.
|
||||||
return
|
return
|
||||||
conf.prefixChars = '@'
|
conf.supybot.prefixChars.set('@')
|
||||||
conf.replyWhenNotCommand = False
|
conf.supybot.reply.whenNotCommand.setValue(False)
|
||||||
self.myVerbose = world.myVerbose
|
self.myVerbose = world.myVerbose
|
||||||
if self.cleanConfDir:
|
if self.cleanConfDir:
|
||||||
for filename in os.listdir(conf.confDir):
|
for filename in os.listdir(conf.supybot.directories.conf()):
|
||||||
os.remove(os.path.join(conf.confDir, filename))
|
os.remove(os.path.join(conf.supybot.directories.conf(),
|
||||||
|
filename))
|
||||||
if self.cleanDataDir:
|
if self.cleanDataDir:
|
||||||
for filename in os.listdir(conf.dataDir):
|
for filename in os.listdir(conf.supybot.directories.data()):
|
||||||
os.remove(os.path.join(conf.dataDir, filename))
|
os.remove(os.path.join(conf.supybot.directories.data(),
|
||||||
|
filename))
|
||||||
ircdb.users.reload()
|
ircdb.users.reload()
|
||||||
ircdb.channels.reload()
|
ircdb.channels.reload()
|
||||||
if self.plugins is None:
|
if self.plugins is None:
|
||||||
@ -130,10 +132,10 @@ class PluginTestCase(unittest.TestCase):
|
|||||||
self.irc = irclib.Irc(nick)
|
self.irc = irclib.Irc(nick)
|
||||||
while self.irc.takeMsg():
|
while self.irc.takeMsg():
|
||||||
pass
|
pass
|
||||||
OwnerModule = Owner.loadPluginModule('Owner')
|
#OwnerModule = Owner.loadPluginModule('Owner')
|
||||||
MiscModule = OwnerModule.loadPluginModule('Misc')
|
MiscModule = Owner.loadPluginModule('Misc')
|
||||||
_ = OwnerModule.loadPluginClass(self.irc, OwnerModule)
|
_ = Owner.loadPluginClass(self.irc, Owner)
|
||||||
_ = OwnerModule.loadPluginClass(self.irc, MiscModule)
|
_ = Owner.loadPluginClass(self.irc, MiscModule)
|
||||||
if isinstance(self.plugins, str):
|
if isinstance(self.plugins, str):
|
||||||
self.plugins = [self.plugins]
|
self.plugins = [self.plugins]
|
||||||
else:
|
else:
|
||||||
@ -300,8 +302,8 @@ class ChannelPluginTestCase(PluginTestCase):
|
|||||||
timeout = self.timeout
|
timeout = self.timeout
|
||||||
if self.myVerbose:
|
if self.myVerbose:
|
||||||
print # Newline, just like PluginTestCase.
|
print # Newline, just like PluginTestCase.
|
||||||
if query[0] not in conf.prefixChars:
|
if query[0] not in conf.supybot.prefixChars():
|
||||||
query = conf.prefixChars[0] + query
|
query = conf.supybot.prefixChars()[0] + query
|
||||||
msg = ircmsgs.privmsg(to, query, prefix=frm)
|
msg = ircmsgs.privmsg(to, query, prefix=frm)
|
||||||
if self.myVerbose:
|
if self.myVerbose:
|
||||||
print 'Feeding: %r' % msg
|
print 'Feeding: %r' % msg
|
||||||
|
Loading…
x
Reference in New Issue
Block a user