Discussion with bss implies that this is no longer needed, now that the dynamic loader and unload is in place. empirical testing seems to confirm this
167 lines
5.5 KiB
Python
167 lines
5.5 KiB
Python
"""
|
|
dr.botzo - a pluggable IRC bot written in Python
|
|
Copyright (C) 2010 Brian S. Stephan
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
from ConfigParser import ConfigParser, NoSectionError, NoOptionError
|
|
import os
|
|
import re
|
|
import socket
|
|
import sys
|
|
import inspect
|
|
import sqlite3
|
|
|
|
from extlib import irclib
|
|
|
|
modlist = []
|
|
moduleList = [ "Countdown", "Dice", "IrcAdmin", "GoogleTranslate", "Seen", "FactFile" ]
|
|
modObjs = []
|
|
|
|
class DrBotServerConnection(irclib.ServerConnection):
|
|
"""Subclass irclib's ServerConnection, in order to expand privmsg."""
|
|
|
|
def privmsg(self, target, text):
|
|
"""Send a PRIVMSG command."""
|
|
splitter = "..."
|
|
|
|
# split messages that are too long. Max length is 512.
|
|
# TODO: this does not properly handle when the hostname has been
|
|
# masked by the ircd
|
|
space = 512 - len('\r\n') - len('PRIVMSG ') - len(' :') - len(target) - len(self.nickname) - len('!') - len(self.username) - len('@') - len(socket.getfqdn())
|
|
splitspace = space - (len(splitter) + 1)
|
|
|
|
if len(text) > space:
|
|
times = 1
|
|
|
|
while len(text) > splitspace:
|
|
splitpos = text.rfind(' ', 0, splitspace)
|
|
splittext = text[0:splitpos] + ' ' + splitter
|
|
text = splitter + ' ' + text[splitpos+1:]
|
|
# unnecessary?
|
|
#try:
|
|
# splittext = unicode(splittext).encode('utf-8')
|
|
#except UnicodeDecodeError: pass
|
|
self.send_raw("PRIVMSG %s :%s" % (target, splittext))
|
|
|
|
times = times + 1
|
|
if times >= 4:
|
|
return
|
|
|
|
# done splitting
|
|
# unnecessary?
|
|
#try:
|
|
# text = unicode(text).encode('utf-8')
|
|
#except UnicodeDecodeError: pass
|
|
self.send_raw("PRIVMSG %s :%s" % (target, text))
|
|
else:
|
|
# unnecessary?
|
|
#try:
|
|
# text = unicode(text).encode('utf-8')
|
|
#except UnicodeDecodeError: pass
|
|
self.send_raw("PRIVMSG %s :%s" % (target, text))
|
|
|
|
class DrBotIRC(irclib.IRC):
|
|
"""Subclass irclib's IRC, in order to create a DrBotServerConnection."""
|
|
|
|
def server(self):
|
|
c = DrBotServerConnection(self)
|
|
self.connections.append(c)
|
|
return c
|
|
|
|
# check argv
|
|
if len(sys.argv) != 2:
|
|
sys.exit("Needs one argument, the config filename")
|
|
|
|
# read config file
|
|
|
|
config = ConfigParser({'debug': 'false'})
|
|
#config.read([os.path.expanduser('~/.dr.botzo.cfg'), 'dr.botzo.cfg'])
|
|
config.read(os.path.expanduser(sys.argv[1]))
|
|
|
|
# load necessary options
|
|
try:
|
|
# load connection info
|
|
botserver = config.get('dr.botzo', 'server')
|
|
botport = config.getint('dr.botzo', 'port')
|
|
botnick = config.get('dr.botzo', 'nick')
|
|
botpass = config.get('dr.botzo', 'pass')
|
|
botuser = config.get('dr.botzo', 'user')
|
|
botircname = config.get('dr.botzo', 'name')
|
|
except NoSectionError as e:
|
|
sys.exit("Aborted due to error with necessary configuration: " + str(e))
|
|
except NoOptionError as e:
|
|
sys.exit("Aborted due to error with necessary configuration: " + str(e))
|
|
|
|
# load additional options
|
|
irclib.DEBUG = config.getboolean('dr.botzo', 'debug')
|
|
|
|
try:
|
|
# make sure we can initialize the database, if such a thing is
|
|
# called for in the config file
|
|
dbfile = config.get('dr.botzo', 'database')
|
|
conn = sqlite3.connect(dbfile)
|
|
try:
|
|
query = """
|
|
SELECT COUNT(*)
|
|
FROM sqlite_master
|
|
WHERE type = 'table' AND name = 'drbotzo_modules'
|
|
"""
|
|
row = conn.execute(query).fetchone()
|
|
if row[0] == 0:
|
|
# need to create the drbotzo_modules table
|
|
query = """
|
|
CREATE TABLE drbotzo_modules (
|
|
module TEXT,
|
|
version INTEGER
|
|
)
|
|
"""
|
|
conn.execute(query)
|
|
conn.commit()
|
|
finally: conn.close()
|
|
except NoOptionError: pass # if the config file has no db property, assume that
|
|
except NoSectionError: pass # the database doesn't need to exist
|
|
|
|
# start up the IRC bot
|
|
|
|
# create IRC and server objects and connect
|
|
irc = DrBotIRC()
|
|
server = irc.server().connect(botserver, botport, botnick, botpass, botuser, botircname)
|
|
|
|
# load features
|
|
try:
|
|
cfgmodlist = config.get('dr.botzo', 'module_list')
|
|
|
|
mods = cfgmodlist.split(',')
|
|
for mod in mods:
|
|
# try to load each module
|
|
mod = mod.strip()
|
|
modstr = 'modules.'+mod
|
|
print "DEBUG: attempting to load module %s" % (modstr)
|
|
__import__(modstr)
|
|
module = sys.modules[modstr]
|
|
botmod = eval('module.' + mod + '(config, server, modlist)')
|
|
botmod.register_handlers(server)
|
|
except NoSectionError as e:
|
|
print("You seem to be missing a modules config section, which you probably wanted.")
|
|
except NoOptionError as e:
|
|
print("You seem to be missing a modlist config option, which you probably wanted.")
|
|
|
|
# loop forever
|
|
irc.process_forever()
|
|
|
|
# vi:tabstop=4:expandtab:autoindent
|
|
# kate: indent-mode python;indent-width 4;replace-tabs on;
|