--- gozerbot-0.99.1.orig/setup.cfg
+++ gozerbot-0.99.1/setup.cfg
@@ -2,4 +2,3 @@
tag_build =
tag_date = 0
tag_svn_revision = 0
-
--- gozerbot-0.99.1.orig/gozerbot.egg-info/SOURCES.txt
+++ gozerbot-0.99.1/gozerbot.egg-info/SOURCES.txt
@@ -1,6 +1,7 @@
Changelog
MANIFEST.in
README.txt
+setup.cfg
setup.py
bin/gozerbot
bin/gozerbot-init
--- gozerbot-0.99.1.orig/gozerbot.egg-info/PKG-INFO
+++ gozerbot-0.99.1/gozerbot.egg-info/PKG-INFO
@@ -1,4 +1,4 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: gozerbot
Version: 0.99.1
Summary: the irc bot and jabber bot in one
--- gozerbot-0.99.1.orig/build/lib/gozerbot/cache.py
+++ gozerbot-0.99.1/build/lib/gozerbot/cache.py
@@ -0,0 +1,12 @@
+# gozerbot.cache
+#
+#
+
+""" attempt to make a global usercache. not used yet. """
+
+# INIT SECTION
+
+# global userhost cache
+userhosts = {}
+
+# END SECTION
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/monitor.py
+++ gozerbot-0.99.1/build/lib/gozerbot/monitor.py
@@ -0,0 +1,168 @@
+# gozerbot/monitor.py
+#
+#
+
+""" `gozerbot.monitor` .. monitor the bots output
+
+This module contains the Monitor base class use to implement callbacks for
+the bot's output. Used in logging plugins. The actual monitor objects live
+irc and xmpp submodules.
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+## IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.config import config
+from gozerbot.stats import stats
+from utils.log import rlog
+from utils.exception import handle_exception
+from utils.trace import calledfrom
+from config import config
+from threads.threadloop import ThreadLoop
+from runner import waitrunners
+import threads.thr as thr
+
+# basic imports
+import Queue, sys
+
+## END IMPORT
+
+## LOCK SECTION
+
+# no locks
+
+## END LOCK
+
+class Monitor(ThreadLoop):
+
+ """ monitor base class. used as base class for jabber and irc
+ output monitoting.
+
+ :param name: name of the monitor
+ :type name: string
+
+ """
+
+ def __init__(self, name="monitor"):
+ ThreadLoop.__init__(self, name)
+ self.outs = []
+
+ def add(self, name, callback, pre, threaded=False):
+
+ """ add a monitoring callback.
+
+ :param name: name of the plugin using this monitor callback
+ :type name: string
+ :param callback: the callback to fire
+ :type callback: function
+ :param pre: precondition (function) to check if callback should fire
+ :type pre: function
+ :param threaded: whether callback should be called in its own thread
+ :type threaded: boolean
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/monitor.py
+ :pyobject: Monitor.add
+
+ """
+
+ name = name or calledfrom(sys._getframe(0))
+
+ if config['loadlist'] and name not in config['loadlist']:
+ return False
+
+ self.outs.append([name, callback, pre, threaded, False])
+ rlog(0, self.name, 'added monitor %s (%s)' % (name, str(callback)))
+ return True
+
+ def disable(self, name):
+ name = name.lower()
+
+ for i in range(len(self.outs)-1, -1, -1):
+ if self.outs[i][0] == name:
+ self.outs[i][4] = False
+
+ def activate(self, name):
+ name = name.lower()
+
+ for i in range(len(self.outs)-1, -1, -1):
+ if self.outs[i][0] == name:
+ self.outs[i][4] = True
+
+ def unload(self, name):
+
+ """ delete monitor callback.
+
+ :param name: name of the plugin which monitors need to be unloaded
+ :type name: string
+ :rtype: integer .. number of monitors removed
+
+ .. literalinclude:: ../../gozerbot/monitor.py
+ :pyobject: Monitor.unload
+
+ """
+
+ name = name.lower()
+ nr = 0
+
+ for i in range(len(self.outs)-1, -1, -1):
+ if self.outs[i][0] == name:
+ del self.outs[i]
+ nr += 1
+
+ return nr
+
+ def handle(self, *args, **kwargs):
+
+ """ check if monitor callbacks need to be fired.
+
+ :param args: arguments passed to the callback
+ :type args: list
+ :param kwargs: quoted arguments passed to the callback
+ :type kwargs: dict
+ :rtype: number of callbacks called
+
+ .. literalinclude:: ../../gozerbot/monitor.py
+ :pyobject: Monitor.handle
+
+ """
+
+ nr = 0
+ for i in self.outs:
+
+ if not i[4]:
+ continue
+ # check if precondition is met
+ try:
+ if i[2]:
+ stats.up('monitors', thr.getname(str(i[2])))
+ rlog(-10, 'monitor', 'checking inloop %s' % str(i[2]))
+ doit = i[2](*args, **kwargs)
+ else:
+ doit = 1
+
+ except Exception, ex:
+ handle_exception()
+ doit = 0
+
+ if doit:
+ # run monitor callback in its own thread
+ rlog(0, 'monitor', 'excecuting monitor callback %s' % i[0])
+ stats.up('monitors', thr.getname(str(i[1])))
+ if not i[3]:
+ waitrunners.put("monitor-%s" % i[0], i[1], *args)
+ else:
+ thr.start_new_thread(i[1], args, kwargs)
+
+ nr += 1
+
+ return nr
+
+## INIT SECTION
+
+# no vars
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/less.py
+++ gozerbot-0.99.1/build/lib/gozerbot/less.py
@@ -0,0 +1,159 @@
+# gozerbot/less.py
+#
+#
+
+""" maintain bot output cache. """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# gozerbot imports
+from utils.limlist import Limlist
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+class Less(object):
+
+ """
+ output cache .. caches upto <nr> item of txt lines per nick.
+
+ :param nr: size of backlog
+ :type nr: integer
+
+ """
+
+ def __init__(self, nr):
+ self.data = {}
+ self.index = {}
+ self.nr = nr
+
+ def add(self, nick, listoftxt):
+
+ """
+ add listoftxt to nick's output .. set index for used by more
+ commands.
+
+ :param nick: nick to add txt to cache for
+ :type nick: string
+ :param listoftxt: list of txt to cache
+ :type listoftxt: list
+
+ .. literalinclude:: ../../gozerbot/less.py
+ :pyobject: Less.add
+
+ """
+
+ nick = nick.lower()
+
+ # see if we already have cached output .. if not create limited list
+ if not self.data.has_key(nick):
+ self.data[nick] = Limlist(self.nr)
+
+ # add data
+ self.data[nick].insert(0, listoftxt)
+ self.index[nick] = 1
+
+ def get(self, nick, index1, index2):
+
+ """
+ return less entry.
+
+ entry is self.data[nick][index1][index2]
+
+ :param nick: nick to get data for
+ :type nick: string
+ :param index1: number of txtlines back
+ :type index1: integer
+ :param index2: index into the txtlines
+ :type index2: integer
+ :rtype: string
+
+ .. literalinclude:: ../../gozerbot/less.py
+ :pyobject: Less.get
+
+ """
+
+ nick = nick.lower()
+
+ try:
+ txt = self.data[nick][index1][index2]
+ except (KeyError, IndexError):
+ txt = None
+ return txt
+
+ def more(self, nick, index1):
+
+ """
+ return more entry pointed to by index .. increase index.
+
+ :param nick: nick to fetch data for
+ :type nick: string
+ :param index1: index into cache data
+ :type index1: integer
+ :rtype: tuple .. (txt, index)
+
+ .. literalinclude:: ../../gozerbot/less.py
+ :pyobject: Less.more
+
+ """
+
+ nick = nick.lower()
+
+ try:
+ nr = self.index[nick]
+ except KeyError:
+ nr = 1
+
+ try:
+ txt = self.data[nick][index1][nr]
+ size = len(self.data[nick][index1])-nr
+ self.index[nick] = nr+1
+ except (KeyError, IndexError):
+ txt = None
+ size = 0
+
+ return (txt, size-1)
+
+ def size(self, nick):
+
+ """
+ return sizes of cached output.
+
+ :param nick: nick to get cache sizes for
+ :type nick: string
+ :rtype: list .. list of sizes
+
+ .. literalinclude:: ../../gozerbot/less.py
+ :pyobject: Less.size
+
+ """
+
+ nick = nick.lower()
+ sizes = []
+
+ if not self.data.has_key(nick):
+ return sizes
+
+ for i in self.data[nick]:
+ sizes.append(len(i))
+
+ return sizes
+
+# ============
+# INIT SECTION
+
+# no vars
+
+# END INIT
+# ========
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/partyline.py
+++ gozerbot-0.99.1/build/lib/gozerbot/partyline.py
@@ -0,0 +1,365 @@
+# gozerbot/partyline.py
+#
+#
+
+""" provide partyline functionality .. manage dcc sockets. """
+
+
+__copyright__ = 'this file is in the public domain'
+__author__ = 'Aim'
+
+## IMPORT SECTION
+
+# gozerbot imports
+from utils.log import rlog
+from utils.exception import handle_exception
+from fleet import fleet
+from simplejson import load
+from threads.thr import start_new_thread
+
+# basic imports
+import thread, pickle, socket
+
+## END IMPORT
+
+## LOCK SECTION
+
+# no locks
+
+## END LOCK
+
+class PartyLine(object):
+
+ """
+ partyline can be used to talk through dcc chat connections.
+
+ """
+
+ def __init__(self):
+ self.socks = [] # partyline sockets list
+ self.jids = []
+ self.lock = thread.allocate_lock()
+
+ def _doresume(self, data, reto=None):
+
+ """
+ resume a party line connection after reboot.
+
+ :param data: resume data
+ :type data: dict .. see PartyLine._resumedata
+ :param reto: nick of user to reply to
+ :type reto: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject PartyLine._doresume
+
+ """
+
+ for i in data['partyline']:
+ bot = fleet.byname(i['botname'])
+ sock = socket.fromfd(i['fileno'], socket.AF_INET, socket.SOCK_STREAM)
+ sock.setblocking(1)
+ nick = i['nick']
+ userhost = i['userhost']
+ channel = i['channel']
+
+ if not bot:
+ rlog(10, 'partyline', "can't find %s bot in fleet" % i['botname'])
+ continue
+
+ self.socks.append({'bot': bot, 'sock': sock, 'nick': nick, 'userhost': userhost, 'channel': channel, 'silent': i['silent']})
+ bot._dccresume(sock, nick, userhost, channel)
+
+ if reto:
+ self.say_nick(nick, 'rebooting done')
+
+ def _resumedata(self):
+
+ """
+ return data used for resume.
+
+ :rtype: list .. list of resumedata (dicts)
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine._resumedata
+ """
+
+ result = []
+
+ for i in self.socks:
+ result.append({'botname': i['bot'].name, 'fileno': i['sock'].fileno(), 'nick': i['nick'], 'userhost': i['userhost'], 'channel': i['channel'], 'silent': i['silent']})
+
+ return result
+
+ def resume(self, sessionfile):
+
+ """
+ resume from session file.
+
+ :param sessionfile: path to resume file
+ :type sessionfile: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject PartyLine.resume
+ """
+
+ session = load(open(sessionfile, 'r'))
+
+ try:
+ reto = session['channel']
+ self._doresume(session, reto)
+
+ except Exception, ex:
+ handle_exception()
+
+ def stop(self, bot):
+
+ """
+ stop all users on bot.
+
+ :param bot: bot to stop users on
+ :type bot: gozerbot.eventbase.EventBase
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.stop
+ """
+
+ for i in self.socks:
+
+ if i['bot'] == bot:
+ try:
+ i['sock'].shutdown(2)
+ i['sock'].close()
+ except:
+ pass
+
+ def stop_all(self):
+
+ """
+ stop every user on partyline.
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.stop_all
+
+ """
+
+ for i in self.socks:
+ try:
+ i['sock'].shutdown(2)
+ i['sock'].close()
+ except:
+ pass
+
+ def loud(self, nick):
+
+ """
+ enable broadcasting of txt for nick.
+
+ :param nick: nick to put into loud mode
+ :type nick: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.loud
+
+ """
+
+ for i in self.socks:
+
+ if i['nick'] == nick:
+ i['silent'] = False
+
+ def silent(self, nick):
+
+ """
+ disable broadcasting txt from/to nick.
+
+ :param nick: nick to put into silent mode
+ :type nick: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.disable
+
+ """
+
+ for i in self.socks:
+
+ if i['nick'] == nick:
+ i['silent'] = True
+
+ def add_party(self, bot, sock, nick, userhost, channel):
+
+ '''
+ add a socket with nick to the list.
+
+ :param bot: bot to add party on
+ :type bot: gozerbot.botbase.BotBase
+ :param sock: socket of party to add
+ :type sock: socket.socket
+ :param nick: nick of party to add
+ :type nick: string
+ :param userhost: userhost of party to add
+ :type userhost: string
+ :param channel: channel of party to add
+ :type channel: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.add_party
+
+ '''
+
+ for i in self.socks:
+
+ if i['sock'] == sock:
+ return
+
+ self.socks.append({'bot': bot, 'sock': sock, 'nick': nick, \
+'userhost': userhost, 'channel': channel, 'silent': False})
+
+ rlog(1, 'partyline', 'added user %s on the partyline' % nick)
+
+ def del_party(self, nick):
+
+ '''
+ remove a socket with nick from the list.
+
+ :param nick: nick to remove
+ :type nick: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.del_party
+
+ '''
+
+ nick = nick.lower()
+ self.lock.acquire()
+
+ try:
+
+ for socknr in range(len(self.socks)-1, -1, -1):
+
+ if self.socks[socknr]['nick'].lower() == nick:
+ del self.socks[socknr]
+
+ rlog(1, 'partyline', 'removed user %s from the partyline' % nick)
+
+ finally:
+ self.lock.release()
+
+ def list_nicks(self):
+
+ '''
+ list all connected nicks.
+
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.list_nicks
+
+ '''
+
+ result = []
+
+ for item in self.socks:
+ result.append(item['nick'])
+
+ return result
+
+ def say_broadcast(self, txt):
+
+ '''
+ broadcast a message to all ppl on partyline.
+
+ :param txt: txt to broadcast
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.say_broadcast
+
+ '''
+
+ for item in self.socks:
+
+ if not item['silent']:
+ item['sock'].send("%s\n" % txt)
+
+ def say_broadcast_notself(self, nick, txt):
+
+ '''
+ broadcast a message to all ppl on partyline, except the sender.
+
+ :param nick: nick to ignore
+ :type nick: string
+ :param txt: text to broadcast
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.say_broadcast_notself
+
+ '''
+
+ nick = nick.lower()
+
+ for item in self.socks:
+
+ if item['nick'] == nick:
+ continue
+
+ if not item['silent']:
+ item['sock'].send("%s\n" % txt)
+
+ def say_nick(self, nickto, msg):
+
+ '''
+ say a message on the partyline to an user.
+
+ :param nickto: nick to send txt to
+ :type nickto: string
+ :param msg: msg to send
+ :type msg: string
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.say_nick
+
+ '''
+
+ nickto = nickto.lower()
+
+ for item in self.socks:
+
+ if item['nick'].lower() == nickto:
+
+ if not '\n' in msg:
+ msg += "\n"
+
+ item['sock'].send("%s" % msg)
+ return
+
+ def is_on(self, nick):
+
+ '''
+ checks if user an is on the partyline.
+
+ :param nick: nick to check
+ :type nick: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/partyline.py
+ :pyobject: PartyLine.is_on
+
+ '''
+
+ nick = nick.lower()
+
+ for item in self.socks:
+
+ if item['nick'].lower() == nick:
+ return True
+
+ return False
+
+## INIT SECTION
+
+# the partyline !
+partyline = PartyLine()
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/plughelp.py
+++ gozerbot-0.99.1/build/lib/gozerbot/plughelp.py
@@ -0,0 +1,73 @@
+# gozerbot/plughelp.py
+#
+#
+
+"""
+ help about plugins.
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+## IMPORT SECTION
+
+# no imports
+
+## END IMPORT
+
+## LOCK SECTION
+
+# no locks
+
+## END LOCK
+
+class PlugHelp(dict):
+
+ """
+ dict holding plugins help string.
+
+ """
+
+ def add(self, item, descr):
+
+ """
+ add plugin help string.
+
+ :param item: the plugin to store description for
+ :type item: string
+ :param descr: the description of the plugin
+ :type descr: string
+
+ .. literalinclude ../../gozerbot/plughelp.py
+ :pyobject: PlugHelp.add
+
+ """
+
+ item = item.lower()
+ self[item] = descr
+
+ def get(self, item):
+
+ """
+ get plugin help string.
+
+ :param item: plugin to get description for
+ :type item: string
+ :rtype: string
+
+ .. literalinclude:: ../../gozerbot/plughelp.py
+ :pyobject: PlugHelp.get
+ """
+
+ item = item.lower()
+ try:
+ return self[item]
+ except KeyError:
+ return None
+
+## INIT SECTION
+
+# plughelp object
+plughelp = PlugHelp()
+
+# END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/generic.py
+++ gozerbot-0.99.1/build/lib/gozerbot/generic.py
@@ -0,0 +1,31 @@
+# generic compat stub
+#
+#
+
+""" utils stub for backwards compatibility. """
+
+# ==============
+# IMPORT SECTION
+
+from utils.log import *
+from utils.generic import *
+from utils.exception import *
+from utils.popen import *
+from utils.timeutils import *
+from utils.fileutils import *
+from utils.reboot import *
+from utils.trace import *
+from utils.locking import *
+from utils.rsslist import *
+from utils.url import *
+
+# END IMPORT
+# ==========
+
+# =========
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
--- gozerbot-0.99.1.orig/build/lib/gozerbot/plugins.py
+++ gozerbot-0.99.1/build/lib/gozerbot/plugins.py
@@ -0,0 +1,1509 @@
+# gozerbot/plugins.py
+#
+#
+
+""" provide plugin infrastructure """
+
+__copyright__ = 'this file is in the public domain'
+
+## gozerbot imports
+
+from gozerbot.stats import stats
+from gozerbot.tests import tests
+from gozerbot.datadir import datadir
+from users import users
+from irc.monitor import outmonitor, saymonitor
+from xmpp.monitor import xmppmonitor
+from utils.log import rlog
+from utils.exception import handle_exception
+from utils.generic import checkchan
+from utils.locking import lockdec, funclocked, Locked
+from utils.generic import plugnames, waitforqueue, uniqlist, makeoptions, makeargrest, cleanpycfile
+from gozerimport import gozer_import, force_import
+from persist.persist import Persist
+from persist.persistconfig import PersistConfig
+from config import config
+from commands import cmnds
+from callbacks import callbacks, jcallbacks, gn_callbacks
+from redispatcher import rebefore, reafter
+from aliases import aliascheck, aliasget
+from ignore import shouldignore
+from threads.thr import start_new_thread, getname
+from persist.persiststate import PersistState
+from simplejson import loads
+from morphs import inputmorphs, outputmorphs
+from eventbase import EventBase
+from admin import cmndtable, pluginlist
+
+# basic imports
+import os, os.path, thread, time, Queue, re, copy
+
+## END IMPORT
+
+## LOCK SECTION
+
+loadlock = thread.allocate_lock()
+loadlocked = lockdec(loadlock)
+
+## END LOCK
+
+class Plugins(object):
+
+ """
+ hold all the plugins.
+
+ """
+
+ def __init__(self):
+ self.plugs = {} # dict with the plugins
+ self.reloadlock = thread.allocate_lock()
+ # persisted data for deny of plugins (blacklist)
+ self.plugdeny = Persist(datadir + os.sep + 'plugdeny', init=False)
+ if not self.plugdeny.data:
+ self.plugdeny.data = []
+ # persisted data for allowing of plugins (whitelist)
+ self.plugallow = Persist(datadir + os.sep + 'plugallow', init=False)
+ if not self.plugallow.data:
+ self.plugallow.data = []
+ self.avail = [] # available plugins
+ self.ondisk = [] # plugisn available for reload
+ self.initcalled = [] # plugins which init functions are called
+ self.overloads = {} # plugins to overload
+ self.activated = {}
+ for plug in config['plugdeny']:
+ self.disable(plug)
+
+ def __getitem__(self, item):
+
+ """
+ return plugin.
+
+ """
+
+ if self.plugs.has_key(item):
+ return self.plugs[item]
+ else:
+ return None
+
+ def get(self, item, attr):
+
+ """
+ get attribute of plugin.
+
+ :param item: plugin to get attribute of
+ :type item: string
+ :param attr: attribute to fetch
+ :type attr: string
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.get
+
+ """
+
+ if self.plugs.has_key(item):
+ return getattr(self.plugs[item], attr)
+
+ def whatperms(self):
+
+ """
+ return what permissions are possible.
+
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.whatperms
+
+ """
+
+ result = []
+
+ # search RE callbacks before the commands
+ for i in rebefore.whatperms():
+ if not i in result:
+ result.append(i)
+
+ # search the commands
+ for i in cmnds.whatperms():
+ if not i in result:
+ result.append(i)
+
+ # search RE callbacks after commands
+ for i in reafter.whatperms():
+ if not i in result:
+ result.append(i)
+
+ result.sort()
+ return result
+
+ def exist(self, name):
+
+ """
+ see if plugin exists.
+
+ :param name: name of plugin to check for
+ :type name: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.exist
+
+ """
+
+ if self.plugs.has_key(name):
+ return True
+ return False
+
+ def disable(self, name):
+
+ """
+ prevent plugin to be loaded. plugins does get imported but
+ commands, callbacks, monitors etc are not enabled.
+
+ :param name: name of the plugin to disable
+ :type name: string
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.disable
+
+ """
+
+ try:
+ config['loadlist'].remove(name)
+ config.save()
+ self.plugdeny.data.append(name)
+ self.plugdeny.save()
+
+ except:
+ pass
+
+ def enable(self, name):
+
+ """
+ enable plugin.
+
+ :param name: name of plugin to enable
+ :type name: string
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.enable
+
+ """
+
+ try:
+
+ if name not in config['loadlist']:
+ config['loadlist'].append(name)
+ config.save()
+
+ except KeyError:
+ pass
+
+ try:
+ self.plugdeny.data.remove(name)
+ self.plugdeny.save()
+
+ except ValueError:
+ pass
+
+ def plugsizes(self):
+
+ """
+ call the size() function in all plugins.
+
+ :rtype: list .. list of plugin sizes
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.plugsizes
+ """
+
+ reslist = []
+ cp = dict(self.plugs)
+ for i, j in cp.iteritems():
+ try:
+ reslist.append("%s: %s" % (i, j.size()))
+ except AttributeError:
+ pass
+ return reslist
+
+ def list(self):
+
+ """
+ list of registered plugins.
+
+ :rtype: list .. list of enabled plugins
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.list
+
+ """
+
+ self.avail.sort()
+ return self.avail
+
+ def plugimport(self, mod, name):
+
+ """
+ import a plugin.
+
+ :param mod: module to import plugin from
+ :type mod: string
+ :param name: name of the plugin to import
+ :type name: string
+ :rtype: module .. the plugin
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.plugimport
+
+ """
+
+ if name in config['loadlist']:
+ return self.load(mod, name)
+
+ def regplugin(self, mod, name):
+
+ """
+ register plugin.
+
+ :param mod: module to import plugin from
+ :type mod: string
+ :param name: name of the plugin to import
+ :type name: string
+ :rtype: module .. the plugin
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.regplugin
+
+ """
+
+ name = name.lower()
+ mod = mod.lower()
+ modname = mod + '.' + name
+
+ # see if plugin is in deny
+ if name in self.avail:
+ rlog(0, 'plugins', '%s already registered' % name)
+ return
+
+ if name in config['plugdeny']:
+ rlog(0, 'plugins', '%s is in config.plugdeny .. not loading' % name)
+ return
+
+ if name in self.plugdeny.data:
+ rlog(0, 'plugins', '%s.%s in deny .. not loading' % (mod, name))
+ return 0
+
+ if config.has_key('loadlist') and name not in config['loadlist'] and 'gplugs' in modname and name not in self.plugallow.data:
+ rlog(9, 'plugins', 'not loading %s.%s' % (mod, name))
+ return 0
+
+ # if plugin is already registered unload it
+ if self.plugs.has_key(name):
+ rlog(10, 'plugins', 'overloading %s plugin with %s version' % (name, mod))
+ self.unloadnosave(name)
+
+ # create the plugin data dir
+ if hasattr(os, 'mkdir'):
+ if not os.path.isdir(datadir + os.sep + 'plugs'):
+ os.mkdir(datadir + os.sep + 'plugs')
+
+ if not os.path.isdir(datadir + os.sep + 'plugs' + os.sep + name):
+ os.mkdir(datadir + os.sep + 'plugs' + os.sep + name)
+
+ # import the plugin
+ plug = self.plugimport(mod, name)
+
+ if plug:
+ rlog(0, 'plugins', "%s.%s registered" % (mod, name))
+
+ if name not in self.avail:
+ self.avail.append(name)
+
+ return plug
+
+ else:
+ rlog(10, 'plugins', "can't import %s.%s .. try plug-enable" % (mod, name))
+
+ def showregistered(self):
+
+ """
+ show registered plugins.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.showregistered
+
+ """
+
+ self.avail.sort()
+ rlog(10, 'plugins', 'registered %s' % ' .. '.join(self.avail))
+ self.overload()
+
+ def regdir(self, dirname, exclude=[]):
+
+ """
+ register a directory.
+
+ :param dirname: directory to import plugins from
+ :type dirname: string
+ :param exclude: plugins to exclude from importing
+ :type exclude: list .. list of plugin names
+ :rtype: list .. list of plugin names that are registered
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.regdir
+
+ """
+
+ threads = []
+ plugs = []
+ for plug in plugnames(dirname):
+ if plug in exclude or plug.startswith('.'):
+ continue
+ try:
+ self.regplugin(dirname, plug)
+ plugs.append(plug)
+ except:
+ handle_exception()
+ self.ondisk.extend(plugs)
+ return plugs
+
+ def regcore(self):
+
+ """
+ register core plugins.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.regcore
+
+ """
+
+ self.plugdeny.init([])
+ self.plugallow.init([])
+ avail = []
+ plugs = force_import('gozerbot.plugs')
+
+ for i in plugs.__plugs__:
+
+ if i not in avail:
+
+ try:
+ self.regplugin('gozerbot.plugs', i)
+ except Exception, ex:
+ handle_exception()
+ else:
+ avail.append(i)
+
+ self.ondisk.extend(avail)
+
+ def enableall(self):
+
+ """
+ enable all plugins
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.enableall
+
+ """
+
+ for name in self.available():
+ self.enable(name)
+
+ def regplugins(self):
+
+ """
+ register all plugins.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.regplugins
+
+ """
+
+ self.regcore()
+ avail = []
+
+ # check for myplugs directory
+ if os.path.isdir('myplugs'):
+ avail.extend(self.regdir('myplugs'))
+
+ for i in os.listdir('myplugs'):
+
+ if i.startswith('.'):
+ continue
+
+ if os.path.isdir('myplugs' + os.sep + i):
+ avail.extend(self.regdir('myplugs' + os.sep + i))
+ else:
+ rlog(10, 'plugins', 'no myplugs directory found')
+
+ # check for gplugs package
+ try:
+ gplugs = gozer_import('gplugs')
+ except ImportError:
+ rlog(20, 'plugins', "no gplugs package found")
+ gplugs = None
+
+ if gplugs:
+
+ for i in gplugs.__plugs__:
+
+ try:
+ self.regplugin('gplugs', i)
+ avail.append(i)
+ except Exception, ex:
+ handle_exception()
+
+ if config.get('db_driver') == "olddb":
+ # check for gplugs package
+ try:
+ gplugs = gozer_import('gplugs.olddb')
+ except ImportError:
+ rlog(20, 'plugins', "no gplugs.old package found")
+ gplugs = None
+
+ if gplugs:
+
+ for i in gplugs.__plugs__:
+
+ try:
+ self.regplugin('gplugs.olddb', i)
+ avail.append(i)
+ except Exception, ex:
+ handle_exception()
+ else:
+ # check for gplugs package
+ try:
+ gplugs = gozer_import('gplugs.alchemy')
+ except ImportError:
+ rlog(20, 'plugins', "no gplugs.alchemy package found")
+ gplugs = None
+
+ if gplugs:
+
+ for i in gplugs.__plugs__:
+
+ try:
+ self.regplugin('gplugs.alchemy', i)
+ avail.append(i)
+ except Exception, ex:
+ handle_exception()
+
+ self.ondisk.extend(avail)
+ self.readoverload()
+ start_new_thread(self.showregistered, ())
+
+ def readoverload(self):
+
+ """
+ see if there is a permoverload file and if so use it to overload
+ permissions based on function name.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.readoverload
+
+ """
+
+ try:
+ overloadfile = open(datadir + os.sep + 'permoverload', 'r')
+ except IOError:
+ return
+
+ try:
+
+ for i in overloadfile:
+ i = i.strip()
+ splitted = i.split(',')
+
+ try:
+ funcname = splitted[0].strip()
+ perms = []
+ for j in splitted[1:]:
+ perms.append(j.strip())
+ except IndexError:
+ rlog(10, 'plugins', "permoverload: can't set perms of %s" \
+% i)
+ continue
+
+ if not funcname:
+ rlog(10, 'plugins', "permoverload: no function provided")
+ continue
+
+ if not perms:
+ rlog(10, 'plugins', "permoverload: no permissions \
+provided for %s" % funcname)
+ continue
+
+ self.overloads[funcname] = perms
+
+ except Exception, ex:
+ handle_exception()
+
+ def overload(self):
+
+ """
+ overload functions in self.overloads.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.overload
+
+ """
+ for funcname, perms in self.overloads.iteritems():
+
+ if self.permoverload(funcname, perms):
+ rlog(0, 'plugins', '%s permission set to %s' % (funcname, \
+perms))
+
+ def available(self):
+
+ """
+ available plugins not yet registered.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.available
+
+ """
+
+ self.ondisk.sort()
+ return self.ondisk
+
+ def saveplug(self, plugname):
+
+ """
+ call save() function of plugin.
+
+ :param plugname: name of the plugin to call save() on
+ :type plugname: string
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.saveplug
+ """
+
+ try:
+ self.plugs[plugname].save()
+
+ except AttributeError:
+ pass
+
+ except KeyError:
+ pass
+
+ def save(self):
+
+ """
+ call registered plugins save.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.save
+
+ """
+
+ for plug in self.plugs.values():
+
+ try:
+ plug.save()
+
+ except AttributeError:
+ pass
+
+ except Exception, ex:
+ handle_exception()
+
+ def save_cfg(self):
+
+ """
+ call registered plugins configuration save.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.save_cfg
+
+ """
+
+ for plug in self.plugs.values():
+ try:
+ cfg = getattr(plug, 'cfg')
+ if isinstance(cfg, PersistConfig):
+ try:
+ cfg.save()
+ except:
+ handle_exception()
+ except AttributeError:
+ continue
+
+ def save_cfgname(self, name):
+
+ """
+ save plugin persisted config data.
+
+ :param name: name of the plugin to call cfg.save for
+ :type name: string
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.save_cfgname
+ """
+
+ try:
+ plug = self.plugs[name]
+ cfg = getattr(plug, 'cfg')
+
+ if isinstance(cfg, PersistConfig):
+
+ try:
+ cfg.save()
+ except:
+ handle_exception()
+
+ except (AttributeError, KeyError):
+ pass
+
+ def exit(self):
+
+ """
+ call shutdown on all registered plugins.
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.exit
+
+ """
+
+ self.save()
+ threadlist = []
+
+ # call shutdown on all plugins
+ for name, plug in self.plugs.iteritems():
+
+ try:
+ shutdown = getattr(plug, 'shutdown')
+ thread = start_new_thread(shutdown, ())
+ threadlist.append((name, thread))
+
+ try:
+ self.initcalled.remove(name)
+ except ValueError:
+ pass
+
+ except AttributeError:
+ continue
+
+ except Exception, ex:
+ rlog(10, 'plugins', 'error shutting down %s: %s' % (name, str(ex)))
+
+ # join shutdown threads
+ try:
+
+ for name, thread in threadlist:
+ thread.join()
+ rlog(10, 'plugins', '%s shutdown finished' % name)
+ except:
+ handle_exception()
+
+ def getoptions(self, command):
+
+ """
+ return options entry of a command.
+
+ :param command: command name to get options of
+ :type command: string
+ :rtype: dict
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.getoptions
+
+ """
+
+ return cmnds.getoptions(command)
+
+ def getdepend(self, plugname):
+
+ """
+ get plugins the plugin depends on. NOT USED ANYMORE ..
+
+ we use the __depending__ attribute now which checks for the
+ reverse case ala what plugins depends on this plugin. code is
+ in reload().
+
+ """
+
+ # try to import the plugin
+ if plugname in self.plugs:
+ plug = self.plugs[plugname]
+ else:
+ for mod in ['gozerbot.plugs', 'gplugs', 'myplugs']:
+ try:
+ plug = gozer_import('%s.%s' % (mod, plugname))
+ except ImportError:
+ continue
+
+ # check for the __depend__ attribute
+ try:
+ depends = plug.__depend__
+ except:
+ depends = []
+
+ return depends
+
+ def load(self, mod , name, enable=True):
+ #if name in config['plugdeny']:
+ # return
+ # force an import of the plugin
+ modname = mod + '.' + name
+ self.down(name)
+ self.unload(name)
+ if enable:
+ self.enable(name)
+ plug = self.plugs[name] = gozer_import(modname)
+ plug.loadtime = time.time()
+ if enable:
+ self.enable(name)
+ self.overload()
+ # call plugins init() function
+ try:
+ rlog(0, 'plugins', 'calling %s init()' % modname)
+ plug.init()
+ self.initcalled.append(modname)
+
+ except (AttributeError, KeyError):
+ pass
+
+ except Exception, ex:
+ rlog(10, 'plugins', '%s module init failed' % name)
+ raise
+
+ rlog(0, 'plugins', 'enabled %s' % name)
+
+ self.activate(name)
+ return plug
+
+ #@loadlocked
+ def reload(self, mod, name, enable=True):
+
+ """
+ reload plugin.
+
+ :param mod: module to import plugin from
+ :type mod: string
+ :param name: name of the plugin to reload
+ :type name: string
+ :param enable: whether plugin should be enabled on reload
+ :type enable: boolean
+ :rtype: list .. list of names of reloaded plugins
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.reload
+
+ """
+
+ # create the plugin data dir
+ if not os.path.isdir(datadir + os.sep + 'plugs'):
+ os.mkdir(datadir + os.sep + 'plugs')
+
+ if not os.path.isdir(datadir + os.sep + 'plugs' + os.sep + name):
+ os.mkdir(datadir + os.sep + 'plugs' + os.sep + name)
+
+ reloaded = []
+ modname = mod + '.' + name
+
+ # force an import of the plugin
+ plug = self.load(mod, name)
+
+ # recurse the reload function if plugin is a dir
+ try:
+ for p in plug.__plugs__:
+ self.load(modname, p)
+ reloaded.append(p)
+
+ except (KeyError, AttributeError):
+ pass
+
+ rlog(0, 'plugins', 'reloaded plugin %s' % modname)
+ reloaded.append(name)
+ self.plugallow.data.append(name)
+
+ try:
+ self.plugdeny.data.remove(name)
+ except ValueError:
+ pass
+
+ if name not in self.avail:
+ self.avail.append(name)
+
+ # recurse on plugins the depend on this plugin
+ try:
+ depends = plug.__depending__
+
+ for plug in depends:
+ rlog(10, 'plugins', 'loading depending plugin %s (%s)' % (plug, name))
+ self.load(mod, plug, False)
+ reloaded.append(plug)
+
+ except AttributeError:
+ pass
+
+ return reloaded
+
+ def activate(self, plugname):
+ self.activated[plugname] = True
+ try:
+ cmnds.activate(plugname)
+ callbacks.activate(plugname)
+ gn_callbacks.activate(plugname)
+ jcallbacks.activate(plugname)
+ rebefore.activate(plugname)
+ reafter.activate(plugname)
+ saymonitor.activate(plugname)
+ outmonitor.activate(plugname)
+ xmppmonitor.activate(plugname)
+ tests.activate(plugname)
+ outputmorphs.activate(plugname)
+ inputmorphs.activate(plugname)
+ except Exception, ex:
+ handle_exception()
+ return 0
+
+ def down(self, plugname):
+ self.activated[plugname] = False
+ try:
+ cmnds.disable(plugname)
+ callbacks.disable(plugname)
+ gn_callbacks.disable(plugname)
+ jcallbacks.disable(plugname)
+ rebefore.disable(plugname)
+ reafter.disable(plugname)
+ saymonitor.disable(plugname)
+ outmonitor.disable(plugname)
+ xmppmonitor.disable(plugname)
+ tests.disable(plugname)
+ outputmorphs.disable(plugname)
+ inputmorphs.disable(plugname)
+ except Exception, ex:
+ handle_exception()
+ return 0
+
+ def unload(self, plugname):
+
+ """
+ unload plugin.
+
+ :param plugname: name of the plugin to unload
+ :type plugname: string
+ :rtype: list .. list of unloaded plugins
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.unload
+
+ """
+
+ # call plugins shutdown function if available
+ unloaded = [plugname, ]
+
+ # recurse if plugin is dir
+ try:
+ plug = self.plugs[plugname]
+
+ for p in plug.__plugs__:
+ if p == plug:
+ raise Exception("same plugin name as dir name (%s)" % plugname)
+ unloaded.extend(self.unload(p))
+
+ except (KeyError, AttributeError):
+ pass
+
+ # save and unload
+ for plugname in unloaded:
+ self.saveplug(plugname)
+ self.unloadnosave(plugname)
+
+ try:
+ self.avail.remove(plugname)
+
+ except ValueError:
+ pass
+
+ return unloaded
+
+ def unloadnosave(self, plugname):
+
+ """
+ unload plugin without saving.
+
+ :param plugname: name of the plugin to unload
+ :type plugname: string
+ :rtype: list .. list of unloaded plugins
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.unloadnosave
+
+ """
+
+ # call shutdown function
+ try:
+ self.plugs[plugname].shutdown()
+ rlog(10, 'plugins', '%s shutdown called' % plugname)
+
+ except (AttributeError, KeyError):
+ pass
+
+ except Exception, ex:
+ handle_exception()
+
+ # remove from plugallow
+ try:
+ self.plugallow.data.remove(plugname)
+ except (KeyError, ValueError):
+ pass
+
+ # remove from avail list
+ try:
+ self.avail.remove(plugname)
+ except ValueError:
+ pass
+
+ # remove from initcalled list
+ try:
+ self.initcalled.remove(plugname)
+ except ValueError:
+ pass
+
+ # unload commands, RE callbacks, callbacks, monitorsetc.
+ try:
+ cmnds.unload(plugname)
+ callbacks.unload(plugname)
+ gn_callbacks.unload(plugname)
+ jcallbacks.unload(plugname)
+ rebefore.unload(plugname)
+ reafter.unload(plugname)
+ saymonitor.unload(plugname)
+ outmonitor.unload(plugname)
+ xmppmonitor.unload(plugname)
+ tests.unload(plugname)
+ outputmorphs.unload(plugname)
+ inputmorphs.unload(plugname)
+
+ if self.plugs.has_key(plugname):
+ del self.plugs[plugname]
+
+ except Exception, ex:
+ handle_exception()
+ return 0
+
+ rlog(0, 'plugins', '%s unloaded' % plugname)
+ return 1
+
+ def whereis(self, what):
+
+ """
+ locate command.
+
+ :param what: name of command to search
+ :type what: string
+ :rtype: string .. plugin the command is in
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.whereis
+
+ """
+
+ return cmnds.whereis(what)
+
+ def permoverload(self, funcname, perms):
+
+ """
+ overload permission of a function.
+
+ :param funcname: name of function to overload permissions of
+ :type funcname: string
+ :param perms: permissions to overload
+ :type perms: list .. list of permissions
+ :rtype: boolean: whether overload worked or not
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.permoverload
+
+ """
+
+ if not rebefore.permoverload(funcname, perms):
+
+ if not cmnds.permoverload(funcname, perms):
+
+ if not reafter.permoverload(funcname, perms):
+ return False
+
+ return True
+
+ def woulddispatch(self, bot, ievent):
+
+ """
+ function to determine whether a event would dispatch.
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :rtype: boolean .. whether the dispatch should fire
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.woulddispatch
+
+ """
+ #self.needreloadcheck(bot, ievent)
+ (what, command) = self.dispatchtest(bot, ievent)
+
+ #if what and not what.activate:
+ # return False
+
+ if what and command:
+ return True
+
+ return False
+
+ #@funclocked
+ def dispatchtest(self, bot, ievent, direct=False):
+
+ """
+ return (dispatcher, command) on which command should fire.
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :param direct: whether user permission should be checked
+ :type direct: boolean .. when set user permission is NOT checked
+ :rtype: tuple .. (dispatcher, command) tuples
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.dispatchtest
+ """
+
+ # check for ignore
+ if shouldignore(ievent.userhost):
+ return (None, None)
+
+ # check for throttle
+ if ievent.userhost in bot.throttle:
+ return (None, None)
+
+ # set target properly
+ if ievent.txt.find(' | ') != -1:
+ target = ievent.txt.split(' | ')[0]
+ elif ievent.txt.find(' && ') != -1:
+ target = ievent.txt.split(' && ')[0]
+ else:
+ target = ievent.txt
+
+ result = []
+
+ # first check for RE before commands dispatcher
+ com = rebefore.getcallback(target)
+
+ if com and not target.startswith('!'):
+ com.re = True
+ result = [rebefore, com]
+ else:
+
+ # try commands
+ if ievent.txt.startswith('!'):
+ ievent.txt = ievent.txt[1:]
+
+ aliascheck(ievent)
+ com = cmnds.getcommand(ievent.txt)
+
+ if com:
+ com.re = False
+ result = [cmnds, com]
+ ievent.txt = ievent.txt.strip()
+
+ else:
+
+ # try RE after commands
+ com = reafter.getcallback(target)
+ if com:
+ com.re = True
+ result = [reafter, com]
+ if result:
+
+ # check for auto registration
+ if config['auto_register'] and not users.getname(ievent.userhost):
+ if bot.google:
+ users.add(ievent.userhost , [ievent.userhost, ], ['USER', ])
+ elif not bot.jabber:
+ users.add("%s!%s" % (ievent.nick, ievent.userhost) , [ievent.userhost, ], ['USER', ])
+ bot.ratelimit(ievent.userhost, 20)
+ else:
+ if ievent.groupchat:
+ users.add(ievent.userhost , [ievent.userhost, ], ['USER', ])
+ bot.ratelimit(ievent.userhost)
+ else:
+ users.add(ievent.stripped , [ievent.stripped, ], ['USER', ])
+ bot.ratelimit(ievent.stripped, 20)
+
+ # check for anon access
+ if config['anon_enable'] and not 'OPER' in result[1].perms:
+ return result
+
+ # check if command is allowed (all-add command)
+ if com.name in bot.state['allowed'] or getname(com.func) in bot.state['allowed']:
+ return result
+
+ # check for channel permissions
+ try:
+ chanperms = bot.channels[ievent.channel.lower()]['perms']
+
+ for i in result[1].perms:
+ if i in chanperms and not ievent.msg:
+ ievent.speed = 1
+ return result
+
+ except (KeyError, TypeError):
+ pass
+
+ # if direct is set dont check the user database
+ if direct:
+ return result
+
+ # use event.stripped in case of jabber
+ if bot.jabber and ievent.jabber:
+ if not ievent.groupchat or ievent.jidchange:
+ if users.allowed(ievent.stripped, result[1].perms):
+ return result
+
+ # irc users check
+ if users.allowed(ievent.userhost, result[1].perms):
+ return result
+
+ return (None, None)
+
+ def cmnd(self, bot, ievent, timeout=15, response=False, onlyqueues=True):
+
+ """
+ launch command and wait for result.
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :param timeout: number of seconds to wait for a result
+ :type timeout: integer
+ :param response: whether to notify user we are running the command
+ :type response: string
+ :rtype: list .. list of results
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.cmnd
+
+ """
+ if response:
+ ievent.reply('launching %s on %s bot' % (ievent.txt, bot.name))
+ #ii = self.clonedevent(bot, ievent)
+ #q = Queue.Queue()
+ #ii.queues.append(q)
+ #ii.onlyqueues = onlyqueues
+ q = Queue.Queue()
+ ievent.queues.append(q)
+ self.trydispatch(bot, ievent)
+ return waitforqueue(q, timeout)
+
+ def waitdispatch(self, bot, ievent, direct=False):
+
+ """
+ dispatch command and wait for results.
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :param direct: whether user permission should be checked
+ :type direct: boolean .. when set user permission is NOT checked
+ :rtype: boolean .. whether dispatch succeeded or not
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.waitdispatch
+
+ """
+ ievent.threaded = True
+ return self.trydispatch(bot, ievent, direct, wait=True)
+
+ def trydispatch(self, bot, ievent, direct=False, wait=False):
+
+ """
+ try to dispatch ievent.
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :param direct: whether user permission should be checked
+ :type direct: boolean .. when set user permission is NOT checked
+ :param wait: whether function should wait for results
+ :type wait: boolean
+ :rtype: boolean .. whether dispatch succeeded or not
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.trydispatch
+
+ """
+
+ # test for ignore
+ if shouldignore(ievent.userhost):
+ return 0
+
+ # set printto
+ if ievent.msg:
+ ievent.printto = ievent.nick
+ else:
+ ievent.printto = ievent.channel
+
+ # see if ievent would dispatch
+ # what is rebefore, cmnds of reafter, com is the command object
+ # check if redispatcher or commands object needs to be used
+ #self.needreloadcheck(bot, ievent)
+
+ (what, com) = self.dispatchtest(bot, ievent, direct)
+
+ if what:
+
+ if com.allowqueue:
+ ievent.txt = ievent.txt.replace(' || ', ' | ')
+
+ if ievent.txt.find(' | ') != -1:
+
+ if ievent.txt[0] == '!':
+ ievent.txt = ievent.txt[1:]
+ else:
+ self.splitpipe(bot, ievent)
+ return
+
+ elif ievent.txt.find(' && ') != -1:
+ self.multiple(bot, ievent)
+ return
+
+ return self.dispatch(what, com, bot, ievent, wait)
+
+ def dispatch(self, what, com, bot, ievent, wait=False):
+
+ """
+ do the actual dispatch of event.
+
+ :param what: the dispatcher to dispatch the command on
+ :type what: gozerbot.redispatcher.REdispatcher or gozerbot.commands.Commands
+ :param com: the command to dispatch
+ :type com: gozerbot.redispatcher.REcallback or gozerbot.commands.Command
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :param wait: whether function should wait for results
+ :type wait: boolean
+ :rtype: boolean .. whether dispatch succeeded or not
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.dispatch
+
+ """
+ if bot.stopped:
+ return False
+
+ # make command options
+ if com.options:
+ makeoptions(ievent, com.options)
+ else:
+ makeoptions(ievent)
+
+ # make arguments and rest
+ makeargrest(ievent)
+ ievent.usercmnd = True
+ rlog(10, 'plugins', 'dispatching %s for %s' % (ievent.command, ievent.userhost))
+
+ # call dispatch
+ what.dispatch(com, bot, ievent, wait)
+ return True
+
+ def clonedevent(self, bot, event):
+
+ """
+ clone a event.
+
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+ :rtype: gozerbot.eventbase.EventBase
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.clonedevent
+
+ """
+
+ ie = copy.deepcopy(event)
+ return ie
+
+
+ def multiple(self, bot, ievent):
+
+ """
+ execute multiple commands.
+
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.multiple
+
+ """
+
+ for i in ievent.txt.split(' && '):
+ ie = self.clonedevent(bot, ievent)
+ ie.txt = i
+ #self.needreloadcheck(bot, ievent)
+ self.trydispatch(bot, ie)
+
+ def splitpipe(self, bot, ievent):
+
+ """
+ execute commands in a pipeline.
+
+ :param bot: bot on which command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering the command
+ :type ievent: gozerbot.eventbase.EventBase
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.splitpipe
+
+ """
+
+ origqueues = ievent.queues
+ ievent.queues = []
+ events = []
+ txt = ievent.txt.replace(' || ', ' ##')
+
+ # split commands
+ for i in txt.split(' | '):
+ item = i.replace(' ##', ' | ')
+ ie = self.clonedevent(bot, ievent)
+ ie.userhost = ievent.userhost
+ ie.onlyqueues = True
+ ie.txt = item.strip()
+ #self.needreloadcheck(bot, ie)
+ events.append(ie)
+
+ # loop over events .. chain queues
+ prevq = None
+
+ for i in events[:-1]:
+ q = Queue.Queue()
+ i.queues.append(q)
+ if prevq:
+ i.inqueue = prevq
+ prevq = q
+
+ events[-1].inqueue = prevq
+ events[-1].onlyqueues = False
+
+ if origqueues:
+ events[-1].queues = origqueues
+
+ # check if all commands would dispatch
+ for i in events:
+ if not self.woulddispatch(bot, i):
+ ievent.reply("can't execute %s" % str(i.txt))
+ return
+
+ # do the dispatch
+ for i in events:
+ (what, com) = self.dispatchtest(bot, i)
+ if what:
+ self.dispatch(what, com, bot, i)
+
+ def needreloadcheck(self, bot, event, target=None):
+
+ if cmndtable:
+
+ try:
+ if target:
+ rlog(10, 'plugins', 'target set: %s' % target)
+ cmnd = 'target-set'
+ plugin = target
+ else:
+ t = event.txt.split()[0]
+ cmnd = aliasget(t) or t
+ plugin = cmndtable[cmnd]
+
+ rlog(10, 'plugins', 'cmnd: %s plugin: %s' % (cmnd, plugin))
+
+ if self.exist(plugin):
+ return
+
+ try:
+ self.reload('gozerbot.plugs', plugin)
+ except ImportError, ex:
+
+ try:
+ self.reload('gplugs', plugin)
+ except ImportError, ex:
+ if config.get('db_driver') == 'olddb':
+ try:
+ self.reload('gplugs.olddb', plugin)
+ except ImportError, ex: pass
+ else:
+ try:
+ self.reload('gplugs.alchemy', plugin)
+ except ImportError, ex: pass
+ try:
+ self.reload('myplugs', plugin)
+ except ImportError, ex:
+ return
+
+ rlog(100, 'plugins', 'reloaded %s' % plugin)
+
+ except KeyError, ex:
+ rlog(10, 'plugins', "can't find plugin to reload for %s" % event.txt.split()[0])
+
+
+ def listreload(self, pluglist):
+
+ """
+ reload list of plugins.
+
+ :param pluglist: list of plugin names
+ :type pluglist: list
+ :rtype: list .. list of plugins where reload failed
+
+ .. literalinclude:: ../../gozerbot/plugins.py
+ :pyobject: Plugins.listreload
+
+ """
+
+ failed = []
+
+ # loop over the plugin list and reload them
+ for what in pluglist:
+ splitted = what[:-3].split(os.sep)
+ mod = '.'.join(splitted[:-1])
+
+ if not mod:
+ if config.get('db_driver') == "olddb":
+ mod = "gplugs.olddb"
+ elif config.get("db_driver") == "alchemy":
+ mod = "gplugs.alchemy"
+ else:
+ mod = 'gplugs'
+
+ plug = splitted[-1]
+
+ # reload the plugin
+ try:
+ self.reload(mod, plug)
+
+ except Exception, ex:
+ failed.append(what)
+
+ return failed
+
+## INIT SECTION
+
+# THE plugins object
+plugins = Plugins()
+
+## END INIT
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/users.py
+++ gozerbot-0.99.1/build/lib/gozerbot/users.py
@@ -0,0 +1,18 @@
+# gozerbot/users.py
+#
+#
+
+from gozerbot.config import config
+
+if config.get('db_driver') == "olddb":
+ try:
+ import gozerbot.database.db
+ import gozerbot.dbusers
+ except Exception, ex:
+ handle_exception()
+ rlog(100, 'users', 'an error has occured while trying to enable the mysql database')
+ die()
+ users = gozerbot.dbusers.Dbusers()
+else:
+ import gozerbot.sausers as sa
+ users = sa.DbUsers()
--- gozerbot-0.99.1.orig/build/lib/gozerbot/ignore.py
+++ gozerbot-0.99.1/build/lib/gozerbot/ignore.py
@@ -0,0 +1,126 @@
+# gozerbot/ignore.py
+#
+#
+
+""" ignore module. """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# gozerbot imports
+from persist.persist import Persist
+from datadir import datadir
+from periodical import interval
+
+# basic imports
+import time, os, thread
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+def addignore(userhost, ttime):
+
+ """
+ add ignore based on userhost .. record time when ignore is set.
+
+ :param userhost: userhost to ignore
+ :type userhost: string
+ :param ttime: duration of the ignore
+ :type ttime: integer
+
+ .. literalinclude:: ../../gozerbot/ignore.py
+ :pyobject: addignore
+
+ """
+
+ global ignore
+
+ ignore[userhost] = int(ttime)
+ timeset[userhost] = time.time()
+
+def delignore(userhost):
+
+ """
+ remove ignore.
+
+ :param userhost: userhost to remove ignore from
+ :type userhost: string
+ :rtype: boolean .. whether delete was succesfull
+
+ .. literalinclude:: ../../gozerbot/ignore.py
+ :pyobject: delignore
+
+ """
+
+ global ignore
+
+ try:
+ del ignore[userhost]
+ del timeset[userhost]
+ return True
+ except KeyError:
+ return False
+
+def shouldignore(userhost):
+
+ """
+ check if we should ignore.
+
+ :param userhost: userhost to check whether we should ignore it
+ :type userhost: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/ignore.py
+ :pyobject: shouldignore
+
+ """
+
+ try:
+ ignoretime = ignore[userhost]
+ ignoreset = timeset[userhost]
+ except KeyError:
+ return False
+
+ if time.time() - ignoretime < ignoreset:
+ return True
+
+ return False
+
+
+@interval(60)
+def ignorecheck():
+
+ """
+ periodic function to remove users that no longer need to be ignored.
+
+ .. literalinclude:: ../../gozerbot/ignore.py
+ :pyobject: ignorecheck
+
+ """
+
+ for userhost in ignore.keys():
+ if not shouldignore(userhost):
+ delignore(userhost)
+
+
+# ============
+# INIT SECTION
+
+ignore = {}
+timeset = {}
+
+# first call to trigger interval
+ignorecheck()
+
+# END INIT
+# =======
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/wait.py
+++ gozerbot-0.99.1/build/lib/gozerbot/wait.py
@@ -0,0 +1,168 @@
+# gozerbot/wait.py
+#
+#
+
+""" wait for ircevent based on ircevent.CMND """
+
+__copyright__ = 'this file is in the public domain'
+
+# gozerbot imports
+from utils.log import rlog
+from utils.locking import lockdec
+import threads.thr as thr
+
+# basic imports
+import time, thread
+
+# locks
+waitlock = thread.allocate_lock()
+locked = lockdec(waitlock)
+
+class Wait(object):
+
+ """ lists of ircevents to wait for """
+
+ def __init__(self):
+ self.waitlist = []
+ self.ticket = 0
+
+ def register(self, cmnd, catch, queue, timeout=15):
+
+ """ register wait for cmnd. """
+
+ rlog(1, 'wait', 'registering for cmnd ' + cmnd)
+ self.ticket += 1
+ self.waitlist.insert(0, (cmnd, catch, queue, self.ticket))
+ if timeout:
+ # start timeout thread
+ thr.start_new_thread(self.dotimeout, (timeout, self.ticket))
+ return self.ticket
+
+ def check(self, ievent):
+
+ """ check if there are wait items for ievent .. check if 'catch'
+ matches on ievent.postfix if so put ievent on queue. """
+
+ cmnd = ievent.cmnd
+ for item in self.waitlist:
+ if item[0] == cmnd:
+ if cmnd == "JOIN":
+ catch = ievent.txt + ievent.postfix
+ else:
+ catch = ievent.nick + ievent.postfix
+ if item[1] in catch:
+ ievent.ticket = item[3]
+ item[2].put_nowait(ievent)
+ self.delete(ievent.ticket)
+ rlog(1, 'wait', 'got response for %s' % item[0])
+ ievent.isresponse = True
+
+ def dotimeout(self, timeout, ticket):
+
+ """ start timeout thread for wait with ticket nr. """
+
+ rlog(1, 'wait', 'starting timeouthread for %s' % str(ticket))
+ time.sleep(float(timeout))
+ self.delete(ticket)
+
+ @locked
+ def delete(self, ticket):
+
+ """ delete wait item with ticket nr. """
+
+ for itemnr in range(len(self.waitlist)-1, -1, -1):
+ if self.waitlist[itemnr][3] == ticket:
+ self.waitlist[itemnr][2].put_nowait(None)
+ del self.waitlist[itemnr]
+ rlog(1, 'wait', 'deleted ' + str(ticket))
+ return 1
+
+class Privwait(Wait):
+
+ """ wait for privmsg .. catch is on nick """
+
+ def register(self, catch, queue, timeout=15):
+
+ """ register wait for privmsg. """
+
+ rlog(1, 'privwait', 'registering for ' + catch)
+ return Wait.register(self, 'PRIVMSG', catch, queue, timeout)
+
+ def check(self, ievent):
+
+ """ check if there are wait items for ievent. """
+
+ for item in self.waitlist:
+ if item[0] == 'PRIVMSG':
+ if ievent.userhost == item[1]:
+ ievent.ticket = item[3]
+ item[2].put_nowait(ievent)
+ self.delete(ievent.ticket)
+ rlog(1, 'privwait', 'got response for %s' % item[0])
+ ievent.isresponse = True
+
+class Jabberwait(Wait):
+
+ """ wait object for jabber messages. """
+
+ def register(self, catch, queue, timeout=15):
+
+ """ register wait for privmsg. """
+
+ rlog(1, 'jabberwait', 'registering for %s' % catch)
+ self.ticket += 1
+ self.waitlist.append((catch, queue, self.ticket))
+ if timeout:
+ thr.start_new_thread(self.dotimeout, (timeout, self.ticket))
+ return self.ticket
+
+ def check(self, msg):
+
+ """ check if <msg> is waited for. """
+
+ for teller in range(len(self.waitlist)-1, -1, -1):
+ i = self.waitlist[teller]
+ if i[0] == msg.userhost:
+ msg.ticket = i[2]
+ i[1].put_nowait(msg)
+ self.delete(msg.ticket)
+ rlog(10, 'jabberwait', 'got response for %s' % i[0])
+ msg.isresponse = 1
+
+ @locked
+ def delete(self, ticket):
+
+ """ delete wait item with ticket nr. """
+
+ for itemnr in range(len(self.waitlist)-1, -1, -1):
+ item = self.waitlist[itemnr]
+ if item[2] == ticket:
+ item[1].put_nowait(None)
+ try:
+ del self.waitlist[itemnr]
+ rlog(1, 'jabberwait', 'deleted ' + str(ticket))
+ except IndexError:
+ pass
+ return 1
+
+class Jabbererrorwait(Jabberwait):
+
+ """ wait for jabber errors. """
+
+ def check(self, msg):
+
+ """ check if <msg> is waited for. """
+
+ if not msg.getType() == 'error':
+ return
+
+ errorcode = msg.getErrorCode()
+
+ for teller in range(len(self.waitlist)-1, -1, -1):
+ i = self.waitlist[teller]
+ if i[0] == 'ALL' or i[0] == errorcode:
+ msg.error = msg.getError()
+ msg.ticket = i[2]
+ i[1].put_nowait(msg)
+ self.delete(msg.ticket)
+ rlog(10,'jabbererrorwait','got error response for %s' % i[0])
--- gozerbot-0.99.1.orig/build/lib/gozerbot/stats.py
+++ gozerbot-0.99.1/build/lib/gozerbot/stats.py
@@ -0,0 +1,67 @@
+# gozerbot/stats.py
+#
+#
+
+""" maintain bot stats. """
+
+## IMPORT SECTION
+
+from gozerbot.utils.statdict import Statdict
+
+## END IMPORT
+
+## LOCK SECTION
+
+# no locks
+
+## END LOCK
+
+class GozerStats(object):
+
+ """ dict containing all gozerbot related stats. """
+
+ def __init__(self):
+ self.data = {}
+
+ def init(self, item):
+
+ """ initialize a stats item. """
+
+ self.data[item] = Statdict()
+
+ def up(self, item, issue):
+
+ """ up a stats item. """
+
+ if not self.data.has_key(item):
+ self.init(item)
+ self.data[item].upitem(issue)
+
+ def get(self, item):
+
+ """ return stats item. """
+
+ try:
+ return self.data[item]
+ except KeyError:
+ return
+
+ def list(self, item):
+
+ """ list all stats belonging to item. """
+
+ if self.data.has_key(item):
+ return self.data[item].keys()
+
+ def all(self):
+
+ """ list all stats items. """
+
+ return self.data.keys()
+
+## INIT SECTION
+
+# the gozerbot stats object
+stats = GozerStats()
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/botbase.py
+++ gozerbot-0.99.1/build/lib/gozerbot/botbase.py
@@ -0,0 +1,394 @@
+# gozerbot/botbase.py
+#
+#
+
+""" bot base class. provides data/methods common to all bots. """
+
+# IMPORT SECTION
+
+# gozerbot imports
+from threads.thr import start_new_thread
+from utils.log import rlog
+from less import Less
+from persist.pdol import Pdol
+from utils.dol import Dol
+from utils.lazydict import LazyDict
+from persist.persiststate import PersistState
+from channels import Channels
+from datadir import datadir
+from persist.pdod import Pdod
+from config import config, Config, fleetbotconfigtxt
+from runner import runners_start
+from monitor import Monitor
+from callbacks import callbacks, gn_callbacks
+from cache import userhosts
+from wait import Wait, Privwait
+from eventhandler import mainhandler
+from exit import globalshutdown
+from utils.exception import handle_exception
+from plugins import plugins
+
+# throttle support
+from gozerbot.plugs.throttle import state as throttlestate
+
+# basic imports
+import time, threading, os, types, sys, copy
+
+# END IMPORT
+
+cpy = copy.deepcopy
+
+class BotBase(object):
+
+ """
+
+ Base class for all bots. Inherit from this.
+
+ :param cfg: configuration
+ :type cfg: dict like
+
+ """
+
+ def __init__(self, name, cfg={}):
+ self.name = name
+ self.encoding = sys.getdefaultencoding()
+
+ # if cfg is not passed on create one
+ if not cfg:
+ cfg = Config(inittxt=fleetbotconfigtxt)
+
+ if not cfg.has_key('dir'):
+ cfg['dir'] = os.getcwd()
+
+ if not cfg.has_key('user'):
+ cfg['user'] = 'gozerbot'
+
+ if not cfg.has_key('type'):
+ cfg['type'] = 'gozernet'
+
+ # set attributes based on config
+ self.__dict__.update(cfg)
+
+ # if name not set in config file use the directory name
+
+ if not cfg.has_key('name'):
+ if 'fleet' in cfg['dir']:
+ self.name = cfg.dir.split(os.sep)[-1]
+ else:
+ self.name = name
+
+ # default nick to gozerbot
+ if not cfg.has_key('nick'):
+ self.nick = 'gozerbot'
+
+ if not cfg.has_key('server'):
+ self.server = 'server not set'
+
+ try:
+ self.host = cfg['host']
+ if not self.host:
+ self.host = self.user.split('@')[1]
+ except (KeyError, IndexError):
+ try:
+ self.host = self.user.split('@')[1]
+ except (ValueError, IndexError):
+ self.host = 'host not set'
+
+
+ # default port to 0 (use default port)
+ if not cfg.has_key('port'):
+ self.port = 0
+
+ if not cfg.has_key('ipv6'):
+ self.ipv6 = 0
+ else:
+ self.ipv6 = cfg['ipv6']
+
+ # make sure bot name is not a directory
+ if '..' in self.name or '/' in self.name:
+ raise Exception('wrong bot name %s' % self.name)
+
+ # set datadir to datadir/fleet/<botname>
+ self.datadir = datadir + os.sep + 'fleet' + os.sep + self.name
+
+ # set datadir to datadir/fleet/<botname>
+ if hasattr(os, 'mkdir'):
+ if not os.path.exists(self.datadir):
+ os.mkdir(self.datadir)
+
+ # bot state
+ self.state = Pdod(self.datadir + os.sep + 'state') # bot state
+
+ # joined channels list .. used to join channels
+ if not self.state.has_key('joinedchannels'):
+ self.state['joinedchannels'] = []
+
+ # allowed commands on the bot
+ if not self.state.has_key('allowed'):
+ self.state['allowed'] = []
+
+ # channels we dont want ops in
+ if not self.state.has_key('no-op'):
+ self.state['no-op'] = []
+
+ # channels we are op in
+ if not self.state.has_key('opchan'):
+ self.state['opchan'] = []
+
+ # the time we joined a channel
+ self.timejoined = {}
+
+ # jabber type doesnt exists anymore .. set type to 'xmpp' instead
+ self.type = self.type or 'gozernet'
+
+ if self.type == 'jabber':
+ self.type = 'xmpp'
+
+ self.networkname = self.server
+ self.jid = "%s@%s" % (self.nick, self.server)
+ self.jids = {}
+ self.shutloop = False
+ self.cfg = cfg # the bots config
+ self.orignick = "" # original nick
+ self.blocking = 1 # use blocking sockets
+ self.lastoutput = 0 # time of last output
+ self.stopped = False # flag to set when bot is to be stopped
+ self.connected = False # conencted flag
+ self.connecting = False # connecting flag
+ self.connectok = threading.Event() # event set when bot has connected
+ self.waitingforconnect = False # flag to indicate we are waiting for connect
+ self.starttime = time.time() # start time of the bot
+ self.nrevents = 0 # number of events processed
+ self.gcevents = 0 # number of garbage collected events
+ self.less = Less(5) # output buffering
+ self.userchannels = Dol() # list of channels a user is in
+ self.channels = Channels(self.datadir + os.sep + 'channels') # channels
+ self.userhosts = PersistState(self.datadir + os.sep + 'userhosts') # userhosts cache
+ self.splitted = [] # list of splitted nicks
+ self.throttle = [] # list of nicks that need to be throttled
+ self.jabber = False # flag is set on jabber bots
+ self.google = False
+ if 'google' in self.host:
+ self.google = True # flag is set on google bots
+ try:
+ import google.appengine.ext
+ self.google = True
+ except:
+ pass
+ self.callbacks = callbacks
+ self.monitor = Monitor()
+ self.wait = Wait()
+ self.privwait = Privwait()
+ self.error = None
+
+ # start runners
+ runners_start()
+ #self.monitor.start()
+
+ def ownercheck(self, ievent, txt=None):
+
+ """
+ check whether an event originated from the bot owner.
+
+ :param ievent: event to check for owner with
+ :param txt: optional txt to report to user when check fails
+ :rtype: 1 or 0
+
+ .. literalinclude:: ../../gozerbot/botbase.py
+ :pyobject: BotBase.ownercheck
+
+ """
+
+ # use owner set in bot's config or else in global config
+ owner = self.cfg['owner'] or config['owner']
+
+ # check if event userhost in in owner .. check lists and string values
+ if type(owner) == types.ListType:
+ if ievent.userhost in owner:
+ return 1
+ elif owner == ievent.userhost:
+ return 1
+ else:
+ rlog(100, self.name, 'failed owner check %s should be in %s' % (ievent.userhost, owner))
+ if not txt:
+ ievent.reply("only owner (see config file) is allowed to perform this command")
+ else:
+ ievent.reply("only owner (see config file) %s" % txt)
+ return 0
+
+ def save(self):
+
+ """ save bot state. """
+
+ self.channels.save()
+ self.userhosts.save()
+ self.state.save()
+
+ def stop(self):
+
+ """ stop the bot. """
+
+ self.stopped = True
+ rlog(10, self.name, 'stopped')
+
+ def exit(self):
+
+ """ shutdown the bot. overload this. """
+
+ pass
+
+ def connect(self, reconnect=True):
+
+ """ connect the bot to the server. reconnects in the default case. """
+
+ pass
+
+ def say(self, printto, what, event=None, who=None, how='msg', fromm=None, speed=0, groupchat=False):
+ print what
+
+ def whois(self, nick):
+ pass
+
+ def sendraw(self, txt):
+ print txt
+
+ def voice(self, channel, txt):
+ pass
+
+ def action(self, channel, txt):
+ pass
+
+ def _raw(self, txt):
+ print txt
+
+ def settopic(self, channel, txt):
+ pass
+
+ def names(self, channel):
+ pass
+
+ def gettopic(self, channel):
+ pass
+
+ def _dcclisten(self, *args):
+ pass
+
+ def donick(self, nick, save=False, setorig=True):
+ pass
+
+ def fakein(self, txt):
+ pass
+
+ def part(self, channel):
+ pass
+
+ def serveforever(self):
+ self.stopped = False
+ self.shutloop = False
+
+ while not self.stopped and not self.shutloop:
+ try:
+ import asyncore
+ asyncore.poll(timeout=0.01)
+ except ImportError:
+ pass
+ except Exception, ex:
+ handle_exception()
+ globalshutdown()
+ os._exit(1)
+ time.sleep(0.01)
+ mainhandler.handle_one()
+
+ def join(self, channel, password=""):
+ pass
+
+ def joinchannels(self):
+
+ """ join all registered channels. overload this. """
+
+ pass
+
+ def connectwithjoin(self, reconnect=True):
+
+ """ connect to the server and join channels. """
+
+ self.connect(reconnect)
+ self.connectok.wait()
+ start_new_thread(self.joinchannels, ())
+
+ def broadcast(self):
+
+ """ announce a message to all channels. overload this"""
+
+ pass
+
+ def send(self, txt):
+
+ """ send txt to the server. overload this"""
+
+ pass
+
+ def shutdown(self):
+
+ """ close sockets of the bot. overload this"""
+
+ pass
+
+ def domsg(self, msg, response=False, wait=False):
+
+ """
+ excecute a message (txt line) on the bot.
+
+ :param msg: text line to execute
+ :type msg: string
+ :rtype: None
+
+ .. literalinclude:: ../../gozerbot/botbase.py
+ :pyobject: BotBase.domsg
+ """
+
+ if response:
+ msg.reply('executing %s (%s) on %s bot' % (msg.txt, msg.userhost, self.name))
+
+ from gozerbot.plugins import plugins
+
+ if wait:
+ plugins.waitdispatch(self, msg)
+ else:
+ plugins.trydispatch(self, msg)
+
+ def ratelimit(self, userhost, cpm=20):
+ try:
+ throttlestate['level'][userhost] = cpm
+ throttlestate.save()
+ rlog(10, self.name, '%s throttled to %s cpm' % (userhost, cpm))
+ except Exception, ex:
+ rlog(100, self.name, "can't set throttle of %s" % userhost)
+ handle_exception()
+
+ def remoteout(self, request, event):
+ request.wfile.write(event.tojson())
+
+ def doevent(self, event):
+
+ """
+ dispatch an event.
+
+ :param event: event to dispatch.
+ :rtype: None
+
+ """
+
+ if not event:
+ return
+
+ e = cpy(event)
+
+ if event.isremote:
+ rlog(10, self.name, 'remote event .. calling gn_callbacks')
+ gn_callbacks.check(self, e)
+ else:
+ callbacks.check(self, e)
+
+ if event.remotecmnd:
+ plugins.trydispatch(self, event)
--- gozerbot-0.99.1.orig/build/lib/gozerbot/gozerimport.py
+++ gozerbot-0.99.1/build/lib/gozerbot/gozerimport.py
@@ -0,0 +1,97 @@
+# gozerbot/myimport.py
+#
+#
+
+""" use the imp module to import modules. """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# basic import
+from gozerbot.utils.log import rlog
+from gozerbot.utils.locking import lockdec
+
+import time, sys, imp, os, thread
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+gozerimportlock = thread.allocate_lock()
+locked = lockdec(gozerimportlock)
+
+# END LOCK
+# ========
+
+#@locked
+def gozer_import(name, path=None):
+
+ """
+ import module <name> with the imp module .. will reload module is
+ already in sys.modules.
+
+ :param name: name of the module to import (may contain dots)
+ :type name: string
+ :param path: optional path to search in
+ :type path: string
+ :rtype: module
+
+ .. literalinclude:: ../../gozerbot/gozerimport.py
+ :pyobject: gozer_import
+
+ """
+
+ rlog(1, 'gozerimport', 'importing %s' % name)
+
+ splitted = name.split('.')
+
+ for plug in splitted:
+ fp, pathname, description = imp.find_module(plug, path)
+ try:
+ result = imp.load_module(plug, fp, pathname, description)
+ try:
+ path = result.__path__
+ except:
+ pass
+ finally:
+ if fp:
+ fp.close()
+
+ if result:
+ return result
+
+#@locked
+def force_import(name):
+
+ """
+ force import of module <name> by replacing it in sys.modules.
+
+ :param name: name of module to import
+ :type name: string
+ :rtype: module
+
+ .. literalinclude:: ../../gozerbot/gozerimport.py
+ :pyobject: force_import
+
+ """
+
+ try:
+ del sys.modules[name]
+ except KeyError:
+ pass
+ plug = gozer_import(name)
+ if plug:
+ sys.modules[name] = plug
+ return plug
+
+# ============
+# INIT SECTION
+
+# no vars
+
+# END INIT
+# ========
--- gozerbot-0.99.1.orig/build/lib/gozerbot/redispatcher.py
+++ gozerbot-0.99.1/build/lib/gozerbot/redispatcher.py
@@ -0,0 +1,394 @@
+# gozerbot/redispatcher.py
+#
+#
+
+""" implement RE (regular expression) dispatcher. """
+
+__copyright__ = 'this file is in the public domain'
+
+## IMPORT SECTION
+
+# gozerbot imports
+from config import config
+from utils.log import rlog
+from utils.trace import calledfrom
+from utils.exception import handle_exception
+from utils.locking import lockdec
+from runner import cmndrunners
+import threads.thr as thr
+
+# basic imports
+import sys, re, copy, types, thread
+
+## END IMPORT
+
+## LOCK SECTION
+
+# locks
+relock = thread.allocate_lock()
+locked = lockdec(relock)
+
+## END LOCK
+
+class RECallback(object):
+
+ """
+ a regular expression callback.
+
+ :param index: index into the callback list
+ :type index: integer
+ :param regex: the regex to match
+ :type regex: string
+ :param func: the callback function
+ :type func: function
+ :param perm: permissions of the callback
+ :type perm: list .. list of permissions
+ :param speed: speed at which the callback should be executed
+ :type speed: integer
+ :param threaded: whether the callback should executed in its own thread
+ :type threaded: boolean
+ :param allowqueue: whether this command is allowed in pipelines
+ :type allowqueue: boolean
+ :param options: options allowed for this command
+ :type options: dict
+
+ """
+
+ def __init__(self, index, regex, func, perm, plugname, speed=5, \
+threaded=True, allowqueue=True, options={}):
+ self.name = thr.getname(func) # name of the callback
+ self.index = index # index into the list
+ self.regex = regex # the RE to match
+ self.compiled = re.compile(regex) # compiled RE
+ self.func = func # the function to call if RE matches
+ # make sure perms is a list
+ if type(perm) == types.ListType:
+ self.perms = list(perm)
+ else:
+ self.perms = [perm, ]
+ # plug name
+ self.plugname = plugname # plugname where RE callbacks is registered
+ self.speed = copy.deepcopy(speed) # speed at which the function runs
+ self.threaded = copy.deepcopy(threaded) # set when run threaade
+ self.allowqueue = copy.deepcopy(allowqueue) # set when pipeline is allowed
+ self.options = dict(options) # options set on the callback
+ self.activate = True
+
+class REDispatcher(object):
+
+ """
+ this is were the regexs callbacks live.
+
+ """
+
+ def __init__(self):
+ self.relist = []
+
+ def size(self):
+
+ """
+ nr of callbacks.
+
+ """
+
+ return len(self.relist)
+
+ def activate(self, plugname):
+ for i in self.relist:
+ if i.plugname == plugname:
+ i.activate = True
+
+ def disable(self, plugname):
+ for i in self.relist:
+ if i.plugname == plugname:
+ i.activate = False
+
+ def whatperms(self):
+
+ """
+ return possible permissions.
+
+ :rtype: list .. list of possible permissions
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.whatperms
+
+ """
+
+ result = []
+
+ for i in self.relist:
+ for j in i.perms:
+ if j not in result:
+ result.append(j)
+
+ return result
+
+ def list(self, perm):
+
+ """
+ list RECallbacks with permission perm.
+
+ :param perm: permission to check for
+ :type perm: string
+ :rtype: list .. list of RECallbacks
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.list
+ """
+
+ result = []
+ perm = perm.upper()
+
+ for recom in self.relist:
+ if perm in recom.perms:
+ result.append(recom)
+
+ return result
+
+ def getfuncnames(self, plug):
+
+ """
+ return function names in plugin.
+
+ :param plug: name of the plugin to get callbacks of
+ :type plug: string
+ :rtype: list .. list of function names
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.getfuncnames
+
+ """
+
+ result = []
+ for i in self.relist:
+ if i.plugname == plug:
+ result.append(i.func.func_name)
+ return result
+
+ def permoverload(self, funcname, perms):
+
+ """
+ overload permission of function with funcname.
+
+ :param funcname: name of the function to overload
+ :type funcname: string
+ :param perms: permission to overload
+ :type perms: list
+ :rtype: boolean .. whether the overload succeeded
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.permoverload
+
+ """
+
+ perms = [perm.upper() for perm in perms]
+ got = 0
+
+ for nr in range(len(self.relist)):
+
+ try:
+ if self.relist[nr].func.func_name == funcname:
+ self.relist[nr].perms = list(perms)
+ rlog(0, 'redispatcher', '%s function overloaded with %s' \
+% (funcname, perms))
+ got = 1
+
+ except AttributeError:
+ rlog(10, 'redispatcher', 'permoverload: no %s function' % \
+funcname)
+ if got:
+ return True
+
+ return False
+
+ def add(self, index, regex, func, perm, speed=5, threaded=True, allowqueue=True, options={}):
+
+ """
+ add a regular expression command.
+
+ :param index: index into the callback list
+ :type index: integer
+ :param regex: the regex to match
+ :type regex: string
+ :param func: the callback function
+ :type func: function
+ :param perm: permissions of the callback
+ :type perm: list .. list of permissions
+ :param speed: speed at which the callback should be executed
+ :type speed: integer
+ :param threaded: whether the callback should executed in its own thread
+ :type threaded: boolean
+ :param allowqueue: whether this command is allowed in pipelines
+ :type allowqueue: boolean
+ :param options: options allowed for this command
+ :type options: dict
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.add
+
+ """
+
+ try:
+ # get plugin name from where callback is added
+ plugname = calledfrom(sys._getframe())
+
+ if config['loadlist'] and plugname not in config['loadlist']:
+ return
+ # add Recallback
+
+ self.relist.append(RECallback(index, regex, func, perm, plugname, \
+speed, threaded, allowqueue, options))
+ # sort of index number
+ self.relist.sort(lambda a, b: cmp(a.index, b.index))
+ rlog(0, 'redispatcher', 'added %s (%s) ' % (regex, plugname))
+
+ finally:
+ pass
+
+ def unload(self, plugname):
+
+ """
+ unload regex commands.
+
+ :param plugname: name of the plugins to unload callbacks from
+ :type plugname: string
+ :rtype: boolean .. whether the unloading succeeded
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.unload
+
+ """
+
+ got = False
+ try:
+
+ for i in range(len(self.relist)-1, -1 , -1):
+ if self.relist[i].plugname == plugname:
+ rlog(1, 'redispatcher', 'unloading %s (%s)' % \
+(self.relist[i].regex, plugname))
+ del self.relist[i]
+ got = True
+ finally:
+ pass
+ return got
+
+ def getcallback(self, txt):
+
+ """
+ get re callback if txt matches.
+
+ :param txt: txt to match against the regular expressions
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.getcallback
+ """
+
+ for i in self.relist:
+
+ try:
+ result = re.search(i.compiled, txt)
+
+ if result:
+ return i
+
+ except:
+ pass
+
+ def dispatch(self, callback, txt, wait=False):
+
+ """
+ try to dispatch callback on txt.
+
+ :param callback: the callback to fire
+ :type callback: RECallback
+ :param txt: txt to match the regular expression
+ :type txt: string
+ :param wait: whether to wait for the result
+ :type wait: boolean
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: REDispatcher.dispatch
+
+ """
+
+ try:
+ result = re.search(callback.compiled, txt)
+
+ if result:
+
+ if callback.threaded:
+ thread = thr.start_new_thread(callback.func, (txt, result.groups()))
+
+ if wait:
+ thread.join()
+
+ else:
+ cmndrunners.put(callback.plugname, callback.func, txt, \
+result.groups())
+
+ return 1
+
+ except Exception, ex:
+ handle_exception()
+
+class BotREDispatcher(REDispatcher):
+
+ """
+ dispatcher on Event.
+
+ """
+
+ def dispatch(self, callback, bot, ievent, wait=False):
+
+ """
+ dispatch callback on ircevent.
+
+ :param callback: the callback to fire
+ :type callback: RECallback
+ :param bot: the bot on which the callback was triggered
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event that triggered the callback
+ :type ievent: gozerbot.eventbase.EventBase
+ :rtype: boolean .. whether the dispatch was succesful
+
+ .. literalinclude:: ../../gozerbot/redispatcher.py
+ :pyobject: BotREDispatcher.dispatch
+
+ """
+
+ if not self.activate:
+ return False
+
+ try:
+ result = re.search(callback.compiled, ievent.txt.strip())
+
+ if result:
+ ievent.groups = list(result.groups())
+
+ if callback.threaded or ievent.threaded:
+ thread = thr.start_bot_command(callback.func, (bot, ievent))
+
+ if thread and wait:
+ thread.join()
+
+ else:
+ cmndrunners.put(callback.plugname, callback.func, bot, \
+ievent)
+ return True
+
+ except Exception, ex:
+ handle_exception(ievent)
+
+ return False
+
+## INIT SECTION
+
+# dispatcher before commands are checked
+rebefore = BotREDispatcher()
+
+# dispatcher after commands are checked
+reafter = BotREDispatcher()
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/eventbase.py
+++ gozerbot-0.99.1/build/lib/gozerbot/eventbase.py
@@ -0,0 +1,602 @@
+# gozerbot/eventbase.py
+#
+#
+
+"""
+ This module implements the EventBase class from which all other
+ events inherit.
+
+ :vars: defaultevent
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# gozerbot imports
+from xmpp.core import XMLDict
+from utils.log import rlog
+from utils.generic import stripident, fix_format, fromenc, toenc
+from utils.lazydict import LazyDict
+from gozerbot.stats import stats
+from gozerbot.config import config
+
+# basic imports
+import time, re, types, copy
+
+from simplejson import loads, dumps
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+## START
+
+# used to copy data
+cpy = copy.deepcopy
+
+def makeargrest(event):
+
+ """
+ set arguments and rest attributes of an event.
+
+ :param event: event to manipulate
+
+ """
+
+ # arguments
+ try:
+ event.args = event.txt.split()[1:]
+ except ValueError:
+ event.args = []
+
+ # txt after command
+ try:
+ cmnd, event.rest = event.txt.split(' ', 1)
+ except ValueError:
+ event.rest = ""
+
+ # the command
+ event.command = event.txt.split(' ')[0]
+
+class EventBase(XMLDict):
+
+ """
+ Base class for all events. Inherit from this.
+
+ :param event: event to clone from (optional)
+ :type event: gozerbot.event.EventBase
+ :param bot: bot on which this event occured
+ :type bot: gozerbot.botbase.BotBase
+
+ """
+
+
+ def __init__(self, event={}, bot=None):
+ self.server = ""
+ XMLDict.__init__(self)
+ self.threaded = False
+ self.onlyqueues = False
+ self.orig = event # the original data .. SET BY HANDLER
+ self.type = 'chat' # type of event
+ self.cbtype = '' # callback type
+ self.jabber = False # set if event is jabber event
+ self.groupchat = False # set if event is groupchat
+ self.botoutput = False # set if event is bot output
+ self.cmnd = None # the event command
+ self.prefix = u"" # txt before the command
+ self.postfix = u"" # txt after the command
+ self.target = u"" # target to give reponse to
+ self.arguments = [] # arguments of event
+ self.nick = u"" # nick of user originating the event
+ self.user = u"" # user originating the event
+ self.ruserhost = u"" # real userhost
+ self.userhost = u"" # userhost that might change
+ self.stripped = u"" # stripped JID
+ self.resource = u"" # resource part of JID
+ self.origin = u"" # source of the event
+ self.origchannel = u"" # original channel
+ self.channel = u"" # channel .. might change
+ self.origtxt = u"" # original txt
+ self.txt = u"" # text .. might change
+ self.command = u"" # the bot command if any
+ self.remoteout = u""
+ self.remotecmnd = False
+ self.usercmnd = False
+ self.alias = u"" # set to alias if one is used
+ self.aliased = u"" # set if commadn is aliased
+ self.time = time.time() # event creation time
+ self.msg = False # set if event is a private message
+ self.args = [] # arguments of command
+ self.rest = u"" # txt following the command
+ self.usercmnd = 0 # set if event is a command
+ self.bot = bot # the bot where the event originated on
+ self.sock = None # socket (set in DCC chat)
+ self.allowqueue = True # allow event to be used in pipeline
+ self.closequeue = True # cloase event queues when execution has ended
+ self.inqueue = None # queue used as input in pipeline
+ self.queues = [] # output queues (only used when set)
+ self.printto = None # target to printto
+ self.speed = 0 # speed with which this event needs to be processed
+ self.groups = None # set if event triggers a RE callback
+ self.cc = u"" # control character
+ self.jid = None # JID of used originating the event
+ self.jidchange = None # set is event changes jid
+ self.conn = None # connection of bot originating the event
+ self.denied = False # set if command is denied
+ self.iscallback = False
+ self.isresponse = False # set if event is a reponse
+ self.isrelay = False
+ self.isremote = False
+ self.isdcc = False # set if event is DCC related
+ self.isctcp = False # set if event is an ACTION
+ self.options = LazyDict() # options dict on the event
+ self.optionset = [] # list of options set
+ self.filter = [] # filter list to use on output
+
+ # wave stuff
+ self.wave = False
+ self.properties = None
+ self.context = None
+ self.eventin = None
+ self.wavelet = None
+
+ # GAE stuff
+ self.google = False
+ self.xmppgae = False
+ self.response = None
+ self.request = None
+
+ # xmpp stuff
+ self.host = self.server
+ self.xml = u""
+ self.realjid = u""
+ self.fromm = u""
+ self.to = u""
+ self.type = u""
+ self.id = 0
+ self.subject = u""
+ self.body = u""
+ self.error = u""
+ self.errorcode = u""
+ self.html = u""
+ self.thread = u""
+ self.x = {}
+
+ if event:
+ self.copyin(event)
+
+ self.toirc()
+
+ # stats
+ stats.up('events', 'created')
+
+ def __copy__(self):
+ return EventBase(self)
+
+ def __deepcopy__(self, bla):
+ return EventBase(self)
+
+ def toirc(self):
+
+ """
+ set ircevent compat attributes.
+
+ .. literalinclude:: ../../gozerbot/eventbase.py
+ :pyobject: EventBase.toirc
+ """
+
+ self.jidchange = False
+ self.cmnd = 'Message'
+
+ try:
+ self.resource = self.fromm.split('/')[1]
+ except IndexError:
+ pass
+
+ self.channel = self['fromm'].split('/')[0]
+ self.origchannel = self.channel
+ self.nick = self.resource
+
+ #try:
+ # self.jid = bot.jids[self.channel][self.resource]
+ # self.jidchange = True
+ #except KeyError:
+ # pass
+
+ self.jid = self.fromm
+ self.ruserhost = self.jid
+ self.userhost = self.jid
+ self.stripped = self.jid.split('/')[0]
+ self.printto = self.channel
+ self.target = self.printto
+
+ for node in self.subelements:
+ try:
+ self.txt = node.body.data
+ except (AttributeError, ValueError):
+ continue
+
+ self.origtxt = self.txt
+ self.time = time.time()
+
+ if self.type == 'groupchat':
+ self.groupchat = True
+ if self.jidchange:
+ self.userhost = self.stripped
+ else:
+ self.groupchat = False
+ self.userhost = self.stripped
+
+ self.msg = not self.groupchat
+
+ def copyin(self, ievent):
+
+ """
+ copy in an event.
+
+ :param ievent: event to copy in
+ :type ievent: EventBase
+
+ .. literalinclude:: ../../gozerbot/eventbase.py
+ :pyobject: EventBase.copyin
+
+ """
+ self.update(ievent)
+
+ if ievent.has_key('options'):
+ self.options = dict(ievent.options)
+
+ if ievent.has_key('queues'):
+ self.queues = list(ievent.queues)
+
+ return self
+
+ def filtered(self, txt):
+
+ """
+ see if txt if filtered on this event.
+
+ :param txt: text to check if its filtered
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/eventbase.py
+ :pyobject: EventBase.filtered
+
+ """
+
+ if not self.filter:
+ return False
+
+ for filter in self.filter:
+ if filter in txt:
+ return False
+
+ return True
+
+ def parse(self, bot, rawstr):
+
+ """
+ parse raw string into event. overload this.
+
+ :param bot: bot on which event is triggered
+ :type bot: gozerbot.botbase.BotBase
+ :param rawstr: string as recieved on the socket
+ :type rawstr: string
+
+ """
+
+ pass
+
+ def make_response(self, txt, result=None, nick=None, dot=False, nritems=False, nr=False, fromm=None, private=False, how=''):
+
+
+ # don't reply is result is empty list
+ if result == []:
+ return
+
+ # stats
+ stats.up('events', 'replies')
+ if not how:
+ try:
+ how = self.options['--how']
+ except KeyError:
+ how = 'msg'
+
+ # init
+ restxt = ""
+ splitted = []
+
+ # make reply if result is a dict
+ if type(result) == types.DictType:
+ for i, j in result.iteritems():
+ if type(j) == types.ListType:
+ try:
+ z = ' .. '.join(j)
+ except TypeError:
+ z = unicode(j)
+ else:
+ z = j
+ res = "%s: %s" % (i, z)
+ splitted.append(res)
+ if dot == True:
+ restxt += "%s%s" % (res, ' .. ')
+ else:
+ restxt += "%s %s" % (dot or ' ', res)
+ if restxt:
+ if dot == True:
+ restxt = restxt[:-6]
+ elif dot:
+ restxt = restxt[:-len(dot)]
+
+ lt = False # set if result is list
+
+ # set vars if result is a list
+ if type(txt) == types.ListType and not result:
+ result = txt
+ origtxt = u""
+ lt = True
+ else:
+ origtxt = txt
+
+ if result:
+ lt = True
+
+ # if queues are set write output to them
+ if self.queues:
+ for i in self.queues:
+ if splitted:
+ for item in splitted:
+ i.put_nowait(item)
+ elif restxt:
+ i.put_nowait(restxt)
+ elif lt:
+ for j in result:
+ i.put_nowait(j)
+ else:
+ i.put_nowait(txt)
+ if self.onlyqueues:
+ return
+
+ # check if bot is set in event
+ if not self.bot:
+ rlog(10, 'event', 'no bot defined in event')
+ return "no bot is defined in this event"
+
+ # make response
+ pretxt = origtxt
+ if lt and not restxt:
+ res = []
+
+ # check if there are list in list
+
+ for i in result:
+ if type(i) == types.ListType or type(i) == types.TupleType:
+ try:
+ res.append(u' .. '.join(i))
+ except TypeError:
+ res.extend(i)
+ else:
+ res.append(i)
+
+ # if nritems is set ..
+ result = res
+ if nritems:
+ if len(result) > 1:
+ pretxt += "(%s items) .. " % len(result)
+ txtlist = result
+
+ # prepend item number for results
+ if not nr is False:
+ try:
+ start = int(nr)
+ except ValueError:
+ start = 0
+ txtlist2 = []
+ teller = start
+ for i in txtlist:
+ txtlist2.append(u"%s) %s" % (teller, i))
+ teller += 1
+ txtlist = txtlist2
+
+ # convert results to encoding
+ txtl = []
+ for item in txtlist:
+ txtl.append(toenc(item))
+ txtlist = txtl
+
+ # join result with dot
+ if dot == True:
+ restxt = ' .. '.join(txtlist)
+ elif dot:
+ restxt = dot.join(txtlist)
+ else:
+ restxt = ' '.join(txtlist)
+
+ # see if txt needs to be prepended
+ if pretxt:
+ try:
+ restxt = pretxt + restxt
+ except TypeError:
+ rlog(10, 'eventbase', "can't add %s and %s" % (str(pretxt), str(restxt)))
+
+ # if txt in result is filtered ignore the reuslt
+ if self.filtered(restxt):
+ return
+
+ if restxt:
+ return restxt
+ else:
+ return "no data found"
+
+ def reply(self, *args, **kwargs):
+
+ """
+ reply to event. this version prints to stdout
+
+ :param txt: txt to reply
+ :type txt: string
+ :param result: result list .. list of items to reply (is prepended to txt)
+ :type result: string
+ :param nick: nick to reply to
+ :type nick: string
+ :param dot: whether results of result list should be seperated with a dot with ' ..' or the txt passed in as dot argument
+ :type dot: boolean or string
+ :param nritems: whether results should be numbered
+ :type nritems: boolean
+ :param nr: the number to start numerbering the result with
+ :type nr: integer
+ :param fromm: the user sending the reply
+ :type fromm: nick or JID
+ :param private: whether the reply should be in private
+ :type private: boolean
+ :param how: how the reply should be made (msg, notice, ctcp)
+ :type how: string
+
+ """
+ resp = self.make_response(*args, **kwargs)
+
+ if not resp:
+ return
+
+ self.bot.say(self.channel, resp)
+
+ def missing(self, txt):
+
+ """
+ show what arguments are missing.
+
+ :param txt: txt to add to missing response
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/eventbase.py
+ :pyobject: EventBase.missing
+
+ """
+
+ stats.up('events', 'missing')
+ if self.origtxt:
+ splitted = self.origtxt.split()
+ if self.bot.nick in splitted[0]:
+ try:
+ cmnd = splitted[1]
+ except IndexError:
+ cmnd = splitted[0]
+ elif 'cmnd' in splitted[0]:
+ try:
+ cmnd = splitted[2]
+ except IndexError:
+ cmnd = splitted[0]
+ else:
+ if self.msg:
+ cmnd = splitted[0]
+ else:
+ if self.aliased:
+ cmnd = self.aliased
+ else:
+ cmnd = splitted[0][1:]
+ self.reply(cmnd + ' ' + txt)
+ else:
+ self.reply('missing origtxt: %s' % txt)
+
+ def ircstr(self):
+
+ """
+ old compat function. use str() now.
+
+ """
+
+ return str(self)
+
+ def handle_error(self, data):
+
+ """
+ function to handler errors. override this.
+
+ :param data: txt describing the error (can be different with inherited classes)
+ :tyoe data: string (can be different with inherited classes)
+
+ """
+
+ rlog(10, self.name.error, 'ERROR: %s' % str(data))
+
+ def done(self, txt=None):
+
+ """
+ reply with the txt 'done'.
+
+ :param txt: txt to prepend to 'done'
+ :type txt: string
+
+ """
+
+ if txt:
+ self.reply('%s done' % txt)
+ else:
+ self.reply('done')
+
+ def tojson(self):
+ new = cpy(self)
+ new.sock = 'setremote'
+ new.bot = 'setremote'
+ new.request = 'setremote'
+ new.response = 'setremote'
+ new.queues = []
+ result = dumps(new)
+ rlog(0, 'eventbase', 'tojson - %s' % str(result))
+ return result
+
+ def fromjsonstring(self, input):
+ temp = loads(input)
+ rlog(10, 'eventbase', str(temp))
+ self.update(temp)
+ return self
+
+ def checkqueues(self, resultlist):
+
+ """
+ check if resultlist is to be sent to the queues. if so do it
+
+ :param resultlist: list of results to send to queues
+ :type resultlist: list
+ :rtype: boolean
+
+ """
+
+ if self.queues:
+
+ for queue in self.queues:
+ for item in resultlist:
+ queue.put_nowait(item)
+
+ return True
+
+ def subelement(self, name):
+ if self.subelements:
+ rlog(10, 'eventbase', "got subelements")
+ for node in self.subelements:
+ try:
+ attr = getattr(node, name)
+ rlog(10, 'eventbase', "got subelement %s" % (name, str(attr)))
+ return attr.data
+ except (AttributeError, TypeError):
+ continue
+
+# ============
+# INIT SECTION
+
+# default event used to initialise events
+defaultevent = EventBase()
+
+
+# END INIT
+# ========
--- gozerbot-0.99.1.orig/build/lib/gozerbot/dbusers.py
+++ gozerbot-0.99.1/build/lib/gozerbot/dbusers.py
@@ -0,0 +1,375 @@
+# gozerbot/dbusers.py
+#
+#
+
+""" bots users for mysql interface"""
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.utils.log import rlog
+from gozerbot.database.db import db
+import types
+
+class Dbusers(object):
+
+ """ users class """
+
+ def __init__(self):
+ self.db = db
+
+ def size(self):
+ """ return nr of users """
+ result = self.db.execute(""" SELECT DISTINCT COUNT(*) FROM userhosts """)
+ if result:
+ return result[0][0]
+
+ def getperms(self, userhost):
+ """ return permission of user"""
+ name = self.getname(userhost)
+ if not name:
+ return ['ANON', ]
+ result = self.db.execute(""" SELECT perm FROM perms WHERE name = %s """, name)
+ res = []
+ for i in result:
+ res.append(i[0])
+ return res
+
+ def exist(self, name):
+ """ see if user with <name> exists """
+ name = name.lower()
+ result = self.db.execute(""" SELECT name,userhost FROM userhosts WHERE name = %s """, name)
+ return result
+
+ def getname(self, userhost):
+ """ get name of user belonging to <userhost> """
+ result = self.db.execute(""" SELECT name FROM userhosts WHERE %s LIKE userhost """, userhost)
+ if result:
+ return result[0][0]
+
+ def add(self, name, userhosts, perms):
+ """ add an user """
+ if type(userhosts) != types.ListType:
+ rlog(10, 'dbusers', 'i need a list of userhosts')
+ return 0
+ for i in userhosts:
+ self.adduserhost(name, i)
+ for i in perms:
+ self.addperm(name, i)
+ rlog(10, 'users', '%s added to user database' % name)
+ return 1
+
+ def adduserhost(self, name, userhost):
+ """ add userhost """
+ name = name.lower()
+ res = None
+ result = self.db.execute(""" INSERT INTO userhosts(name, userhost) values(%s, %s) """, (name, userhost))
+ if result:
+ res = 1
+ rlog(10, 'users', '%s (%s) added to userhosts' % (name, userhost))
+ return res
+
+ def addperm(self, name, perm):
+ """ add permission """
+ name = name.lower()
+ perm = perm.upper()
+ res = None
+ result = self.db.execute(""" INSERT INTO perms(name, perm) values(%s, %s) """, (name, perm))
+ if result:
+ res = 1
+ rlog(10, 'users', '%s perm %s added' % (name, perm))
+ return res
+
+ def addstatus(self, name, status):
+ """ add permission """
+ name = name.lower()
+ status = status.upper()
+ res = None
+ result = self.db.execute(""" INSERT INTO statuses(name, status) values(%s, %s) """, (name, status))
+ if result:
+ res = 1
+ rlog(10, 'users', '%s status %s added' % (name, status))
+ return res
+
+ def addpermit(self, name, who, what):
+ """ add permission """
+ p = '%s %s' % (who, what)
+ res = None
+ result = self.db.execute(""" INSERT INTO permits(name, permit) values(%s, %s) """, (name, p))
+ if result:
+ res = 1
+ rlog(10, 'users', '%s permit %s added' % (name, p))
+ return res
+
+ def delperm(self, name, perm):
+ """ add permission """
+ name = name.lower()
+ perm = perm.upper()
+ result = self.db.execute(""" DELETE FROM perms WHERE name = %s AND perm = %s """, (name, perm))
+ if result:
+ rlog(10, 'users', '%s perm %s deleted' % (name, perm))
+ return result
+
+ def permitted(self, userhost, who, what):
+ """ check if (who,what) is in users permit list """
+ name = self.getname(userhost)
+ res = None
+ if name:
+ result = self.db.execute(""" SELECT permit FROM permits WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if "%s %s" % (who, what) == i[0]:
+ res = 1
+ return res
+
+ def names(self):
+ """ get names of all users """
+ res = []
+ result = self.db.execute(""" SELECT DISTINCT name FROM userhosts """)
+ if result:
+ for i in result:
+ res.append(i[0])
+ return res
+
+ def merge(self, name, userhost):
+ """ add userhosts to user with name """
+ name = name.lower()
+ if not self.exist(name):
+ return 0
+ res = None
+ result = self.db.execute(""" INSERT INTO userhosts(userhost, name) VALUES (%s, %s) """, (userhost, name))
+ if result:
+ res = 1
+ return res
+
+ def deluserpermit(self, name, permit):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ p = '%s %s' % permit
+ return self.db.execute(""" DELETE FROM permits WHERE name = %s AND permit = %s """, (name, p))
+
+ def deluserhost(self, name, userhost):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ return self.db.execute(""" DELETE FROM userhosts WHERE name = %s AND userhost = %s """, (name, userhost))
+
+ def deluserperms(self, name, perm):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ return self.db.execute(""" DELETE FROM perms WHERE name = %s AND perm = %s """, (name, perm))
+
+ def deluserstatus(self, name, status):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ return self.db.execute(""" DELETE FROM statuses WHERE name = %s AND status = %s """, (name, status))
+
+ def deluserstatus(self, name, status):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ return self.db.execute(""" DELETE FROM statuses WHERE name = %s AND status = %s """, (name, status))
+
+ def delete(self, name):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ nr1 = self.db.execute(""" DELETE FROM userhosts WHERE name = %s """, name)
+ nr2 = self.db.execute(""" DELETE FROM perms WHERE name = %s """, name)
+ if nr1 and nr2:
+ res = 1
+ return res
+
+ def status(self, userhost, status):
+ """ check if user with <userhost> has <status> set """
+ name = self.getname(userhost)
+ res = None
+ if name:
+ status = status.upper()
+ result = self.db.execute(""" SELECT status FROM statuses WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if status == i[0]:
+ res = 1
+ return res
+
+ def gotperm(self, name, perm):
+ """ check if user had permission """
+ name = name.lower()
+ perm = perm.upper()
+ result = self.db.execute(""" SELECT perm FROM perms WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if i[0] == perm:
+ return True
+
+ def getuserstatuses(self, name):
+ """ check if user had permission """
+ name = name.lower()
+ return self.db.execute(""" SELECT status FROM statuses WHERE name = %s """, name)
+
+ def getuseremail(self, name):
+ """ check if user had permission """
+ name = name.lower()
+ return self.db.execute(""" SELECT email FROM email WHERE name = %s """, name)
+
+ def getuserperms(self, name):
+ """ check if user had permission """
+ name = name.lower()
+ return self.db.execute(""" SELECT perm FROM perms WHERE name = %s """, name)
+
+ def getuserstatus(self, name):
+ """ check if user has status """
+ name = name.lower()
+ status = status.upper()
+ return self.db.execute(""" SELECT status FROM statuses WHERE name = %s """, name)
+
+ def gotstatus(self, name, status):
+ """ check if user has status """
+ name = name.lower()
+ status = status.upper()
+ result = self.db.execute(""" SELECT status FROM statuses WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if status == i[0]:
+ return True
+
+ def gotuserhost(self, name, userhost):
+ """ check if user has userhost """
+ name = name.lower()
+ result = self.db.execute(""" SELECT userhost FROM userhosts WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if i[0] == userhost:
+ return True
+
+ def getuserhosts(self, name):
+ """ check if user has userhost """
+ name = name.lower()
+ return self.db.execute(""" SELECT userhost FROM userhosts WHERE name = %s """, name)
+
+ gethosts = getuserhosts
+
+ def gotpermit(self, name, permit):
+ """ check if user permits something """
+ name = name.lower()
+ result = self.db.execute(""" SELECT permit FROM permits WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if "%s %s" % permit == i[0]:
+ return True
+
+ def getuserpermits(self, name):
+ """ check if user permits something """
+ name = name.lower()
+ return self.db.execute(""" SELECT permit FROM permits WHERE name = %s """, name)
+
+ def allowed(self, userhost, perms, log=True):
+ """ check if user with userhosts is allowed to execute perm command """
+ if not type(perms) == types.ListType:
+ perms = [perms, ]
+ if 'ANY' in perms:
+ return 1
+ res = None
+ name = self.getname(userhost)
+ if not name:
+ if log:
+ rlog(10, 'users', '%s userhost denied' % userhost)
+ return res
+ result = self.db.execute(""" SELECT perm FROM perms WHERE name = %s """, name)
+ if result:
+ for i in result:
+ if i[0] in perms:
+ res = 1
+ if not res:
+ if log:
+ rlog(10, 'users', "%s perm %s denied" % (userhost, perms))
+ return res
+
+ def getemail(self, name):
+ """ get email of user """
+ name = name.lower()
+ email = None
+ email = self.db.execute(""" SELECT email FROM email WHERE name = %s """, name)
+ if email:
+ return email[0][0]
+
+ def setemail(self, name, email):
+ """ set email of user """
+ res = 0
+ try:
+ result = self.db.execute(""" INSERT INTO email(name, email) VALUES (%s, %s) """, (name, email))
+ except:
+ try:
+ result = self.db.execute(""" UPDATE email SET email = %s WHERE name = %s """, (email, name))
+ except:
+ pass
+ if result:
+ res = 1
+ return res
+
+ def getuserhosts(self, name):
+ """ check if user has userhost """
+ name = name.lower()
+ return self.db.execute(""" SELECT userhost FROM userhosts WHERE name = %s """, name)
+
+
+ def addpermall(self, perm):
+ """ add permission to all users """
+ perm = perm.upper()
+ for i in self.names():
+ try:
+ self.addperm(i, perm)
+ except:
+ pass
+
+ def delpermall(self, perm):
+ """ delete permission from all users """
+ perm = perm.upper()
+ for i in self.names():
+ try:
+ self.delperm(i, perm)
+ except:
+ pass
+
+ def make_owner(self, userhosts):
+
+ """
+ see if owner already has a user account if not merge otherwise
+ add.
+
+ :param userhosts: userhosts to inititalize owner with
+ :type userhosts: list or string
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.make_owner
+
+ """
+
+ owner = []
+
+ if type(userhosts) != types.ListType:
+ owner.append(userhosts)
+ else:
+ owner = userhosts
+
+ for userhost in owner:
+ username = self.getname(unicode(userhost))
+
+ if not username:
+ if not self.merge('owner', unicode(userhost)):
+ self.add('owner', [unicode(userhost), ], ['USER', 'OPER'])
+ elif username != 'owner':
+ self.delete(username)
+ if not self.merge('owner', unicode(userhost)):
+ self.add('owner', [unicode(userhost), ], ['USER', 'OPER'])
+
+ def usersearch(self, name):
+ name = name.lower()
+ res = []
+ for n in self.names():
+ if name in n.lower(): res.append(n)
+ return res
+
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/callbacks.py
+++ gozerbot-0.99.1/build/lib/gozerbot/callbacks.py
@@ -0,0 +1,274 @@
+# gozerbot/callbacks.py
+#
+#
+
+"""
+ bot callbacks .. callbacks occure on registered events. a precondition
+ function can optionaly be provided to see if the callback should fire.
+ callback can be executed in a Runner (1 thread that executes more jobs)
+ or in a seperate thread. callbacks are now unified for bot irc and jabber
+ events.
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.stats import stats
+from gozerbot.threads.thr import getname
+from config import config
+from utils.log import rlog
+from utils.exception import handle_exception
+from utils.trace import calledfrom
+from utils.generic import makeargrest
+from utils.locking import lockdec
+from utils.dol import Dol
+from threads.thr import start_new_thread, getname
+from runner import cbrunners
+
+# basic imports
+import sys, copy, thread
+
+# END IMPORT
+
+# LOCK SECTION
+
+# locks
+callbacklock = thread.allocate_lock()
+locked = lockdec(callbacklock)
+
+# END LOCKS
+
+class Callback(object):
+
+ """
+ class representing a callback.
+
+ :param func: function to execute
+ :param prereq: prerequisite function
+ :param plugname: plugin to register this callback with
+ :param kwargs: dict to pass on to the callback
+ :param threaded: whether the callback should be executed in its own thread
+ :param speed: determines which runnerspool to run this callback on
+
+ """
+
+ def __init__(self, func, prereq, plugname, kwargs, threaded=False, \
+speed=5):
+ self.func = func # the callback function
+ self.prereq = prereq # pre condition function
+ self.plugname = plugname # plugin name
+ self.kwargs = kwargs # kwargs to pass on to function
+ self.threaded = copy.deepcopy(threaded) # run callback in thread
+ self.speed = copy.deepcopy(speed) # speed to execute callback with
+ self.activate = False
+ stats.up('callbacks', 'created')
+
+class Callbacks(object):
+
+ """
+ dict of lists containing callbacks. Callbacks object take care of
+ dispatching the callbacks based on incoming events. see Callbacks.check()
+
+ """
+
+ def __init__(self):
+
+ # self.cbs holds the dict of list. entry value is the event (string)
+ self.cbs = Dol()
+
+ def size(self):
+
+ """ return number of callbacks. """
+
+ return len(self.cbs)
+
+ def add(self, what, func, prereq=None, kwargs=None, threaded=False, nr=False, speed=5):
+
+ """
+ add a callback.
+
+ :param what: event to fire callback for
+ :param func: function to execute
+ :param prereq: prerequisite function
+ :param plugname: plugin to register this callback with
+ :param kwargs: dict to pass on to the callback
+ :param threaded: whether the callback should be executed in its own thread
+ :param speed: determines which runnerspool to run this callback on
+
+ """
+
+ what = what.upper()
+
+ # get the plugin this callback was registered from
+ plugname = calledfrom(sys._getframe(0))
+
+ # check if plugname is in loadlist .. if not don't add callback
+ if config['loadlist'] and not plugname in config['loadlist']:
+ rlog(-1, plugname, 'not in loadlist .. not adding callback')
+ return
+
+ # see if kwargs is set if not init to {}
+ if not kwargs:
+ kwargs = {}
+
+ # add callback to the dict of lists
+ if nr != False:
+ self.cbs.insert(nr, what, Callback(func, prereq, plugname, kwargs, threaded, speed))
+ else:
+ self.cbs.add(what, Callback(func, prereq, plugname, kwargs, threaded, speed))
+
+ rlog(0, 'callbacks', 'added %s (%s)' % (what, plugname))
+
+ def unload(self, plugname):
+
+ """ unload all callbacks registered in a plugin. """
+
+ unload = []
+
+ # look for all callbacks in a plugin
+ for name, cblist in self.cbs.iteritems():
+ index = 0
+ for item in cblist:
+ if item.plugname == plugname:
+ unload.append((name, index))
+ index += 1
+
+ # delete callbacks
+ for callback in unload[::-1]:
+ self.cbs.delete(callback[0], callback[1])
+ rlog(1, 'callbacks', 'unloaded %s' % callback[0])
+
+ def disable(self, plugname):
+
+ """ disable all callbacks registered in a plugin. """
+
+ unload = []
+
+ # look for all callbacks in a plugin
+ for name, cblist in self.cbs.iteritems():
+ index = 0
+ for item in cblist:
+ if item.plugname == plugname:
+ item.activate = False
+
+ def activate(self, plugname):
+
+ """ activate all callbacks registered in a plugin. """
+
+ unload = []
+
+ # look for all callbacks in a plugin
+ for name, cblist in self.cbs.iteritems():
+ index = 0
+ for item in cblist:
+ if item.plugname == plugname:
+ item.activate = True
+
+ def whereis(self, cmnd):
+
+ """ show where ircevent.CMND callbacks are registered """
+
+ result = []
+ cmnd = cmnd.upper()
+
+ # locate callbacks for CMND
+ for c, callback in self.cbs.iteritems():
+ if c == cmnd:
+ for item in callback:
+ if not item.plugname in result:
+ result.append(item.plugname)
+
+ return result
+
+ def list(self):
+
+ """ show all callbacks. """
+
+ result = []
+
+ # loop over callbacks and collect callback functions
+ for cmnd, callbacks in self.cbs.iteritems():
+ for cb in callbacks:
+ result.append(getname(cb.func))
+
+ return result
+
+ def check(self, bot, ievent):
+
+ """
+ check for callbacks to be fired.
+
+ :param bot: bot where event originates from
+ :param ievent: event that needs to be checked
+
+ .. literalinclude:: ../../gozerbot/callbacks.py
+ :pyobject: Callbacks.check
+
+ """
+
+ # check for "ALL" callbacks
+ if self.cbs.has_key('ALL'):
+ for cb in self.cbs['ALL']:
+ stats.up('callbacks', 'ALL')
+ self.callback(cb, bot, ievent)
+
+ cmnd = ievent.cbtype or ievent.cmnd.upper()
+
+ # check for CMND callbacks
+ if self.cbs.has_key(cmnd):
+ for cb in self.cbs[cmnd]:
+ stats.up('callbacks', cmnd)
+ self.callback(cb, bot, ievent)
+
+ def callback(self, cb, bot, ievent):
+
+ """
+ do the actual callback with provided bot and ievent as arguments.
+
+ :param cb: the callback to fire
+ :param bot: bot to call the callback on
+ :param ievent: the ievent that triggered the callback
+
+ .. literalinclude:: ../../gozerbot/callbacks.py
+ :pyobject: Callbacks.callback
+
+ """
+
+ try:
+ if not cb.activate:
+ return
+ # see if the callback pre requirement succeeds
+ if cb.prereq:
+ rlog(0, 'callbacks', 'excecuting in loop %s' % str(cb.prereq))
+ if not cb.prereq(bot, ievent):
+ return
+
+ # check if callback function is there
+ if not cb.func:
+ return
+
+ # log and stats
+ rlog(0, 'callbacks', 'excecuting callback %s' % str(cb.func))
+ stats.up('callbacks', getname(cb.func))
+ stats.up('callbacks', cb.plugname)
+
+ ievent.iscallback = True
+
+ # launcn the callback .. either threaded or dispatched at runners
+ if cb.threaded:
+ start_new_thread(cb.func, (bot, ievent), cb.kwargs)
+ else:
+ cbrunners.put(cb.plugname, cb.func, bot, ievent, **cb.kwargs)
+
+ except Exception, ex:
+ handle_exception()
+
+# INIT SECTION
+
+# callbacks object is the same for ICR and Jabber
+callbacks = jcallbacks = Callbacks()
+gn_callbacks = Callbacks()
+
+# END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/morphs.py
+++ gozerbot-0.99.1/build/lib/gozerbot/morphs.py
@@ -0,0 +1,159 @@
+# gozerbot/morphs.py
+#
+#
+
+""" convert input/output stream. """
+
+## IMPORT SECTION
+
+# gozerbot imports
+from utils.exception import handle_exception
+from utils.trace import calledfrom
+
+# basic imports
+import sys
+
+## END IMPORT
+
+## LOCK SECTION
+
+# no locks
+
+## END LOCK
+
+class Morph(object):
+
+ """
+ transform stream.
+
+ :param func: morphing function
+ :type func: function
+
+ """
+
+ def __init__(self, func):
+ self.plugname = calledfrom(sys._getframe(0))
+ self.func = func
+ self.activate = False
+
+ def do(self, *args, **kwargs):
+
+ """
+ do the morphing.
+
+ .. literalinclude:: ../../gozerbot/morphs.py
+ :pyobject: Morph.do
+ """
+ if not self.activate:
+ return
+
+ try:
+ return self.func(*args, **kwargs)
+ except Exception, ex:
+ handle_exception()
+
+class MorphList(list):
+
+ """ list of morphs. """
+
+ def add(self, func, index=None):
+
+ """
+ add morph.
+
+ :param func: morphing function
+ :type func: function
+ :param index: index into the morphlist
+ :type index: integer
+ :rtype: self
+
+ .. literalinclude:: ../../gozerbot/morphs.py
+ :pyobject: MorphList.add
+
+ """
+
+ if not index:
+ self.append(Morph(func))
+ else:
+ self.insert(index, Moprh(func))
+
+ return self
+
+ def do(self, input, *args, **kwargs):
+
+ """
+ call morphing chain.
+
+ :param input: data to do the morphing on
+ :type input: string
+
+ .. literalinclude:: ../../gozerbot/morphs.py
+ :pyobject: MorphList.do
+
+ """
+
+ for morph in self:
+ input = morph.do(input, *args, **kwargs) or input
+
+ return input
+
+ def unload(self, plugname):
+
+ """
+ unload morhps belonging to plug <plugname>.
+
+ :param plugname: the plugname to unload the morphs from
+ :type plugname: string
+
+ .. literalinclude:: ../../gozerbot/morphs.py
+ :pyobject: MorphList.unload
+
+ """
+
+ for index in range(len(self)-1, -1, -1):
+ if self[index].plugname == plugname:
+ del self[index]
+
+ def disable(self, plugname):
+
+ """
+ disable morhps belonging to plug <plugname>.
+
+ :param plugname: the plugname to unload the morphs from
+ :type plugname: string
+
+ .. literalinclude:: ../../gozerbot/morphs.py
+ :pyobject: MorphList.disable
+
+ """
+
+ for index in range(len(self)-1, -1, -1):
+ if self[index].plugname == plugname:
+ self[index].activate = False
+
+ def activate(self, plugname):
+
+ """
+ activate morhps belonging to plug <plugname>.
+
+ :param plugname: the plugname to unload the morphs from
+ :type plugname: string
+
+ .. literalinclude:: ../../gozerbot/morphs.py
+ :pyobject: MorphList.activate
+
+ """
+
+ for index in range(len(self)-1, -1, -1):
+ if self[index].plugname == plugname:
+ self[index].activate = False
+
+## INIT SECTION
+
+# moprhs used on input
+inputmorphs = MorphList()
+
+# morphs used on output
+outputmorphs = MorphList()
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/jsonusers.py
+++ gozerbot-0.99.1/build/lib/gozerbot/jsonusers.py
@@ -0,0 +1,751 @@
+# gozerbot/jsonusers.py
+#
+#
+
+""" bot's users in JSON file. NOT USED AT THE MOMENT. """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.datadir import datadir
+from gozerbot.utils.log import rlog
+from gozerbot.utils.generic import stripident, stripidents
+from gozerbot.utils.exception import handle_exception, exceptionmsg
+from gozerbot.utils.generic import die, stripped
+from gozerbot.persist.persist import Persist
+from gozerbot.utils.lazydict import LazyDict
+from gozerbot.config import config
+
+# basic imports
+import re, types, os, time
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+
+class JsonUser(Persist):
+
+ """ LazyDict representing a user. """
+
+ def __init__(self, name="", userhosts=[], perms=[], permits=[], status=[], email=[]):
+ Persist.__init__(self, u"users" + os.sep + name)
+ self.data.name = self.data.name or name
+ self.data.userhosts = self.data.userhosts or userhosts
+ self.data.perms = self.data.perms or perms
+ self.data.permits = self.data.permits or permits
+ self.data.status = self.data.status or status
+ self.data.email = self.data.email or email
+
+class JsonUsers(Persist):
+
+ """ class representing all users. """
+
+ def __init__(self, filename, ddir=None):
+ self.datadir = ddir or datadir
+ Persist.__init__(self, filename)
+ if not self.data:
+ self.data = LazyDict()
+ self.data.names = self.data.names or {}
+
+ def all(self):
+
+ """ get all users. """
+
+ result = []
+ for name in self.data['names'].values():
+ result.append(JsonUser(name))
+ return result
+
+ ### Misc. Functions
+ def size(self):
+
+ """ return nr of users. """
+
+ return len(self.data['names'])
+
+ def names(self):
+
+ """ get names of all users. """
+
+ return self.data.names
+
+ def byname(self, name):
+ """ return user by name. """
+ try:
+ return JsonUser(name)
+ except KeyError:
+ return
+
+ def merge(self, name, userhost):
+ """ add userhosts to user with name """
+ user = self.byname(name)
+ if user:
+ user.userhosts.append(userhost)
+ self.save()
+ rlog(10, 'users', "%s merged with %s" % (userhost, name))
+ return 1
+
+ def usersearch(self, userhost):
+ """ search for users with a userhost like the one specified """
+
+ result = []
+
+ for u, name in self.data.names.iteritems():
+
+ if userhost in u:
+ result.append((name, u))
+
+ return result
+
+ def getuser(self, userhost):
+ try:
+ return JsonUser(self.data.names[userhost])
+ except KeyError:
+ return
+
+ ### Check functions
+ def exist(self, name):
+ """ see if user with <name> exists """
+ return self.byname(name)
+
+ def allowed(self, userhost, perms, log=True):
+ """ check if user with userhosts is allowed to execute perm command """
+ if not type(perms) == types.ListType:
+ perms = [perms, ]
+ if 'ANY' in perms:
+ return 1
+ res = None
+ user = self.getuser(userhost)
+ if not user and log:
+ rlog(10, 'users', '%s userhost denied' % userhost)
+ return res
+ else:
+ uperms = set(user.perms)
+ sperms = set(perms)
+ intersection = sperms.intersection(uperms)
+ res = list(intersection) or None
+ if not res and log:
+ rlog(10, 'users', "%s perm %s denied" % (userhost, str(perms)))
+ return res
+
+ def permitted(self, userhost, who, what):
+ """ check if (who,what) is in users permit list """
+ user = self.getuser(userhost)
+ res = None
+ if user:
+ if '%s %s' % (who, what) in user.permits:
+ res = 1
+ return res
+
+ def status(self, userhost, status):
+ """ check if user with <userhost> has <status> set """
+ user = self.getuser(userhost)
+ res = None
+ if user:
+ if status.upper() in user.statuses:
+ res = 1
+ return res
+
+ def gotuserhost(self, name, userhost):
+ """ check if user has userhost """
+ user = self.byname(name)
+ return userhost in user.userhosts
+
+ def gotperm(self, name, perm):
+ """ check if user had permission """
+ user = self.byname(name)
+ if user:
+ return perm.upper() in user.perms
+
+ def gotpermit(self, name, permit):
+ """ check if user permits something. permit is a (who, what) tuple """
+ user = self.byname(name)
+ if user:
+ return '%s %s' % permit in user.permits
+
+ def gotstatus(self, name, status):
+ """ check if user has status """
+ user = self.byname(name)
+ return status.upper() in user.statuses
+
+ ### Get Functions
+ def getname(self, userhost):
+ """ get name of user belonging to <userhost> """
+ user = self.getuser(userhost)
+ if user:
+ return user.name
+
+ def gethosts(self, userhost):
+ """ return the userhosts of the user associated with the specified userhost """
+ user = self.getuser(userhost)
+ if user:
+ return user.userhosts
+
+ def getemail(self, userhost):
+ """ return the email of the specified userhost """
+ user = self.getuser(userhost)
+ if user:
+ if user.email:
+ return user.email[0]
+
+ def getperms(self, userhost):
+ """ return permission of user"""
+ user = self.getuser(userhost)
+ if user:
+ return user.perms
+
+ def getpermits(self, userhost):
+ """ return permits of the specified userhost"""
+ user = self.getuser(userhost)
+ if user:
+ return user.permits
+
+ def getstatuses(self, userhost):
+
+ """
+ return the list of statuses for the specified userhost.
+
+ """
+
+ user = self.getuser(userhost)
+ if user:
+ return user.status
+
+ def getuserhosts(self, name):
+
+ """
+ return the userhosts associated with the specified user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ return user.userhosts
+
+ def getuseremail(self, name):
+
+ """
+ get email of user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ if user.email:
+ return user.email[0]
+
+ def getuserperms(self, name):
+
+ """
+ return permission of user.
+
+ """
+
+ user = self.byname(name)
+ if user:
+ return user.perms
+
+ def getuserpermits(self, name):
+
+ """
+ return permits of user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ return user.permits
+
+ def getuserstatuses(self, name):
+
+ """
+ return the list of statuses for the specified user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ return user.status
+
+ def getpermusers(self, perm):
+
+ """
+ return all users that have the specified perm.
+
+ """
+
+ result = []
+
+ for userdata in self.users.values():
+ user = JsonUser(d=userdata)
+
+ if perm.upper() in user.perms:
+ result.append(user.name)
+
+ return result
+
+ def getstatususers(self, status):
+
+ """
+ return all users that have the specified status.
+
+ """
+
+ result = []
+
+ for userdata in self.users.values():
+ user = JsonUser(d=userdata)
+
+ if status in user.status:
+ result.append(user.name)
+
+ return result
+
+ ### Set Functions
+ def setemail(self, name, email):
+
+ """
+ set email of user.
+
+ """
+
+ user = self.byname(name)
+ if user:
+ try:
+ user.email.remove(email)
+ except:
+ pass
+ user.email.insert(0, email)
+ self.save()
+ return True
+ return False
+
+ ### Add functions
+ def add(self, name, userhosts, perms):
+
+ """
+ add an user.
+
+ """
+
+ if type(userhosts) != types.ListType:
+ rlog(10, 'jsonusers', 'i need a list of userhosts')
+ return 0
+
+ if not os.path.isdir(self.datadir + os.sep + 'users'):
+ os.mkdir(self.datadir + os.sep + 'users')
+
+ if not os.path.isdir(self.datadir + os.sep + 'users' + os.sep + name):
+ os.mkdir(self.datadir + os.sep + 'users' + os.sep + name)
+
+ user = self.byname(name)
+
+ if not user:
+
+ try:
+ newuser = JsonUser(name=name)
+ newuser.userhosts.extend(userhosts)
+ newuser.perms.extend(perms)
+ self.users[name] = newuser
+ self.save()
+ except Exception, ex:
+ rlog(10, 'jsonusers', str(ex))
+ return False
+
+ rlog(10, 'users', '%s %s %s added to user database' % (name, \
+userhosts, perms))
+
+ return True
+
+ def addemail(self, userhost, email):
+
+ """
+ add an email address to the userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+ user.email.append(email)
+ self.save()
+ rlog(10, 'users', '%s (%s) added to email' % (email, userhost))
+ return 1
+
+ def addperm(self, userhost, perm):
+
+ """
+ add the specified perm to the userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+ user.perms.append(perm.upper())
+ self.save()
+ rlog(10, 'users', '%s perm %s added' % (userhost, perm))
+ return 1
+
+ def addpermit(self, userhost, permit):
+
+ """
+ add the given (who, what) permit to the given userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+ #p = '%s %s' % permit
+ user.permits.append(permit)
+ self.save()
+ rlog(10, 'users', '%s permit %s added' % (userhost, p))
+ return 1
+
+ def addstatus(self, userhost, status):
+
+ """
+ add status to given userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+ user.status.append(status.upper())
+ self.save()
+ rlog(10, 'users', '%s status %s added' % (name, status))
+ return 1
+
+ def adduserhost(self, name, userhost):
+
+ """
+ add userhost.
+
+ """
+
+ user = self.byname(name)
+
+ if not user:
+ user = self.users[name] = User(name=name)
+
+ user.userhosts.append(userhost)
+ self.save(user)
+ rlog(10, 'users', '%s (%s) added to userhosts' % (name, userhost))
+ return 1
+
+ def adduseremail(self, name, email):
+
+ """
+ add email to specified user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ user.email.append(email)
+ self.save()
+ rlog(10, 'users', '%s email %s added' % (name, email))
+ return 1
+
+ def adduserperm(self, name, perm):
+
+ """
+ add permission.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ perm = perm.upper()
+ user.perms.append(perm)
+ self.save()
+ rlog(10, 'users', '%s perm %s added' % (name, perm))
+ return 1
+
+ def adduserpermit(self, name, permit):
+
+ """
+ add (who, what) permit tuple to sepcified user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ p = '%s %s' % permit
+ user.permits.append(p)
+ self.save()
+ rlog(10, 'users', '%s permit %s added' % (name, p))
+ return 1
+
+ def adduserstatus(self, name, status):
+
+ """
+ add status to given user.
+
+ """
+
+ user = byname(name)
+
+ if user:
+ user.status.append(status.upper())
+ self.save()
+ rlog(10, 'users', '%s status %s added' % (name, status))
+ return 1
+
+ def addpermall(self, perm):
+
+ """
+ add permission to all users.
+
+ """
+
+ for user in self.users.values():
+ user.perms.append(perm.upper())
+
+ self.save()
+
+ ### Delete functions
+
+ def delemail(self, userhost, email):
+
+ """
+ delete email from userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+
+ if email in user.emails:
+ user.emails.remove(email)
+ self.save()
+ return 1
+
+ def delperm(self, userhost, perm):
+
+ """
+ delete perm from userhost.
+
+ """
+
+ user = self.getuser(userhost)
+ if user:
+ p = perm.upper()
+ if p in user.perms:
+ user.perms.remove(p)
+ self.save()
+ return 1
+
+ def delpermit(self, userhost, permit):
+
+ """
+ delete permit from userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+ p = '%s %s' % permit
+
+ if p in user.permits:
+ user.permits.remove(p)
+ self.save()
+ return 1
+
+ def delstatus(self, userhost, status):
+
+ """
+ delete status from userhost.
+
+ """
+
+ user = self.getuser(userhost)
+
+ if user:
+ st = status.upper()
+
+ if st in user.status:
+ user.status.remove(st)
+ self.save()
+ return 1
+
+ def delete(self, name):
+
+ """
+ delete user with name.
+
+ """
+
+ del self.users[name]
+ self.save()
+ return 1
+
+ def deluserhost(self, name, userhost):
+
+ """
+ delete the userhost entry.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+
+ if userhost in user.userhosts:
+ user.userhosts.remove(userhost)
+ self.save()
+ rlog(10, 'users', '%s userhost %s deleted' % (name, userhost))
+ return 1
+
+ def deluseremail(self, name, email):
+
+ """
+ delete email.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+
+ if email in user.email:
+ user.email.remove(email)
+ self.save()
+ rlog(10, 'users', '%s email %s deleted' % (name, email))
+ return 1
+
+ def deluserperm(self, name, perm):
+
+ """
+ delete permission.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ p = perm.upper()
+
+ if p in user.perms:
+ user.perms.remove(p)
+ self.save()
+ rlog(10, 'users', '%s perm %s deleted' % (name, p))
+ return 1
+
+ def deluserpermit(self, name, permit):
+
+ """
+ delete permit.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ p = '%s %s' % permit
+
+ if p in user.permits:
+ user.permits.remove(p)
+ self.save()
+ rlog(10, 'users', '%s permit %s deleted' % (name, p))
+ return 1
+
+ def deluserstatus(self, name, status):
+
+ """
+ delete the status from the given user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ st = status.upper()
+
+ if st in user.status:
+ user.status.remove(status)
+ self.save()
+ rlog(10, 'users', '%s status %s deleted' % (name, st))
+ return 1
+
+ def delallemail(self, name):
+
+ """
+ Delete all emails for the specified user.
+
+ """
+
+ user = self.byname(name)
+
+ if user:
+ user.email = []
+ self.save()
+ rlog(10, 'users', '%s emails deleted' % (name, ))
+ return 1
+
+ def delpermall(self, perm):
+
+ """
+ delete permission from all users.
+
+ """
+
+ for user in self.users.values():
+ if user.name != 'owner':
+ del user.perms
+
+ self.save()
+ return 1
+
+ def make_owner(self, userhosts):
+
+ """
+ see if owner already has a user account if not merge otherwise add.
+
+ """
+
+ assert(userhosts)
+ owner = []
+
+ if type(userhosts) != types.ListType:
+ owner.append(userhosts)
+ else:
+ owner = userhosts
+
+ for userhost in owner:
+ username = self.getname(unicode(userhost))
+
+ if not username:
+
+ if not self.merge('owner', unicode(userhost)):
+ self.add('owner', [unicode(userhost), ], ['USER', 'OPER'])
+
+# ============
+# INIT SECTION
+
+# no vars
+
+# END INIT
+# ========
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/sausers.py
+++ gozerbot-0.99.1/build/lib/gozerbot/sausers.py
@@ -0,0 +1,1189 @@
+# gozerbot/users.py
+#
+#
+
+""" bot users """
+
+__copyright__ = 'this file is in the public domain'
+
+## IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.datadir import datadir
+from gozerbot.utils.log import rlog
+from gozerbot.utils.locking import lockdec
+from gozerbot.utils.generic import stripident, stripidents
+from gozerbot.utils.exception import handle_exception, exceptionmsg
+from gozerbot.utils.generic import die, stripped
+from gozerbot.utils.name import stripname
+from gozerbot.persist.persist import Persist
+from gozerbot.config import config
+from gozerbot.jsonusers import JsonUsers
+
+# basic imports
+import re, types, os, time, thread, sqlalchemy
+
+## END IMPORT
+
+## LOCK SECTION
+
+deletelock = thread.allocate_lock()
+deletelocked = lockdec(deletelock)
+
+## END LOCK
+
+# see if we need to use the database or use the jsonusers
+
+if True:
+ if not config['nodb']:
+ from gozerbot.database.samodels import UserHost, User, Perms, Statuses
+ from gozerbot.database.alchemy import Session, query, getuser, byname, eagerload, dblocked
+
+ else:
+ def trans(func, *args, **kwargs):
+ def transaction(*args, **kwargs):
+ func(*args, **kwargs)
+ return transaction
+
+
+class DbUsers(object):
+
+ """
+ sqlalchemy backed users.
+
+ """
+
+ def __init__(self, ddir=None):
+ self.datadir = ddir or datadir
+
+ ### Misc. Functions
+ def size(self):
+
+ """
+ return nr of users.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.size
+ """
+
+ return int(query(User).count())
+
+ def names(self):
+
+ """
+ get names of all users.
+
+ :rtype: list .. list of usernames
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.names
+
+ """
+ a = query(User).all()
+ return [n.name for n in a]
+
+ @dblocked
+ def merge(self, name, userhost):
+
+ """
+ add userhosts to user with name.
+
+ :param session: the session to act upon
+ :type session: sqllachemy.session.Session
+ :param name: name of the user to merge with
+ :type name: string
+ :param userhost: userhosts to merge
+ :type userhost: list .. list of userhosts
+ :rtype: boolean .. whether the merge succeeded
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.merge
+
+ """
+
+ user = byname(name)
+
+ if user:
+
+ if name not in user.userhosts:
+ #Session.begin()
+ user.userhosts.append(userhost)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', "%s merged with %s" % (userhost, name))
+ return True
+
+ return False
+
+ def usersearch(self, userhost):
+
+ """
+ search for users with a userhost like the one specified.
+
+ :param userhost: userhost to search for
+ :type userhost: string
+ :rtype: list .. list of (user.name, user.userhost) tuples
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.usersearch
+
+ """
+
+ n = query(UserHost).filter(UserHost.userhost.like('%%%s%%' % userhost)).all()
+ return [(u.name, u.userhost) for u in n]
+
+ ### Check functions
+ def exist(self, name):
+
+ """
+ see if user with <name> exists.
+
+ :param name: name of the user
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.exist
+
+ """
+
+ a = byname(name)
+
+ if a:
+ return True
+
+ return False
+
+ def allowed(self, userhost, perms, log=True):
+
+ """
+ check if user with userhosts is allowed to execute perm command.
+
+ :param userhost: userhost to check
+ :type userhost: string
+ :param perms: the permissions to check
+ :type perms: list
+ :param log: whether the check should be logged
+ :type log: boolean
+ :rtype: list .. list of matching permissions or None
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.allowed
+
+ """
+
+ if not type(perms) == types.ListType:
+ perms = [perms, ]
+
+ if 'ANY' in perms:
+ return ['ANY', ]
+
+ res = None
+ user = getuser(userhost)
+
+ if not user:
+
+ if log:
+ rlog(10, 'users', '%s userhost denied' % userhost)
+ return res
+
+ else:
+ uperms = set(user.perms)
+ sperms = set(perms)
+ intersection = sperms.intersection(uperms)
+ res = list(intersection) or None
+
+ if not res and log:
+ rlog(10, 'users', "%s perm %s denied" % (userhost, str(perms)))
+
+ if res and log:
+ rlog(10, 'users', 'allowed %s %s perm' % (userhost, str(perms)))
+
+ return res
+
+ def permitted(self, userhost, who, what):
+
+ """
+ check if (who,what) is in users permit list.
+
+ :param userhost: userhost to check permits for
+ :type userhost: string
+ :param who: who to permit
+ :type who: string
+ :param what: what to allow
+ :type what: string
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.permitted
+ """
+
+ user = getuser(userhost)
+ res = False
+
+ if user:
+ if '%s %s' % (who, what) in user.permits:
+ res = True
+
+ return res
+
+ def status(self, userhost, status):
+
+ """
+ check if user with <userhost> has <status> set.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.status
+
+ """
+
+ user = getuser(userhost)
+ res = False
+
+ if user:
+ if status.upper() in user.statuses:
+ res = True
+
+ return res
+
+ def gotuserhost(self, name, userhost):
+
+ """
+ check if user has userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.gotuserhost
+
+ """
+
+ user = byname(name)
+
+ if user:
+ return userhost in user.userhosts
+
+ return False
+
+ def gotperm(self, name, perm):
+
+ """
+ check if user has permission.
+
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.gotperm
+ """
+
+ user = byname(name)
+
+ if user:
+ return perm.upper() in user.perms
+
+ return False
+
+ def gotpermit(self, name, permit):
+
+ """
+ check if user permits something. permit is a [who, what] list.
+
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.gotpermit
+
+ """
+
+ user = byname(name)
+
+ if user:
+ return '%s %s' % permit in user.permits
+
+ return ""
+
+ def gotstatus(self, name, status):
+
+ """
+ check if user has status.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.gotstatus
+
+ """
+
+ user = byname(name)
+ if user:
+ return status.upper() in user.statuses
+
+ return False
+
+ ### Get Functions
+ def getname(self, userhost):
+
+ """
+ get name of user belonging to <userhost>.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getname
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ return str(user.name)
+
+ return ""
+
+ def gethosts(self, userhost):
+
+ """
+ return the userhosts of the user associated with the
+ specified userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.gethosts
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ return list(user.userhosts)
+
+ return []
+
+ def getemail(self, userhost):
+
+ """
+ return the email of the specified userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getemail
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ if user.email:
+ return str(user.email[0])
+
+ return ""
+
+ def getperms(self, userhost):
+
+ """
+ return permissions of user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getperms
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ return list(user.perms)
+
+ return []
+
+ def getpermits(self, userhost):
+
+ """
+ return permits of the specified userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getpermits
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ return list(user.permits)
+
+ return []
+
+ def getstatuses(self, userhost):
+
+ """
+ return the list of statuses for the specified userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getstatuses
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ return list(user.statuses)
+
+ def getuserhosts(self, name):
+
+ """
+ return the userhosts associated with the specified user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getuserhosts
+ """
+
+ user = byname(name)
+
+ if user:
+ return list(user.userhosts)
+
+ def getuseremail(self, name):
+
+ """
+ get email of user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getuseremail
+
+ """
+
+ user = byname(name)
+
+ if user:
+ if user.email:
+ return str(user.email[0])
+
+ def getuserperms(self, name):
+
+ """
+ return permission of user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getuserperms
+ """
+
+ user = byname(name)
+
+ if user:
+ return list(user.perms)
+
+ def getuserpermits(self, name):
+
+ """
+ return permits of user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getuserpermits
+ """
+
+ user = byname(name)
+
+ if user:
+ return list(user.permits)
+
+ def getuserstatuses(self, name):
+
+ """
+ return the list of statuses for the specified user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getuserstatuses
+ """
+
+ user = byname(name)
+
+ if user:
+ return list(user.statuses)
+
+ def getpermusers(self, perm):
+
+ """
+ return all users that have the specified perm.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getpermusers
+
+ """
+ n = query(Perms).filter(Perms.perm==perm.upper()).all()
+ return [user.name for user in n]
+
+ def getstatususers(self, status):
+
+ """
+ return all users that have the specified status.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.getstatususers
+
+ """
+
+ n = query(Statuses).filter(Statuses.status==status.upper()).all()
+ return [user.name for user in n]
+
+ ### Set Functions
+
+ @dblocked
+ def setemail(self, name, email):
+
+ """
+ set email of user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.setemail
+ """
+
+ user = byname(name)
+
+ if user:
+ #Session.begin()
+ try:
+ user.email.remove(email)
+ except:
+ pass
+ user.email.insert(0, email)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ return True
+
+ return False
+
+ ### Add functions
+
+ @dblocked
+ def add(self, name, userhosts, perms):
+
+ """
+ add an user. session argument is provided by @trans
+
+ :param name: name of the user
+ :type name: string
+ :param userhosts: userhosts to add
+ :type userhosts: list .. list of userhosts
+ :param perms: the permissions to add
+ :type perms: list .. list of permissions
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.add
+
+ """
+
+ if type(userhosts) != types.ListType:
+ rlog(10, 'users', 'i need a list of userhosts')
+ return False
+
+ name = stripname(name.lower())
+
+ if not os.path.isdir(self.datadir + os.sep + 'users'):
+ os.mkdir(self.datadir + os.sep + 'users')
+
+ if not os.path.isdir(self.datadir + os.sep + 'users' + os.sep + name):
+ os.mkdir(self.datadir + os.sep + 'users' + os.sep + name)
+
+ user = byname(name)
+
+ if not user:
+
+ try:
+ #Session.begin()
+ newuser = User(name=name)
+ newuser.userhosts.extend(userhosts)
+ newuser.perms.extend(perms)
+ Session.add(newuser)
+ #Session.commit()
+ #Session.close()
+ except sqlalchemy.exc.IntegrityError, ex:
+ if 'not unique' in str(ex):
+ rlog(10, 'users', '%s %s already exists' % (name, userhosts))
+ Session.close()
+ return True
+ else:
+ raise
+ except Exception, ex:
+ raise
+
+ rlog(10, 'users', '%s %s %s added to user database' % (name, userhosts, perms))
+
+ return True
+
+ @dblocked
+ def addemail(self, userhost, email):
+
+ """
+ add an email address to the userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.addemail
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ #Session.begin()
+ user.email.append(email)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s (%s) added to email' % (email, userhost))
+ return True
+
+ return False
+
+ @dblocked
+ def addperm(self, userhost, perm):
+
+ """
+ add the specified perm to the userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.addperm
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ #Session.begin()
+ user.perms.append(perm.upper())
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s perm %s added' % (userhost, perm))
+ return True
+
+ return False
+
+ @dblocked
+ def addpermit(self, userhost, permit):
+
+ """
+ add the given [who, what] permit to the given userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.addpermit
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ p = '%s %s' % permit
+ #Session.begin()
+ user.permits.append(p)
+ Session.refesh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s permit %s added' % (userhost, p))
+ return True
+
+ return False
+
+ @dblocked
+ def addstatus(self, userhost, status):
+
+ """
+ add status to given userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.addstatus
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ #Session.begin()
+ user.statuses.append(status.upper())
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', '%s status %s added' % (name, status))
+ return True
+
+ return False
+
+ @dblocked
+ def adduserhost(self, name, userhost):
+
+ """
+ add userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.adduserhost
+
+ """
+
+ user = byname(name)
+ #Session.begin()
+ if not user:
+ user = User(name=name)
+ Session.add(user)
+
+ user.userhosts.append(userhost)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', '%s (%s) added to userhosts' % (name, userhost))
+ return True
+
+ @dblocked
+ def adduseremail(self, name, email):
+
+ """
+ add email to specified user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.adduseremail
+
+ """
+
+ user = byname(name)
+
+ if user:
+ #Session.begin()
+ user.email.append(email)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', '%s email %s added' % (name, email))
+ return True
+
+ @dblocked
+ def adduserperm(self, name, perm):
+
+ """
+ add permission.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.adduserperm
+
+ """
+
+ user = byname(name)
+
+ if user:
+ #Session.begin()
+ perm = perm.upper()
+ user.perms.append(perm)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', '%s perm %s added' % (name, perm))
+ return True
+
+ return False
+
+ @dblocked
+ def adduserpermit(self, name, who, permit):
+
+ """
+ add (who, what) permit tuple to specified user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.adduserpermit
+
+ """
+
+ user = byname(name)
+
+ if user:
+ p = '%s %s' % (who, permit)
+ #Session.begin()
+ user.permits.append(p)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', '%s permit %s added' % (name, p))
+ return True
+
+ return False
+
+ @dblocked
+ def adduserstatus(self, name, status):
+
+ """
+ add status to given user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.adduserstatus
+
+ """
+
+ user = byname(name)
+
+ if user:
+ #Session.begin()
+ user.statuses.append(status.upper())
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ rlog(10, 'users', '%s status %s added' % (name, status))
+ return True
+
+ return False
+
+ @dblocked
+ def addpermall(self, perm):
+
+ """
+ add permission to all users.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.addpermall
+ """
+
+ users = query(User).all()
+
+ if users:
+ #Session.begin()
+ for user in users:
+ user.perms.append(perm.upper())
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+
+ ### Delete functions
+
+ @dblocked
+ def delemail(self, userhost, email):
+
+ """
+ delete email from userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delemail
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ if email in user.emails:
+ #Session.begin()
+ user.emails.remove(email)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ return True
+
+ return False
+
+ @dblocked
+ def delperm(self, userhost, perm):
+
+ """
+ delete perm from userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delperm
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ p = perm.upper()
+
+ if p in user.perms:
+ #Session.begin()
+ user.perms.remove(p)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ return True
+
+ return False
+
+ @dblocked
+ def delpermit(self, userhost, permit):
+
+ """
+ delete permit from userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delpermit
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ p = '%s %s' % permit
+
+ if p in user.permits:
+ #Session.begin()
+ user.permits.remove(p)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ return True
+
+ return False
+
+ @dblocked
+ def delstatus(self, userhost, status):
+
+ """
+ delete status from userhost.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delstatus
+
+ """
+
+ user = getuser(userhost)
+
+ if user:
+ st = status.upper()
+
+ if st in user.statuses:
+ #Session.begin()
+ user.statuses.remove(st)
+ #Session.commit()
+ #Session.refresh(user)
+ #Session.close()
+ return True
+
+ return False
+
+ @dblocked
+ def delete(self, name):
+
+ """
+ delete user with name.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delete
+
+ """
+ name = stripname(name)
+ user = byname(name)
+
+ if user:
+ rlog(10, 'users', "deleting %s" % name)
+ #Session.begin()
+ Session.delete(user)
+ #Session.commit()
+ #Session.close()
+ return True
+
+ return False
+
+ @dblocked
+ def deluserhost(self, name, userhost):
+
+ """
+ delete the userhost entry.
+
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.deluserhost
+ """
+
+ user = byname(name)
+
+ if user:
+ if userhost in user.userhosts:
+ #Session.begin()
+ user.userhosts.remove(userhost)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s userhost %s deleted' % (name, userhost))
+ return True
+
+ return False
+
+ @dblocked
+ def deluseremail(self, name, email):
+
+ """
+ delete email.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.deluseremail
+
+ """
+
+ user = byname(name)
+
+ if user:
+ if email in user.email:
+ #Session.begin()
+ user.email.remove(email)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s email %s deleted' % (name, email))
+ return True
+
+ return False
+
+ @dblocked
+ def deluserperm(self, name, perm):
+
+ """
+ delete permission.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.deluserperm
+
+ """
+
+ user = byname(name)
+
+ if user:
+ p = perm.upper()
+
+ if p in user.perms:
+ #Session.begin()
+ user.perms.remove(p)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s perm %s deleted' % (name, p))
+ return True
+
+ return False
+
+ @dblocked
+ def deluserpermit(self, name, permit):
+
+ """
+ delete permit.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.deluserpermit
+
+ """
+
+ user = byname(name)
+
+ if user:
+ p = '%s %s' % permit
+
+ if p in user.permits:
+ #Session.begin()
+ user.permits.remove(p)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s permit %s deleted' % (name, p))
+ return True
+
+ return False
+
+ @dblocked
+ def deluserstatus(self, name, status):
+
+ """
+ delete the status from the given user.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.deluserstatus
+
+ """
+
+ user = byname(name)
+
+ if user:
+ st = status.upper()
+
+ if st in user.statuses:
+ #Session.begin()
+ user.statuses.remove(status)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s status %s deleted' % (name, st))
+ return True
+
+ return False
+
+ @dblocked
+ def delallemail(self, name):
+
+ """
+ Delete all emails of the specified user.
+
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delallemail
+
+ """
+
+ user = byname(name)
+
+ if user:
+ #Session.begin()
+ user.email = []
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ rlog(10, 'users', '%s emails deleted' % (name, ))
+ return True
+
+ return False
+
+ @dblocked
+ def delpermall(self, perm):
+
+ """
+ delete permission from all users.
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.delpermall
+
+ """
+
+ users = query(User).options(eagerload('perms')).all()
+
+ for user in users:
+
+ if user.name != 'owner':
+
+ try:
+ #Session.begin()
+ user.perms.remove(perm)
+ #Session.refresh(user)
+ #Session.commit()
+ #Session.close()
+ except ValueError:
+ pass
+
+ return True
+
+ def make_owner(self, userhosts):
+
+ """
+ see if owner already has a user account if not merge otherwise
+ add.
+
+ :param userhosts: userhosts to inititalize owner with
+ :type userhosts: list or string
+
+ .. literalinclude:: ../../gozerbot/users.py
+ :pyobject: DbUsers.make_owner
+
+ """
+
+ owner = []
+
+ if type(userhosts) != types.ListType:
+ owner.append(userhosts)
+ else:
+ owner = userhosts
+
+ for userhost in owner:
+ username = self.getname(unicode(userhost))
+
+ if not username:
+ if not self.merge('owner', unicode(userhost)):
+ self.add('owner', [unicode(userhost), ], ['USER', 'OPER'])
+ elif username != 'owner':
+ self.delete(username)
+ if not self.merge('owner', unicode(userhost)):
+ self.add('owner', [unicode(userhost), ], ['USER', 'OPER'])
+
+## INIT SECTION
+
+# default to database
+
+if not config['nodb']:
+ users = DbUsers()
+else:
+ # otheriwse use json users
+ users = JsonUsers(datadir + os.sep + (config['jsonuser'] or 'users.json'))
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/periodical.py
+++ gozerbot-0.99.1/build/lib/gozerbot/periodical.py
@@ -0,0 +1,567 @@
+# gozerbot/periodical.py
+#
+#
+
+__author__ = "Wijnand 'tehmaze' Modderman - http://tehmaze.com"
+__license__ = "BSD License"
+
+## IMPORT SECTION
+
+# gozerbot imports
+
+from utils.exception import handle_exception
+from utils.trace import calledfrom, whichmodule
+from utils.locking import lockdec
+from utils.log import rlog
+from utils.timeutils import strtotime
+import threads.thr as thr
+
+# basic imorts
+import datetime, sys, time, thread, types
+
+## END IMPORT
+
+## LOCK SECTION
+# locks and vars
+plock = thread.allocate_lock()
+locked = lockdec(plock)
+pidcount = 0
+
+# END LOCK
+
+class JobError(Exception):
+
+ """
+ job error exception.
+
+ """
+
+ pass
+
+class Job(object):
+
+ """
+ job to be scheduled.
+
+ """
+
+ group = ''
+ pid = -1
+
+ def __init__(self):
+ global pidcount
+ pidcount += 1
+ self.pid = pidcount
+
+ def id(self):
+
+ """
+ return job id.
+
+ """
+
+ return self.pid
+
+ def member(self, group):
+
+ """
+ check for group membership.
+
+ :param group: group to check for
+ :type group: string
+ :rtype: boolean
+
+ """
+
+ return self.group == group
+
+ def do(self):
+ # try the callback
+ try:
+ self.func(*self.args, **self.kw)
+ except Exception, ex:
+ handle_exception()
+
+class JobAt(Job):
+
+ """
+ job to run at a specific time/interval/repeat.
+
+ :param start: start time
+ :type start: int, float or string
+ :param interval: time between alarms
+ :type interval: integer
+ :param repeat: number of repeats
+ :type interval: integer
+ :param func: the function to execute
+ :type func: function
+
+ """
+
+ def __init__(self, start, interval, repeat, func, *args, **kw):
+ Job.__init__(self)
+ self.func = func
+ self.args = args
+ self.kw = kw
+ self.repeat = repeat
+ self.description = ""
+ self.counts = 0
+
+ # check start time format
+ if type(start) in [types.IntType, types.FloatType]:
+ self.next = float(start)
+ elif type(start) in [types.StringType, types.UnicodeType]:
+ d = strtotime(start)
+ if d and d > time.time():
+ self.next = d
+ else:
+ raise JobError("invalid date/time")
+
+ if type(interval) in [types.IntType]:
+ d = datetime.timedelta(days=interval)
+ self.delta = d.seconds
+ else:
+ self.delta = interval
+
+ def __repr__(self):
+
+ """
+ return a string representation of the JobAt object.
+
+ """
+
+ return '<JobAt instance next=%s, interval=%s, repeat=%d, function=%s>' % (str(self.next),
+ str(self.delta), self.repeat, str(self.func))
+
+ def check(self):
+
+ """
+ run check to see if job needs to be scheduled.
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: JobAt.check
+
+ """
+
+ if self.next <= time.time():
+ rlog(0, 'periodical', 'running %s - %s' % (str(self.func), self.description))
+ self.func(*self.args, **self.kw)
+ self.next += self.delta
+ self.counts += 1
+ if self.repeat > 0 and self.counts >= self.repeat:
+ return False # remove this job
+ return True
+
+class JobInterval(Job):
+
+ """
+ job to be scheduled at certain interval.
+
+ :param interval: time between alarms
+ :type interval: integer
+ :param repeat: number of repeats
+ :type interval: integer
+ :param func: the function to execute
+ :type func: function
+
+ """
+
+ def __init__(self, interval, repeat, func, *args, **kw):
+ Job.__init__(self)
+ self.func = func
+ self.args = args
+ self.kw = kw
+ self.repeat = int(repeat)
+ self.counts = 0
+ self.interval = float(interval)
+ self.description = ""
+ self.next = time.time() + self.interval
+ self.group = None
+ rlog(-10, 'periodical', 'scheduled next run of %s in %d seconds' % \
+(str(self.func), self.interval))
+
+ def __repr__(self):
+ return '<JobInterval instance next=%s, interval=%s, repeat=%d, group=%s, \
+function=%s>' % (str(self.next), str(self.interval), self.repeat, self.group,
+str(self.func))
+
+ def check(self):
+
+ """
+ run check to see if job needs to be scheduled.
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: JobInterval.check
+ """
+
+ if self.next <= time.time():
+ rlog(0, 'periodical', 'running %s - %s' % (str(self.func), self.description))
+ self.next = time.time() + self.interval
+ thr.start_new_thread(self.do, ())
+ self.counts += 1
+ if self.repeat > 0 and self.counts >= self.repeat:
+ return False # remove this job
+ return True
+
+
+class Periodical(object):
+
+ """
+ periodical scheduler.
+
+ """
+
+ SLEEPTIME = 1 # smallest interval possible
+
+ def __init__(self):
+ self.jobs = []
+ self.running = []
+ self.run = True
+
+ def start(self):
+
+ """
+ start the periodical scheduler.
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.start
+ """
+
+ thr.start_new_thread(self.checkloop, ())
+
+ def addjob(self, sleeptime, repeat, function, description="" , *args, **kw):
+
+ """
+ add a periodical job.
+
+ :param sleeptime: sleeptime between intervals
+ :type sleeptime: float
+ :param repeat: number of times to repeat
+ :type repeat: integer
+ :param function: function to execute
+ :type function: function
+ :param description: description of the periodical job
+ :type description: string
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.addjob
+
+ """
+
+ job = JobInterval(sleeptime, repeat, function, *args, **kw)
+ job.group = calledfrom(sys._getframe())
+ job.description = str(description) or whichmodule()
+ self.jobs.append(job)
+ return job.pid
+
+ def changeinterval(self, pid, interval):
+
+ """
+ change interval of of peridical job.
+
+ :param pid: id op the periodical job
+ :type pid: integer
+ :param interval: interval to set
+ :type interval: integer
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.changeinterval
+ """
+
+ for i in periodical.jobs:
+
+ if i.pid == pid:
+ i.interval = interval
+ i.next = time.time() + interval
+
+ def looponce(self):
+ for job in self.jobs:
+
+ if job.next <= time.time():
+ self.runjob(job)
+
+ def checkloop(self):
+
+ """
+ main loop of the periodical scheduler.
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.checkloop
+
+ """
+
+ while self.run:
+
+ for job in self.jobs:
+
+ if job.next <= time.time():
+ self.runjob(job)
+
+ time.sleep(self.SLEEPTIME)
+
+ def runjob(self, job):
+
+ """
+ run a periodical job
+
+ :param job: the job to be runned
+ :type job: Job
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.runjob
+
+ """
+
+ if not job.check():
+ self.killjob(job.id())
+ else:
+ self.running.append(job)
+
+ def kill(self):
+
+ '''
+ kill all jobs invoked by another module.
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.kill
+ '''
+
+ group = calledfrom(sys._getframe())
+ self.killgroup(group)
+
+ def killgroup(self, group):
+
+ '''
+ kill all jobs with the same group.
+
+ :param group: the group of jobs to kill
+ :type group: string
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.killgroup
+
+ '''
+
+ def shoot():
+
+ """ knock down all jobs belonging to group. """
+
+ deljobs = [job for job in self.jobs if job.member(group)]
+
+ for job in deljobs:
+ self.jobs.remove(job)
+
+ try:
+ self.running.remove(job)
+ except ValueError:
+ pass
+
+ rlog(5, 'periodical', 'killed %d jobs for %s' % (len(deljobs), \
+group))
+
+ del deljobs
+
+ shoot() # *pow* you're dead ;)
+
+ def killjob(self, jobId):
+
+ '''
+ kill one job by its id.
+
+ :param jobId: the id of the job to kill
+ :type jobId: integer
+ :rtype: integer .. number of jobs killed
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: Periodical.killjob
+ '''
+
+ def shoot():
+ deljobs = [x for x in self.jobs if x.id() == jobId]
+ numjobs = len(deljobs)
+ for job in deljobs:
+ self.jobs.remove(job)
+ try:
+ self.running.remove(job)
+ except ValueError:
+ pass
+ del deljobs
+ return numjobs
+
+ return shoot() # *pow* you're dead ;)
+
+
+def interval(sleeptime, repeat=0):
+
+ """
+ interval decorator.
+
+ :param sleeptime: time to sleep
+ :type sleeptime: integer
+ :param repeat: number of times to repeat the job
+ :type repeat: integet
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: interval
+
+ """
+
+ group = calledfrom(sys._getframe())
+
+ def decorator(function):
+ decorator.func_dict = function.func_dict
+
+ def wrapper(*args, **kw):
+ job = JobInterval(sleeptime, repeat, function, *args, **kw)
+ job.group = group
+ job.description = whichmodule()
+ periodical.jobs.append(job)
+ rlog(-15, 'periodical', 'new interval job %d with sleeptime %d' % \
+(job.id(), sleeptime))
+
+ return wrapper
+
+ return decorator
+
+def at(start, interval=1, repeat=1):
+
+ """
+ at decorator.
+
+ :param start: start time of the periodical job
+ :type start: integer, float or string
+ :param interval: time between jobs
+ :type sleeptime: integer
+ :param repeat: number of times to repeat the job
+ :type repeat: integet
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: at
+
+ """
+
+ group = calledfrom(sys._getframe())
+
+ def decorator(function):
+ decorator.func_dict = function.func_dict
+
+ def wrapper(*args, **kw):
+ job = JobAt(start, interval, repeat, function, *args, **kw)
+ job.group = group
+ job.description = whichmodule()
+ periodical.jobs.append(job)
+
+ wrapper.func_dict = function.func_dict
+ return wrapper
+
+ return decorator
+
+def persecond(function):
+
+ """
+ per second decorator.
+
+ :param function: function to execute every second
+ :type function: function
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: persecond
+ """
+
+ minutely.func_dict = function.func_dict
+ group = calledfrom(sys._getframe())
+
+ def wrapper(*args, **kw):
+ job = JobInterval(1, 0, function, *args, **kw)
+ job.group = group
+ job.description = whichmodule()
+ periodical.jobs.append(job)
+ rlog(-15, 'periodical', 'new interval job %d running per second' % \
+job.id())
+
+ return wrapper
+
+def minutely(function):
+
+ """
+ minute decorator.
+
+ :param function: function to execute every minute
+ :type function: function
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: minutely
+
+ """
+
+ minutely.func_dict = function.func_dict
+ group = calledfrom(sys._getframe())
+
+ def wrapper(*args, **kw):
+ job = JobInterval(60, 0, function, *args, **kw)
+ job.group = group
+ job.description = whichmodule()
+ periodical.jobs.append(job)
+ rlog(-15, 'periodical', 'new interval job %d running minutely' % \
+job.id())
+
+ return wrapper
+
+def hourly(function):
+
+ """
+ hour decorator.
+
+ :param function: function to execute every hour
+ :type function: function
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: hourly
+
+ """
+
+ rlog(-15, 'periodical', '@hourly(%s)' % str(function))
+ hourly.func_dict = function.func_dict
+ group = calledfrom(sys._getframe())
+
+ def wrapper(*args, **kw):
+ job = JobInterval(3600, 0, function, *args, **kw)
+ job.group = group
+ job.description = whichmodule()
+ rlog(-15, 'periodical', 'new interval job %d running hourly' % job.id())
+ periodical.jobs.append(job)
+
+ return wrapper
+
+def daily(function):
+
+ """
+ day decorator.
+
+ :param function: function to execute every hour
+ :type function: function
+
+ .. literalinclude:: ../../gozerbot/periodical.py
+ :pyobject: daily
+
+ """
+
+ rlog(-15, 'periodical', '@daily(%s)' % str(function))
+ daily.func_dict = function.func_dict
+ group = calledfrom(sys._getframe())
+
+ def wrapper(*args, **kw):
+ job = JobInterval(86400, 0, function, *args, **kw)
+ job.group = group
+ job.description = whichmodule()
+ periodical.jobs.append(job)
+ rlog(-15, 'periodical', 'new interval job %d running daily' % job.id())
+
+ return wrapper
+
+## INIT SECTION
+
+# the periodical scheduler
+periodical = Periodical()
+
+## END INIT
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/exit.py
+++ gozerbot-0.99.1/build/lib/gozerbot/exit.py
@@ -0,0 +1,73 @@
+# gozerbot/exit.py
+#
+#
+
+""" gozerbot's finaliser """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+
+# gozerbot imports
+from utils.log import rlog
+from utils.trace import whichmodule
+from eventhandler import mainhandler
+from plugins import plugins
+from fleet import fleet
+from persist.persist import saving
+from runner import runners_stop
+from gozerbot.config import config
+
+# basic imports
+import atexit, os, time, sys
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+def globalshutdown():
+
+ """
+ shutdown the bot.
+
+ .. literalinclude:: ../../gozerbot/exit.py
+ :pyobject: globalshutdown
+
+ """
+
+ rlog(10, 'GOZERBOT', 'SHUTTING DOWN')
+
+ try:
+ os.remove('gozerbot.pid')
+ except:
+ pass
+
+ try:
+ runners_stop()
+ rlog(10, 'gozerbot', 'shutting down fleet')
+ fleet.exit()
+ rlog(10, 'gozerbot', 'shutting down plugins')
+ plugins.exit()
+ rlog(10, 'GOZERBOT', 'done')
+ os._exit(0)
+
+ except Exception, ex:
+ rlog(10, 'gozerbot.exit', 'exit error %s:' % str(ex))
+
+# ============
+# INIT SECTION
+
+# register shutdown function
+#atexit.register(globalshutdown)
+
+# END INIT
+# ========
--- gozerbot-0.99.1.orig/build/lib/gozerbot/channels.py
+++ gozerbot-0.99.1/build/lib/gozerbot/channels.py
@@ -0,0 +1,136 @@
+# gozerbot/channels.py
+#
+#
+
+"""
+ channel related data. implemented with a persisted dict of dicts.
+
+ :example:
+
+ key = channels[event.channel]['key']
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# IMPORT SECTION
+# gozerbot imports
+from persist.pdod import Pdod
+
+# END IMPORT
+
+class Channels(Pdod):
+
+ """
+ channels class .. per channel data.
+
+ :param fname: filename to persist the data to
+ :type fname: string
+
+ """
+
+ def __init__(self, fname):
+
+ # call base constructor
+ Pdod.__init__(self, fname)
+
+ # make sure attributes are initialised
+ for j in self.data.values():
+ if not j.has_key('perms'):
+ j['perms'] = []
+ if not j.has_key('autovoice'):
+ j['autovoice'] = 0
+
+ def __setitem__(self, a, b):
+
+ # if item is not in dict initialise it to empty dict
+ if not self.data.has_key(a):
+ self.data[a] = {}
+
+ # assign data
+ self.data[a] = b
+
+ def getchannels(self):
+
+ """
+ return channels.
+
+ .. literalinclude:: ../../gozerbot/channels.py
+ :pyobject: Channels.getchannels
+
+ """
+
+ result = [] # list of channels found
+
+ # loop over channels
+ for channel in self.data.keys():
+ channel = channel.strip()
+ if channel not in result:
+ result.append(channel)
+
+ return result
+
+ def getchannelswithkeys(self):
+
+ """
+ return channels with keys.
+
+ .. literalinclude:: ../../gozerbot/channels.py
+ :pyobject: Channels.getchannelswithkeys
+
+ """
+
+ result = []
+
+ # loop over channels gathering channel name and key
+ for channel in self.data.keys():
+ channel = channel.strip()
+ try:
+ key = self.data[channel]['key']
+ if not channel + ' ' + key in result:
+ result.append(channel + ' ' + key)
+ except KeyError:
+ if channel not in result:
+ result.append(channel)
+
+ return result
+
+ def getkey(self, channel):
+
+ """
+ return key of channel if set.
+
+ :param channel: channel to get key from
+ :type channel: string
+
+ .. literalinclude:: ../../gozerbot/channels.py
+ :pyobject: Channels.getkey
+
+ """
+
+ try:
+ key = self.data[channel]['key']
+ except:
+ key = None
+
+ return key
+
+ def getnick(self, channel):
+
+ """
+ return bot nick of channel if set.
+
+ :param channel: channel to get key from
+ :type channel: string
+
+ .. literalinclude:: ../../gozerbot/channels.py
+ :pyobject: Channels.getnick
+
+ """
+
+ try:
+ nick = self.data[channel]['nick']
+ except:
+ nick = None
+
+ return nick
--- gozerbot-0.99.1.orig/build/lib/gozerbot/tests.py
+++ gozerbot-0.99.1/build/lib/gozerbot/tests.py
@@ -0,0 +1,326 @@
+# gozerbot/tests.py
+#
+#
+
+""" gozerbot tests framework. """
+
+## IMPORT SECTION
+
+# gozerbot imports
+from config import config
+from threads.thr import start_new_thread
+from utils.locking import lockdec
+from utils.log import rlog
+from utils.trace import calledfrom, whichmodule
+from utils.exception import exceptionmsg
+from utils.dol import Dol
+from eventbase import EventBase
+
+# basic imports
+import sys, re, thread, copy, time, threading, random
+
+## END IMPORT
+
+# used to copy attributes
+cpy = copy.deepcopy
+
+## LOCK SECTION
+
+# locks
+testlock = threading.RLock()
+locked = lockdec(testlock)
+
+## END LOCK
+
+class Test(object):
+
+ """ a test object. """
+
+ def __init__(self, execstring="", expect="", descr="", where="", fakein=""):
+ self.plugin = calledfrom(sys._getframe(1))
+ if not self.plugin:
+ self.plugin = calledfrom(sys._getframe(2))
+ self.descr = cpy(descr)
+ self.execstring = cpy(execstring)
+ self.expect = cpy(expect)
+ self.response = ""
+ self.groups = []
+ self.error = ""
+ self.where = cpy(where)
+ self.fakein = cpy(fakein)
+ self.start = None
+ self.end = None
+ self.prev = None
+ self.activate = False
+
+ def __str__(self):
+ return "test %s (%s) %s ==> %s (%s)" % (self.descr, self.where, self.execstring, self.response, self.error)
+
+ def begin(self):
+ if self.start:
+ self.start()
+ return self
+
+ def run(self, bot, event):
+
+ """ run the test on bot with event. """
+
+ if not self.activate:
+ return
+
+ if config['loadlist'] and self.plugin not in config['loadlist']:
+ return
+
+ mevent = copy.deepcopy(event)
+ mevent.onlyqueues = False
+ mevent.channel = '#dunkbots'
+ bot.userhosts['bottest'] = 'bottest@test'
+ bot.userhosts['mtest'] = 'mekker@test'
+ bot.userhosts['exec'] = 'exec@gozerbot'
+ if 'exec@gozerbot' not in bot.state['joinedchannels']:
+ bot.state['joinedchannels'].append('exec@gozerbot')
+ bot.channels['exec@gozerbot'] = {}
+ if '#dunkbots' not in bot.state['joinedchannels']:
+ bot.state['joinedchannels'].append('#dunkbots')
+ bot.channels['#dunkbots'] = {'cc': '!'}
+ self.error = ""
+ self.response = ""
+ self.groups = []
+ origexec = self.execstring
+ origexpect = self.expect
+ if self.start:
+ self.start()
+ return self
+ if self.end:
+ self.end()
+ return self
+ if self.fakein:
+ bot.fakein(self.fakein)
+ return self
+ if self.prev and self.prev.groups:
+ try:
+ execstring = self.execstring % self.prev.groups
+ self.execstring = execstring
+ except TypeError:
+ pass
+ try:
+ expect = self.expect % self.prev.groups
+ self.expect = expect
+ except TypeError:
+ pass
+
+ self.execstring = self.execstring.replace('{{ me }}', mevent.nick)
+ mevent.txt = mevent.origtxt = str(self.execstring)
+ rlog(100, 'tests', 'launching %s' % mevent.txt)
+
+ from gozerbot.plugins import plugins
+ self.response = plugins.cmnd(bot, mevent)
+
+ if self.response and self.expect:
+ self.expect = self.expect.replace('{{ me }}', mevent.nick)
+ expects = self.expect.split('|')
+ got = False
+ for expect in expects:
+ regex = re.compile(expect)
+ result = regex.search(str(self.response))
+
+ if result:
+ got = True
+ break
+
+ if not got:
+ self.error = 'invalid response'
+ else:
+ self.groups = result.groups()
+
+ self.execstring = origexec
+ self.expect = origexpect
+
+ return self
+
+class Tests(object):
+
+ """ collection of all tests. """
+
+ def __init__(self):
+ self.tests = []
+ self.err = Dol()
+ self.toolate = Dol()
+ self.teller = 0
+
+ #@locked
+ def add(self, execstr, expect=None, descr="", fakein=""):
+
+ """ add a test. """
+
+ where = whichmodule(1)
+ if not where:
+ where = whichmodule(2)
+ if not where:
+ where = whichmodule(3)
+ test = Test(execstr, expect, descr, where, fakein)
+ self.tests.append(test)
+ return self
+
+ #@locked
+ def fakein(self, execstr, expect=None, descr=""):
+
+ """ call bot.fakein(). """
+
+ where = whichmodule(1)
+ if not where:
+ where = whichmodule(2)
+ if not where:
+ where = whichmodule(3)
+ test = Test(execstr, expect, descr, where, execstr)
+ test.where = where
+ self.tests.append(test)
+ return self
+
+ def start(self, func):
+
+ """ optional start function. """
+ where = whichmodule(1)
+ if not where:
+ where = whichmodule(2)
+ if not where:
+ where = whichmodule(3)
+ test = Test()
+ test.start = func
+ test.where = where
+ test.execstring = 'start'
+ self.tests.append(test)
+ return self
+
+ def end(self, func):
+
+ """ optional end function. """
+
+ where = whichmodule(1)
+ if not where:
+ where = whichmodule(2)
+ if not where:
+ where = whichmodule(3)
+ test = Test()
+ test.end = func
+ test.where = where
+ test.execstring = 'end'
+ self.tests.append(test)
+ return self
+
+ def unload(self, plugname):
+
+ """ unload tests. """
+
+ for i in range(len(self.tests)-1, -1, -1):
+ if self.tests[i].plugin == plugname:
+ del self.tests[i]
+
+ return self
+
+ def activate(self, plugname):
+
+ """ activate tests. """
+
+ for i in range(len(self.tests)-1, -1, -1):
+ if self.tests[i].plugin == plugname:
+ self.tests[i].activate = True
+
+ return self
+
+ def disable(self, plugname):
+
+ """ unload tests. """
+
+ for i in range(len(self.tests)-1, -1, -1):
+ if self.tests[i].plugin == plugname:
+ self.tests[i].activate = False
+
+ return self
+
+ def dorun(self, bot, event, tests, where, plug=None):
+ teller = 0
+ err = {}
+ toolate = []
+ prev = None
+ for test in tests:
+ if event.rest and event.rest not in test.plugin:
+ continue
+ if prev:
+ test.prev = prev
+ prev = test
+ if test.expect:
+ teller += 1
+ try:
+ starttime = time.time()
+ self.teller += 1
+ e = copy.deepcopy(event)
+ result = test.run(bot, e)
+ finished = time.time()
+ if finished - starttime > 10:
+ self.toolate[test.execstring] = finished - starttime
+ if not result:
+ continue
+ if not result.error:
+ event.reply("OK %s (%s) ==> %s" % (test.execstring, test.where, result.response))
+ else:
+ self.err[test.execstring] = test
+ event.reply('ERROR %s (%s): %s ==> %s (%s)' % (test.error, test.where, test.execstring, test.response, test.expect))
+ except Exception, ex:
+ test.error = exceptionmsg()
+ self.err[test.execstring] = test
+ event.reply(test.error)
+
+ return self
+
+ def dotests(self, bot, event, threaded=False, plug=None):
+
+ """ fire all tests. """
+
+ #event = EventBase(eventin)
+ groups = Dol()
+
+ for test in self.tests:
+ groups.add(test.where, test)
+
+ threads = []
+ testlist = []
+
+ for where, tests in groups.iteritems():
+ testlist.append((where, tests))
+
+ random.shuffle(testlist)
+
+ for t in testlist:
+ where, tests = t
+ if plug and plug not in where:
+ continue
+ event.reply("running tests on %s" % where)
+ if threaded:
+ thread = start_new_thread(self.dorun, (bot, event, tests, where, plug))
+ threads.append(thread)
+ else:
+ self.dorun(bot, event, tests, where, plug)
+
+ for thread in threads:
+ thread.join()
+
+ event.done()
+
+ def sleep(self, seconds):
+
+ """ sleep nr of seconds. """
+
+ time.sleep(seconds)
+ return self
+
+## INIT SECTION
+
+# expect is for examples
+
+expect = {}
+
+# the tests
+tests = Tests()
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/__init__.py
+++ gozerbot-0.99.1/build/lib/gozerbot/__init__.py
@@ -0,0 +1,45 @@
+# gozerbot package
+#
+#
+
+""" gozerbot core package. """
+
+__copyright__ = 'this file is in the public domain'
+
+__version__ = "0.99.1"
+
+__all__ = ['aliases', 'database', 'ignore', 'periodical', 'tests', \
+'botbase', 'datadir', 'persist', 'threads', \
+'cache', 'eventbase', 'irc', 'plughelp', 'users', \
+'callbacks', 'eventhandler', 'jabber', 'plugins', 'utils', \
+'channels', 'examples', 'jsonusers', 'plugs', 'wait', \
+'commands', 'exit', 'less', 'redispatcher', \
+'compat', 'fleet', 'monitor', 'rest', \
+'config', 'morphs', 'runner', 'wave', \
+'contrib', 'gozerimport', 'partyline', 'stats', 'utils', 'reboot', 'xmpp']
+
+# ==============
+# IMPORT SECTION
+
+from eggs import loadegg
+import os
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+# ============
+# INIT SECTION
+
+loadegg('simplejson', [os.getcwd(), os.getcwd() + os.sep + 'gozernest'], log=False)
+loadegg('sqlalchemy', [os.getcwd(), os.getcwd() + os.sep + 'gozernest'], log=False)
+
+# END INIT
+# ========
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/commands.py
+++ gozerbot-0.99.1/build/lib/gozerbot/commands.py
@@ -0,0 +1,579 @@
+# gozerbot/commands.py
+#
+#
+
+"""
+
+ This module implements the commands a user can give. It also contains
+ the global cmnds object to which all commands are added.
+
+ example:
+
+ ::
+
+ cmnds.add('hello', handle_hello, 'USER')
+
+
+ :var cmnds: global commands object
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.stats import stats
+from utils.generic import makeoptions
+from eventbase import defaultevent
+from config import config
+from utils.log import rlog
+from utils.trace import calledfrom
+from utils.exception import handle_exception
+from utils.locking import lockdec
+from runner import cmndrunners
+from threads.thr import start_new_thread, start_bot_command
+
+# basic imports
+import sys, re, copy, types, thread
+
+# END IMPORT
+
+# LOCK SECTION
+
+# command lock
+commandlock = thread.allocate_lock()
+locked = lockdec(commandlock)
+
+# END LOCK
+
+class Command(object):
+
+ """
+ implements a command.
+
+ :param func: the function to call when a commands gets triggered
+ :param perm: permissions the command needs before it gets fired
+ :type perm: list
+ :param plugname: the plugin this commands is implemented in
+ :type param: string
+ :param threaded: determines if the command has to be run in its own thread
+ :type threaded: False or True
+ :param allowqueue: determines if output of this commands can be used in pipeline queues
+ :type threaded: False or True
+ :param options: options for this command
+ :type options: dict
+
+ """
+
+ def __init__(self, func, perm, plugname, speed=5, threaded=False, allowqueue=True, options={'--speed': 5, '--chan': '', '--filter': '', '--how': 'msg'}):
+
+ self.name = str(func) # function name is string representation of the function
+ self.func = func # function to call
+
+ # make sure permission(s) are stored in a list
+ if type(perm) == types.ListType:
+ self.perms = list(perm)
+ else:
+ self.perms = [perm, ]
+
+ self.plugname = plugname # plugin name
+ self.speed = copy.deepcopy(speed) # speed to execute command with
+ self.threaded = copy.deepcopy(threaded) # set if threaded exec is required
+ self.allowqueue = copy.deepcopy(allowqueue) # set if command is allowed to be used in pipeline
+ self.options = dict(options) # options set in the command
+ self.activate = True
+
+class Commands(dict):
+
+ """
+ the commands object is a dict containing the commands. dict key is the
+ command (1 word).
+
+ """
+
+ def __setitem__(self, name, value):
+
+ """ set command. """
+
+ dict.__setitem__(self, name, value)
+
+ def __delitem__(self, name):
+
+ """ delete command. """
+
+ dict.__delitem__(self, name)
+
+ def size(self):
+
+ """
+ nr of commands.
+
+ :rtype: integer
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.size
+
+ """
+
+ return len(self)
+
+ def activate(self, plugname):
+ cp = dict(self)
+ for i in cp.values():
+ if i.plugname == plugname:
+ i.activate = True
+
+ def disable(self, plugname):
+ cp = dict(self)
+ for i in cp.values():
+ if i.plugname == plugname:
+ i.activate = False
+
+ def whatperms(self):
+
+ """
+ return all possible permissions.
+
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.whatperms
+
+ """
+
+ result = []
+
+ # loop over the commands and collect all possible permissions
+ cp = dict(self)
+ for i in cp.values():
+ for j in i.perms:
+ if j not in result:
+ result.append(j)
+
+ return result
+
+ def list(self, perm):
+
+ """
+ list commands with permission perm.
+
+ :param perm: the permission
+ :type perm: string
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.list
+
+ """
+
+ result = []
+
+ # make sure perm is a list
+ if type(perm) != types.ListType:
+ perm = perm.upper()
+ perms = [perm, ]
+ else:
+ perms = perm
+
+ # loop over commands collecting all command having permission
+ cp = dict(self)
+ for name, cmnd in cp.items():
+ for i in perms:
+ if i in cmnd.perms:
+ result.append(name)
+
+ return result
+
+ def getfuncnames(self, plug):
+
+ """
+ get all function names of commands in a plugin.
+
+ :param plug: plugname
+ :type plug: string
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.getfuncnames
+
+ """
+
+ result = []
+
+ # collect function names
+ cp = dict(self)
+ for i in cp.values():
+ if i.plugname == plug:
+ result.append(i.func.func_name)
+
+ return result
+
+ def getoptions(self, command):
+
+ """
+ get options of a command.
+
+ :param command: the command to get options for
+ :type command: string
+ :rtype: dict
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.getoptions
+
+ """
+
+ cp = dict(self)
+ for name, cmnd in cp.iteritems():
+ if name == command:
+ return makeoptions(defaultevent, cmnd.options)
+
+ #@locked
+ def permoverload(self, name, perms):
+
+ """
+ overload permission of function with funcname.
+
+ :param name: name of command to overload permission of
+ :type name: string
+ :param perms: permission to overload the command with
+ :type perms: list
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.permoverload
+
+ """
+
+ # make sure all perms are uppercase
+ perms = [perm.upper() for perm in perms]
+
+ # overload the command with given permissions
+ for com in self.values():
+ try:
+ if com.func.func_name == name:
+ com.perms = perms
+ return True
+ except AttributeError:
+ rlog(10, 'commands', "permoverload: no %s function" % name)
+ return False
+
+ #@locked
+ def add(self, cmnd, func, perm, speed=5, threaded=False, allowqueue=True, options={'--speed': 5, '--chan': '', '--filter': '', '--how': 'msg'}):
+
+ """
+ add a command.
+
+ :param func: the function to call when a commands gets triggered
+ :param perm: permissions the command needs before it gets fired
+ :type perm: list
+ :param plugname: the plugin this commands is implemented in
+ :type param: string
+ :param threaded: determines if the command has to be run in its own thread
+ :type threaded: boolean
+ :param allowqueue: determines if output of this commands can be used in pipeline queues
+ :type threaded: boolean
+ :param options: options for this command
+ :type options: dict
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.add
+
+ """
+
+ # plugin where the command is added
+ plugname = calledfrom(sys._getframe(0))
+ # check if plugin is in loadlist .. if not dont register command.
+ if config['loadlist'] and plugname not in config['loadlist']:
+ rlog(1, 'commands', 'NOT LOADING %s' % plugname)
+ return
+
+ rlog(-3, 'commands', 'added %s (%s) ' % (cmnd, plugname))
+
+ # add command
+ self[cmnd.lower()] = Command(func, perm, plugname, speed, threaded, allowqueue, options)
+ self[cmnd.lower()].name = cmnd.lower()
+
+ def apropos(self, txt, perms=[]):
+
+ """
+ search for command.
+
+ :param txt: txt to search commands with
+ :type txt: string
+ :param perms: contain permission that must match first
+ :type perms: list
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.apropos
+
+ """
+
+ result = []
+
+ # loop over commands collecting all commands that contain given txt
+ cp = dict(self)
+ for name, cmnd in cp.iteritems():
+ if perms:
+ go = False
+ for i in perms:
+ if i in cmnd.perms:
+ go = True
+ if not go:
+ continue
+ if re.search(txt, name):
+ result.append(name)
+
+ return result
+
+ #@locked
+ def unload(self, plugname):
+
+ """
+ unload plugin commands.
+
+ :param plugname: name of the plugin that needs to be unloaded
+ :type plugname: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.unload
+
+ """
+
+ results = []
+
+ # look for the commands registerd in plugin
+ for name, cmnd in self.iteritems():
+ if cmnd.plugname == plugname:
+ results.append(name)
+
+ got = False
+
+ # remove commands
+ for name in results:
+
+ try:
+ del self[name]
+ rlog(-3, 'commands', 'unloaded %s (%s)' % (name, plugname))
+ got = True
+ except KeyError:
+ got = False
+
+ if got:
+ return True
+
+ def whereis(self, command):
+
+ """
+ locate plugin a command is registered in.
+
+ :param command: command to search for
+ :type command: string
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.whereis
+
+ """
+
+ result = []
+
+ # find plugin
+ cp = dict(self)
+ for name, cmnd in cp.iteritems():
+ if name == command:
+ if not cmnd.plugname in result:
+ result.append(cmnd.plugname)
+
+ return result
+
+ def perms(self, name):
+
+ """
+ get permission of command.
+
+ :param command: command to lookup permissions for
+ :type command: string
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.perms
+
+ """
+
+ name = name.lower()
+
+ if self.has_key(name):
+ return self[name].perms
+ else:
+ return []
+
+ #@locked
+ def setperm(self, command, perm):
+
+ """
+ set permission of command.
+
+ :param command: command to set permission of
+ :type command: string
+ :param perm: the permission
+ :type perm: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.setperm
+
+ """
+
+ command = command.lower()
+ perm = perm.upper()
+
+ if self.has_key(command):
+ if perm not in self[command].perms:
+ self[command].perms.append(perm)
+ return True
+ return False
+
+ def getcommand(self, txt):
+
+ """
+ return command matching txt.
+
+ :param txt: txt to match commands against
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.getcommand
+
+ """
+
+ textlist = txt.split()
+
+ if not textlist:
+ return None
+
+ cmnd = textlist[0].lower()
+ if self.has_key(cmnd):
+ com = self[cmnd] # the command
+ return com
+ else:
+ return None
+
+ def options(self, command):
+
+ """
+ return options dict of command.
+
+ :param command: the command to get the options of
+ :type command: string
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.options
+
+ """
+
+ try:
+ return self[command].options
+ except KeyError:
+ return
+
+ def getcommands(self, plugin):
+
+ """
+ get all commands of a plugin.
+
+ :param plugin: the plugin to get commands of
+ :type plugin: string
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.getcommands
+
+ """
+
+ result = []
+
+ tmp = dict(self)
+ for name, cmnd in tmp.iteritems():
+ if cmnd.plugname == plugin:
+ result.append(name)
+
+ return result
+
+ #@locked
+ def dispatch(self, com, txt, wait=False):
+
+ """
+ dispatch command.
+
+ :param com: the command object to dispatch with
+ :type com: Command
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Commands.dispatch
+
+ """
+
+ if com.threaded:
+ thread = start_new_thread(com.func, (txt, ))
+ if wait:
+ thread.join()
+ else:
+ cmndrunners[10-com.speed].put(com.name, com.func, txt)
+ return 1
+
+class Botcommands(Commands):
+
+ """
+ commands for the bot .. dispatch with (bot, ircevent) as arguments.
+
+ """
+
+ #@locked
+ def dispatch(self, com, bot, ievent, wait=False):
+
+ """
+ dispatch on event passing bot and ievent as arguments.
+
+ :param com: the command object
+ :type com: gozerbot.commands.Command
+ :param bot: the bot this command is given on
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: the event triggering this command
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/commands.py
+ :pyobject: Botcommands.dispatch
+
+ """
+
+ if not com.activate:
+ return False
+
+ if bot.stopped:
+ return False
+
+ #ievent = copy.deepcopy(ieventin)
+
+ # stats
+ stats.up('cmnds', com.name)
+ stats.up('cmnds', com.plugname)
+ stats.up('cmnds', 'speed%s' % com.speed)
+
+ # execute command
+ if com.threaded or ievent.threaded:
+ thread = start_bot_command(com.func, (bot, ievent))
+ #if thread and wait:
+ # thread.join()
+ else:
+ speed = ievent.speed or com.speed
+ ievent.speed = speed
+ cmndrunners.put(com.name, com.func, bot, ievent)
+ return True
+
+# INIT SECTION
+
+cmnds = Botcommands()
+
+# END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/eventhandler.py
+++ gozerbot-0.99.1/build/lib/gozerbot/eventhandler.py
@@ -0,0 +1,192 @@
+# gozerbot/eventhandler.py
+#
+#
+
+"""
+ event handler. use to dispatch function in main loop.
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# gozerbot imports
+from utils.exception import handle_exception
+from utils.log import rlog
+from utils.locking import lockdec
+from threads.thr import start_new_thread
+
+# basic imports
+import Queue, thread
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# locks
+handlerlock = thread.allocate_lock()
+locked = lockdec(handlerlock)
+
+# END LOCK
+# ========
+
+## START
+
+class Eventhandler(object):
+
+ """
+ events are handled in 11 queues with different priorities:
+ queue0 is tried first queue10 last.
+
+ """
+
+ def __init__(self):
+ self.sortedlist = []
+ self.queues = {}
+
+ for i in range(11):
+ self.queues[i] = Queue.Queue()
+ self.sortedlist.append(i)
+
+ self.sortedlist.sort()
+ self.go = Queue.Queue()
+ self.stopped = False
+ self.running = False
+ self.nooutput = False
+
+ def start(self):
+
+ """
+ start the eventhandler thread.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.start
+
+ """
+
+ self.stopped = False
+
+ if not self.running:
+ start_new_thread(self.handleloop, ())
+ self.running = True
+
+ def stop(self):
+
+ """
+ stop the eventhandler thread.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.stop
+
+ """
+
+ self.running = False
+ self.stopped = True
+ self.go.put('Yihaaa')
+
+ def put(self, speed, func, *args, **kwargs):
+
+ """
+ put item on the queue.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.put
+
+ """
+
+ self.queues[10-speed].put_nowait((func, args, kwargs))
+ self.go.put('go')
+
+ def getready(self):
+
+ """
+ check queues from available functions to execute.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.getready
+
+ """
+
+ ready = []
+
+ for i in self.sortedlist:
+ if self.queues[i].qsize():
+ ready.append(i)
+ break
+
+ return ready
+
+ def handle_one(self):
+
+ """
+ do 1 loop over ready queues.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.handle_one
+
+ """
+
+ ready = self.getready()
+
+ for i in ready:
+ self.dispatch(self.queues[i])
+
+ def handleloop(self):
+
+ """
+ thread that polls the queues for items to dispatch.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.handleloop
+
+ """
+
+ rlog(0, 'eventhandler', 'starting handle thread')
+
+ while not self.stopped:
+ self.go.get()
+ self.handle_one()
+
+ rlog(0, 'eventhandler', 'stopping %s' % str(self))
+
+ def dispatch(self, queue):
+
+ """
+ dispatch functions from provided queue.
+
+ .. literalinclude:: ../../gozerbot/eventhandler.py
+ :pyobject: Eventhandler.dispatch
+
+ """
+
+
+ try:
+ todo = queue.get_nowait()
+ except Queue.Empty:
+ return
+
+ try:
+ (func, args, kwargs) = todo
+ func(*args, **kwargs)
+ except ValueError:
+ try:
+ (func, args) = todo
+ func(*args)
+ except ValueError:
+ (func, ) = todo
+ func()
+
+ except:
+ handle_exception()
+
+# INIT SECTION
+
+# handler to use in main prog
+mainhandler = Eventhandler()
+
+
+# END INIT
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/runner.py
+++ gozerbot-0.99.1/build/lib/gozerbot/runner.py
@@ -0,0 +1,172 @@
+# jsb/runner.py
+#
+#
+
+""" threads management to run jobs. """
+
+## jsb imports
+
+from gozerbot.threads.thr import getname, start_new_thread, start_bot_command
+from gozerbot.utils.generic import handle_exception
+from gozerbot.utils.trace import callstack
+from gozerbot.threads.threadloop import RunnerLoop
+from gozerbot.utils.log import rlog
+
+## basic imports
+
+import Queue
+import time
+import thread
+import random
+import logging
+import sys
+
+## Runner class
+
+class Runner(RunnerLoop):
+
+ """
+ a runner is a thread with a queue on which jobs can be pushed.
+ jobs scheduled should not take too long since only one job can
+ be executed in a Runner at the same time.
+
+ """
+
+ def __init__(self, name="runner", doready=True):
+ RunnerLoop.__init__(self, name)
+ self.working = False
+ self.starttime = time.time()
+ self.elapsed = self.starttime
+ self.finished = time.time()
+ self.doready = doready
+
+ def handle(self, descr, func, *args, **kwargs):
+ """ schedule a job. """
+ self.working = True
+ name = getname(str(func))
+ try:
+ #rlockmanager.acquire(getname(str(func)))
+ name = getname(str(func))
+ self.name = name
+ rlog(10, "runner", 'running %s: %s' % (descr, name))
+ self.starttime = time.time()
+ func(*args, **kwargs)
+ self.finished = time.time()
+ self.elapsed = self.finished - self.starttime
+ #if self.elapsed > 3:
+ #logging.debug('ALERT %s %s job taking too long: %s seconds' % (descr, str(func), self.elapsed))
+ except Exception, ex: handle_exception()
+ #finally: rlockmanager.release()
+ self.working = False
+
+## BotEventRunner class
+
+class BotEventRunner(Runner):
+
+ def handle(self, descr, func, bot, ievent, *args, **kwargs):
+ """ schedule a bot command. """
+ try:
+ self.starttime = time.time()
+ #lockmanager.acquire(getname(str(func)))
+ name = getname(str(func))
+ self.name = name
+ self.working = True
+ rlog(10, "runner", "now running %s" % name)
+ func(bot, ievent, *args, **kwargs)
+
+ for queue in ievent.queues:
+ queue.put_nowait(None)
+
+ self.finished = time.time()
+ self.elapsed = self.finished - self.starttime
+ #if self.elapsed > 3:
+ # logging.info('ALERT %s %s job taking too long: %s seconds' % (descr, str(func), self.elapsed))
+ #if ievent.iscommand: ievent.ready()
+ #if not ievent.type == "OUTPUT" and not ievent.dontclose: ievent.ready()
+ #time.sleep(0.001)
+ except Exception, ex:
+ handle_exception(ievent)
+ #finally: lockmanager.release(getname(str(func)))
+ self.working = False
+ self.name = "finished"
+
+## Runners class
+
+class Runners(object):
+
+ """ runners is a collection of runner objects. """
+
+ def __init__(self, max=100, runnertype=Runner, doready=True):
+ self.max = max
+ self.runners = []
+ self.runnertype = runnertype
+ self.doready = doready
+
+ def runnersizes(self):
+ """ return sizes of runner objects. """
+ result = []
+ for runner in self.runners: result.append("%s - %s" % (runner.queue.qsize(), runner.name))
+ return result
+
+ def stop(self):
+ """ stop runners. """
+ for runner in self.runners: runner.stop()
+
+ def start(self):
+ """ overload this if needed. """
+ pass
+
+ def put(self, *data):
+ """ put a job on a free runner. """
+ #logging.debug("size is %s" % len(self.runners))
+ for runner in self.runners:
+ if not runner.queue.qsize():
+ runner.put(*data)
+ return
+ runner = self.makenew()
+ runner.put(*data)
+
+ def running(self):
+ """ return list of running jobs. """
+ result = []
+ for runner in self.runners:
+ if runner.queue.qsize(): result.append(runner.nowrunning)
+ return result
+
+ def makenew(self):
+ """ create a new runner. """
+ runner = None
+ for i in self.runners:
+ if not i.queue.qsize(): return i
+ if len(self.runners) < self.max:
+ runner = self.runnertype(self.doready)
+ runner.start()
+ self.runners.append(runner)
+ else: runner = random.choice(self.runners)
+ return runner
+
+ def cleanup(self):
+ """ clean up idle runners. """
+ #if not len(self.runners): logging.debug("nothing to clean")
+ for index in range(len(self.runners)-1, -1, -1):
+ runner = self.runners[index]
+ #logging.debug("cleanup %s" % runner.name)
+ if not runner.queue.qsize():
+ try: runner.stop() ; del self.runners[index]
+ except IndexError: pass
+ except: handle_exception()
+ #else: logging.info("now running: %s" % runner.nowrunning)
+
+## global runners
+
+cmndrunners = defaultrunner = longrunner = Runners(50, BotEventRunner)
+cbrunners = Runners(100, BotEventRunner, doready=False)
+waitrunners = Runners(10, Runner)
+
+## runners_start
+
+def runners_start():
+ pass
+
+def runners_stop():
+ pass
--- gozerbot-0.99.1.orig/build/lib/gozerbot/config.py
+++ gozerbot-0.99.1/build/lib/gozerbot/config.py
@@ -0,0 +1,425 @@
+# gozerbot/config.py
+#
+#
+
+"""
+ gozerbot config module.
+
+ :var config: default config object
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# IMPORT SECTION
+
+# gozerbot imports
+from utils.exception import handle_exception
+from utils.log import rlog
+
+# simplejson imports
+
+from simplejson import loads, dumps
+
+# basic imports
+import os, types, thread, logging
+
+# END IMPORT
+
+class Config(dict):
+
+ """
+ config class is a dict containing json strings. is writable to file
+ and human editable.
+
+ :param ddir: datadir where the config file lives
+ :type ddir: string
+ :param filename: filename of the config file
+ :type filename: string
+ :param inittxt: initial txt to fill the config file with
+ :type inittxt: string
+
+ """
+
+ def __init__(self, ddir=None, filename=None, inittxt=None, verbose=False, *args, **kw):
+ dict.__init__(self, *args, **kw)
+ self.jsondb = None
+ self.dir = ddir or 'gozerdata'
+ self.filename = filename or 'config'
+ self.cfile = self.dir + os.sep + self.filename
+
+ if hasattr(os, 'mkdir'):
+ # check if provided dir exists if not create it
+ if not os.path.exists(self.dir):
+ os.mkdir(self.dir)
+
+ # see if initial data has to be written
+ if inittxt and not os.path.exists(self.cfile):
+ self.write_init(inittxt)
+
+ self.configlist = []
+ self.lock = thread.allocate_lock()
+ self.load(verbose)
+
+ def __getitem__(self, item):
+ if not self.has_key(item):
+ return None
+ else:
+ return dict.__getitem__(self, item)
+
+ def set(self, item, value):
+ dict.__setitem__(self, item, value)
+ self.save()
+
+ def load(self, verbose=False):
+
+ """
+ load the config file.
+
+ .. literalinclude:: ../../gozerbot/config.py
+ :pyobject: Config.load
+
+ """
+
+ self.reload()
+
+ if self.filename == 'mainconfig':
+ self.setdefault('owner', [])
+ self.setdefault('loglevel', 10)
+ self.setdefault('loglist', [])
+ self.setdefault('resource', 'gozerbot')
+ self.setdefault('quitmsg', "http://gozerbot.googlecode.com")
+ self.setdefault('mask', "700")
+ self.setdefault('debug', 0)
+ self.setdefault('nodb', 0)
+ self.setdefault('plugdeny', [])
+ self.setdefault('db_driver', 'olddb')
+ self.setdefault('dbtype', "sqlite")
+ self.setdefault('dbname', "db/main.db")
+ self.setdefault('dbhost', "localhost")
+ self.setdefault('dbuser', "bart")
+ self.setdefault('dbpasswd', "mekker2")
+ self.setdefault('loadlist', ["alias", "all", "at", "chanperm", "choice", "code", "core", "count", "fleet", "googletalk", "grep", "ignore", "irc", "jabber", "job", "misc", "nickcapture", "nickserv", "not", "quote", "reload", "rest", "reverse", "size", "sort", "tail", "tell", "to", "underauth", "uniq", "user", "userstate", "stats", "throttle"])
+ self.setdefault('dotchars', " .. ")
+ self.setdefault('floodallow', 1)
+ self.setdefault('auto_register', 0)
+
+ elif 'fleet' in self.dir:
+ self.setdefault("enable", 1)
+ self.setdefault("type", "irc")
+ self.setdefault("owner", [])
+ self.setdefault("user", "")
+ self.setdefault("nick", "gozerbot")
+ self.setdefault("server", "")
+ self.setdefault("host", "")
+ self.setdefault("password", "")
+ self.setdefault("port", 0)
+ self.setdefault("ssl", 0)
+ self.setdefault("ipv6", 0)
+ self.setdefault("username", "gozerbot")
+ self.setdefault("realname", "GOZERBOT")
+ self.setdefault("defaultcc", "!")
+ self.setdefault("quitmsg", "http://gozerbot.googlecode.com")
+ self.setdefault("bindhost", "")
+ self.setdefault("nolimiter", 0)
+ self.setdefault("nickservpass", "")
+ self.setdefault("nickservtxt", ["set unfiltered on", ])
+ self.setdefault("auto_register", 0)
+ self.setdefault("stripident", 0)
+ self.setdefault("loadlist", [])
+
+ import gozerbot
+ self['version'] = "GOZERBOT %s " % gozerbot.__version__
+ self['version'] += "RELEASE"
+
+ if verbose:
+ rlog(10, 'config', str(self))
+
+ def save(self):
+
+ """
+ save the config file.
+
+ :rtype: integer .. number of lines saved
+
+ .. literalinclude:: ../../gozerbot/config.py
+ :pyobject: Config.save
+
+
+ """
+
+ written = []
+ curitem = None
+
+ try:
+
+ self.lock.acquire()
+
+ # read existing config file if available
+ try:
+ self.configlist = open(self.cfile, 'r').readlines()
+ except IOError:
+ self.configlist = []
+
+ # make temp file
+ configtmp = open(self.cfile + '.tmp', 'w')
+ teller = 0
+
+ # write header if not already there
+ if not self.configlist:
+ configtmp.write('# %s\n\n' % self.cfile)
+
+ # loop over original lines replacing updated data
+ for line in self.configlist:
+ teller += 1
+
+ # skip comment
+ if line.startswith('#'):
+ configtmp.write(line)
+ continue
+
+ # take part after the =
+ try:
+ keyword = line.split('=')[0].strip()
+ curitem = keyword
+ except IndexError:
+ configtmp.write(line)
+ continue
+
+ # write JSON string of data
+ if self.has_key(keyword):
+ configtmp.write('%s = %s\n' % (keyword, dumps(self[keyword])))
+ written.append(keyword)
+ else:
+ configtmp.write(line)
+
+ # write data not found in original config file
+ for keyword, value in self.iteritems():
+ if keyword in written:
+ continue
+ curitem = keyword
+ configtmp.write('%s = %s\n' % (keyword, dumps(value)))
+
+ # move temp file to original
+ configtmp.close()
+ try:
+ os.rename(self.cfile + '.tmp', self.cfile)
+ except WindowsError:
+ # no atomic operation supported on windows! error is thrown when destination exists
+ os.remove(self.cfile)
+ os.rename(self.cfile + '.tmp', self.cfile)
+ self.lock.release()
+ return teller
+
+ except Exception, ex:
+ print "ERROR WRITING %s CONFIG FILE: %s .. %s" % (self.cfile, str(ex), curitem)
+ try:
+ self.lock.release()
+ except:
+ pass
+ return
+
+ def reload(self):
+
+ """
+ reload the config file.
+
+ .. literalinclude:: ../../gozerbot/config.py
+ :pyobject: Config.reload
+
+
+ """
+
+ curline = ""
+
+ # read file and set config values to loaded JSON entries
+ try:
+
+ # open file
+ f = open(self.cfile, 'r')
+
+ # loop over data in config file
+ for line in f:
+ curline = line
+ line = line.strip()
+ if not line or line.startswith('#'):
+ continue
+ else:
+ key, value = line.split('=', 1)
+ self[key.strip()] = loads(unicode(value.strip()))
+
+ except IOError:
+ pass
+ except Exception, ex:
+ print "ERROR READING %s CONFIG FILE: %s .. %s" % (self.cfile, str(ex), curline)
+
+ def write_init(self, txt):
+
+ """
+ write initial version of the config file .. mainconfig or fleet
+ config.
+
+ :param txt: txt to write to config file
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/config.py
+ :pyobject: Config.write_init
+
+
+ """
+ if hasattr(os, 'mkdir'):
+ # check if datadir is there .. if not create it
+ if not os.path.isdir(self.dir):
+ os.mkdir(self.dir)
+
+ # check if config file is already there .. if not init it
+ if not os.path.isfile(self.cfile):
+ cfgfile = open(self.cfile, 'w')
+ cfgfile.write(txt)
+ cfgfile.close()
+
+
+mainconfigtxt = """# gozerbot config
+#
+#
+# TAKE NOTE THAT FORMAT IS IN JSON NOW SO USE " not '
+
+# GLOBAL OWNER
+
+# example: owner = ["~bart@127.0.0.1"] (include ident if needed)
+owner = []
+
+# logging level
+loglevel = 10
+
+# list of plugins to log
+loglist = []
+
+# quit message
+quitmsg = "http://gozerbot.googlecode.com"
+
+# botterdata dir mask
+mask = "700"
+
+# enable debugging
+debug = 0
+
+# database stuff
+
+nodb = 0
+db_driver = "olddb"
+dbtype = "sqlite"
+dbname = "db/main.db"
+dbhost = "localhost"
+dbuser = "bart"
+dbpasswd = "mekker2"
+
+# json backstore
+
+#jsonuser = "users.json"
+
+# loadlist
+loadlist = ["alias", "all", "at", "chanperm", "choice", "code", "core", "count", "fleet", "googletalk", "grep", "ignore", "irc", "jabber", "job", "misc", "nickcapture", "nickserv", "not", "quote", "reload", "rest", "reverse", "size", "sort", "tail", "tell", "to", "underauth", "uniq", "user", "userstate", "plug", "test", "stats", "inform", "admin", "throttle", "mysqlkeepalive", "gozernet"]
+
+# chars used to seperate result
+dotchars = " .. "
+
+# nr of lines before flood protect kicks in
+
+floodallow = 2
+
+# auto register new users
+
+auto_register = 0
+
+# resource used by xmpp bot (global)
+resource = "gozerbot"
+
+"""
+
+
+""" init txt for fleet config """
+
+
+fleetbotconfigtxt = """# gozerbot fleet bot config
+#
+#
+# TAKE NOTE THAT FORMAT IS IN JSON NOW SO USE " not '
+
+## MAIN STUFF
+
+# set to 0 to disable
+enable = 1
+
+# set type to jabber or irc
+type = "irc"
+
+# owner (irc/jabber)
+owner = []
+
+## CONNECTION STUFF
+
+# user (jabber) .. needs to be full JID because server is taken from it
+user = "botter@jsonbot.org"
+
+# nick (irc)
+nick = "gozerbot"
+
+# server (irc)
+server = ""
+
+# host (jabber) .. server to connect to
+host = ""
+
+# password (irc and jabber)
+password = ""
+
+# port (irc and jabber) .. 0 uses default value
+port = 0
+
+# ssl (irc)
+ssl = 0
+
+# use ipv6 (irc)
+ipv6 = 0
+
+# bots username (irc)
+username = "gozerbot"
+
+# bots realname (irc)
+realname = "GOZERBOT"
+
+## OTHER STUFF
+
+# default control character
+defaultcc = "!"
+
+# quit message
+quitmsg = "http://gozerbot.googlecode.com"
+
+# bindhost .. uncomment to enable
+bindhost = ""
+
+# disable limiter (irc)
+nolimiter = 0
+
+# nickserv .. set pass to enable nickserv ident (irc)
+nickservpass = ""
+nickservtxt = ["set unfiltered on"]
+
+# allow every command except OPER commands
+auto_register = 0
+
+# strip ident string
+stripident = 0
+
+loadlist = []
+
+"""
+
+# INIT SECTION
+
+# main config object
+config = Config(filename='mainconfig', inittxt=mainconfigtxt)
+
+# END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/examples.py
+++ gozerbot-0.99.1/build/lib/gozerbot/examples.py
@@ -0,0 +1,113 @@
+# gozerbot/examples.py
+#
+#
+
+"""
+ examples is a dict of example objects.
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+
+# basic imports
+import re
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+class Example(object):
+
+ """
+ an example.
+
+ :param descr: description of the example
+ :type descr: string
+ :param ex: the example
+ :type ex: string
+
+ """
+
+ def __init__(self, descr, ex):
+ self.descr = descr
+ self.example = ex
+
+class Examples(dict):
+
+ """
+ examples object is a dict.
+
+ """
+
+ def add(self, name, descr, ex):
+
+ """
+ add description and example.
+
+ :param name: name of the example
+ :type name: string
+ :param descr: description of the example
+ :type descr: string
+ :param ex: the example
+ :type ex: string
+
+ .. literalinclude:: ../../gozerbot/examples.py
+ :pyobject: Examples.add
+
+ """
+
+ self[name.lower()] = Example(descr, ex)
+
+ def size(self):
+
+ """
+ return size of examples dict.
+
+ :rtype: integer
+
+ .. literalinclude:: ../../gozerbot/examples.py
+ :pyobject: Examples.size
+
+ """
+
+ return len(self.keys())
+
+ def getexamples(self):
+
+ """
+ get all examples in list.
+
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/examples.py
+ :pyobject: Examples.getexamples
+ """
+
+ result = []
+ for i in self.values():
+ ex = i.example.lower()
+ exampleslist = re.split('\d\)', ex)
+ for example in exampleslist:
+ if example:
+ result.append(example.strip())
+ return result
+
+# ============
+# INIT SECTION
+
+# main examples object
+examples = Examples()
+
+# END INIT
+# ========
--- gozerbot-0.99.1.orig/build/lib/gozerbot/aliases.py
+++ gozerbot-0.99.1/build/lib/gozerbot/aliases.py
@@ -0,0 +1,135 @@
+# gozerbot/aliases.py
+#
+#
+
+"""
+ command aliases. this module contains the aliases of commands. aliases
+ are stored in the gozerdata/aliases.new json file.
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+### IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.persist.persist import Persist
+from gozerbot.datadir import datadir
+from gozerbot.utils.locking import lockdec
+# basic import
+import os, thread
+
+### END IMPORT
+
+## LOCK SECTION
+
+aliaslock = thread.allocate_lock()
+aliaslocked = lockdec(aliaslock)
+
+#@aliaslocked
+def aliasreverse(what):
+
+ """ get the reverse of an alias.
+
+ :param what: alias to get command for
+ :type what: string
+
+ .. literalinclude:: ../../gozerbot/aliases.py
+ :pyobject: aliasreverse
+ """
+
+ for i, j in aliases.data.iteritems():
+ if what == j:
+ return i
+
+#@aliaslocked
+def aliascheck(ievent):
+
+ """ check if alias is available.
+
+ :param ievent: event to check for aliases
+
+ .. literalinclude:: ../../gozerbot/aliases.py
+ :pyobject: aliascheck
+ """
+
+ try:
+
+ cmnd = ievent.txt.split()[0]
+ alias = aliases.data[cmnd]
+ ievent.txt = ievent.txt.replace(cmnd, alias, 1)
+ ievent.alias = alias
+ ievent.aliased = cmnd
+
+ except (IndexError, KeyError):
+ pass
+
+@aliaslocked
+def aliassave():
+
+ """ save aliases to json file.
+
+ .. literalinclude:: ../../gozerbot/aliases.py
+ :pyobject: aliassave
+ """
+
+ aliases.save()
+
+@aliaslocked
+def aliasset(fromm, to):
+
+ """ set an alias.
+
+ :param from: alias to set
+ :type from: string
+ :param to: command to alias
+ :type to: string
+
+ .. literalinclude:: ../../gozerbot/aliases.py
+ :pyobject: aliasset
+ """
+
+ aliases.data[fromm] = to
+
+@aliaslocked
+def aliasdel(fromm):
+
+ """ delete an alias.
+
+ :param fromm: alias to delete
+ :type fromm: string
+
+ .. literalinclude:: ../../gozerbot/aliases.py
+ :pyobject: aliasdel
+ """
+
+ try:
+
+ del aliases.data[fromm]
+ return 1
+
+ except KeyError:
+ pass
+
+def aliasget(fromm):
+
+ """ retrieve an alias.
+
+ :param fromm: alias to get command for
+ :type fromm: string
+
+ .. literalinclude:: ../../gozerbot/aliases.py
+ :pyobject: aliasget
+ """
+
+ if aliases.data.has_key(fromm):
+ return aliases.data[fromm]
+
+### INIT SECTION
+
+# the aliases object
+aliases = Persist(datadir + os.sep + 'aliases.new', init=False)
+if not aliases.data:
+ aliases.data = {}
+
+### END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/admin.py
+++ gozerbot-0.99.1/build/lib/gozerbot/admin.py
@@ -0,0 +1,19 @@
+# gozerbot/admin.py
+#
+#
+
+""" gozerbot admin related funtions. """
+
+
+from simplejson import loads
+
+try:
+ cmndtable = loads(open('gozerdata' + os.sep + 'run' + os.sep + 'cmndtable').read())
+except:
+ cmndtable = {}
+
+try:
+ pluginlist = loads(open('gozerdata' + os.sep + 'run' + os.sep + 'pluginlist').read())
+except:
+ pluginlist = []
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/datadir.py
+++ gozerbot-0.99.1/build/lib/gozerbot/datadir.py
@@ -0,0 +1,57 @@
+# gozerbot/datadir.py
+# -*- coding: utf-8 -*-
+#
+
+"""
+ :mod: `gozerbot.datadir` -- the datadir of the bot
+
+ .. data::
+ datadir .. points to the datadir of the bot
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# IMPORT SECTION
+
+# basic imports
+import re, os
+
+# END IMPORT
+
+def makedirs(ddir=None):
+
+ """
+ make subdirs in datadir. users, db, fleet, pgp, plugs and old.
+
+ .. literalinclude:: ../../gozerbot/datadir.py
+ :pyobject: makedirs
+
+ """
+
+ ddir = ddir or datadir
+ curdir = os.getcwd()
+
+ if not os.path.isdir(ddir):
+ os.mkdir(ddir)
+ if not os.path.isdir(ddir + '/run/'):
+ os.mkdir(ddir + '/run/')
+ if not os.path.isdir(ddir + '/users/'):
+ os.mkdir(ddir + '/users/')
+ if not os.path.isdir(ddir + '/db/'):
+ os.mkdir(ddir + '/db/')
+ if not os.path.isdir(ddir + '/fleet/'):
+ os.mkdir(ddir + '/fleet/')
+ if not os.path.isdir(ddir + '/pgp/'):
+ os.mkdir(ddir + '/pgp/')
+ if not os.path.isdir(ddir + '/plugs/'):
+ os.mkdir(ddir + '/plugs/')
+ if not os.path.isdir(ddir + '/old/'):
+ os.mkdir(ddir + '/old/')
+
+# INIT SECTION
+
+# the datadir
+datadir = 'gozerdata'
+
+# END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/reboot.py
+++ gozerbot-0.99.1/build/lib/gozerbot/reboot.py
@@ -0,0 +1,74 @@
+# gozerbot/utils/reboot.py
+#
+#
+
+"""
+ reboot code.
+
+"""
+
+## IMPORT SECTION
+
+from gozerbot.fleet import fleet
+from gozerbot.config import config
+
+from simplejson import dump
+
+import os, sys, pickle, tempfile
+
+## END IMPORT
+
+## LOCK SECTION
+
+# no locks
+
+## END LOCK
+
+def reboot():
+
+ """
+ reboot the bot.
+
+ .. literalinclude:: ../../gozerbot/reboot.py
+ :pyobject: reboot
+
+ """
+
+ fleet.exit()
+ os.execl(sys.argv[0], *sys.argv)
+
+def reboot_stateful(bot, ievent, fleet, partyline):
+ """
+ reboot the bot, but keep the connections.
+
+ :param bot: bot on which the reboot command is given
+ :type bot: gozerbot.botbase.BotBase
+ :param ievent: event that triggered the reboot
+ :type ievent: gozerbot.eventbase. EventBase
+ :param fleet: the fleet of the bot
+ :type fleet: gozerbot.fleet.Fleet
+ :param partyline: partyline of the bot
+ :type partyline: gozerbot.partyline.PartyLine
+
+ .. literalinclude:: ../../gozerbot/reboot.py
+ :pyobject: reboot_stateful
+
+ """
+ config.reload()
+ session = {'bots': {}, 'name': bot.name, 'channel': ievent.channel, 'partyline': []}
+
+ for i in fleet.bots:
+ session['bots'].update(i._resumedata())
+
+ session['partyline'] = partyline._resumedata()
+ sessionfile = tempfile.mkstemp('-session', 'gozerbot-')[1]
+ dump(session, open(sessionfile, 'w'))
+ fleet.save()
+ fleet.exit(jabber=True)
+ os.execl(sys.argv[0], sys.argv[0], '-r', sessionfile)
+
+## INIT SECTION
+
+# no vars
+
+## END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/fleet.py
+++ gozerbot-0.99.1/build/lib/gozerbot/fleet.py
@@ -0,0 +1,654 @@
+# gozerbot/fleet.py
+#
+#
+
+""" fleet is a list of bots. """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+# gozerbot imports
+
+from gozerbot.datadir import datadir
+from utils.exception import handle_exception
+from utils.generic import waitforqueue
+from utils.log import rlog
+from utils.locking import lockdec
+from threads.thr import start_new_thread, threaded
+from config import Config, fleetbotconfigtxt, config
+from users import users
+from plugins import plugins
+from simplejson import load
+
+# basic imports
+
+import Queue, os, types, threading, time, pickle, glob, logging, shutil, thread
+
+# END IMPORT
+
+# ============
+# LOCK SECTION
+
+fleetlock = thread.allocate_lock()
+fleetlocked = lockdec(fleetlock)
+
+# END LOCK
+# ========
+
+## START
+
+class FleetBotAlreadyExists(Exception):
+ pass
+
+
+class Fleet(object):
+
+ """
+ a fleet contains multiple bots (list of bots). used the datadir
+ set in gozerbot/datadir.py
+
+ """
+
+ def __init__(self):
+ self.datadir = datadir + os.sep + 'fleet'
+ if hasattr(os, 'mkdir'):
+ if not os.path.exists(self.datadir):
+ os.mkdir(self.datadir)
+ self.startok = threading.Event()
+ self.bots = []
+
+ def getfirstbot(self):
+
+ """
+ return the main bot of the fleet.
+
+ :rtype: gozerbot.botbase.BotBase
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.getfirstbot
+
+ """
+ self.startok.wait()
+ return self.bots[0]
+
+ def getfirstjabber(self):
+
+ """
+ return the first jabber bot of the fleet.
+
+ :rtype: gozerbot.botbase.BotBase
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.getfirstjabber
+
+ """
+
+ self.startok.wait()
+
+ for bot in self.bots:
+ if bot.type == 'xmpp':
+ return bot
+
+ def size(self):
+
+ """
+ return number of bots in fleet.
+
+ :rtype: integer
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.size
+
+ """
+
+ return len(self.bots)
+
+ def resume(self, sessionfile):
+
+ """
+ resume bot from session file.
+
+ :param sessionfile: filename of the session data file
+ :type sessionfile: string
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.resume
+ """
+
+ # read JSON session file
+ session = load(open(sessionfile))
+
+ # resume bots in session file
+ for name in session['bots'].keys():
+ reto = None
+ if name == session['name']:
+ reto = session['channel']
+ start_new_thread(self.resumebot, (name, session['bots'][name], reto))
+
+ # allow 5 seconds for bots to resurrect
+ time.sleep(5)
+
+ # set start event
+ self.startok.set()
+
+ def makebot(self, name, cfg=None):
+
+ """
+ create a bot .. use configuration if provided.
+
+ :param name: the name of the bot
+ :type name: string
+ :param cfg: configuration file for the bot
+ :type cfg: gozerbot.config.Config
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.makebot
+
+ """
+
+ if self.byname(name):
+ raise FleetBotAlreadyExists("there is already a %s bot in the fleet" % name)
+
+ rlog(10, 'fleet', 'making bot')
+ bot = None
+
+ # if not config create a default bot
+ if not cfg:
+ cfg = Config(self.datadir + os.sep + name, 'config', inittxt=fleetbotconfigtxt)
+ cfg.save()
+
+ # create bot based on type
+ if cfg['type'] == 'irc':
+ from gozerbot.irc.bot import Bot
+ bot = Bot(name, cfg)
+ elif cfg['type'] == 'xmpp' or cfg['type'] == 'jabber':
+ from gozerbot.xmpp.bot import Bot
+ bot = Bot(name, cfg)
+ elif cfg['type'] == 'gozernet':
+ from gozerbot.gozernet.bot import GozerNetBot
+ bot = GozerNetBot(name, cfg)
+ else:
+ rlog(10, 'fleet', '%s .. unproper type: %s' % (cfg['name'], cfg['type']))
+
+ # set bot name and initialize bot
+ if bot:
+ cfg['name'] = bot.name = name
+ self.initbot(bot)
+ return bot
+
+ # failed to created the bot
+ raise Exception("can't make %s bot" % name)
+
+ def resumebot(self, botname, data={}, printto=None):
+
+ """
+ resume individual bot.
+
+ :param botname: name of the bot to resume
+ :type botname: string
+ :param data: resume data
+ :type data: dict
+ :param printto: whom to reply to that resuming is done
+ :type printto: nick or JID
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.resumebot
+
+ """
+
+ # see if we need to exit the old bot
+ oldbot = self.byname(botname)
+ if oldbot:
+ oldbot.exit()
+
+ # recreate config file of the bot
+ cfg = Config(datadir + os.sep + 'fleet' + os.sep + botname, 'config')
+
+ # make the bot and resume (IRC) or reconnect (Jabber)
+ bot = self.makebot(botname, cfg)
+ rlog(100, 'fleet', 'bot made: %s' % str(bot))
+
+ if bot:
+ if oldbot:
+ self.replace(oldbot, bot)
+ else:
+ self.bots.append(bot)
+
+ if not bot.jabber:
+ bot._resume(data, printto)
+ else:
+ start_new_thread(bot.connectwithjoin, ())
+
+ def start(self, botlist=[], enable=False):
+
+ """
+ startup the bots.
+
+ :param botlist: list of bots to start .. if not provided the bots in the gozerdata/fleet dir will be used
+ :type botlist: list
+ :param enable: whether the bot should be enabled
+ :type enable: boolean
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.start
+
+ """
+
+ # scan the fleet datadir for bots
+ dirs = []
+ got = []
+ for bot in botlist:
+ dirs.append(self.datadir + os.sep + bot)
+
+ if not dirs:
+ dirs = glob.glob(self.datadir + os.sep + "*")
+
+ for fleetdir in dirs:
+
+ if fleetdir.endswith('fleet'):
+ continue
+
+ rlog(10, 'fleet', 'found bot: ' + fleetdir)
+ cfg = Config(fleetdir, 'config')
+
+ if not cfg:
+ rlog(10, 'fleet', "can't read %s config file" % fleetdir)
+ continue
+
+ name = fleetdir.split(os.sep)[-1]
+
+ if not name:
+ rlog(10, 'fleet', "can't read botname from %s config file" % \
+fleetdir)
+ continue
+
+ if not enable and not cfg['enable']:
+ rlog(10, 'fleet', '%s bot is disabled' % name)
+ continue
+ else:
+ rlog(10, 'fleet', '%s bot is enabled' % name)
+
+ if not name in fleetdir:
+ rlog(10, 'fleet', 'bot name in config file doesnt match dir name')
+ continue
+
+ try:
+ bot = self.makebot(name, cfg)
+ except FleetBotAlreadyExists:
+ rlog(10, 'fleet', 'there is already a fleetbot with the name %s' % name)
+ continue
+
+ if bot:
+ self.addbot(bot)
+ start_new_thread(bot.connectwithjoin, ())
+ got.append(bot)
+
+ # set startok event
+ self.startok.set()
+
+ return got
+
+ def save(self):
+
+ """
+ save fleet data and call save on all the bots.
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.save
+
+ """
+
+ for i in self.bots:
+
+ try:
+ i.save()
+ except Exception, ex:
+ handle_exception()
+
+ def avail(self):
+
+ """
+ show available fleet bots.
+
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.avail
+
+ """
+
+ return os.listdir(self.datadir)
+
+ def list(self):
+
+ """
+ return list of bot names.
+
+ :rtype: list
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.list
+
+ """
+
+ result = []
+
+ for i in self.bots:
+ result.append(i.name)
+
+ return result
+
+ def stopall(self):
+
+ """
+ call stop() on all fleet bots.
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.stopall
+
+ """
+
+ for i in self.bots:
+
+ try:
+ i.stop()
+ except:
+ pass
+
+ def byname(self, name):
+
+ """
+ return bot by name.
+
+ :param name: name of the bot
+ :type name: string
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.byname
+
+ """
+
+ for i in self.bots:
+ if name == i.name:
+ return i
+
+ def replace(self, name, bot):
+
+ """
+ replace bot with a new bot.
+
+ :param name: name of the bot to replace
+ :type name: string
+ :param bot: bot to replace old bot with
+ :type bot: gozerbot.botbase.BotBase
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.replace
+
+ """
+
+ for i in range(len(self.bots)):
+ if name == self.bots[i].name:
+ self.bots[i] = bot
+ return
+
+ def initbot(self, bot):
+
+ """
+ initialise a bot.
+
+ :param bot: bot to initialise
+ :type bot: gozerbot.botbase.BotBase
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.initbot
+
+ """
+
+ if bot not in self.bots:
+
+ if not os.path.exists(self.datadir + os.sep + bot.name):
+ os.mkdir(self.datadir + os.sep + bot.name)
+
+ if type(bot.cfg['owner']) == types.StringType or type(bot.cfg['owner']) == types.UnicodeType:
+ bot.cfg['owner'] = [bot.cfg['owner'], ]
+ bot.cfg.save()
+
+ users.make_owner(config['owner'] + bot.cfg['owner'])
+ rlog(10, 'fleet', 'added bot: ' + bot.name)
+
+ @fleetlocked
+ def addbot(self, bot):
+
+ """
+ add a bot to the fleet .. remove all existing bots with the
+ same name.
+
+ :param bot: bot to add
+ :type bot: gozerbot.botbase.BotBase
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.addbot
+
+ """
+
+ if bot:
+
+ for i in range(len(self.bots)-1, -1, -1):
+ if self.bots[i].name == bot.name:
+ rlog(10, 'fleet', 'removing %s from fleet' % bot.name)
+ del self.bots[i]
+
+ rlog(10, 'fleet', 'adding %s' % bot.name)
+ self.bots.append(bot)
+ return True
+
+ return False
+
+ def connect(self, name):
+
+ """
+ connect bot to the server.
+
+ :param name: name of the bot
+ :type name: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.connect
+
+ """
+
+ for i in self.bots:
+
+ if i.name == name:
+ got = i.connect()
+
+ if got:
+ start_new_thread(i.joinchannels, ())
+ return True
+ else:
+ return False
+
+ @fleetlocked
+ def delete(self, name):
+
+ """
+ delete bot with name from fleet.
+
+ :param name: name of bot to delete
+ :type name: string
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.delete
+
+ """
+
+ for i in self.bots:
+
+ if i.name == name:
+ i.exit()
+ self.remove(i)
+ i.cfg['enable'] = 0
+ i.cfg.save()
+ rlog(10, 'fleet', '%s disabled' % i.name)
+ return True
+
+ return False
+
+
+ def remove(self, bot):
+
+ """
+ delete bot by object.
+
+ :param bot: bot to delete
+ :type bot: gozerbot.botbase.BotBase
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.remove
+
+ """
+
+ try:
+ self.bots.remove(bot)
+ return True
+ except ValueError:
+ return False
+
+ def exit(self, name=None, jabber=False):
+
+ """
+ call exit on all bots. if jabber=True only jabberbots will exit.
+
+ :param name: name of the bot to exit. if not provided all bots will exit.
+ :type name: string
+ :param jabber: flag to set when only jabberbots should exit
+ :type jabber: boolean
+ :rtype: boolean
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.exit
+
+ """
+
+ if not name:
+ threads = []
+
+ for i in self.bots:
+ if jabber and not i.jabber:
+ pass
+ else:
+ threads.append(start_new_thread(i.exit, ()))
+
+ for thr in threads:
+ thr.join()
+
+ return
+
+
+ for i in self.bots:
+
+ if i.name == name:
+ try:
+ i.exit()
+ except:
+ handle_exception()
+ self.remove(i)
+ return True
+
+ return False
+
+ def cmnd(self, event, name, cmnd):
+
+ """
+ do command on a bot.
+
+ :param event: event to pass on to the dispatcher
+ :type event: gozerbot.event.EventBase
+ :param name: name of the bot to pass on to the dispatcher
+ :type name: string
+ :param cmnd: command to execute on the fleet bot
+ :type cmnd: string
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.cmnd
+
+ """
+
+ bot = self.byname(name)
+
+ if not bot:
+ return 0
+
+ from gozerbot.eventbase import EventBase
+ j = plugins.clonedevent(bot, event)
+ j.onlyqueues = True
+ j.txt = cmnd
+ q = Queue.Queue()
+ j.queues = [q]
+ j.speed = 3
+ start_new_thread(plugins.trydispatch, (bot, j))
+ result = waitforqueue(q)
+
+ if not result:
+ return
+
+ res = ["<%s>" % bot.name, ]
+ res += result
+ event.reply(res)
+
+ def cmndall(self, event, cmnd):
+
+ """
+ do a command on all bots.
+
+ :param event: event to pass on to dispatcher
+ :type event: gozerbot.eventbase.EventBase
+ :param cmnd: the command string to execute
+ :type cmnd: string
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.cmndall
+
+ """
+
+ threads = []
+
+ for i in self.bots:
+ thread = start_new_thread(self.cmnd, (event, i.name, cmnd))
+ threads.append(thread)
+
+ for i in threads:
+ i.join()
+
+ def broadcast(self, txt):
+
+ """
+ broadcast txt to all bots.
+
+ :param txt: text to broadcast on all bots
+ :type txt: string
+
+ .. literalinclude:: ../../gozerbot/fleet.py
+ :pyobject: Fleet.broadcast
+
+ """
+
+ for i in self.bots:
+ i.broadcast(txt)
+
+# ============
+# INIT SECTION
+
+
+# main fleet object
+fleet = Fleet()
+
+# END INIT
+# ========
--- gozerbot-0.99.1.orig/build/lib/gozerbot/eggs.py
+++ gozerbot-0.99.1/build/lib/gozerbot/eggs.py
@@ -0,0 +1,188 @@
+# gozerbot/eggs.py
+#
+#
+
+"""
+
+ :mod: `gozerbot.eggs` -- eggs related functions
+
+ this module is used to load the eggs on which gozerbot depends from
+ specified dir .. most of the time this is the gozernest dir.
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+# IMPORT SECTION
+
+import os, sys
+from utils.exception import handle_exception
+from utils.log import rlog
+
+# END IMPORT
+
+mainenv = None
+
+def init(eggdir, log=False):
+
+ """
+ make sure setuptools is available.
+
+ :param eggdir: directory to scan for eggs
+ :type eggdir: string
+ :param log: whether to log the registration of the setuptools egg
+ :type log: True or False
+
+ .. literalinclude:: ../../gozerbot/eggs.py
+ :pyobject: init
+
+ """
+
+ try:
+ import setuptools
+ except ImportError, ex:
+ try:
+ sys.path.insert(0, eggdir)
+ for egg in os.listdir(eggdir):
+ if egg.startswith('setuptools'):
+ log and rlog(10, 'eggs', 'loaded %s' % egg)
+ sys.path.insert(0, eggdir + os.sep + egg)
+ except OSError:
+ pass
+
+latest = {}
+
+def enable_egg(env, egg, log=True):
+
+ """
+ search for the latest version of an egg in the enviroment and put
+ it on sys.path.
+
+ :param env: the environment to search the egg in
+ :type env: pkg_resources.Environment
+ :param egg: egg to load or find a newer version for
+ :param log: determine if we should log the enabling of the egg
+
+ .. literalinclude:: ../../gozerbot/eggs.py
+ :pyobject: enable_egg
+
+ """
+
+ try:
+ from pkg_resources import DistributionNotFound, VersionConflict, working_set, parse_requirements, require
+
+ if not latest.has_key(egg.project_name):
+ latest[egg.project_name] = egg
+
+ req = egg.as_requirement()
+ reqstr = str(req)
+ reqq = parse_requirements([reqstr.replace('==', '>='), ])
+ for e in working_set.resolve(reqq, mainenv):
+ if e.location not in sys.path:
+ env.add(e)
+ working_set.add(e)
+ working_set.add_entry(e.location)
+ latest[egg.project_name] = e
+ sys.path.insert(0, egg.location)
+ log and rlog(3, 'eggs', 'loaded %s' % e)
+ else:
+ log and rlog(3, 'eggs', '%s already on path' % e)
+ except DistributionNotFound, ex:
+ env.add(egg)
+ working_set.add(egg)
+ working_set.add_entry(egg.location)
+ latest[egg.project_name] = egg
+ sys.path.insert(0, egg.location)
+ log and rlog(3, 'eggs', 'loaded %s' % egg)
+ except VersionConflict, ex:
+ if egg > ex[0]:
+ env.add(egg)
+ working_set.add_entry(egg.location)
+ working_set.add(egg)
+ latest[egg.project_name] = egg
+ sys.path.insert(0, egg.location)
+ log and rlog(3, 'eggs', 'override %s' % egg)
+
+def loadegg(name, eggdirs=['gozernest',], log=True):
+
+ """
+ scan eggdir for a egg matching `name`.
+
+ :param name: piece of txt which should be in the egg projectname
+ :type name: string
+ :param eggdirs: directories to search in
+ :type eggdirs: list
+ :param log: boolean which indicates whether loading should be logged
+ :type log: boolean
+
+ .. literalinclude:: ../../gozerbot/eggs.py
+ :pyobject: loadegg
+
+ """
+
+ try:
+ from pkg_resources import find_distributions, Environment
+ global mainenv
+
+ for eggdir in eggdirs:
+ if mainenv:
+ mainenv += Environment(eggdir)
+ else:
+ mainenv = Environment(eggdir)
+ eggs = find_distributions(eggdir)
+ for egg in eggs:
+ if name.lower() in egg.project_name.lower():
+ enable_egg(mainenv, egg, log)
+
+ except ImportError:
+ return
+ except Exception, ex:
+ handle_exception()
+
+def loadeggs(eggdir, log=True):
+
+ """
+ load all eggs in a directory.
+
+ :param eggdir: directory to load eggs from
+ :type eggdir: string
+
+ .. literalinclude:: ../../gozerbot/eggs.py
+ :pyobject: loadeggs
+
+ """
+
+ rlog(3, 'eggs', 'scanning %s' % eggdir)
+ try:
+ from pkg_resources import find_distributions, Environment
+ global mainenv
+
+ if mainenv:
+ mainenv += Environment(eggdir)
+ else:
+ mainenv = Environment(eggdir)
+ eggs = find_distributions(eggdir)
+ for egg in eggs:
+ if not egg.project_name.startswith('setuptools'):
+ enable_egg(mainenv, egg, log)
+
+ except ImportError:
+ return
+ except Exception, ex:
+ handle_exception()
+
+ res = []
+ for name, egg in latest.iteritems():
+ res.append("%s: %s" % (name, egg.version))
+
+ rlog(3, 'eggs', 'loaded: %s' % ' .. '.join(res))
+
+
+# INIT SECTION
+
+
+# first search for setuptools and load it
+init(os.getcwd())
+init(os.getcwd() + os.sep + 'gozernest')
+
+# END INIT
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/persistconfig.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/persistconfig.py
@@ -0,0 +1,420 @@
+# gozerbot/persistconfig.py
+#
+#
+
+""" allow data to be pickled to disk .. creating the persisted object
+ restores data
+
+usage:
+ !plug-cfg -> shows list of all config
+ !plug-cfg key value -> sets value to key
+ !plug-cfg key -> shows list of key
+ !plug-cfg key add value -> adds value to list
+ !plug-cfg key remove value -> removes value from list
+ !plug-cfg key clear -> clears entire list
+ !plug-cfgsave -> force save configuration to disk
+
+todo:
+ - plugin api (more work needed?)
+
+"""
+
+__copyright__ = 'this file is in the public domain'
+__author__ = 'Bas van Oostveen'
+
+from gozerbot.utils.log import rlog
+from gozerbot.utils.trace import calledfrom
+from gozerbot.compat.persist import Persist
+from gozerbot.commands import cmnds, Command
+from gozerbot.examples import examples
+from gozerbot.datadir import datadir
+import sys, os, types, time
+
+class Option(object):
+
+ def __init__(self, value, desc, perm, example, name, exposed):
+ assert isinstance(name, str), "Option.self.name must be a string"
+ self.value = value
+ self.desc = desc
+ self.perm = perm
+ self.example = example
+ self.name = name.lower()
+ self.exposed = exposed
+
+ def __casattr__(self, name, val):
+ # Update option if needed
+ if not hasattr(self, name):
+ setattr(self, name, val)
+ return True
+ else:
+ #if val and getattr(self, name)!=val: # old style
+ if val != None and type(getattr(self, name)) != type(val):
+ setattr(self, name, val)
+ return True
+ return False
+
+ def check(self, key, plugname, value, desc, perm, example, name, exposed):
+ upd = False
+ # maybe checking value is too much here
+ if self.__casattr__("value", value): upd = True
+ if self.__casattr__("example", example): upd = True
+ if self.__casattr__("name", name): upd = True
+ if self.__casattr__("perm", perm): upd = True
+ if self.__casattr__("exposed", exposed): upd = True
+ if self.name == None:
+ self.name = "%s-cfg-%s" % (plugname, str(key))
+ upd = True
+ return upd
+
+ def __lt__(self, other):
+ return self.value < other
+
+ def __le__(self, other):
+ return self.value <= other
+
+ def __eq__(self, other):
+ return self.value == other
+
+ def __ne__(self, other):
+ return self.value != other
+
+ def __gt__(self, other):
+ return self.value >= other
+
+ def __ge__(self, other):
+ return self.value >= other
+
+class LazyValueDict(object):
+
+ """ emulates the normal Persist.data (key, value) dict """
+
+ def __init__(self, cfg):
+ self.__cfg = cfg
+
+ def __len__(self):
+ return len(self.__persistData)
+
+ def __getitem__(self, key):
+ return self.__cfg.data[key].value
+
+ def __setitem__(self, key, value):
+ if not self.__cfg.data.has_key(key) or not \
+isinstance(self.__cfg.data[key], Option):
+ name = "%s-cfg-%s" % (self.__cfg.plugname, str(key))
+ self.__cfg.define(value, "", 'OPER', "", name, exposed=False)
+ self.__cfg.set(key, value)
+
+ def __delitem__(self, key):
+ raise Exception("Direct deletion not supported, use \
+persistConfig.undefine()")
+
+ def __iter__(self):
+ return self.__cfg.data.__iter__()
+
+ def iterkeys(self):
+ return self.__iter__()
+
+ def __contains__(self, item):
+ return self.__cfg.data.has_key(item)
+
+class PersistConfigError(Exception): pass
+
+class PersistConfig(Persist):
+
+ """ persist plugin configuration and create default handlers """
+
+ def __init__(self):
+ self.__basename__ = self.__class__.__name__
+ self.plugname = calledfrom(sys._getframe())
+ Persist.__init__(self, os.path.join(datadir, "%s-config" % \
+self.plugname), {})
+ self.__callbacks = {}
+ cmndname = "%s-cfg" % self.plugname
+ rlog(-3, 'persistconfig', 'added command %s (%s)' % (cmndname, \
+self.plugname))
+ cmnds[cmndname] = Command(self.cmnd_cfg, 'OPER', self.plugname, \
+threaded=True)
+ examples.add(cmndname, "plugin configuration", cmndname)
+ cmndnamesave = cmndname + "save"
+ cmnds[cmndnamesave] = Command(self.cmnd_cfgsave, 'OPER', \
+self.plugname, threaded=True)
+ examples.add(cmndnamesave, "save plugin configuration", cmndnamesave)
+
+ def __getattribute__(self, name):
+ # make sure the attribute data is not called from Persist or
+ # PersistConfig returning a persist compatible (key, value) dict
+ # instead of the rich persistconfig
+ cf = calledfrom(sys._getframe())
+ ## (key, option(value, ...)) is only for persistconfig internal usage.
+ if name == "data" and cf != "persistconfig" and cf != "persist" and \
+cf != self.__basename__:
+ # intercept data block, return a clean dict with lazy binding
+ # to option.value
+ return LazyValueDict(self)
+ return super(PersistConfig, self).__getattribute__(name)
+
+ def handle_callback(self, event, key, value=None):
+ if self.__callbacks.has_key((key, event)):
+ cb, extra_data = self.__callbacks[(key, event)]
+ if callable(cb):
+ cb(key, value, event, extra_data)
+ else:
+ rlog(5, 'persistconfig', 'invalid callback for %s %s' % (key, \
+event))
+ del self.__callbacks[(key, event)]
+
+ ### cmnds
+
+ def show_cfg(self, bot, ievent):
+ s = []
+ for key, option in sorted(self.data.items()):
+ if not isinstance(option, Option):
+ rlog(5, 'persistconfig', 'Option %s is not a valid option' % \
+key)
+ continue
+ if not option.exposed:
+ continue
+ v = option.value
+ if type(v) in [str, unicode]:
+ v = '"'+v+'"'
+ v = str(v)
+ s.append("%s=%s" % (key, v))
+ ievent.reply("options: " + ' .. '.join(s))
+
+ def cmnd_cfgsave(self, bot, ievent):
+ self.save()
+ ievent.reply("config saved")
+
+ def cmnd_cfg_edit(self, bot, ievent, args, key, option):
+ if type(option.value) == types.ListType:
+ if args[0].startswith("[") and args[-1].endswith("]"):
+ values = []
+ for v in ' '.join(args)[1:-1].replace(", ", ",").split(","):
+ if v[0]=='"' and v[-1]=='"':
+ # string
+ v = v.replace('"', '')
+ elif v[0]=="'" and v[-1]=="'":
+ # string
+ v = v.replace("'", "")
+ elif '.' in v:
+ # float
+ try:
+ v = float(v)
+ except ValueError:
+ ievent.reply("invalid long literal: %s" % v)
+ return
+ else:
+ # int
+ try:
+ v = int(v)
+ except ValueError:
+ ievent.reply("invalid int literal: %s" % v)
+ return
+ values.append(v)
+ self.set(key, values)
+ ievent.reply("%s set %s" % (key, values))
+ return
+ command = args[0]
+ value = ' '.join(args[1:])
+ if command == "clear":
+ self.clear(key)
+ ievent.reply("list empty")
+ elif command == "add":
+ self.append(key, value)
+ ievent.reply("%s added %s" % (key, value))
+ elif command == "remove" or command == "del":
+ try:
+ self.remove(key, value)
+ ievent.reply("%s removed" % str(value))
+ except ValueError:
+ ievent.reply("%s is not in list" % str(value))
+ else:
+ ievent.reply("invalid command")
+ return
+ else:
+ value = ' '.join(args)
+ try:
+ value = type(option.value)(value)
+ except:
+ pass
+ if type(value) == type(option.value):
+ self.set(key, value)
+ ievent.reply("%s set" % key)
+ elif type(value) == types.LongType and \
+type(option.value) == types.IntType:
+ # allow upscaling from int to long
+ self.set(key, value)
+ ievent.reply("%s set" % key)
+ else:
+ ievent.reply("value %s (%s) is not of the same type as %s \
+(%s)" % (value, type(value), option.value, type(option.value)))
+
+ def cmnd_cfg(self, bot, ievent):
+ if not ievent.args:
+ self.show_cfg(bot, ievent)
+ return
+ argc = len(ievent.args)
+ key = ievent.args[0]
+ try:
+ option = self.data[key]
+ except KeyError:
+ ievent.reply("%s option %s not found" % (self.plugname, key))
+ return
+ if not isinstance(option, Option):
+ rlog(5, 'persistconfig', 'Option %s is not a valid option' % key)
+ return
+ if not option.exposed:
+ return
+ if argc == 1:
+ ievent.reply(str(option.value))
+ return
+ self.cmnd_cfg_edit(bot, ievent, ievent.args[1:], key, option)
+
+ def generic_cmnd(self, key):
+ def func(bot, ievent):
+ try:
+ option = self.data[key]
+ except KeyError:
+ ievent.reply("%s not found" % key)
+ # need return ?
+ if not isinstance(option, Option):
+ rlog(5, 'persistconfig', 'Option %s is not a valid option' % \
+key)
+ return
+ if ievent.args:
+ value = ' '.join(ievent.args)
+ try:
+ value = type(option.value)(value)
+ except:
+ pass
+ self.cmnd_cfg_edit(bot, ievent, ievent.args, key, option)
+ else:
+ ievent.reply(str(option.value))
+ return func
+
+ ### plugin api
+
+ def define(self, key, value=None, desc="plugin option", perm='OPER', \
+example="", name=None, exposed=True):
+ if name:
+ name = name.lower()
+ if not self.data.has_key(key):
+ if name == None:
+ name = "%s-cfg-%s" % (self.plugname, str(key))
+ option = Option(value, desc, perm, example, name, exposed)
+ self.data[key] = option
+ self.save()
+ else:
+ option = self.data[key]
+ # if unpickled option is not of class Option recreate the option
+ # also if the type of value has changed recreate the option
+ # exception if value got upgraded from int to long, then nothing
+ # has to be changed
+ if not isinstance(option, Option):
+ if name == None:
+ name = "%s-cfg-%s" % (self.plugname, str(key))
+ if type(value) == type(option):
+ value = option
+ option = Option(value, desc, perm, example, name, exposed)
+ self.data[key] = option
+ self.save()
+ else:
+ if type(option.value) == types.LongType and \
+type(value) == types.IntType:
+ value = long(value)
+ if option.check(key, self.plugname, value, desc, perm, \
+example, name, exposed):
+ self.data[key] = option
+ self.save()
+
+ def undefine(self, key, throw=False):
+ try:
+ option = self.data[key]
+ if option.exposed:
+ if cmnds.has_key(option.name):
+ del cmnds[option.name]
+ if examples.has_key(option.name):
+ del examples[option.name]
+ del self.data[key]
+ self.save()
+ return True
+ except KeyError, e:
+ if throw:
+ raise
+ return False
+
+ def checkoption(self, key):
+ if not isinstance(self.data[key], Option):
+ raise PersistConfigError("Option %s is not a valid option" % key)
+ return True
+
+ def set(self, key, value, throw=False):
+ if type(value)==unicode:
+ value = str(value)
+ try:
+ self.checkoption(key)
+ except (KeyError, PersistConfigError):
+ if throw:
+ raise
+ self.define(key, value)
+ self.handle_callback('change', key, value)
+ else:
+ self.data[key].value = value
+ self.handle_callback('change', key, value)
+ self.save()
+
+ def append(self, key, value):
+ self.checkoption(key)
+ self.data[key].value.append(value)
+ self.save()
+ self.handle_callback('change', key, value)
+ self.handle_callback('add', key, value)
+
+ def remove(self, key, value):
+ self.checkoption(key)
+ self.data[key].value.remove(value)
+ self.save()
+ self.handle_callback('change', key, value)
+ self.handle_callback('remove', key, value)
+
+ def clear(self, key):
+ self.checkoption(key)
+ self.data[key].value = []
+ self.save()
+ self.handle_callback('change', key, [])
+ self.handle_callback('clear', key)
+
+ def get(self, key, default=None):
+ try:
+ return self.data[key].value
+ except KeyError:
+ return default
+
+ def has_key(self, key):
+ return self.data.has_key(key)
+
+ def callback(self, key, event, callback, extra_data=None):
+ callbacks = ["change", "add", "remove", "clear"]
+ if not event in callbacks:
+ raise PersistConfigError("Unsupported callback event %s" % event)
+ self.__callbacks[(key, event)] = (callback, extra_data)
+
+ def syncold(self, filename, remove=False):
+ """ sync with old config data """
+ if os.path.isfile(filename):
+ synckey = "persistconfig-syncold"
+ oldconfig = Persist(filename)
+ if not oldconfig.data.has_key(synckey):
+ rlog(10, 'persistconfig', "syncing old config %s with \
+persistconfig" % filename)
+ for i, j in oldconfig.data.iteritems():
+ if i == synckey:
+ continue
+ if j and not self.get(i):
+ self.set(i, oldconfig.data[i])
+ oldconfig.data[synckey] = time.localtime()
+ oldconfig.save()
+ del oldconfig
+ if remove:
+ os.unlink(filename)
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/persist.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/persist.py
@@ -0,0 +1,64 @@
+# gozerbot/persist.py
+#
+#
+
+""" allow data to be pickled to disk .. creating the persisted object
+ restores data
+"""
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.utils.log import rlog
+import cPickle, thread, os, copy
+
+saving = []
+stopsave = 0
+
+class Persist(object):
+
+ """ persist data attribute to pickle file """
+
+ def __init__(self, filename, default=None):
+ rlog(1, 'compat-persist', 'reading %s' % filename)
+ self.fn = filename
+ self.lock = thread.allocate_lock()
+ self.data = None
+ # load data from pickled file
+ try:
+ datafile = open(filename, 'r')
+ except IOError:
+ if default != None:
+ self.data = copy.deepcopy(default)
+ return
+ try:
+ self.data = cPickle.load(datafile)
+ datafile.close()
+ except:
+ if default != None:
+ self.data = copy.deepcopy(default)
+ else:
+ rlog(100, 'compat-persist', 'ERROR: %s' % filename)
+ raise
+
+ def save(self):
+ """ save persist data """
+ if stopsave:
+ rlog(100, 'compat-persist', 'stopping mode .. not saving %s' % self.fn)
+ return
+ try:
+ saving.append(str(self.fn))
+ self.lock.acquire()
+ # first save to temp file and when done rename
+ tmp = self.fn + '.tmp'
+ try:
+ datafile = open(tmp, 'w')
+ except IOError:
+ rlog(100, 'compat-persist', "can't save %s" % self.fn)
+ return
+ cPickle.dump(self.data, datafile)
+ datafile.close()
+ os.rename(tmp, self.fn)
+ rlog(10, 'compat-persist', '%s saved' % self.fn)
+ finally:
+ saving.remove(self.fn)
+ self.lock.release()
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/users.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/users.py
@@ -0,0 +1,246 @@
+# gozerbot/users.py
+#
+#
+
+""" bot's users """
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.datadir import datadir
+from gozerbot.utils.log import rlog
+from gozerbot.utils.generic import stripident, stripidents
+from gozerbot.utils.exception import handle_exception
+from gozerbot.utils.generic import die, stripped
+from gozerbot.compat.persist import Persist
+from gozerbot.config import config
+import re, types, os
+
+config.load()
+
+class User(object):
+
+ """ repesents a user """
+
+ def __init__(self, name, userhosts, perms):
+ self.name = str(name)
+ self.userhosts = list(userhosts)
+ self.perms = list(perms)
+ self.email = ""
+ self.permit = []
+ self.status = []
+ self.passwd = ""
+ self.allowed = []
+ self.notallowed = []
+ self.tempuserhosts = []
+ self.userdata = {}
+
+ def __str__(self):
+ return "name: %s userhosts: %s perms: %s email: %s status: %s \
+allowed: %s notallowed: %s tempusershosts: %s permit: %s" % (self.name, \
+self.userhosts, self.perms, self.email, self.status, self.allowed, \
+self.notallowed, self.tempuserhosts, self.permit)
+
+class Users(Persist):
+
+ """ holds multiple users """
+
+ def __init__(self, filename):
+ self.userhosts = {}
+ self.masks = {}
+ self.compiled = {}
+ Persist.__init__(self, filename)
+ if not self.data:
+ self.data = []
+ for i in self.data:
+ for j in i.userhosts:
+ self.adduserhost(j, i)
+
+ def adduserhost(self, userhost, user):
+ """ add userhost/mask """
+ if '?' in userhost or '*' in userhost:
+ tmp = re.escape(userhost)
+ tmp = tmp.replace('\?','.')
+ tmp = tmp.replace('\*','.*?')
+ regex = re.compile(tmp)
+ self.compiled[regex] = user
+ self.masks[userhost] = regex
+ else:
+ self.userhosts[userhost] = user
+
+ def deluserhost(self, userhost):
+ """ del userhost/mask """
+ try:
+ if '?' in userhost or '*' in userhost:
+ regex = self.masks[userhost]
+ del self.compiled[regex]
+ del self.masks[userhost]
+ else:
+ del self.userhosts[userhost]
+ return 1
+ except KeyError:
+ return 0
+
+ def exist(self, name):
+ """ see if user with username exists """
+ name = name.lower()
+ for i in self.data:
+ if i.name == name:
+ return 1
+
+ def getperms(self, userhost):
+ """ get permissions """
+ user = self.getuser(userhost)
+ if user:
+ return user.perms
+ else:
+ return ['ANON', ]
+
+ def getuser(self, userhost):
+ """ get user for which userhost matches """
+ userhost = stripident(userhost)
+ if userhost in self.userhosts:
+ return self.userhosts[userhost]
+ else:
+ for i in self.compiled:
+ if re.search(i, userhost):
+ return self.compiled[i]
+ for user in self.data:
+ for i in user.userhosts:
+ if i == userhost or i == stripped(userhost):
+ return user
+ return None
+
+ def gotperm(self, name, perm):
+ user = self.byname(name)
+ if not user:
+ return 0
+ if perm in user.perms:
+ return 1
+
+ def size(self):
+ """ return nr of users """
+ return len(self.data)
+
+ def add(self, name, userhosts, perms):
+ """ add user """
+ self.addnosave(name, userhosts, perms)
+ self.save()
+ return 1
+
+ def addnosave(self, name, userhosts, perms):
+ """ add user without saving """
+ name = name.lower()
+ for item in self.data:
+ if item.name == name:
+ return 0
+ userhosts = stripidents(userhosts)
+ # add user
+ user = User(name, userhosts, perms)
+ self.data.append(user)
+ rlog(10, 'users', 'added user %s %s with perms %s' % (name, \
+userhosts, perms))
+ for i in userhosts:
+ self.adduserhost(i, user)
+ return 1
+
+ def permitted(self, userhost, who, what):
+ """ check if (who,what) is in users permit list """
+ user = self.getuser(userhost)
+ if not user:
+ return 0
+ if (who, what) in user.permit:
+ return 1
+
+ def names(self):
+ """ get names of all users """
+ result = []
+ for item in self.data:
+ result.append(item.name)
+ return result
+
+ def getname(self, userhost):
+ """ get name of user with userhost """
+ item = self.getuser(userhost)
+ if item:
+ return item.name
+ else:
+ return None
+
+ def byname(self, name):
+ """ return user with name """
+ name = name.lower()
+ for item in self.data:
+ if item.name.lower() == name:
+ return item
+ return None
+
+ def merge(self, name, userhost):
+ """ add userhosts to user with name """
+ name = name.lower()
+ for item in self.data:
+ if item.name == name:
+ userhost = stripident(userhost)
+ item.userhosts.append(userhost)
+ self.adduserhost(userhost, item)
+ self.save()
+ rlog(10, 'users', 'merged %s (%s) with %s' % (name, \
+userhost, item.name))
+ return 1
+ return None
+
+ def delete(self, name):
+ """ delete user with name """
+ data = self.data
+ name = name.lower()
+ got = 0
+ for itemnr in range(len(data)-1, -1, -1):
+ if data[itemnr].name == name:
+ for i in data[itemnr].userhosts:
+ self.deluserhost(i)
+ del data[itemnr]
+ got = 1
+ if got:
+ self.save()
+ return 1
+ return None
+
+ def allowed(self, userhost, perms, log=True):
+ """ check if user with userhosts is allowed to execute perm command """
+ if type(perms) != types.ListType:
+ perms = [perms, ]
+ if 'ANY' in perms:
+ return 1
+ item = self.getuser(userhost)
+ if not item:
+ if log:
+ rlog(10, 'users', '%s userhost denied' % userhost)
+ return 0
+ for i in perms:
+ if i in item.perms:
+ return 1
+ if log:
+ rlog(10, 'users', '%s perm %s denied' % (userhost, perms))
+ return 0
+
+ def status(self, userhost, status):
+ """ check if user has status set """
+ status = status.upper()
+ item = self.getuser(userhost)
+ if not item:
+ return 0
+ if status in item.status:
+ return 1
+ return 0
+
+ def getemail(self, name):
+ """ return email of user """
+ user = self.byname(name)
+ return user.email
+
+ def setemail(self, name, email):
+ """ set email of user """
+ user = self.byname(name)
+ user.email = email
+ self.save()
+ return 1
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/karma.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/karma.py
@@ -0,0 +1,270 @@
+# plugs/karma.py
+#
+#
+
+""" karma plugin """
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.commands import cmnds
+from gozerbot.examples import examples
+from gozerbot.redispatcher import rebefore
+from gozerbot.datadir import datadir
+from gozerbot.utils.exception import handle_exception
+from gozerbot.utils.log import rlog
+from gozerbot.utils.locking import lockdec
+from gozerbot.utils.statdict import Statdict
+from gozerbot.aliases import aliases
+from gozerbot.plughelp import plughelp
+from gozerbot.config import config
+import thread, pickle, time, os
+
+plughelp.add('karma', 'maintain karma of items .. use ++ to raise karma by 1 \
+or use -- to lower by 1 .. reason might be given after a "#"')
+
+savelist = []
+
+class Karma:
+
+ """ holds karma data """
+
+ def __init__(self, ddir):
+ rlog(0, 'karma', 'reading %s' % datadir + os.sep + 'karma')
+ self.datadir = ddir
+ self.lock = thread.allocate_lock()
+ try:
+ karmafile = open(ddir + os.sep + 'karma', 'r')
+ self.karma = pickle.load(karmafile)
+ karmafile.close()
+ except:
+ self.karma = {}
+ try:
+ reasonupfile = open(ddir + os.sep + 'reasonup', 'r')
+ self.reasonup = pickle.load(reasonupfile)
+ reasonupfile.close()
+ except:
+ self.reasonup = {}
+ try:
+ reasondownfile = open(ddir + os.sep + 'reasondown', 'r')
+ self.reasondown = pickle.load(reasondownfile)
+ reasondownfile.close()
+ except:
+ self.reasondown = {}
+ try:
+ whoupfile = open(ddir + os.sep + 'whoup', 'r')
+ self.whoup = pickle.load(whoupfile)
+ whoupfile.close()
+ except:
+ self.whoup = {}
+ try:
+ whodownfile = open(ddir + os.sep + 'whodown', 'r')
+ self.whodown = pickle.load(whodownfile)
+ whodownfile.close()
+ except:
+ self.whodown = {}
+
+ def size(self):
+ return len(self.karma)
+
+ def save(self):
+ """ save karma data """
+ try:
+ self.lock.acquire()
+ karmafile = open(self.datadir + os.sep + 'karma', 'w')
+ pickle.dump(self.karma, karmafile)
+ karmafile.close()
+ rlog(1, 'karma', '%s karma saved' % self.datadir)
+ reasonupfile = open(self.datadir + os.sep + 'reasonup', 'w')
+ pickle.dump(self.reasonup, reasonupfile)
+ reasonupfile.close()
+ rlog(1, 'karma', '%s reasonup saved' % self.datadir)
+ reasondownfile = open(self.datadir + os.sep + 'reasondown', 'w')
+ pickle.dump(self.reasondown, reasondownfile)
+ reasondownfile.close()
+ rlog(1, 'karma', '%s reasondown saved' % self.datadir)
+ whoupfile = open(self.datadir + os.sep + 'whoup', 'w')
+ pickle.dump(self.whoup, whoupfile)
+ whoupfile.close()
+ rlog(1, 'karma', '%s whoup saved' % self.datadir)
+ whodownfile = open(self.datadir + os.sep + 'whodown', 'w')
+ pickle.dump(self.whoup, whodownfile)
+ whodownfile.close()
+ rlog(1, 'karma', '%s whodown saved' % self.datadir)
+ finally:
+ self.lock.release()
+
+ def add(self, item, value):
+ """ set karma value of item """
+ self.karma[item.lower()] = value
+
+ def delete(self, item):
+ """ delete karma item """
+ item = item.lower()
+ try:
+ del self.karma[item]
+ return 1
+ except KeyError:
+ return 0
+
+ def get(self, item):
+ """ get karma of item """
+ item = item.lower()
+ if self.karma.has_key(item):
+ return self.karma[item]
+ else:
+ return None
+
+ def addwhy(self, item, updown, reason):
+ """ add why of karma up/down """
+ item = item.lower()
+ if not self.karma.has_key(item):
+ return 0
+ reason = reason.strip()
+ if updown == 'up':
+ if self.reasonup.has_key(item):
+ self.reasonup[item].append(reason)
+ else:
+ self.reasonup[item] = [reason]
+ elif updown == 'down':
+ if self.reasondown.has_key(item):
+ self.reasondown[item].append(reason)
+ else:
+ self.reasondown[item] = [reason]
+
+ def upitem(self, item, reason=None):
+ """ up a karma item with/without reason """
+ item = item.lower()
+ if self.karma.has_key(item):
+ self.karma[item] += 1
+ else:
+ self.karma[item] = 1
+ if reason:
+ reason = reason.strip()
+ if self.reasonup.has_key(item):
+ self.reasonup[item].append(reason)
+ else:
+ self.reasonup[item] = [reason]
+
+ def down(self, item, reason=None):
+ """ lower a karma item with/without reason """
+ item = item.lower()
+ if self.karma.has_key(item):
+ self.karma[item] -= 1
+ else:
+ self.karma[item] = -1
+ if reason:
+ reason = reason.strip()
+ if self.reasondown.has_key(item):
+ self.reasondown[item].append(reason)
+ else:
+ self.reasondown[item] = [reason]
+
+ def whykarmaup(self, item):
+ """ get why of karma ups """
+ item = item.lower()
+ if self.reasonup.has_key(item):
+ return self.reasonup[item]
+
+ def whykarmadown(self, item):
+ """ get why of karma downs """
+ item = item.lower()
+ if self.reasondown.has_key(item):
+ return self.reasondown[item]
+
+ def setwhoup(self, item, nick):
+ """ set who upped a karma item """
+ item = item.lower()
+ if self.whoup.has_key(item):
+ self.whoup[item].append(nick)
+ else:
+ self.whoup[item] = [nick]
+
+ def setwhodown(self, item, nick):
+ """ set who lowered a karma item """
+ item = item.lower()
+ if self.whodown.has_key(item):
+ self.whodown[item].append(nick)
+ else:
+ self.whodown[item] = [nick]
+
+ def getwhoup(self, item):
+ """ get list of who upped a karma item """
+ item = item.lower()
+ try:
+ return self.whoup[item]
+ except KeyError:
+ return None
+
+ def getwhodown(self, item):
+ """ get list of who downed a karma item """
+ item = item.lower()
+ try:
+ return self.whodown[item]
+ except KeyError:
+ return None
+
+ def good(self, limit=10):
+ """ show top 10 of karma items """
+ statdict = Statdict()
+ for i in self.karma.keys():
+ if i.startswith('quote '):
+ continue
+ statdict.upitem(i, value=self.karma[i])
+ return statdict.top(limit=limit)
+
+ def bad(self, limit=10):
+ """ show lowest 10 of negative karma items """
+ statdict = Statdict()
+ for i in self.karma.keys():
+ if i.startswith('quote '):
+ continue
+ statdict.upitem(i, value=self.karma[i])
+ return statdict.down(limit=limit)
+
+ def quotegood(self, limit=10):
+ """ show top 10 of karma items """
+ statdict = Statdict()
+ for i in self.karma.keys():
+ if not i.startswith('quote '):
+ continue
+ statdict.upitem(i, value=self.karma[i])
+ return statdict.top(limit=limit)
+
+ def quotebad(self, limit=10):
+ """ show lowest 10 of negative karma items """
+ statdict = Statdict()
+ for i in self.karma.keys():
+ if not i.startswith('quote '):
+ continue
+ statdict.upitem(i, value=self.karma[i])
+ return statdict.down(limit=limit)
+
+ def search(self, item):
+ """ search karma items """
+ result = []
+ item = item.lower()
+ for i, j in self.karma.iteritems():
+ if item in i:
+ result.append((i, j))
+ return result
+
+ def whatup(self, nick):
+ """ show what items where upped by nick """
+ nick = nick.lower()
+ statdict = Statdict()
+ for i, j in self.whoup.iteritems():
+ for z in j:
+ if nick == z:
+ statdict.upitem(i)
+ return statdict.top()
+
+ def whatdown(self, nick):
+ """ show what items where lowered by nick """
+ nick = nick.lower()
+ statdict = Statdict()
+ for i, j in self.whodown.iteritems():
+ for z in j:
+ if nick == z:
+ statdict.upitem(i)
+ return statdict.top()
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/dbusers.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/dbusers.py
@@ -0,0 +1,264 @@
+# gozerbot/dbusers.py
+#
+#
+
+""" bots users for mysql interface"""
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.utils.log import rlog
+from gozerbot.database.db import Db
+import types
+
+class Dbusers(object):
+
+ """ users class """
+
+ def __init__(self):
+ self.db = Db()
+
+ def size(self):
+ """ return nr of users """
+ result = self.db.execute(""" SELECT DISTINCT COUNT(*) FROM userhosts \
+""")
+ if result:
+ return result[0][0]
+
+ def getperms(self, userhost):
+ """ return permission of user"""
+ name = self.getname(userhost)
+ if not name:
+ return ['ANON', ]
+ result = self.db.execute(""" SELECT perm FROM perms WHERE name = %s \
+""", name)
+ res = []
+ for i in result:
+ res.append(i[0])
+ return res
+
+ def exist(self, name):
+ """ see if user with <name> exists """
+ name = name.lower()
+ result = self.db.execute(""" SELECT name,userhost FROM userhosts WHERE \
+name = %s """, name)
+ return result
+
+ def getname(self, userhost):
+ """ get name of user belonging to <userhost> """
+ result = self.db.execute(""" SELECT name FROM userhosts WHERE \
+%s LIKE userhost """, userhost)
+ if result:
+ return result[0][0]
+
+ def add(self, name, userhosts, perms):
+ """ add an user """
+ if type(userhosts) != types.ListType:
+ rlog(10, 'dbusers', 'i need a list of userhosts')
+ return 0
+ for i in userhosts:
+ self.adduserhost(name, i)
+ for i in perms:
+ self.addperm(name, i)
+ rlog(10, 'users', '%s added to user database' % name)
+ return 1
+
+ def adduserhost(self, name, userhost):
+ """ add userhost """
+ name = name.lower()
+ res = None
+ result = self.db.execute(""" INSERT INTO userhosts(name, userhost) \
+values(%s, %s) """, (name, userhost))
+ if result:
+ res = 1
+ rlog(10, 'users', '%s (%s) added to userhosts' % (name, userhost))
+ return res
+
+ def addperm(self, name, perm):
+ """ add permission """
+ name = name.lower()
+ perm = perm.upper()
+ res = None
+ result = self.db.execute(""" INSERT INTO perms(name, perm) \
+values(%s, %s) """, (name, perm))
+ if result:
+ res = 1
+ rlog(10, 'users', '%s perm %s added' % (name, perm))
+ return res
+
+ def delperm(self, name, perm):
+ """ add permission """
+ name = name.lower()
+ perm = perm.upper()
+ result = self.db.execute(""" DELETE FROM perms WHERE name = %s AND \
+perm = %s """, (name, perm))
+ if result:
+ rlog(10, 'users', '%s perm %s deleted' % (name, perm))
+ return result
+
+ def permitted(self, userhost, who, what):
+ """ check if (who,what) is in users permit list """
+ name = self.getname(userhost)
+ res = None
+ if name:
+ result = self.db.execute(""" SELECT permit FROM permits WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if "%s %s" % (who, what) == i[0]:
+ res = 1
+ return res
+
+ def names(self):
+ """ get names of all users """
+ res = []
+ result = self.db.execute(""" SELECT DISTINCT name FROM userhosts """)
+ if result:
+ for i in result:
+ res.append(i[0])
+ return res
+
+ def merge(self, name, userhost):
+ """ add userhosts to user with name """
+ name = name.lower()
+ if not self.exist(name):
+ return 0
+ res = None
+ result = self.db.execute(""" INSERT INTO userhosts(userhost, name) \
+VALUES (%s, %s) """, (userhost, name))
+ if result:
+ res = 1
+ return res
+
+ def delete(self, name):
+ """ delete user with name """
+ name = name.lower()
+ res = None
+ nr1 = self.db.execute(""" DELETE FROM userhosts WHERE name = %s \
+""", name)
+ nr2 = self.db.execute(""" DELETE FROM perms WHERE name = %s \
+""", name)
+ if nr1 and nr2:
+ res = 1
+ return res
+
+ def status(self, userhost, status):
+ """ check if user with <userhost> has <status> set """
+ name = self.getname(userhost)
+ res = None
+ if name:
+ status = status.upper()
+ result = self.db.execute(""" SELECT status FROM statuses WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if status == i[0]:
+ res = 1
+ return res
+
+ def gotperm(self, name, perm):
+ """ check if user had permission """
+ name = name.lower()
+ perm = perm.upper()
+ result = self.db.execute(""" SELECT perm FROM perms WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if i[0] == perm:
+ return True
+
+ def gotstatus(self, name, status):
+ """ check if user has status """
+ name = name.lower()
+ status = status.upper()
+ result = self.db.execute(""" SELECT status FROM statuses WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if status == i[0]:
+ return True
+
+ def gotuserhost(self, name, userhost):
+ """ check if user has userhost """
+ name = name.lower()
+ result = self.db.execute(""" SELECT userhost FROM userhosts WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if i[0] == userhost:
+ return True
+
+ def gotpermit(self, name, permit):
+ """ check if user permits something """
+ name = name.lower()
+ result = self.db.execute(""" SELECT permit FROM permits WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if "%s %s" % permit == i[0]:
+ return True
+
+ def allowed(self, userhost, perms, log=True):
+ """ check if user with userhosts is allowed to execute perm command """
+ if not type(perms) == types.ListType:
+ perms = [perms, ]
+ if 'ANY' in perms:
+ return 1
+ res = None
+ name = self.getname(userhost)
+ if not name:
+ if log:
+ rlog(10, 'users', '%s userhost denied' % userhost)
+ return res
+ result = self.db.execute(""" SELECT perm FROM perms WHERE \
+name = %s """, name)
+ if result:
+ for i in result:
+ if i[0] in perms:
+ res = 1
+ if not res:
+ if log:
+ rlog(10, 'users', "%s perm %s denied" % (userhost, perms))
+ return res
+
+ def getemail(self, name):
+ """ get email of user """
+ name = name.lower()
+ email = None
+ email = self.db.execute(""" SELECT email FROM email WHERE name = %s \
+""", name)
+ if email:
+ return email[0][0]
+
+ def setemail(self, name, email):
+ """ set email of user """
+ res = 0
+ try:
+ result = self.db.execute(""" INSERT INTO email(name, email) \
+VALUES (%s, %s) """, (name, email))
+ except:
+ try:
+ result = self.db.execute(""" UPDATE email SET email = %s \
+WHERE name = %s """, (email, name))
+ except:
+ pass
+ if result:
+ res = 1
+ return res
+
+ def addpermall(self, perm):
+ """ add permission to all users """
+ perm = perm.upper()
+ for i in self.names():
+ try:
+ self.addperm(i, perm)
+ except:
+ pass
+
+ def delpermall(self, perm):
+ """ delete permission from all users """
+ perm = perm.upper()
+ for i in self.names():
+ try:
+ self.delperm(i, perm)
+ except:
+ pass
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/pdod.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/pdod.py
@@ -0,0 +1,75 @@
+# gozerbot/pdod.py
+#
+#
+
+""" pickled dicts of dicts """
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.utils.locking import lockdec
+from persist import Persist
+import thread
+
+pdodlock = thread.allocate_lock()
+locked = lockdec(pdodlock)
+
+class Pdod(Persist):
+
+ """ pickled dicts of dicts """
+
+ def __init__(self, filename):
+ Persist.__init__(self, filename)
+ if not self.data:
+ self.data = {}
+
+ def __getitem__(self, name):
+ """ return item with name """
+ if self.data.has_key(name):
+ return self.data[name]
+
+ @locked
+ def save(self):
+ Persist.save(self)
+
+ @locked
+ def __delitem__(self, name):
+ """ delete name item """
+ if self.data.has_key(name):
+ return self.data.__delitem__(name)
+
+ @locked
+ def __setitem__(self, name, item):
+ """ set name item """
+ self.data[name] = item
+
+ def __contains__(self, name):
+ return self.data.__contains__(name)
+
+ @locked
+ def setdefault(self, name, default):
+ """ set default of name """
+ return self.data.setdefault(name, default)
+
+ def has_key(self, name):
+ """ has name key """
+ return self.data.has_key(name)
+
+ def has_key2(self, name1, name2):
+ """ has [name1][name2] key """
+ if self.data.has_key(name1):
+ return self.data[name1].has_key(name2)
+
+ def get(self, name1, name2):
+ """ get data[name1][name2] """
+ try:
+ result = self.data[name1][name2]
+ return result
+ except KeyError:
+ return None
+
+ @locked
+ def set(self, name1, name2, item):
+ """ set name, name2 item """
+ if not self.data.has_key(name1):
+ self.data[name1] = {}
+ self.data[name1][name2] = item
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/__init__.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/__init__.py
@@ -0,0 +1,32 @@
+# gozerbot package
+#
+#
+
+""" gozerbot compatibility package. """
+
+__copyright__ = 'this file is in the public domain'
+
+# ==============
+# IMPORT SECTION
+
+from gozerbot.eggs import loadegg
+import os
+
+# END IMPORT
+# ==========
+
+# ============
+# LOCK SECTION
+
+# no locks
+
+# END LOCK
+# ========
+
+# ============
+# INIT SECTION
+
+loadegg('feedparser', [os.getcwd(), os.getcwd() + os.sep + 'gozernest'], log=False)
+
+# END INIT
+# ========
\ No newline at end of file
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/config.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/config.py
@@ -0,0 +1,313 @@
+# gozerbot/config.py
+#
+#
+
+""" this is where the config dict lives .. use pickle to persist config data
+ .. use this pickle on start until the config file has changed """
+
+__copyright__ = 'this file is in the public domain'
+
+from gozerbot.datadir import datadir
+import os, pickle, subprocess
+
+# version string
+ver = 'GOZERBOT 0.8.1.1 RELEASE'
+
+def diffdict(dictfrom, dictto):
+ """ check for differences between two dicts """
+ temp = {}
+ for i in dictto.iteritems():
+ if dictfrom.has_key(i[0]):
+ if dictfrom[i[0]] != i[1]:
+ temp.setdefault(i[0], i[1])
+ else:
+ temp.setdefault(i[0], i[1])
+ return temp
+
+class Config(dict):
+
+ """ config object is a dict """
+
+ def __init__(self, ddir, *args, **kw):
+ dict.__init__(self, *args, **kw)
+ self.dir = str(ddir)
+ self['dbtype'] = 'mysql'
+
+ def __getitem__(self, item):
+ """ get config item .. return None if not available"""
+ if not self.has_key(item):
+ return None
+ else:
+ return dict.__getitem__(self, item)
+
+ def set(self, item, value):
+ """ set a config item """
+ dict.__setitem__(self, item, value)
+ self.save()
+
+ def load(self):
+ """ load the config file """
+ frompickle = {}
+ picklemodtime = None
+ # first do reload of the data/config file
+ self.reload()
+ # see if there is a configpickle
+ try:
+ picklemodtime = os.stat(self.dir + os.sep + 'configpickle')[8]
+ configpickle = open(self.dir + os.sep + 'configpickle', 'r')
+ frompickle = pickle.load(configpickle)
+ configpickle.close()
+ except OSError:
+ return
+ except:
+ pass
+ # see if data/config is more recent than the configpickle
+ configmodtime = os.stat(self.dir + os.sep + 'config')[8]
+ if picklemodtime and picklemodtime > configmodtime:
+ # if so update the config dict with the pickled data
+ # a = diffdict(self, frompickle)
+ self.update(frompickle)
+ # set version
+ if self['dbenable']:
+ self['version'] = ver + ' ' + self['dbtype'].upper()
+ else:
+ self['version'] = ver
+
+ def save(self):
+ """ save config data to pickled file """
+ picklefile = open(self.dir + os.sep + 'configpickle', 'w')
+ pickle.dump(self, picklefile)
+ picklefile.close()
+
+ def reload(self):
+ """ use execfile to reload data/config """
+ try:
+ execfile(self.dir + os.sep + 'config', self)
+ except IOError:
+ self.defaultconfig()
+ # remove builtin data
+ try:
+ del self['__builtins__']
+ except:
+ pass
+ # set version
+ if self['dbenable']:
+ self['version'] = ver + ' ' + self['dbtype'].upper()
+ else:
+ self['version'] = ver
+
+ def defaultconfig(self):
+ """ init default config values if no config file is found """
+ self['loglevel'] = 100
+ self['jabberenable'] = 0
+ self['ircdisable'] = 0
+ self['stripident'] = 1
+ self['owneruserhost'] = ['bart@127.0.0.1', ]
+ self['nick'] = 'gozerbot'
+ self['server'] = 'localhost'
+ self['port'] = 6667
+ self['ipv6'] = 0
+ self['username'] = 'gozerbot'
+ self['realname'] = 'GOZERBOT'
+ self['defaultcc'] = "!"
+ self['nolimiter'] = 0
+ self['quitmsg'] = 'http://gozerbot.org'
+ self['dbenable'] = 0
+ self['udp'] = 0
+ self['partyudp'] = 0
+ self['mainbotname'] = 'main'
+ self['addonallow'] = 0
+ self['allowedchars'] = []
+
+configtxt = """# config
+#
+#
+
+__copyright__ = 'this file is in the public domain'
+
+# gozerdata dir umask
+umask = 0700
+
+# logging level .. the higher this value is the LESS the bot logs
+loglevel = 10
+
+## jabber section:
+
+jabberenable = 0
+jabberowner = 'bartholo@localhost'
+jabberhost = 'localhost'
+jabberuser = 'gozerbot@localhost'
+jabberpass = 'pass'
+jabberoutsleep = 0.1
+
+## irc section:
+
+ircdisable = 0
+
+# stripident .. enable stripping of ident from userhost
+stripident = 1
+
+# userhost of owner .. make sure this matches your client's userhost
+# if it doesn't match you will get an userhost denied message when you
+# try to send commands to the bot
+owneruserhost = ['bart@127.0.0.1', ]
+
+# the nick the bot tries to use, only used if no nick is set
+# otherwise the bot will use the last nick used by the !nick command
+nick = 'gozerbot'
+
+# alternick
+#alternick = 'gozerbot2'
+
+# server to connect to
+server = 'localhost'
+
+# irc port to connect to
+port = 6667
+
+# ircd password for main bot
+#password = 'bla'
+
+# ipv6
+ipv6 = 0
+
+# bindhost .. uncomment and edit to use
+#bindhost = 'localhost'
+
+# bots username
+username = 'gozerbot'
+
+# realname
+realname = 'GOZERBOT'
+
+# default control character
+defaultcc = "!"
+
+# no limiter
+nolimiter = 0
+
+# quit message
+quitmsg = 'http://gozerbot.org'
+
+# nickserv .. set pass to enable nickserv ident
+nickservpass = ""
+nickservtxt = ['set unfiltered on', ]
+
+## if you want to use a database:
+
+dbenable = 0 # set to 1 to enable
+dbtype = 'mysql' # one of mysql or sqlite
+dbname = "gb_db"
+dbhost = "localhost"
+dbuser = "bart"
+dbpasswd = "mekker2"
+dboldstyle = False # set to True if mysql database is <= 4.1
+
+## if you want to use udp:
+
+# udp
+udp = 0 # set to 1 to enable
+partyudp = 0
+udpipv6 = 0
+udphost = 'localhost'
+udpport = 5500
+udpmasks = ['192.168*', ]
+udpallow = ['127.0.0.1', ]
+udpallowednicks = ['#dunkbots', 'dunker']
+udppassword = 'mekker'
+udpseed = "" # set this to 16 char wide string if you want to encrypt the data
+udpstrip = 1 # strip all chars < char(32)
+udpsleep = 0 # sleep in sendloop .. can be used to delay packet traffic
+
+# tcp
+tcp = 0 # set to 1 to enable
+partytcp = 0
+tcpipv6 = 0
+tcphost = 'localhost'
+tcpport = 5500
+tcpmasks = ['192.168*', ]
+tcpallow = ['127.0.0.1', ]
+tcpallowednicks = ['#dunkbots', 'dunker', 'dunker@jabber.xs4all.nl']
+tcppassword = 'mekker'
+tcpseed = "bla1234567890bla"
+# set this to 16 char wide string if you want to encrypt the data
+tcpstrip = 1
+tcpsleep = 0
+
+## other stuff:
+
+# plugin server
+pluginserver = 'http://gozerbot.org'
+
+# upgradeurl .. only needed if mercurial repo changed
+#upgradeurl = 'http://gozerbot.org/hg/gozerbot'
+
+# mail related
+mailserver = None
+mailfrom = None
+
+# collective boot server
+collboot = "gozerbot.org:8088"
+
+# name of the main bot
+mainbotname = 'main'
+
+# allowed character for strippedtxt
+allowedchars = []
+
+# set to 1 to allow addons
+addonallow = 0
+
+# enable loadlist
+loadlist = 0
+"""
+
+def writeconfig():
+ """ wtite default config file to datadir/config """
+ if not os.path.isfile(datadir + os.sep + 'config'):
+ cfgfile = open(datadir + os.sep + 'config', 'w')
+ cfgfile.write(configtxt)
+ cfgfile.close()
+
+loadlist = """
+core
+misc
+irc
+not
+grep
+reverse
+count
+chanperm
+choice
+fleet
+ignore
+upgrade
+job
+reload
+rest
+tail
+user
+googletalk
+all
+at
+backup
+install
+reload
+tell
+reverse
+to
+underauth
+userstate
+alias
+nickserv
+"""
+
+def writeloadlist():
+ """ write loadlist to datadir """
+ if not os.path.isfile(datadir + os.sep + 'loadlist'):
+ cfgfile = open(datadir + os.sep + 'loadlist', 'w')
+ cfgfile.write(loadlist)
+ cfgfile.close()
+
+# create the config dict and load it from file
+#config = Config(datadir)
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/todo.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/todo.py
@@ -0,0 +1,172 @@
+# plugs/todo.py
+#
+#
+
+from gozerbot.compat.persist import Persist
+import time
+
+class Todoitem:
+
+ """ a todo item """
+
+ def __init__(self, name, descr, ttime=None, duration=None, warnsec=None, \
+priority=None, num=0):
+ self.name = name
+ self.time = ttime
+ self.duration = duration
+ self.warnsec = warnsec
+ self.descr = descr
+ self.priority = priority
+ self.num = num
+
+ def __str__(self):
+ return "name: %s num: %d time: %s duration: %s warnsec: %s \
+description: %s priority: %s" % (self.name, self.num, \
+time.ctime(self.time), self.duration, self.warnsec, self.descr, self.priority)
+
+class Todolist:
+
+ """ a dict faking list of todo items .. index is number """
+
+ def __init__(self):
+ self.max = 0
+ self.data = {}
+
+ def __len__(self):
+ return len(self.data)
+
+ def __getitem__(self, num):
+ return self.data[num]
+
+ def __delitem__(self, num):
+ del self.data[num]
+
+ def __iter__(self):
+ tmplist = self.data.values()
+ tmplist.sort(lambda x, y: cmp(x.priority, y.priority), reverse=True)
+ return tmplist.__iter__()
+
+ def append(self, item):
+ """ add todo item """
+ self.max += 1
+ item.num = self.max
+ self.data[self.max] = item
+
+ def __str__(self):
+ return str(self.data)
+
+
+class Todo(Persist):
+
+ """ Todoos """
+
+ def __init__(self, filename):
+ Persist.__init__(self, filename)
+ if not self.data:
+ return
+ for key in self.data.keys():
+ todoos = self.data[key]
+ for (k, v) in todoos.data.items():
+ v.num = k
+ newd = Todolist()
+ for i in todoos:
+ newd.append(i)
+ self.data[key] = newd
+
+ def size(self):
+ """ return number of todo entries """
+ return len(self.data)
+
+ def get(self, name):
+ """ get todoos of <name> """
+ if self.data.has_key(name):
+ return self.data[name]
+
+ def add(self, name, txt, ttime, warnsec=0):
+ """ add a todo """
+ name = name.lower()
+ if not self.data.has_key(name):
+ self.data[name] = Todolist()
+ self.data[name].append(Todoitem(name, txt.strip(), ttime, \
+warnsec=0-warnsec))
+ self.save()
+ return len(self.data[name])
+
+ def addnosave(self, name, txt, ttime):
+ """ add but don't save """
+ name = name.lower()
+ if not self.data.has_key(name):
+ self.data[name] = Todolist()
+ self.data[name].append(Todoitem(name, txt, ttime))
+
+ def reset(self, name):
+ name = name.lower()
+ if self.data.has_key(name):
+ self.data[name] = Todolist()
+ self.save()
+
+ def delete(self, name, nr):
+ """ delete todo item """
+ if not self.data.has_key(name):
+ return 0
+ todoos = self.data[name]
+ try:
+ if todoos[nr].warnsec:
+ alarmnr = 0 - todoos[nr].warnsec
+ if alarmnr > 0:
+ alarms.delete(alarmnr)
+ del todoos[nr]
+ except KeyError:
+ return 0
+ self.save()
+ return 1
+
+ def toolate(self, name):
+ """ show if there are any time related todoos that are too late """
+ now = time.time()
+ teller = 0
+ for i in self.data[name]:
+ if i.time < now:
+ teller += 1
+ return teller
+
+ def timetodo(self, name):
+ """ show todoos with time field set """
+ result = []
+ if not self.data.has_key(name):
+ return result
+ for i in self.data[name]:
+ if i.time:
+ result.append(i)
+ return result
+
+ def withintime(self, name, time1, time2):
+ """ show todoos within time frame """
+ result = []
+ if not self.data.has_key(name):
+ return result
+ for i in self.data[name]:
+ if i.time >= time1 and i.time < time2:
+ result.append(i)
+ return result
+
+ def setprio(self, who, itemnr, prio):
+ """ set priority of todo item """
+ try:
+ todoitems = self.get(who)
+ todoitems[itemnr].priority = prio
+ self.save()
+ return 1
+ except (KeyError, TypeError):
+ pass
+
+ def settime(self, who, itemnr, ttime):
+ """ set time of todo item """
+ try:
+ todoitems = self.get(who)
+ todoitems[itemnr].time = ttime
+ self.save()
+ return 1
+ except (KeyError, TypeError):
+ pass
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/quote.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/quote.py
@@ -0,0 +1,114 @@
+# plugs/quote.py
+#
+#
+
+from gozerbot.compat.persist import Persist
+
+class Quoteitem(object):
+
+ """ object representing a quote """
+
+ def __init__(self, idnr, txt, nick=None, userhost=None, ttime=None):
+ self.id = idnr
+ self.txt = txt
+ self.nick = nick
+ self.userhost = userhost
+ self.time = ttime
+
+class Quotes(Persist):
+
+ """ list of quotes """
+
+ def __init__(self, fname):
+ Persist.__init__(self, fname)
+ if not self.data:
+ self.data = []
+
+ def size(self):
+ """ return nr of quotes """
+ return len(self.data)
+
+ def add(self, nick, userhost, quote):
+ """ add a quote """
+ id = nextid.next('quotes')
+ item = Quoteitem(id, quote, nick, userhost, \
+time.time())
+ self.data.append(item)
+ self.save()
+ return id
+
+ def addnosave(self, nick, userhost, quote, ttime):
+ """ add quote but don't call save """
+ id = nextid.next('quotes')
+ item = Quoteitem(nextid.next('quotes'), quote, nick, userhost, ttime)
+ self.data.append(item)
+ return id
+
+ def delete(self, quotenr):
+ """ delete quote with id == nr """
+ for i in range(len(self.data)):
+ if self.data[i].id == quotenr:
+ del self.data[i]
+ self.save()
+ return 1
+
+ def random(self):
+ """ get random quote """
+ if not self.data:
+ return None
+ quotenr = random.randint(0, len(self.data)-1)
+ return self.data[quotenr]
+
+ def idquote(self, quotenr):
+ """ get quote by id """
+ for i in self.data:
+ if i.id == quotenr:
+ return i
+
+ def whoquote(self, quotenr):
+ """ get who quoted the quote """
+ for i in self.data:
+ if i.id == quotenr:
+ return (i.nick, i.time)
+
+ def last(self, nr=1):
+ """ get last quote """
+ return self.data[len(self.data)-nr:]
+
+ def search(self, what):
+ """ search quotes """
+ if not self.data:
+ return []
+ result = []
+ andre = re.compile('and', re.I)
+ ands = re.split(andre, what)
+ got = 0
+ for i in self.data:
+ for item in ands:
+ if i.txt.find(item.strip()) == -1:
+ got = 0
+ break
+ got = 1
+ if got:
+ result.append(i)
+ return result
+
+ def searchlast(self, what, nr=1):
+ """ search quotes backwards limit to 1"""
+ if not self.data:
+ return []
+ result = []
+ andre = re.compile('and', re.I)
+ ands = re.split(andre, what)
+ got = 0
+ for i in self.data[::-1]:
+ for item in ands:
+ if i.txt.find(item.strip()) == -1:
+ got = 0
+ break
+ got = 1
+ if got:
+ result.append(i)
+ got = 0
+ return result
+
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/rss.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/rss.py
@@ -0,0 +1,1124 @@
+# plugs/rss.py
+#
+#
+
+"""the rss mantra is of the following:
+
+as OPER:
+
+. add a url with rss-add
+. start the watcher with rss-watch
+
+now the user can start the bot sending messages of the feed to him with
+rss-start. if an OPER gives a rss-start command in a channel data will be
+send to the channel.
+ """
+
+__copyright__ = 'this file is in the public domain'
+__gendocfirst__ = ['rss-add', 'rss-watch', 'rss-start']
+__gendocskip__ = ['rss-dump', ]
+
+from gozerbot.compat.persist import Persist
+from gozerbot.utils.url import geturl2
+from gozerbot.utils.exception import handle_exception
+from gozerbot.utils.log import rlog
+from gozerbot.utils.locking import lockdec
+from gozerbot.utils.generic import strippedtxt, fromenc
+from gozerbot.utils.url import striphtml, useragent
+from gozerbot.utils.rsslist import rsslist
+from gozerbot.utils.statdict import Statdict
+from gozerbot.fleet import fleet
+from gozerbot.commands import cmnds
+from gozerbot.examples import examples
+from gozerbot.datadir import datadir
+from gozerbot.utils.dol import Dol
+from gozerbot.compat.pdod import Pdod
+from gozerbot.compat.pdol import Pdol
+from gozerbot.plughelp import plughelp
+from gozerbot.periodical import periodical
+from gozerbot.aliases import aliasset
+from gozerbot.users import users
+import feedparser
+import gozerbot.threads.thr as thr
+import time, os, types, thread, socket, xml
+
+plughelp.add('rss', 'manage rss feeds')
+
+savelist = []
+
+def txtindicts(result, d):
+ """ return lowlevel values in (nested) dicts """
+ for j in d.values():
+ if type(j) == types.DictType:
+ txtindicts(result, j)
+ else:
+ result.append(j)
+
+def checkfordate(data, date):
+ for item in data:
+ try:
+ d = item['updated']
+ except KeyError:
+ continue
+ if date == d:
+ return True
+ return False
+
+rsslock = thread.allocate_lock()
+locked = lockdec(rsslock)
+
+class RssException(Exception):
+ pass
+
+class Rss301(RssException):
+ pass
+
+class RssStatus(RssException):
+ pass
+
+class RssBozoException(RssException):
+ pass
+
+class RssNoSuchItem(RssException):
+ pass
+
+class Rssitem(object):
+
+ """ item that contains rss data """
+
+ def __init__(self, name, url, itemslist, watchchannels=[], \
+sleeptime=30*60):
+ self.name = name
+ self.url = url
+ self.itemslist = list(itemslist)
+ self.watchchannels = list(watchchannels)
+ self.sleeptime = int(sleeptime)
+ self.running = 0
+ self.stoprunning = 0
+ self.botname = None
+
+ def __str__(self):
+ return "name=%s url=%s itemslist=%s watchchannels=%s sleeptime=%s \
+running=%s" % (self.name, self.url, str(self.itemslist), \
+str(self.watchchannels), str(self.sleeptime), self.running)
+
+class Rssdict(Persist):
+
+ """ dict of rss entries """
+
+ def __init__(self, filename):
+ Persist.__init__(self, filename)
+ if not self.data:
+ self.data = {}
+ if self.data.has_key('itemslists'):
+ del self.data['itemslists']
+ self.itemslists = Pdol(filename + '.itemslists')
+ self.handlers = {}
+ self.results = {}
+ self.jobids = {}
+ self.rawresults = {}
+ self.results = Dol()
+ self.modified = {}
+ self.etag = {}
+ self.markup = Pdod(filename + '.markup')
+
+ def size(self):
+ """ return number of rss entries """
+ return len(self.data)
+
+ @locked
+ def add(self, name, url):
+ """ add rss item """
+ rlog(10, 'rss', 'adding %s %s' % (name, url))
+ self.data[name] = Rssitem(name, url, ['title', ])
+ self.save()
+
+ @locked
+ def delete(self, name):
+ """ delete rss item by name """
+ target = None
+ for j, i in self.data.iteritems():
+ if i.name == name:
+ target = i
+ if target:
+ try:
+ target.running = 0
+ del self.data[name]
+ self.save()
+ except:
+ pass
+
+ def byname(self, name):
+ """ return rss item by name """
+ try:
+ return self.data[name]
+ except:
+ return
+
+ def getdata(self, name):
+ """ get data of rss feed """
+ rssitem = self.byname(name)
+ if rssitem == None:
+ raise RssNoSuchItem("no %s rss item found" % name)
+ try:
+ modified = self.modified[name]
+ except KeyError:
+ modified = None
+ try:
+ etag = self.etag[name]
+ except KeyError:
+ etag = None
+ result = feedparser.parse(rssitem.url, modified=modified, etag=etag, \
+agent=useragent())
+ if result and result.has_key('bozo_exception'):
+ rlog(1, 'rss', '%s bozo_exception: %s' % (name, \
+result['bozo_exception']))
+ #raise RssStatus(result['bozo_exception'])
+ try:
+ status = result.status
+ except AttributeError:
+ status = 200
+ if status != 200 and status != 301 and status != 302 and status != 304:
+ raise RssStatus(status)
+ try:
+ self.modified[name] = result.modified
+ except AttributeError:
+ pass
+ try:
+ self.etag[name] = result.etag
+ except AttributeError:
+ pass
+ if status == 304:
+ return self.rawresults[name]
+ else:
+ self.rawresults[name] = result.entries
+ return result.entries
+
+class Rsswatcher(Rssdict):
+
+ """ rss watchers """
+
+ def __init__(self, filename):
+ Rssdict.__init__(self, filename)
+
+ def sync(self, name):
+ result = self.getdata(name)
+ if result:
+ self.results[name] = result
+
+ def changeinterval(self, name, interval):
+ periodical.changeinterval(self.jobids[name], interval)
+
+ @locked
+ def startwatchers(self):
+ """ start watcher threads """
+ for j, i in self.data.iteritems():
+ if i.running:
+ thr.start_new_thread(self.watch, (i.name, ))
+
+ @locked
+ def stopwatchers(self):
+ """ stop all watcher threads """
+ for j, i in self.data.iteritems():
+ if i.running:
+ i.stoprunning = 1
+ periodical.killgroup('rss')
+
+ def dowatch(self, name, sleeptime=1800):
+ rssitem = self.byname(name)
+ if not rssitem:
+ rlog(10, 'rss', "no %s rss item available" % name)
+ return
+ while 1:
+ try:
+ self.watch(name)
+ except Exception, ex:
+ rlog(100, 'rss', '%s feed error: %s' % (name, str(ex)))
+ rlog(100, 'rss', '%s sleeping %s seconds for retry' % \
+(name, sleeptime))
+ time.sleep(sleeptime)
+ if not rssitem.running:
+ break
+ else:
+ break
+
+ def makeresult(self, name, target, data):
+ res = []
+ for j in data:
+ tmp = {}
+ if not self.itemslists[(name, target)]:
+ return []
+ for i in self.itemslists[(name, target)]:
+ try:
+ tmp[i] = unicode(j[i])
+ except KeyError:
+ continue
+ res.append(tmp)
+ return res
+
+ def watch(self, name):
+ """ start a watcher thread """
+ # get basic data
+ rlog(10, 'rss', 'trying %s rss feed watcher' % name)
+ try:
+ result = self.getdata(name)
+ except RssException, ex:
+ rlog(10, 'rss', "%s error: %s" % (name, str(ex)))
+ result = []
+ rssitem = self.byname(name)
+ if not rssitem:
+ raise RssNoItem()
+ # poll every sleeptime seconds
+ self.results[name] = result
+ pid = periodical.addjob(rssitem.sleeptime, 0, self.peek, name, name)
+ self.jobids[name] = pid
+ rlog(10, 'rss', 'started %s rss watch' % name)
+
+ def makeresponse(self, name, res, channel, sep="\002||\002"):
+ # loop over result to make a response
+ result = ""
+ itemslist = self.itemslists[(name, channel)]
+ if not itemslist:
+ rssitem = self.byname(name)
+ if not rssitem:
+ return "no %s rss item" % name
+ else:
+ self.itemslists.extend((name, channel), rssitem.itemslist)
+ self.itemslists.save()
+ for j in res:
+ resultstr = ""
+ for i in self.itemslists[(name, channel)]:
+ try:
+ item = unicode(j[i])
+ if not item:
+ continue
+ if item.startswith('http://'):
+ resultstr += "<%s> - " % item
+ else:
+ resultstr += "%s - " % striphtml(item)
+ except KeyError:
+ continue
+ resultstr = resultstr[:-3]
+ if resultstr:
+ result += "%s %s " % (resultstr, sep)
+ return result[:-6]
+
+ def peek(self, name, *args):
+ rssitem = self.byname(name)
+ if not rssitem or not rssitem.running or rssitem.stoprunning:
+ return
+ try:
+ try:
+ res = self.getdata(name)
+ except socket.timeout:
+ rlog(10, 'rss', 'socket timeout of %s' % name)
+ return
+ except RssException, ex:
+ rlog(10, 'rss', '%s error: %s' % (name, str(ex)))
+ return
+ if not res:
+ return
+ res2 = []
+ for j in res:
+ try:
+ d = j['date']
+ except KeyError:
+ if j not in self.results[name]:
+ self.results[name].append(j)
+ res2.append(j)
+ else:
+ if not checkfordate(self.results[name], d):
+ self.results[name].append(j)
+ res2.append(j)
+ if not res2:
+ return
+ for item in rssitem.watchchannels:
+ try:
+ (botname, channel) = item
+ except:
+ rlog(10, 'rss', '%s is not in the format \
+(botname,channel)' % str(item))
+ bot = fleet.byname(botname)
+ if not bot:
+ continue
+ if self.markup.get((name, channel), 'all-lines'):
+ for i in res2:
+ response = self.makeresponse(name, [i, ], channel)
+ bot.say(channel, "\002%s\002: %s" % \
+(rssitem.name, response), fromm=rssitem.name)
+ else:
+ sep = self.markup.get((name, channel), 'seperator')
+ if sep:
+ response = self.makeresponse(name, res2, channel, \
+sep=sep)
+ else:
+ response = self.makeresponse(name, res2, channel)
+ bot.say(channel, "\002%s\002: %s" % (rssitem.name, \
+response), fromm=rssitem.name)
+ except Exception, ex:
+ handle_exception(txt=name)
+
+ @locked
+ def stopwatch(self, name):
+ """ stop watcher thread """
+ for i, j in self.data.iteritems():
+ if i == name:
+ j.running = 0
+ try:
+ del self.results[name]
+ except KeyError:
+ pass
+ self.save()
+ try:
+ periodical.killjob(self.jobids[i])
+ except KeyError:
+ pass
+ return 1
+
+ @locked
+ def list(self):
+ """ return of rss names """
+ feeds = self.data.keys()
+ return feeds
+
+ @locked
+ def runners(self):
+ """ show names/channels of running watchers """
+ result = []
+ for j, i in self.data.iteritems():
+ if i.running == 1 and not i.stoprunning:
+ result.append((i.name, i.watchchannels))
+ return result
+
+ @locked
+ def feeds(self, botname, channel):
+ """ show names/channels of running watcher """
+ result = []
+ for j, i in self.data.iteritems():
+ if (botname, channel) in i.watchchannels:
+ result.append(i.name)
+ return result
+
+ @locked
+ def url(self, name):
+ """ return url of rssitem """
+ for j, i in self.data.iteritems():
+ if i.name == name:
+ return i.url
+
+ def scan(self, name):
+ """ scan a rss url for used xml items """
+ try:
+ result = self.getdata(name)
+ except RssException, ex:
+ rlog(10, 'rss', '%s error: %s' % (name, str(ex)))
+ return
+ if not result:
+ return
+ keys = []
+ for item in self.rawresults[name]:
+ for key in item.keys():
+ keys.append(key)
+ statdict = Statdict()
+ for key in keys:
+ statdict.upitem(key)
+ return statdict.top()
+
+ def search(self, name, item, search):
+ res = []
+ for result in self.rawresults[name]:
+ try:
+ title = result['title']
+ txt = result[item]
+ except KeyError:
+ continue
+ if search in title.lower():
+ if txt:
+ res.append(txt)
+ return res
+
+ def searchall(self, item, search):
+ res = []
+ for name, results in self.rawresults.iteritems():
+ for result in results:
+ try:
+ title = result['title']
+ txt = result[item]
+ except KeyError:
+ continue
+ if search in title.lower():
+ if txt:
+ res.append("%s: %s" % (name, txt))
+ return res
+
+ def all(self, name, item):
+ res = []
+ for result in self.rawresults[name]:
+ try:
+ txt = result[item]
+ except KeyError:
+ continue
+ if txt:
+ res.append(txt)
+ return res
+
+watcher = Rsswatcher(datadir + os.sep + 'old' + os.sep + 'rss')
+
+def init():
+ """ called after plugin import """
+ thr.start_new_thread(watcher.startwatchers, ())
+ return 1
+
+def size():
+ """ return number of watched rss entries """
+ return watcher.size()
+
+def shutdown():
+ """ called before plugin import """
+ watcher.stopwatchers()
+ return 1
+
+def handle_rssadd(bot, ievent):
+ """ rss-add <name> <url> .. add a rss item """
+ try:
+ (name, url) = ievent.args
+ except ValueError:
+ ievent.missing('<name> <url>')
+ return
+ watcher.add(name, url)
+ ievent.reply('rss item added')
+
+cmnds.add('rss-add', handle_rssadd, 'OPER')
+examples.add('rss-add', 'rss-add <name> <url> to the rsswatcher', 'rss-add \
+gozerbot http://gozerbot.org/hg/gozerbot/?cmd=changelog;style=rss')
+
+def handle_rssdel(bot, ievent):
+ """ rss-del <name> .. delete a rss item """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ if watcher.byname(name):
+ watcher.stopwatch(name)
+ watcher.delete(name)
+ ievent.reply('rss item deleted')
+ else:
+ ievent.reply('there is no %s rss item' % name)
+
+cmnds.add('rss-del', handle_rssdel, 'OPER')
+examples.add('rss-del', 'rss-del <name> .. remove <name> from the \
+rsswatcher', 'rss-del mekker')
+
+def handle_rsswatch(bot, ievent):
+ """ rss-watch <name> .. start watcher thread """
+ if not ievent.channel:
+ ievent.reply('no channel provided')
+ try:
+ name, sleepsec = ievent.args
+ except ValueError:
+ try:
+ name = ievent.args[0]
+ sleepsec = 1800
+ except IndexError:
+ ievent.missing('<name> [secondstosleep]')
+ return
+ try:
+ sleepsec = int(sleepsec)
+ except ValueError:
+ ievent.reply("time to sleep needs to be in seconds")
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss object" % name)
+ return
+ got = None
+ if not rssitem.running:
+ rssitem.sleeptime = sleepsec
+ rssitem.running = 1
+ rssitem.stoprunning = 0
+ got = True
+ watcher.save()
+ try:
+ watcher.watch(name)
+ except Exception, ex:
+ ievent.reply(str(ex))
+ return
+ if got:
+ watcher.save()
+ ievent.reply('watcher started')
+ else:
+ ievent.reply('already watching %s' % name)
+
+cmnds.add('rss-watch', handle_rsswatch, 'OPER')
+examples.add('rss-watch', 'rss-watch <name> [seconds to sleep] .. go \
+watching <name>', '1) rss-watch gozerbot 2) rss-watch gozerbot 600')
+
+def handle_rssstart(bot, ievent):
+ """ rss-start <name> .. start a rss feed to a user """
+ if not ievent.rest:
+ ievent.missing('<feed name>')
+ return
+ name = ievent.rest
+ rssitem = watcher.byname(name)
+ if bot.jabber:
+ target = ievent.userhost
+ else:
+ if users.allowed(ievent.userhost, ['OPER', ]) and not ievent.msg:
+ target = ievent.channel
+ else:
+ target = ievent.nick
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss object" % name)
+ return
+ if not rssitem.running:
+ ievent.reply('%s watcher is not running' % name)
+ return
+ if (bot.name, target) in rssitem.watchchannels:
+ ievent.reply('we are already monitoring %s on (%s,%s)' % \
+(name, bot.name, target))
+ return
+ rssitem.watchchannels.append((bot.name, target))
+ for item in rssitem.itemslist:
+ watcher.itemslists.adduniq((name, target), item)
+ watcher.save()
+ ievent.reply('%s started' % name)
+
+cmnds.add('rss-start', handle_rssstart, ['RSS', 'USER'])
+examples.add('rss-start', 'rss-start <name> .. start a rss feed \
+(per user/channel) ', 'rss-start gozerbot')
+
+def handle_rssstop(bot, ievent):
+ """ rss-start <name> .. start a rss feed to a user """
+ if not ievent.rest:
+ ievent.missing('<feed name>')
+ return
+ name = ievent.rest
+ rssitem = watcher.byname(name)
+ if bot.jabber:
+ target = ievent.userhost
+ else:
+ if users.allowed(ievent.userhost, ['OPER', ]) and not ievent.msg:
+ target = ievent.channel
+ else:
+ target = ievent.nick
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss feed" % name)
+ return
+ if not rssitem.running:
+ ievent.reply('%s watcher is not running' % name)
+ return
+ if not (bot.name, target) in rssitem.watchchannels:
+ ievent.reply('we are not monitoring %s on (%s,%s)' % \
+(name, bot.name, target))
+ return
+ rssitem.watchchannels.remove((bot.name, target))
+ watcher.save()
+ ievent.reply('%s stopped' % name)
+
+cmnds.add('rss-stop', handle_rssstop, ['RSS', 'USER'])
+examples.add('rss-stop', 'rss-stop <name> .. stop a rss feed \
+(per user/channel) ', 'rss-stop gozerbot')
+
+def handle_rsschannels(bot, ievent):
+ """ rss-channels <name> .. show channels of rss feed """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing("<name>")
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss object" % name)
+ return
+ if not rssitem.watchchannels:
+ ievent.reply('%s is not in watch mode' % name)
+ return
+ result = []
+ for i in rssitem.watchchannels:
+ result.append(str(i))
+ ievent.reply("channels of %s: " % name, result, dot=True)
+
+cmnds.add('rss-channels', handle_rsschannels, 'OPER')
+examples.add('rss-channels', 'rss-channels <name> .. show channels', \
+'rss-channels gozerbot')
+
+def handle_rssaddchannel(bot, ievent):
+ """ rss-addchannel <name> [<botname>] <channel> .. add a channel to \
+ rss item """
+ try:
+ (name, botname, channel) = ievent.args
+ except ValueError:
+ try:
+ (name, channel) = ievent.args
+ botname = bot.name
+ except ValueError:
+ try:
+ name = ievent.args[0]
+ botname = bot.name
+ channel = ievent.channel
+ except IndexError:
+ ievent.missing('<name> [<botname>] <channel>')
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss object" % name)
+ return
+ if not rssitem.running:
+ ievent.reply('%s watcher is not running' % name)
+ return
+ if (botname, channel) in rssitem.watchchannels:
+ ievent.reply('we are already monitoring %s on (%s,%s)' % \
+(name, botname, channel))
+ return
+ rssitem.watchchannels.append((botname, channel))
+ watcher.save()
+ ievent.reply('%s added to %s rss item' % (channel, name))
+
+cmnds.add('rss-addchannel', handle_rssaddchannel, 'OPER')
+examples.add('rss-addchannel', 'rss-addchannel <name> [<botname>] <channel> \
+..add <channel> or <botname> <channel> to watchchannels of <name>', \
+'1) rss-addchannel gozerbot #dunkbots 2) rss-addchannel gozerbot main \
+#dunkbots')
+
+def handle_rssadditem(bot, ievent):
+ try:
+ (name, item) = ievent.args
+ except ValueError:
+ ievent.missing('<name> <item>')
+ return
+ if bot.jabber or users.allowed(ievent.userhost, ['OPER', ]):
+ target = ievent.channel.lower()
+ else:
+ target = ievent.nick.lower()
+ if not watcher.byname(name):
+ ievent.reply("we don't have a %s feed" % name)
+ return
+ watcher.itemslists.adduniq((name, target), item)
+ watcher.itemslists.save()
+ #watcher.sync(name)
+ ievent.reply('%s added to (%s,%s) itemslist' % (item, name, target))
+
+cmnds.add('rss-additem', handle_rssadditem, ['RSS', 'USER'])
+examples.add('rss-additem', 'add a token to the itemslist (per user/channel)',\
+ 'rss-additem gozerbot link')
+
+def handle_rssdelitem(bot, ievent):
+ try:
+ (name, item) = ievent.args
+ except ValueError:
+ ievent.missing('<name> <item>')
+ return
+ if users.allowed(ievent.userhost, ['OPER', 'RSS']):
+ target = ievent.channel.lower()
+ else:
+ target = ievent.nick.lower()
+ if not watcher.byname(name):
+ ievent.reply("we don't have a %s feed" % name)
+ return
+ try:
+ watcher.itemslists.remove((name, target), item)
+ watcher.itemslists.save()
+ except RssNoSuchItem:
+ ievent.reply("we don't have a %s rss feed" % name)
+ return
+ ievent.reply('%s removed from (%s,%s) itemslist' % (item, name, target))
+
+cmnds.add('rss-delitem', handle_rssdelitem, ['RSS', 'USER'])
+examples.add('rss-delitem', 'remove a token from the itemslist \
+(per user/channel)', 'rss-delitem gozerbot link')
+
+def handle_rssmarkup(bot, ievent):
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ if users.allowed(ievent.userhost, ['OPER', ]):
+ target = ievent.channel.lower()
+ else:
+ target = ievent.nick.lower()
+ try:
+ ievent.reply(str(watcher.markup[(name, target)]))
+ except KeyError:
+ pass
+
+cmnds.add('rss-markup', handle_rssmarkup, ['RSS', 'USER'])
+examples.add('rss-markup', 'show markup list for a feed (per user/channel)', \
+'rss-markup gozerbot')
+
+def handle_rssaddmarkup(bot, ievent):
+ try:
+ (name, item, value) = ievent.args
+ except ValueError:
+ ievent.missing('<name> <item> <value>')
+ return
+ if users.allowed(ievent.userhost, ['OPER', ]):
+ target = ievent.channel.lower()
+ else:
+ target = ievent.nick.lower()
+ try:
+ watcher.markup.set((name, target), item, value)
+ watcher.markup.save()
+ ievent.reply('%s added to (%s,%s) markuplist' % (item, name, target))
+ except KeyError:
+ ievent.reply("no (%s,%s) feed available" % (name, target))
+
+cmnds.add('rss-addmarkup', handle_rssaddmarkup, ['RSS', 'USER'])
+examples.add('rss-addmarkup', 'add a markup option to the markuplist \
+(per user/channel)', 'rss-addmarkup gozerbot noseperator 1')
+
+def handle_rssdelmarkup(bot, ievent):
+ try:
+ (name, item) = ievent.args
+ except ValueError:
+ ievent.missing('<name> <item>')
+ return
+ if users.allowed(ievent.userhost, ['OPER', 'RSS']):
+ target = ievent.channel.lower()
+ else:
+ target = ievent.nick.lower()
+ try:
+ del watcher.markup[(name, target)][item]
+ except (KeyError, TypeError):
+ ievent.reply("can't remove %s from %s feed's markup" % (item, name))
+ return
+ watcher.markup.save()
+ ievent.reply('%s removed from (%s,%s) markuplist' % (item, name, target))
+
+cmnds.add('rss-delmarkup', handle_rssdelmarkup, ['RSS', 'USER'])
+examples.add('rss-delmarkup', 'remove a markup option from the markuplist \
+(per user/channel)', 'rss-delmarkup gozerbot noseperator')
+
+def handle_rssdelchannel(bot, ievent):
+ """ rss-delchannel <name> [<botname>] <channel> .. delete channel \
+ from rss item """
+ botname = None
+ try:
+ (name, botname, channel) = ievent.args
+ except ValueError:
+ try:
+ (name, channel) = ievent.args
+ botname = bot.name
+ except ValueError:
+ try:
+ name = ievent.args[0]
+ botname = bot.name
+ channel = ievent.channel
+ except IndexError:
+ ievent.missing('<name> [<botname>] [<channel>]')
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss object" % name)
+ return
+ if (botname, channel) not in rssitem.watchchannels:
+ ievent.reply('we are not monitoring %s on (%s,%s)' % \
+(name, botname, channel))
+ return
+ rssitem.watchchannels.remove((botname, channel))
+ ievent.reply('%s removed from %s rss item' % (channel, name))
+ watcher.save()
+
+cmnds.add('rss-delchannel', handle_rssdelchannel, 'OPER')
+examples.add('rss-delchannel', 'rss-delchannel <name> [<botname>] \
+[<channel>] .. delete <channel> or <botname> <channel> from watchchannels of \
+<name>', '1) rss-delchannel gozerbot #dunkbots 2) rss-delchannel gozerbot \
+main #dunkbots')
+
+def handle_rssstopwatch(bot, ievent):
+ """ rss-stopwatch <name> .. stop a watcher thread """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ rssitem = watcher.byname(name)
+ if not rssitem:
+ ievent.reply("there is no %s rssitem" % name)
+ return
+ if not watcher.stopwatch(name):
+ ievent.reply("can't stop %s watcher" % name)
+ return
+ ievent.reply('stopped %s rss watch' % name)
+
+cmnds.add('rss-stopwatch', handle_rssstopwatch, 'OPER')
+examples.add('rss-stopwatch', 'rss-stopwatch <name> .. stop polling <name>', \
+'rss-stopwatch gozerbot')
+
+def handle_rsssleeptime(bot, ievent):
+ """ rss-sleeptime <name> .. get sleeptime of rss item """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss item" % name)
+ return
+ try:
+ ievent.reply('sleeptime for %s is %s seconds' % (name, \
+str(rssitem.sleeptime)))
+ except AttributeError:
+ ievent.reply("can't get sleeptime for %s" % name)
+
+cmnds.add('rss-sleeptime', handle_rsssleeptime, 'OPER')
+examples.add('rss-sleeptime', 'rss-sleeptime <name> .. get sleeping time \
+for <name>', 'rss-sleeptime gozerbot')
+
+def handle_rsssetsleeptime(bot, ievent):
+ """ rss-setsleeptime <name> <seconds> .. set sleeptime of rss item """
+ try:
+ (name, sec) = ievent.args
+ sec = int(sec)
+ except ValueError:
+ ievent.missing('<name> <seconds>')
+ return
+ if sec < 60:
+ ievent.reply('min is 60 seconds')
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss item" % name)
+ return
+ rssitem.sleeptime = sec
+ if rssitem.running:
+ watcher.changeinterval(name, sec)
+ watcher.save()
+ ievent.reply('sleeptime set')
+
+cmnds.add('rss-setsleeptime', handle_rsssetsleeptime, 'OPER')
+examples.add('rss-setsleeptime', 'rss-setsleeptime <name> <seconds> .. set \
+sleeping time for <name> .. min 60 sec', 'rss-setsleeptime gozerbot 600')
+
+def handle_rssget(bot, ievent):
+ """ rss-get <name> .. fetch rss data """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ rssitem = watcher.byname(name)
+ if rssitem == None:
+ ievent.reply("we don't have a %s rss item" % name)
+ return
+ try:
+ result = watcher.getdata(name)
+ except Exception, ex:
+ ievent.reply('%s error: %s' % (name, str(ex)))
+ return
+ response = watcher.makeresponse(name, result, ievent.channel)
+ if response:
+ ievent.reply("results of %s: %s" % (name, response))
+ else:
+ ievent.reply("can't match watcher data")
+
+cmnds.add('rss-get', handle_rssget, ['RSS', 'USER', 'ANON'])
+examples.add('rss-get', 'rss-get <name> .. get data from <name>', \
+'rss-get gozerbot')
+
+def handle_rssrunning(bot, ievent):
+ """ rss-running .. show which watchers are running """
+ result = watcher.runners()
+ resultlist = []
+ teller = 1
+ for i in result:
+ resultlist.append("%s %s" % (i[0], i[1]))
+ if resultlist:
+ ievent.reply("running rss watchers: ", resultlist, nr=1)
+ else:
+ ievent.reply('nothing running yet')
+
+cmnds.add('rss-running', handle_rssrunning, ['RSS', 'USER'])
+examples.add('rss-running', 'rss-running .. get running rsswatchers', \
+'rss-running')
+
+def handle_rsslist(bot, ievent):
+ """ rss-list .. return list of rss items """
+ result = watcher.list()
+ result.sort()
+ if result:
+ ievent.reply("rss items: ", result, dot=True)
+ else:
+ ievent.reply('no rss items yet')
+
+cmnds.add('rss-list', handle_rsslist, ['RSS', 'USER', 'ANON'])
+examples.add('rss-list', 'get list of rss items', 'rss-list')
+
+def handle_rssurl(bot, ievent):
+ """ rss-url <name> .. return url of rss item """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ result = watcher.url(name)
+ ievent.reply('url of %s: %s' % (name, result))
+
+cmnds.add('rss-url', handle_rssurl, ['RSS', 'USER', 'ANON'])
+examples.add('rss-url', 'rss-url <name> .. get url from rssitem with \
+<name>', 'rss-url gozerbot')
+
+def handle_rssitemslist(bot, ievent):
+ """ rss-itemslist <name> .. show itemslist of rss item """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ try:
+ itemslist = watcher.itemslists[(name, ievent.channel.lower())]
+ except KeyError:
+ ievent.reply("no itemslist set for (%s, %s)" % (name, \
+ievent.channel.lower()))
+ return
+ ievent.reply("itemslist of (%s, %s): " % (name, ievent.channel.lower()), \
+itemslist, dot=True)
+
+cmnds.add('rss-itemslist', handle_rssitemslist, ['RSS', 'USER'])
+examples.add('rss-itemslist', 'rss-itemslist <name> .. get itemslist of \
+<name> ', 'rss-itemslist gozerbot')
+
+def handle_rssscan(bot, ievent):
+ """ rss-scan <name> .. scan rss item for used xml items """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ if not watcher.byname(name):
+ ievent.reply('no %s feeds available' % name)
+ return
+ try:
+ result = watcher.scan(name)
+ except Exception, ex:
+ ievent.reply(str(ex))
+ return
+ if result == None:
+ ievent.reply("can't get data for %s" % name)
+ return
+ res = []
+ for i in result:
+ res.append("%s=%s" % i)
+ ievent.reply("tokens of %s: " % name, res)
+
+cmnds.add('rss-scan', handle_rssscan, 'OPER')
+examples.add('rss-scan', 'rss-scan <name> .. get possible items of <name> ', \
+'rss-scan gozerbot')
+
+def handle_rsssync(bot, ievent):
+ """ rss-sync <name> .. sync rss item data """
+ try:
+ name = ievent.args[0]
+ except IndexError:
+ ievent.missing('<name>')
+ return
+ try:
+ result = watcher.sync(name)
+ ievent.reply('%s synced' % name)
+ except Exception, ex:
+ ievent.reply("%s error: %s" % (name, str(ex)))
+
+cmnds.add('rss-sync', handle_rsssync, 'OPER')
+examples.add('rss-sync', 'rss-sync <name> .. sync data of <name>', \
+'rss-sync gozerbot')
+
+def handle_rssfeeds(bot, ievent):
+ """ rss-feeds <channel> .. show what feeds are running in a channel """
+ try:
+ channel = ievent.args[0]
+ except IndexError:
+ channel = ievent.printto
+ try:
+ result = watcher.feeds(bot.name, channel)
+ if result:
+ ievent.reply("feeds running in %s: " % channel, result, dot=True)
+ else:
+ ievent.reply('%s has no feeds running' % channel)
+ except Exception, ex:
+ ievent.reply("ERROR: %s" % str(ex))
+
+cmnds.add('rss-feeds', handle_rssfeeds, ['USER', 'RSS'])
+examples.add('rss-feeds', 'rss-feeds <name> .. show what feeds are running \
+in a channel', '1) rss-feeds 2) rss-feeds #dunkbots')
+
+def handle_rsslink(bot, ievent):
+ try:
+ feed, rest = ievent.rest.split(' ', 1)
+ except ValueError:
+ ievent.missing('<feed> <words to search>')
+ return
+ rest = rest.strip().lower()
+ try:
+ res = watcher.search(feed, 'link', rest)
+ if not res:
+ res = watcher.search(feed, 'feedburner:origLink', rest)
+ if res:
+ ievent.reply(res, dot=" \002||\002 ")
+ except KeyError:
+ ievent.reply('no %s feed data available' % feed)
+ return
+
+cmnds.add('rss-link', handle_rsslink, ['RSS', 'USER'])
+examples.add('rss-link', 'give link of item which title matches search key', \
+'rss-link gozerbot gozer')
+
+def handle_rssdescription(bot, ievent):
+ try:
+ feed, rest = ievent.rest.split(' ', 1)
+ except ValueError:
+ ievent.missing('<feed> <words to search>')
+ return
+ rest = rest.strip().lower()
+ res = ""
+ try:
+ ievent.reply(watcher.search(feed, 'description', rest), \
+dot=" \002||\002 ")
+ except KeyError:
+ ievent.reply('no %s feed data available' % feed)
+ return
+
+cmnds.add('rss-description', handle_rssdescription, ['RSS', 'USER'])
+examples.add('rss-description', 'give description of item which title \
+matches search key', 'rss-description gozerbot gozer')
+
+def handle_rssall(bot, ievent):
+ try:
+ feed = ievent.args[0]
+ except IndexError:
+ ievent.missing('<feed>')
+ return
+ try:
+ ievent.reply(watcher.all(feed, 'title'), dot=" \002||\002 ")
+ except KeyError:
+ ievent.reply('no %s feed data available' % feed)
+ return
+
+cmnds.add('rss-all', handle_rssall, ['RSS', 'USER'])
+examples.add('rss-all', "give titles of a feed", 'rss-all gozerbot')
+
+def handle_rsssearch(bot, ievent):
+ try:
+ txt = ievent.args[0]
+ except IndexError:
+ ievent.missing('<txt>')
+ return
+ try:
+ ievent.reply(watcher.searchall('title', txt), dot=" \002||\002 ")
+ except KeyError:
+ ievent.reply('no %s feed data available' % feed)
+ return
+
+cmnds.add('rss-search', handle_rsssearch, ['RSS', 'USER'])
+examples.add('rss-search', "search titles of all current feeds", \
+'rss-search goz')
+
+def handle_rssdump(bot, ievent):
+ try:
+ ievent.reply(str(watcher.rawresults[ievent.rest]))
+ except Exception, ex:
+ ievent.reply(str(ex))
+
+cmnds.add('rss-dump', handle_rssdump, 'OPER')
+examples.add('rss-dump', 'dump cached rss data', 'rss-dump')
--- gozerbot-0.99.1.orig/build/lib/gozerbot/compat/pdol.py
+++ gozerbot-0.99.1/build/lib/gozerbot/compat/pdol.py
@@ -0,0 +1,72 @@
+# gozerbot/pdol.py
+#
+#
+
+""" pickled dict of lists """
+
+__copyright__ = 'this file is in the public domain'
+
+from persist import Persist
+
+class Pdol(Persist):
+
+ """ pickled dict of lists """
+
+ def __init__(self, fname):
+ Persist.__init__(self, fname)
+ if not self.data:
+ self.data = {}
+
+ def __iter__(self, name):
+ return self.data[name].__iter__()
+
+ def __getitem__(self, item):
+ if self.data.has_key(item):
+ return self.data[item]
+
+ def __delitem__(self, item):
+ if self.data.has_key(item):
+ self.data.__delitem__(item)
+ return 1
+
+ def __setitem__(self, item, what):
+ if self.data.has_key(item):
+ self.data[item].append(what)
+ else:
+ self.data[item] = [what]
+ return 1
+
+ def add(self, item, what):
+ """ add what to items list """
+ return self.__setitem__(item, what)
+
+ def adduniq(self, item, what):
+ """ add what to items list if item not yet added """
+ if not self.data.has_key(item):
+ self.new(item)
+ if what not in self.data[item]:
+ return self.__setitem__(item, what)
+
+ def get(self, item):
+ """ get items list """
+ return self.__getitem__(item)
+
+ def new(self, what):
+ """ reset list of what """
+ self.data[what] = []
+
+ def delete(self, item, what):
+ """ remove what from item's list """
+ del self.data[item][what]
+
+ def extend(self, item, what):
+ if not self.data.has_key(item):
+ self.new(item)
+ self.data[item].extend(what)
+
+ def remove(self, item, what):
+ try:
+ self.data[item].remove(what)
+ return 1
+ except (ValueError, KeyError):
+ return 0
--- gozerbot-0.99.1.orig/build/lib/gozerbot/threads/thr.py
+++ gozerbot-0.99.1/build/lib/gozerbot/threads/thr.py
@@ -0,0 +1,163 @@
+# gozerbot/thr.py
+#
+#
+
+""" own threading wrapper. """
+
+__copyright__ = 'this file is in the public domain'
+
+# gozerbot imports
+from gozerbot.stats import stats
+from gozerbot.utils.exception import handle_exception
+from gozerbot.utils.log import rlog
+from gozerbot.utils.locking import lockdec
+from gozerbot.config import config
+
+# basic imports
+import threading, re, time, thread
+
+dontshowthreads = ['Periodical.runjob', ]
+
+# regular expression to determine thread name
+methodre = re.compile('method\s+(\S+)', re.I)
+funcre = re.compile('function\s+(\S+)', re.I)
+
+threadlock = thread.allocate_lock()
+locked = lockdec(threadlock)
+
+class Botcommand(threading.Thread):
+
+ """ thread for running bot commands. """
+
+ def __init__(self, group, target, name, args, kwargs):
+ threading.Thread.__init__(self, None, target, name, args, kwargs)
+ self.name = name
+ self.ievent = args[1]
+ self.setDaemon(True)
+
+ def join(self):
+ threading.Thread.join(self)
+
+ def run(self):
+
+ """ run the bot command. """
+
+ try:
+ rlog(10, 'thr', 'running bot command thread %s' % self.name)
+ stats.up('threads', self.name)
+ result = threading.Thread.run(self)
+
+ if self.ievent.closequeue:
+ rlog(4, 'thr', 'closing queue for %s' % self.ievent.userhost)
+ for i in self.ievent.queues:
+ i.put_nowait(None)
+
+ except Exception, ex:
+ handle_exception(self.ievent)
+ time.sleep(0.1)
+
+class Thr(threading.Thread):
+
+ """ thread wrapper. """
+
+ def __init__(self, group, target, name, args, kwargs):
+ threading.Thread.__init__(self, None, target, name, args, kwargs)
+ rlog(-14, 'thr', 'running %s .. args: %s' % (name, args))
+ self.setDaemon(True)
+ self.name = name
+ time.sleep(0.001)
+
+ def join(self):
+ threading.Thread.join(self)
+
+ def run(self):
+ """ run the thread. """
+ try:
+ if self.name not in dontshowthreads:
+ rlog(-4, 'thr', 'running thread %s' % self.name)
+ stats.up('threads', self.name)
+ threading.Thread.run(self)
+ except Exception, ex:
+ handle_exception()
+ time.sleep(1)
+
+def getname(func):
+
+ """ get name of function/method. """
+
+ name = ""
+
+ method = re.search(methodre, str(func))
+ if method:
+ name = method.group(1)
+ else:
+ function = re.search(funcre, str(func))
+ if function:
+ name = function.group(1)
+ else:
+ name = str(func)
+ return name
+
+#@locked
+def start_new_thread(func, arglist, kwargs=None):
+
+ """ start a new thread .. set name to function/method name."""
+
+ if not kwargs:
+ kwargs = {}
+
+ try:
+ name = getname(func)
+
+ if not name:
+ name = 'noname'
+
+ thread = Thr(None, target=func, name=name, args=arglist, \
+kwargs=kwargs)
+
+ rlog(-1, 'thr', 'starting %s thread' % str(func))
+
+ thread.start()
+ return thread
+
+ except:
+ handle_exception()
+ time.sleep(1)
+
+#@locked
+def start_bot_command(func, arglist, kwargs={}):
+
+ """ start a new thread .. set name to function/method name. """
+
+ if not kwargs:
+ kwargs = {}
+
+ try:
+ name = getname(func)
+
+ if not name:
+ name = 'noname'
+
+ thread = Botcommand(group=None, target=func, name=name, args=arglist, \
+kwargs=kwargs)
+
+ rlog(-1, 'thr', 'starting %s thread' % str(func))
+
+ thread.start()
+ return thread
+
+ except:
+ handle_exception()
+ time.sleep(1)
+
+def threaded(func):
+
+ """ threading decorator. """
+
+ def threadedfunc(*args, **kwargs):
+ if config['PAE']:
+ func(*args, **kwargs)
+ else:
+ start_new_thread(func, args, kwargs)
+
+ return threadedfunc
--- gozerbot-0.99.1.orig/build/lib/gozerbot/threads/threadloop.py
+++ gozerbot-0.99.1/build/lib/gozerbot/threads/threadloop.py
@@ -0,0 +1,135 @@
+# gozerbot/threads/threadloop.py
+#
+#
+
+""" class to implement start/stoppable threads. """
+
+__copyright__ = 'this file is in the public domain'
+
+# gozerbot imports
+from gozerbot.utils.log import rlog
+from gozerbot.config import config
+from gozerbot.utils.exception import handle_exception
+
+# core thread import
+from thr import start_new_thread
+
+# basic imports
+import Queue, time
+
+class ThreadLoop(object):
+
+ """ implement startable/stoppable threads. """
+
+ def __init__(self, name="", queue=None):
+ self.name = name or 'idle'
+ self.stopped = False
+ self.running = False
+ self.outs = []
+ self.queue = queue or Queue.Queue()
+ self.nowrunning = "none"
+
+ def _loop(self):
+ rlog(0, "threadloop", 'starting threadloop')
+ while not self.stopped:
+ try:
+ self.running = True
+ try:
+ data = self.queue.get_nowait()
+ except Queue.Empty:
+ if self.stopped:
+ break
+ time.sleep(0.1)
+ continue
+
+ if self.stopped:
+ break
+
+ if not data:
+ break
+ rlog(0, self.name, 'running %s' % str(data))
+ self.handle(*data)
+ except Exception, ex: handle_exception()
+
+ self.running = False
+ rlog(0, self.name, 'stopping threadloop')
+
+ def put(self, *data):
+
+ """ put data on task queue. """
+
+ self.queue.put_nowait(data)
+
+ def start(self):
+
+ """ start the thread. """
+
+ if not self.running:
+ start_new_thread(self._loop, ())
+
+ def stop(self):
+
+ """ stop the thread. """
+
+ self.stopped = True
+ self.running = False
+ self.queue.put(None)
+
+ def handle(self, *args, **kwargs):
+
+ """ overload this. """
+
+ pass
+
+class RunnerLoop(ThreadLoop):
+
+ """ dedicated threadloop for bot commands/callbacks. """
+
+
+ def _loop(self):
+ rlog(0, "runnerloop", 'starting threadloop')
+ self.running = True
+
+ while not self.stopped:
+
+ try:
+ data = self.queue.get()
+ except Queue.Empty:
+ if self.stopped:
+ break
+ time.sleep(0.1)
+ continue
+
+ if self.stopped:
+ break
+
+ if not data:
+ break
+
+ self.nowrunning = data[0]
+ rlog(0, 'runnerloop', 'now running %s' % self.nowrunning)
+ self.handle(*data)
+
+ self.running = False
+ rlog(0, 'runnerloop', 'stopping threadloop')
+
+class ThreadSleeper(ThreadLoop):
+
+ def __init__(self, name="", timeout=1800):
+ ThreadLoop.__init__(self, name)
+ self.timeout = timeout
+
+ def _loop(self):
+ rlog(0, 'threadsleeper', 'starting threadloop')
+ self.running = True
+
+ while not self.stopped:
+ time.sleep(self.timeout)
+
+ if self.stopped:
+ break
+ rlog(-1, self.name, 'running')
+ self.handle()
+
+ self.running = False
+ rlog(0, 'threadsleeper', 'stopping threadloop')
--- gozerbot-0.99.1.orig/build/lib/gozerbot/xmpp/bot.py
+++ gozerbot-0.99.1/build/lib/gozerbot/xmpp/bot.py
@@ -0,0 +1,1125 @@
+# gozerbot/xmpp/bot.py
+#
+#
+
+""" jabber bot definition """
+
+__copyright__ = 'this file is in the public domain'
+
+## IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.users import users
+from gozerbot.utils.log import rlog
+from gozerbot.utils.exception import handle_exception
+from gozerbot.utils.trace import whichmodule
+from gozerbot.utils.locking import lockdec
+from gozerbot.utils.generic import waitforqueue, toenc, fromenc, jabberstrip, getrandomnick
+from gozerbot.config import config
+from gozerbot.persist.pdod import Pdod
+from gozerbot.utils.dol import Dol
+from gozerbot.datadir import datadir
+from gozerbot.channels import Channels
+from gozerbot.less import Less
+from gozerbot.ignore import shouldignore
+from gozerbot.callbacks import jcallbacks
+from gozerbot.threads.thr import start_new_thread
+from gozerbot.fleet import fleet
+from gozerbot.botbase import BotBase
+
+# xmpp imports
+from presence import Presence
+from message import Message
+from iq import Iq
+from core import XMLStream
+from monitor import xmppmonitor
+from wait import XMPPWait, XMPPErrorWait
+from jid import JID, InvalidJID
+
+# basic imports
+import time, Queue, os, threading, thread, types, xml, re, hashlib
+
+## END IMPORT
+
+## LOCK SECTION
+
+# locks
+outlock = thread.allocate_lock()
+inlock = thread.allocate_lock()
+connectlock = thread.allocate_lock()
+outlocked = lockdec(outlock)
+inlocked = lockdec(inlock)
+connectlocked = lockdec(connectlock)
+
+## END LOCK
+
+class Bot(XMLStream, BotBase):
+
+ """
+ xmpp bot class.
+
+ :param name: name of the xmpp bot
+ :type name: string
+ :param cfg: config file for the bot
+ :type config: gozerbot.config.Config
+ :rtype: None
+
+ """
+
+ def __init__(self, name, cfg={}):
+ BotBase.__init__(self, name, cfg)
+
+ if not self.port:
+ self.port = 5222
+
+ if not self.host:
+ raise Exception("host not set in %s xmpp bot" % self.name)
+
+ self.username = self.user.split('@')[0]
+ XMLStream.__init__(self, self.host, self.port, self.name)
+ self.type = 'xmpp'
+ self.outqueue = Queue.Queue()
+ self.sock = None
+ self.me = self.user
+ self.jid = self.me
+ self.lastin = None
+ self.test = 0
+ self.connecttime = 0
+ self.connection = None
+ self.privwait = XMPPWait()
+ self.errorwait = XMPPErrorWait()
+ self.monitor = xmppmonitor
+ self.jabber = True
+ self.connectok = threading.Event()
+ self.jids = {}
+ self.topics = {}
+ self.timejoined = {}
+ self.channels409 = []
+
+ if not self.state.has_key('ratelimit'):
+ self.state['ratelimit'] = 0.05
+
+ if self.port == 0:
+ self.port = 5222
+
+ self.monitor.start()
+
+ def _resumedata(self):
+
+ """
+ return data needed for resuming.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot._resumedata
+
+ """
+
+ return {self.name: [self.server, self.user, self.password, self.port]}
+
+ def _outputloop(self):
+
+ """
+ loop to take care of output to the server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot._outputloop
+
+ """
+
+ rlog(10, self.name, 'starting outputloop')
+ lastsend = time.time()
+ charssend = 0
+
+ while not self.stopped:
+ time.sleep(0.01)
+ what = self.outqueue.get()
+
+ if self.stopped or what == None:
+ break
+
+ if charssend + len(what) < 1000:
+
+ try:
+ self._raw(what)
+ except Exception, ex:
+ self.error = str(ex)
+ handle_exception
+ continue
+
+ lastsend = time.time()
+ charssend += len(what)
+
+ else:
+
+ if time.time() - lastsend > 1:
+
+ try:
+ self._raw(what)
+ except Exception, ex:
+ handle_exception()
+ continue
+
+ lastsend = time.time()
+ charssend = len(what)
+ continue
+
+ charssend = 0
+ sleeptime = self.cfg['jabberoutsleep'] or config['jabberoutsleep']
+
+ if not sleeptime:
+ sleeptime = 1
+
+ rlog(10, self.name, 'jabberoutsleep .. sleeping %s seconds' % sleeptime)
+ time.sleep(sleeptime)
+
+ try:
+ self._raw(what)
+ except Exception, ex:
+ handle_exception()
+
+ rlog(10, self.name, 'stopping outputloop .. %s' % (self.error or 'no error set'))
+
+ def _keepalive(self):
+
+ """
+ keepalive method .. send empty string to self every 3 minutes.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot._keepalive
+
+ """
+
+ nrsec = 0
+
+
+
+ while not self.stopped:
+ time.sleep(1)
+ nrsec += 1
+
+ if nrsec < 180:
+ continue
+ else:
+ nrsec = 0
+
+ self.sendpresence()
+
+ def sendpresence(self):
+ """
+ send presence based on status and status text
+ set by user
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.sendpresence
+
+ """
+
+ if self.state.has_key('status') and self.state['status']:
+ status = self.state['status']
+ else:
+ status = ""
+ if self.state.has_key('show') and self.state['show']:
+ show = self.state['show']
+ else:
+ show = ""
+ rlog(4, self.name, 'keepalive: %s - %s' % (show, status))
+ if show and status:
+ p = Presence({'to': self.me, 'show': show, 'status': status}, self)
+ elif show:
+ p = Presence({'to': self.me, 'show': show }, self)
+ elif status:
+ p = Presence({'to': self.me, 'status': status}, self)
+ else:
+ p = Presence({'to': self.me }, self)
+
+ self.send(p)
+
+ def _keepchannelsalive(self):
+
+ """
+ channels keep alive method.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot._keepchannelsalive
+
+ """
+
+ nrsec = 0
+ p = Presence({'to': self.me, 'txt': '' }, self)
+
+ while not self.stopped:
+ time.sleep(1)
+ nrsec += 1
+
+ if nrsec < 600:
+ continue
+ else:
+ nrsec = 0
+
+ for chan in self.state['joinedchannels']:
+
+ if chan not in self.channels409:
+ p = Presence({'to': chan}, self)
+ self.send(p)
+
+ def connect(self, reconnect=True):
+
+ """
+ connect the xmpp server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.connect
+
+ """
+
+
+ if self.stopped:
+ rlog(100, self.name, 'bot is stopped .. not connecting')
+ return
+ try:
+ if not XMLStream.connect(self):
+ rlog(10, self.name, 'connect to %s:%s failed' % (self.host, self.port))
+ return
+ else:
+ rlog(10, self.name, 'connected')
+ self.logon(self.user, self.password)
+ start_new_thread(self._outputloop, ())
+ start_new_thread(self._keepalive, ())
+ #start_new_thread(self._keepchannelsalive, ())
+ self.requestroster()
+ self._raw("<presence/>")
+ self.connectok.set()
+ self.sock.settimeout(None)
+ return True
+ except Exception, ex:
+ handle_exception()
+ if reconnect:
+ self.reconnect()
+
+ def logon(self, user, password):
+
+ """
+ logon the xmpp server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.logon
+
+ """
+
+ iq = self.initstream()
+ if not self.auth(user, password, iq.id):
+ if self.register(user, password):
+ time.sleep(5)
+ self.auth(user, password)
+ else:
+ self.exit()
+ return
+ XMLStream.logon(self)
+
+ def initstream(self):
+
+ """
+ send initial string sequence to the xmpp server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.initstream
+
+ """
+
+
+ rlog(10, self.name, 'starting initial stream sequence')
+ self._raw("""<stream:stream to='%s' xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams'>""" % (self.user.split('@')[1], ))
+ result = self.connection.read()
+ iq = self.loop_one(result)
+ rlog(3, self.name, "initstream: %s" % result)
+ return iq
+
+ def register(self, jid, password):
+
+ """
+ register the jid to the server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.register
+
+ """
+
+ try:
+ resource = jid.split("/")[1]
+ except IndexError:
+ resource = "gozerbot"
+ rlog(10, self.name, 'registering %s' % jid)
+ self._raw("""<iq type='get'><query xmlns='jabber:iq:register'/><username>%s</username></iq>""" % jid.split("@")[0])
+ #self._raw("""<iq type='get' id='reg1' />""")
+ result = self.connection.read()
+ #rlog(3, self.name, 'register: %s' % result)
+ iq = self.loop_one(result)
+ if not iq:
+ rlog(10, self.name, "unable to register")
+ return
+ rlog(3, self.name, 'register: %s' % str(iq))
+ self._raw("""<iq type='set'><query xmlns='jabber:iq:register'><username>%s</username><resource>%s</resource><password>%s</password></query></iq>""" % (jid.split('@')[0], resource, password))
+ result = self.connection.read()
+ rlog(3, self.name, 'register: %s' % result)
+ if not result:
+ return False
+ iq = self.loop_one(result)
+ if not iq:
+ rlog(10, self.name, "can't decode data: %s" % result)
+ return False
+ rlog(3, self.name, 'register: %s' % result)
+ if iq.error:
+ rlog(10, self.name, 'REGISTER FAILED: %s' % iq.error)
+ if iq.error.code == "405":
+ rlog(10, self.name, "this server doesn't allow registration by the bot, you need to create an account for it yourself")
+ else:
+ rlog(10, self.name, result)
+ self.error = iq.error
+ return False
+ rlog(10, self.name, 'register ok')
+ return True
+
+ def auth(self, jid, password, digest=""):
+
+ """
+ auth against the xmpp server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.auth
+
+ """
+
+ rlog(10, self.name, 'authing %s' % jid)
+ name = jid.split('@')[0]
+ rsrc = self.cfg['resource'] or config['resource'] or 'gozerbot';
+ self._raw("""<iq type='get'><query xmlns='jabber:iq:auth'><username>%s</username></query></iq>""" % name)
+ result = self.connection.read()
+ iq = self.loop_one(result)
+ rlog(3, self.name, 'auth:' + result)
+ if ('digest' in result) and digest:
+ s = hashlib.new('SHA1')
+ s.update(digest)
+ s.update(password)
+ d = s.hexdigest()
+ self._raw("""<iq type='set'><query xmlns='jabber:iq:auth'><username>%s</username><digest>%s</digest><resource>%s</resource></query></iq>""" % (name, d, rsrc))
+ else:
+ self._raw("""<iq type='set'><query xmlns='jabber:iq:auth'><username>%s</username><resource>%s</resource><password>%s</password></query></iq>""" % (name, rsrc, password))
+ result = self.connection.read()
+ iq = self.loop_one(result)
+ if not iq:
+ rlog(10, self.name, 'auth failed: %s' % result)
+ return False
+ rlog(3, self.name, 'auth: ' + result)
+ if iq.error:
+ rlog(10, self.name, 'AUTH FAILED: %s' % iq.error)
+ if iq.error.code == "401":
+ rlog(10, self.name, "wrong user or password (or user not known)")
+ else:
+ rlog(10, self.name, result)
+ self.error = iq.error
+ return False
+ rlog(10, self.name, 'auth ok')
+ return True
+
+ def requestroster(self):
+
+ """
+ request roster from xmpp server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.requestroster
+
+ """
+
+ self._raw("<iq type='get'><query xmlns='jabber:iq:roster'/></iq>")
+
+ def disconnectHandler(self, ex):
+
+ """
+ disconnect handler.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.disconnectHandler
+
+ """
+
+ rlog(100, self.name, "disconnected: %s" % str(ex))
+
+ if not self.stopped:
+ self.reconnect()
+ else:
+ self.exit()
+
+ def joinchannels(self):
+
+ """
+ join all already joined channels.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.joinchannels
+
+ """
+
+
+ for i in self.state['joinedchannels']:
+ key = self.channels.getkey(i)
+ nick = self.channels.getnick(i)
+ result = self.join(i, key, nick)
+ if result == 1:
+ rlog(10, self.name, 'joined %s' % i)
+ else:
+ rlog(10, self.name, 'failed to join %s: %s' % (i, result))
+
+ def broadcast(self, txt):
+
+ """
+ broadcast txt to all joined channels.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.broadcast
+
+ """
+
+ for i in self.state['joinedchannels']:
+ self.say(i, txt)
+
+ def handle_iq(self, data):
+
+ """
+ iq handler .. overload this when needed.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.handle_iq
+
+ """
+
+ pass
+
+ def handle_message(self, data):
+
+ """
+ message handler.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.handle_message
+
+ """
+
+ if self.test:
+ return
+
+ m = Message(data, self)
+
+ if data.type == 'groupchat' and data.subject:
+ self.topiccheck(m)
+ nm = Message(m, bot=self)
+ jcallbacks.check(self, nm)
+ return
+
+ if data.get('x').xmlns == 'jabber:x:delay':
+ rlog(5, self.name, "ignoring delayed message")
+ return
+
+ self.privwait.check(m)
+
+ if m.isresponse:
+ return
+
+ if m.groupchat:
+ m.msg = False
+
+ jid = None
+ m.origjid = m.jid
+
+ for node in m.subelements:
+ try:
+ m.jid = node.x.item.jid
+ except (AttributeError, TypeError):
+ continue
+
+ #if not m.txt:
+ # return
+ if self.me in m.fromm:
+ return 0
+
+ #if m.groupchat and self.nick == m.resource:
+ # return 0
+ go = 0
+
+ try:
+ cc = self.channels[m.channel]['cc']
+ except (TypeError, KeyError):
+ cc = config['defaultcc'] or '!'
+
+ try:
+ channick = self.channels[m.channel]['nick']
+ except (TypeError, KeyError):
+ channick = self.nick
+
+ if m.msg and not config['noccinmsg']:
+ go = 1
+ if not m.txt:
+ go = 0
+ elif m.txt[0] in cc:
+ go = 1
+ elif m.txt.startswith("%s: " % channick):
+ m.txt = m.txt.replace("%s: " % channick, "")
+ go = 1
+ elif m.txt.startswith("%s, " % channick):
+ m.txt = m.txt.replace("%s, " % channick, "")
+ go = 1
+
+ if m.txt and m.txt[0] in cc:
+ m.txt = m.txt[1:]
+
+ if go:
+ try:
+ from gozerbot.plugins import plugins
+ if plugins.woulddispatch(self, m):
+ m.usercmnd = True
+ plugins.trydispatch(self, m)
+ except:
+ handle_exception()
+
+ try:
+ if m.type == 'error':
+ if m.code:
+ rlog(10, self.name + '.error', str(m))
+ self.errorwait.check(m)
+ self.errorHandler(m)
+ except Exception, ex:
+ handle_exception()
+
+ mm = Message(m, self)
+ jcallbacks.check(self, mm)
+
+ def errorHandler(self, event):
+
+ """
+ error handler .. calls the errorhandler set in the event.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.errorHandler
+
+ """
+
+ try:
+ event.errorHandler()
+ except AttributeError:
+ rlog(10, self.name, 'unhandled error: %s' % event)
+
+ def handle_presence(self, data):
+
+ """
+ presence handler.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.handle_presence
+
+ """
+
+ p = Presence(data, self)
+ frm = p.fromm
+ nickk = ""
+ nick = p.nick
+
+ if self.me in p.userhost:
+ return 0
+
+ if nick:
+ self.userhosts.data[nick] = str(frm)
+ nickk = nick
+
+ jid = None
+
+ for node in p.subelements:
+ try:
+ jid = node.x.item.jid
+ except (AttributeError, TypeError):
+ continue
+
+ if nickk and jid:
+ channel = p.channel
+ if not self.jids.has_key(channel):
+ self.jids[channel] = {}
+ self.jids[channel][nickk] = jid
+ self.userhosts.data[nickk] = str(jid)
+ rlog(0, self.name, 'setting jid of %s (%s) to %s' % (nickk, \
+ channel, jid))
+
+ if p.type == 'subscribe':
+ pres = Presence({'to': p.fromm, 'type': 'subscribed'}, self)
+ self.send(pres)
+ pres = Presence({'to': p.fromm, 'type': 'subscribe'}, self)
+ self.send(pres)
+
+ nick = p.resource
+
+ if p.type != 'unavailable':
+ self.userchannels.adduniq(nick, p.channel)
+ p.joined = True
+ p.type = 'available'
+ elif self.me in p.userhost:
+ try:
+ del self.jids[p.channel]
+ rlog(0, self.name, 'removed %s channel jids' % p.channel)
+ except KeyError:
+ pass
+ else:
+ try:
+ del self.jids[p.channel][p.nick]
+ rlog(0, self.name, 'removed %s jid' % p.nick)
+ except KeyError:
+ pass
+
+ pp = Presence(p, self)
+ jcallbacks.check(self, pp)
+
+ if p.type == 'error':
+ for node in p.subelements:
+ try:
+ err = node.error.code
+ except (AttributeError, TypeError):
+ err = 'no error set'
+ try:
+ txt = node.text.data
+ except (AttributeError, TypeError):
+ txt = ""
+ if err:
+ rlog(10, self.name + '.error', "%s: %s" % (err, txt))
+
+ self.errorwait.check(p)
+
+ try:
+ method = getattr(self,'handle_' + err)
+ # try to call method
+ try:
+ method(p)
+ except:
+ handle_exception()
+ except AttributeError:
+ # no command method to handle event
+ pass
+
+ def reconnect(self):
+
+ """
+ reconnect to the server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.reconnect
+
+ """
+
+ if self.stopped:
+ rlog(100, self.name, 'bot is stopped .. not reconnecting')
+ return
+
+ rlog(100, self.name, 'reconnecting .. sleeping 15 seconds')
+ self.exit()
+ time.sleep(15)
+ newbot = Bot(self.name, self.cfg)
+
+ if newbot.connect():
+ self.name += '.old'
+ newbot.joinchannels()
+ fleet.replace(self.name, newbot)
+ return True
+
+ return False
+
+
+ def send(self, what):
+
+ """
+ send stanza to the server.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.send
+
+ """
+
+ try:
+ to = what['to']
+ except (KeyError, TypeError):
+ rlog(10, self.name, "can't determine where to send %s to" % what)
+ return
+
+ try:
+ jid = JID(to)
+ except (InvalidJID, AttributeError):
+ rlog(10, self.name, "invalid jid %s .. %s" % (str(to), str(what)))
+ return
+
+ try:
+ del what['from']
+ #del what['fromm']
+ except KeyError:
+ pass
+
+ try:
+ xml = what.toxml()
+ if not xml:
+ raise Exception("can't convert %s to xml .. bot.send()" % what)
+ except (AttributeError, TypeError):
+ handle_exception()
+ return
+ #raise Exception("can't convert %s to xml .. bot.send()" % what)
+
+ self.outqueue.put(toenc(xml))
+ self.monitor.put(self, what)
+
+ def sendnocb(self, what):
+
+ """
+ send to server without calling callbacks/monitors.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.sendnocb
+
+ """
+
+ try:
+ xml = what.toxml()
+ except AttributeError:
+ xml = what
+ self.outqueue.put(toenc(xml))
+
+ def action(self, printto, txt, fromm=None, groupchat=True):
+
+ """
+ send an action.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.action
+
+ """
+
+ txt = "/me " + txt
+
+ if self.google:
+ fromm = self.me
+
+ if printto in self.state['joinedchannels'] and groupchat:
+ message = Message({'to': printto, 'txt': txt, 'type': 'groupchat'}, self)
+ else:
+ message = Message({'to': printto, 'txt': txt}, self)
+
+ if fromm:
+ message.fromm = fromm
+
+ self.send(message)
+
+ def say(self, printto, txt, fromm=None, groupchat=True, speed=5, type="normal", how=''):
+
+ """
+ say txt to channel/JID.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.say
+
+ """
+
+ txt = jabberstrip(txt)
+
+ if self.google:
+ fromm = self.me
+
+ if printto in self.state['joinedchannels'] and groupchat:
+ message = Message({'to': printto, 'body': txt, 'type': 'groupchat'}, self)
+ else:
+ message = Message({'to': printto, 'body': txt, 'type': 'chat'}, self)
+
+ if fromm:
+ message.fromm = fromm
+ else:
+ message.fromm = self.me
+
+ self.send(message)
+
+ def saynocb(self, printto, txt, fromm=None, groupchat=True, speed=5, type="normal", how=''):
+
+ """
+ say txt to channel/JID without calling callbacks/monitors.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.saynocb
+
+ """
+
+ txt = jabberstrip(txt)
+
+ #if self.google:
+ # fromm = self.me
+
+ if printto in self.state['joinedchannels'] and groupchat:
+ message = Message({'to': printto, 'body': txt, 'type': 'groupchat'}, self)
+ else:
+ message = Message({'to': printto, 'body': txt}, self)
+
+ if fromm:
+ message.fromm = fromm
+ else:
+ message.fromm = self.me
+
+ self.send(message)
+
+ def userwait(self, msg, txt):
+
+ """
+ wait for user response.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.userwait
+
+ """
+
+ msg.reply(txt)
+ queue = Queue.Queue()
+ self.privwait.register(msg, queue)
+ result = queue.get()
+
+ if result:
+ return result.txt
+
+ def save(self):
+
+ """
+ save bot's state.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.save
+
+ """
+
+ self.state.save()
+
+ def quit(self):
+
+ """
+ send unavailable presence.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.quit
+
+ """
+
+ presence = Presence({'type': 'unavailable'}, self)
+
+ for i in self.state['joinedchannels']:
+ presence.to = i
+ self.send(presence)
+
+ presence = Presence({'type': 'unavailable'}, self)
+ presence['from'] = self.me
+ self.send(presence)
+ time.sleep(1)
+
+ def exit(self):
+
+ """
+ exit the bot.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.exit
+
+ """
+
+ self.quit()
+ self.stopped = 1
+ self.outqueue.put_nowait(None)
+ self.save()
+ time.sleep(3)
+ rlog(10, self.name, 'exit')
+
+ def join(self, channel, password=None, nick=None):
+
+ """
+ join conference.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.join
+
+ """
+
+ if '#' in channel:
+ return
+
+ try:
+ if not nick:
+ nick = channel.split('/')[1]
+ except IndexError:
+ nick = self.nick
+
+ channel = channel.split('/')[0]
+
+ if not self.channels.has_key(channel):
+ # init channel data
+ self.channels.setdefault(channel, {})
+
+ # setup error wait
+ q = Queue.Queue()
+ self.errorwait.register("409", q, 3)
+ self.errorwait.register("401", q, 3)
+ self.errorwait.register("400", q, 3)
+
+ # do the actual join
+ presence = Presence({'to': channel + '/' + nick}, self)
+
+ if password:
+ presence.x.password = password
+# passnode = Node('password')
+# passnode.addData(password)
+# presence.addChild(name='x', namespace='http://jabber.org/protocol/muc', \
+#payload=[passnode, ])
+
+ self.send(presence)
+ errorobj = waitforqueue(q, 3)
+
+ if errorobj:
+ err = errorobj[0].error
+ rlog(100, self.name, 'error joining %s: %s' % (channel, err))
+ if err >= '400':
+ if channel not in self.channels409:
+ self.channels409.append(channel)
+ return err
+
+ self.timejoined[channel] = time.time()
+ chan = self.channels[channel]
+ # if password is provided set it
+ chan['nick'] = nick
+
+ if password:
+ chan['key'] = password
+
+ # check for control char .. if its not there init to !
+ if not chan.has_key('cc'):
+ chan['cc'] = config['defaultcc'] or '!'
+
+ if not chan.has_key('perms'):
+ chan['perms'] = []
+
+ self.channels.save()
+
+ if channel not in self.state['joinedchannels']:
+ self.state['joinedchannels'].append(channel)
+
+ if channel in self.channels409:
+ self.channels409.remove(channel)
+
+ self.state.save()
+ return 1
+
+ def part(self, channel):
+
+ """
+ leave conference.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.part
+
+ """
+
+ if '#' in channel:
+ return
+
+ presence = Presence({'to': channel}, self)
+ presence.type = 'unavailable'
+ self.send(presence)
+
+ if channel in self.state['joinedchannels']:
+ self.state['joinedchannels'].remove(channel)
+
+ self.state.save()
+ return 1
+
+ def outputnolog(self, printto, what, how, who=None, fromm=None):
+
+ """
+ do output but don't log it.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.outputnolog
+
+ """
+
+ if fromm and shouldignore(fromm):
+ return
+
+ self.saynocb(printto, what)
+
+ def topiccheck(self, msg):
+
+ """
+ check if topic is set.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.topiccheck
+
+ """
+
+ if msg.groupchat:
+ try:
+ topic = msg.subject
+ if not topic:
+ return None
+ self.topics[msg.channel] = (topic, msg.userhost, time.time())
+ rlog(0, self.name, 'topic of %s set to %s' % \
+(msg.channel, topic))
+ except AttributeError:
+ return None
+
+ def settopic(self, channel, txt):
+
+ """
+ set topic.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.settopic
+
+ """
+
+ pres = Message({'to': channel, 'subject': txt}, self)
+ pres.type = 'groupchat'
+ self.send(pres)
+
+ def gettopic(self, channel):
+
+ """
+ get topic.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.gettopic
+
+ """
+
+ try:
+ topic = self.topics[channel]
+ return topic
+ except KeyError:
+ return None
+
+ def domsg(self, msg):
+
+ """
+ dispatch an msg on the bot.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.domsg
+
+ """
+
+ from gozerbot.plugins import plugins
+ plugins.trydispatch(self, msg)
+
+ def sendraw(self, data):
+
+ """
+ compat function.
+
+ .. literalinclude:: ../../../gozerbot/xmpp/bot.py
+ :pyobject: Bot.sendraw
+
+ """
+
+ self._raw(data)
--- gozerbot-0.99.1.orig/build/lib/gozerbot/xmpp/monitor.py
+++ gozerbot-0.99.1/build/lib/gozerbot/xmpp/monitor.py
@@ -0,0 +1,41 @@
+# gozerbot/xmpp/monitor.py
+#
+#
+
+""" monitors .. call callback on bot output. """
+
+__copyright__ = 'this file is in the public domain'
+
+# gozerbot imports
+from gozerbot.utils.exception import handle_exception
+from gozerbot.monitor import Monitor
+from gozerbot.config import config
+from gozerbot.eventbase import EventBase
+from message import Message
+
+class XMPPmonitor(Monitor):
+
+ """ monitor jabber output """
+
+ def handle(self, bot, event):
+
+ """ fire jabber monitor callbacks. """
+
+ try:
+ #event.fromm = event['from'] = event.to
+ e = Message()
+ e.copyin(event)
+ e.isreply = True
+ e.iscmnd = True
+ e.remotecmnd = True
+ e.remoteout = bot.jid
+ e.channel = event.to
+ e.fromm = e['from'] = bot.jid
+ e.nick = bot.nick
+ e.botoutput = True
+ Monitor.handle(self, bot, e)
+ except AttributeError:
+ handle_exception()
+
+# xmpp monitor
+xmppmonitor = XMPPmonitor('xmppmonitor')
--- gozerbot-0.99.1.orig/build/lib/gozerbot/xmpp/core.py
+++ gozerbot-0.99.1/build/lib/gozerbot/xmpp/core.py
@@ -0,0 +1,677 @@
+# gozerbot/xmpp/core.py
+#
+#
+
+"""
+ this module contains the core xmpp handling functions.
+
+"""
+
+
+## IMPORT SECTION
+
+# gozerbot imports
+from gozerbot.datadir import datadir
+from gozerbot.config import Config, config
+from gozerbot.utils.generic import toenc, jabberstrip
+from gozerbot.utils.log import rlog
+from gozerbot.utils.lazydict import LazyDict
+from gozerbot.utils.exception import handle_exception
+from gozerbot.utils.locking import lockdec
+from gozerbot.threads.thr import start_new_thread
+from gozerbot.utils.trace import whichmodule
+
+# dom imports
+from gozerbot.contrib.xmlstream import NodeBuilder, XMLescape
+
+# for exceptions
+import xml.parsers.expat
+
+from namespace import attributes, subelements
+
+# basic imports
+import socket, os, time, copy, logging, thread
+
+## END IMPORT
+
+## LOCK SECTION
+
+# locks
+outlock = thread.allocate_lock()
+inlock = thread.allocate_lock()
+connectlock = thread.allocate_lock()
+outlocked = lockdec(outlock)
+inlocked = lockdec(inlock)
+connectlocked = lockdec(connectlock)
+
+## END LOCK
+
+class XMLDict(LazyDict):
+
+
+ """
+ dictionairy to store xml stanza attributes.
+
+ :params input: optional dict to init with
+ :type input: dict
+
+ """
+
+ def __init__(self, input={}):
+
+ if input == None:
+ LazyDict.__init__(self)
+ else:
+ LazyDict.__init__(self, input)
+
+ try:
+ self['fromm'] = self['from']
+ except (KeyError, TypeError):
+ self['fromm'] = ''
+
+ def __getattr__(self, name):
+
+ """
+ override getattribute so nodes in payload can be accessed.
+
+ """
+
+ if not self.has_key(name) and self.has_key('subelements'):
+
+ for i in self['subelements']:
+
+ if name in i:
+ return i[name]
+
+ return LazyDict.__getattr__(self, name, default="")
+
+ def get(self, name):
+
+ """
+ get a attribute by name.
+
+ :param name: name of the attribute
+ :type name: string
+
+ .. literalinclude:: ../../../gozerbot/xmpp/core.py
+ :pyobject: XMLDict.get