def checkuser(response, request, event=None): """ check for user based on web response. first try google otherwise return 'notath@IP' """ from google.appengine.api import users as gusers userhost = "notauth" u = "notauth" nick = "notauth" user = gusers.get_current_user() if event: hostid = "%s-%s" % (request.remote_addr, event.bot.uuid) else: hostid = request.remote_addr if not user: try: email = request.get('USER_EMAIL') if not email: email = "notauth" auth_domain = request.get('AUTH_DOMAIN') who = request.get('who') if not who:who = email if auth_domain: userhost = nick = "%s@%s" % (who, auth_domain) else: userhost = nick = "%s@%s" % (who, hostid) except KeyError: userhost = nick = "notauth@%s" % hostid else: userhost = user.email() or user.nickname() if not userhost: userhost = nick = "notauth@%s" % hostid nick = user.nickname() u = userhost cfrom = whichmodule() if 'jsb' in cfrom: cfrom = whichmodule(1) if 'jsb' in cfrom: cfrom = whichmodule(2) return (userhost, user, u, nick)
def checkuser(response, request, event=None): """ check for user based on web response. first try google otherwise return 'notath@IP' """ from google.appengine.api import users as gusers userhost = "notauth" u = "notauth" nick = "notauth" user = gusers.get_current_user() hostid = request.remote_addr if not user: try: email = request.get('USER_EMAIL') if not email: email = "notauth" auth_domain = request.get('AUTH_DOMAIN') who = request.get('who') if not who:who = email if auth_domain: userhost = nick = "%s@%s" % (who, auth_domain) else: userhost = nick = "%s@%s" % (who, hostid) except KeyError: userhost = nick = "notauth@%s" % hostid else: userhost = user.email() or user.nickname() if not userhost: userhost = nick = "notauth@%s" % hostid nick = user.nickname() u = userhost cfrom = whichmodule() if 'jsb' in cfrom: cfrom = whichmodule(1) if 'jsb' in cfrom: cfrom = whichmodule(2) return (userhost, user, u, nick)
def __setattr__(self, attr, value): """ set attribute. """ if not self.overload and self.has_key(attr) and type(self[attr]) in [types.FunctionType, types.MethodType]: mod = whichmodule(2) logging.error("lazydict - cannot change a function of method: %s - called from %s" % (attr, mod)) return self[attr] = value
def doit(self, bot, event, target, direct=False): """ do the dispatching. """ if not target.enable: return if target.modname in event.chan.data.denyplug: logging.warn("%s is denied in channel %s - %s" % (target.plugname, event.channel, event.userhost)) return id = event.auth or event.userhost event.iscommand = True event.how = event.how or target.how or "overwrite" aliascheck(event) display = "%s/%s/%s" % (target.plugname, bot.cfg.name, event.nick or event.channel) logging.warning('dispatching %s (%s)' % (event.usercmnd, display)) try: if direct or event.direct: target.func(bot, event) elif (target.threaded or event.threaded) and not event.nothreads: logging.warning("DIRECT COMMAND THREAD %s (%s)" % (event.usercmnd, display)) t = start_bot_command(target.func, (bot, event)) event.threaded = True event.thread = t else: event.dontclose = False cmndrunner.put(target.speed or event.speed, display, target.func, bot, event) except Exception, ex: logging.error('%s - error executing %s' % (whichmodule(), str(target.func))) raise
def send(self, what): """ send stanza to the server. """ if not what: logging.debug("%s - can't send empty message" % self.cfg.name) return try: to = what['to'] except (KeyError, TypeError): logging.error("%s - can't determine where to send %s to" % (self.cfg.name, str(what))) return try: jid = JID(to) except (InvalidJID, AttributeError): logging.error("%s - invalid jid - %s - %s" % (self.cfg.name, str(to), whichmodule(2))) return try: del what['from'] except KeyError: pass try: xml = what.tojabber() if not xml: raise Exception("can't convert %s to xml .. bot.send()" % what) except (AttributeError, TypeError): handle_exception() return if not self.checkifvalid(xml): logging.error("%s - NOT PROPER XML - %s" % (self.cfg.name, xml)) else: self._raw(xml)
def _raw(self, stanza): """ output a xml stanza to the socket. """ if not self.connection: return time.sleep(0.01) try: stanza = stanza.strip() if not stanza: logging.debug("%s - no stanze provided. called from: %s" % (self.name, whichmodule())) return what = jabberstrip(stanza) what = toenc(stanza) logging.debug("%s - out - %s" % (self.name, what)) if not what.endswith('>') or not what.startswith('<'): logging.error('%s - invalid stanza: %s' % (self.name, what)) return if what.startswith('<stream') or what.startswith( '<message') or what.startswith( '<presence') or what.startswith('<iq'): logging.debug(u"%s - sxmpp - out - %s" % (self.name, what)) try: self.connection.send(what + u"\r\n") except AttributeError: self.connection.write(what) else: logging.error('%s - invalid stanza: %s' % (self.name, what)) except socket.error, ex: if 'Broken pipe' in str(ex): logging.debug('%s - core - broken pipe .. ignoring' % self.name) return self.error = str(ex) handle_exception()
def addjob(self, sleeptime, repeat, function, description="", *args, **kw): """ add a periodical job. """ 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 doit(self, bot, event, target, direct=False): """ do the dispatching. """ if not target.enable: return if target.modname in event.chan.data.denyplug: logging.warn("%s is denied in channel %s - %s" % (target.plugname, event.channel, event.userhost)) return id = event.auth or event.userhost event.iscommand = True event.how = event.how or target.how or "overwrite" aliascheck(event) logging.warning('dispatching %s (%s)' % (event.usercmnd, bot.cfg.name)) try: if bot.isgae: if not event.notask and (target.threaded or event.threaded) and not event.nothreads: logging.warn("LAUNCHING AS TASK") from jsb.drivers.gae.tasks import start_botevent if target.threaded == "backend": start_botevent(bot, event, "backend") else: start_botevent(bot, event, target.speed or event.speed) event.reply("task started for %s" % event.auth) else: target.func(bot, event) else: if direct or event.direct: target.func(bot, event) elif target.threaded and not event.nothreads: logging.warning("launching thread for %s (%s)" % (event.usercmnd, bot.cfg.name)) t = start_bot_command(target.func, (bot, event)) event.thread = t else: event.dontclose = False; cmndrunner.put(target.speed or event.speed, target.modname, target.func, bot, event) except Exception, ex: logging.error('%s - error executing %s' % (whichmodule(), str(target.func))) raise
def init(self): """ initialize the config object. """ if self.filename == 'mainconfig': self.comments["whitelist"] = "# whitelist used to allow ips .. bot maintains this" self.setdefault("whitelist", []) self.comments["blacklist"] = "# blacklist used to deny ips .. bot maintains this" self.setdefault("blacklist", []) self.comments["owner"] = "# global owner of all bots" self.setdefault('owner', []) self.comments["loglist"] = "# loglist .. maintained by the bot." self.setdefault('loglist', []) self.comments["loglevel"] = "# loglevel of all bots" self.setdefault('loglevel', "warn") self.comments["loadlist"] = "# loadlist .. not used yet." self.setdefault('loadlist', []) self.comments["quitmsg"] = "# message to send on quit" self.setdefault('quitmsg', "http://jsonbot.googlecode.com") self.comments["dotchars"] = "# characters to used as seperator" self.setdefault('dotchars', ", ") self.comments["floodallow"] = "# whether the bot is allowed to flood." self.setdefault('floodallow', 0) self.comments["auto_register"] = "# enable automatic registration of new users" self.setdefault('auto_register', 0) self.comments["guestasuser"] = "******" self.setdefault('guestasuser', 0) self.comments["app_id"] = "# application id used by appengine" self.setdefault('app_id', "jsonbot") self.comments["appname"] = "# application name as used by the bot" self.setdefault('appnamer', "JSONBOT") self.comments["domain"] = "# domain .. used for WAVE" self.setdefault('domain', "") self.cfile = self.dir + os.sep + self.filename self['createdfrom'] = whichmodule() self.comments["uuid"] = "# bot generated uuid for this config file"
def __init__(self, id, botname=None, type="notset", needexist=False): if not id: raise NoChannelSet() if not botname: Persist.__init__(self, getdatadir() + os.sep + 'channels' + os.sep + stripname(id), needexist=needexist) else: Persist.__init__(self, getdatadir() + os.sep + 'fleet' + os.sep + stripname(botname) + os.sep + 'channels' + os.sep + stripname(id), needexist=needexist) self.id = id self.type = type self.lastmodified = time.time() self.data.id = id self.data.enable = self.data.enable or False self.data.ops = self.data.ops or [] self.data.taglist = self.data.taglist or [] self.data.silentcommands = self.data.silentcommands or [] self.data.allowcommands = self.data.allowcommands or [] self.data.feeds = self.data.feeds or [] self.data.forwards = self.data.forwards or [] self.data.allowwatch = self.data.allowwatch or [] self.data.watched = self.data.watched or [] self.data.passwords = self.data.passwords or {} self.data.cc = self.data.cc or "" self.data.nick = self.data.nick or "jsb" self.data.key = self.data.key or "" self.data.denyplug = self.data.denyplug or [] self.data.createdfrom = whichmodule() self.data.cacheindex = 0 self.data.tokens = self.data.tokens or [] self.data.webchannels = self.data.webchannels or []
def wrapper(*args, **kw): job = JobInterval(sleeptime, repeat, function, *args, **kw) job.group = group job.description = whichmodule() periodical.jobs.append(job) logging.warn('new interval job %d with sleeptime %d' % (job.id(), sleeptime))
def __init__(self, filename, verbose=False, input={}, ddir=None, nolog=False, *args, **kw): assert filename LazyDict.__init__(self, input, *args, **kw) self.origname = filename self.origdir = ddir or getdatadir() self.setcfile(ddir, filename) self.jsondb = None if not self._comments: self._comments = {} try: import waveapi self.isdb = True self.isgae = True except ImportError: self.isgae = False self.isdb = False dodb = False try: logging.info("fromfile - %s from %s" % (self.origname, whichmodule(2))) self.fromfile(self.cfile) except IOError, ex: handle_exception() ; dodb = True if dodb or (self.isgae and not "mainconfig" in filename): try: from persist import Persist self.jsondb = Persist(self.cfile) if self.jsondb: self.merge(self.jsondb.data) logging.warn("fromdb - %s" % self.cfile) except ImportError: logging.warn("can't read config from %s - %s" % (self.cfile, str(ex))) self.init() if self.owner: logging.info("owner is %s" % self.owner) if not self.has_key("uuid"): self.setuuid() if not self.has_key("cfile"): self.cfile = self.setcfile(self.origdir, self.origname) assert self.cfile
def bind(self, bot=None, user=None, chan=None): """ bind event.bot event.user and event.chan to execute a command on it. """ target = self.auth assert target bot = bot or self.bot assert bot if not self.user and target: cfg = Config() if cfg.auto_register: bot.users.addguest(target) self.user = user or bot.users.getuser(target) logging.info("eventbase - binding user - %s - from %s" % (str(self.user), whichmodule())) if not self.chan: if chan: self.chan = chan elif self.channel: self.chan = ChannelBase(self.channel, bot.botname) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.botname) logging.info("eventbase - binding channel - %s" % str(self.chan)) if not self.user: logging.info("eventbase - no %s user found .. setting nodispatch" % target) self.nodispatch = True self.prepare(bot) return self
def doit(self, bot, event, target, wait=0): """ do the dispatching. """ if not target.enable: return if target.modname in event.chan.data.denyplug: logging.warn("commands - %s is denied in channel %s - %s" % (target.plugname, event.channel, event.userhost)) return id = event.auth or event.userhost event.iscommand = True event.how = target.how logging.warning('commands - dispatching %s for %s' % (event.usercmnd, id)) try: if bot.isgae: if not event.notask and (target.threaded or event.threaded) and not event.nothreads: logging.warn("commands - LAUNCHING AS TASK") from jsb.lib.gae.tasks import start_botevent event.txt = event.origtxt start_botevent(bot, event, event.speed) event.reply("task started for %s" % event.auth) else: target.func(bot, event) ; event.ready() ; return event else: if target.threaded and not event.nothreads: logging.warning("commands - launching thread for %s" % event.usercmnd) t = start_bot_command(target.func, (bot, event)) event.threads.append(t) else: event.dontclose = False; cmndrunner.put(target.modname, target.func, bot, event) except Exception, ex: logging.error('commands - %s - error executing %s' % (whichmodule(), str(target.func))) raise
def addjob(self, sleeptime, repeat, function, description="" , *args, **kw): """ add a periodical job. """ 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 __setattr__(self, attr, value): """ set attribute. """ if not self.overload and self.has_key(attr) and type( self[attr]) in [types.FunctionType, types.MethodType]: mod = whichmodule(2) raise Exception( "lazydict - cannot change a function of method: %s - called from %s" % (attr, mod)) self[attr] = value
def ready(self, finish=True): """ signal the event as ready - push None to all queues. """ logging.debug("%s - %s - ready called from %s" % (self.cbtype, self.txt, whichmodule())) time.sleep(0.01) if self.closequeue and self.queues: for q in self.queues: q.put_nowait(None) if not self.dontclose: self.outqueue.put_nowait(None) self.resqueue.put_nowait(None) self.inqueue.put_nowait(None) if finish: self.finished.set()
def tofile(self, filename=None, stdout=False): """ save config object to file. """ if not filename: filename = self.cfile if not filename: raise Exception("no cfile found - %s" % whichmodule(3)) logging.warn("saving %s" % self.origname) if filename.startswith(os.sep): d = [os.sep,] else: d = [] for p in filename.split(os.sep)[:-1]: if not p: continue d.append(p) ddir = os.sep.join(d) if not os.path.isdir(ddir): logging.debug("persist - creating %s dir" % ddir) try: os.mkdir(ddir) except OSError, ex: logging.error("persist - not saving - failed to make %s - %s" % (ddir, str(ex))) return
def register(self, cbtypes, cbs=None, userhosts=None, event=None, queue=None): """ add a wait object to the waiters dict. """ logging.warn("waiter - registering wait object: %s - %s" % (str(cbtypes), str(userhosts))) key = str(uuid.uuid4()) self.waiters[key] = Wait(cbtypes, cbs, userhosts, modname=whichmodule(), event=event, queue=queue) return key
def load_module(self, fullname): logging.info("importing %s from %s" % (fullname, whichmodule(1))) if 'jsb.plugs' in fullname or 'myplugs' in fullname: return _import(fullname) if fullname == "sys": return None if fullname in __builtins__: try: mod = imp.load_module(self.name, self.file, self.pathname, self.desc) finally: if self.file: self.file.close() sys.modules[fullname] = mod else: if self.file: self.file.close() mod = makeImportedModule(self.name, self.pathname, self.desc, self.scope) sys.modules[fullname] = mod return mod
def load_module(self, fullname): logging.info("importing %s from %s" % (fullname, whichmodule(1))) if "jsb.plugs" in fullname or "myplugs" in fullname: return _import(fullname) if fullname == "sys": return None if fullname in __builtins__: try: mod = imp.load_module(self.name, self.file, self.pathname, self.desc) finally: if self.file: self.file.close() sys.modules[fullname] = mod else: if self.file: self.file.close() mod = makeImportedModule(self.name, self.pathname, self.desc, self.scope) sys.modules[fullname] = mod return mod
def makebot(self, type, name, config={}, domain="", showerror=False): """ create a bot .. use configuration if provided. """ if not name: logging.error(" name is not correct: %s" % name) return if not type: type = self.data.types.get(name) if not type: logging.error("no type found for %s bot" % name) return if config: logging.debug('making %s (%s) bot - %s - from: %s' % (type, name, config.tojson(), whichmodule())) bot = None if not config: cfg = Config('fleet' + os.sep + stripname(name) + os.sep + 'config') else: cfg = config cfg.init() if not cfg.name: cfg['name'] = name cfg['botname'] = cfg['name'] if cfg.disable: logging.info("%s bot is disabled. see %s" % (name, cfg.cfile)) return if not cfg.type and type: logging.debug("%s - setting type to %s" % (cfg.cfile, type)) cfg.type = type if not cfg['type']: try: self.data['names'].remove(name) self.save() except ValueError: pass raise Exception("no bot type specified") if not cfg.owner: logging.debug("%s - owner not set .. using global config." % cfg.name) cfg.owner = getmainconfig().owner if not cfg.domain and domain: cfg.domain = domain if not cfg: raise Exception("can't make config for %s" % name) #cfg.save() bot = BotFactory().create(type, cfg) return bot
def __init__(self, filename, verbose=False, input={}, ddir=None, nolog=False, *args, **kw): assert filename LazyDict.__init__(self, input, *args, **kw) a = "%s%s" % (os.sep, os.sep) filename = filename.replace(a, os.sep) self.origname = filename self.origdir = ddir or getdatadir() self.setcfile(ddir or getdatadir(), filename) self.jsondb = None if not self._comments: self._comments = {} logging.info("fromfile - %s from %s" % (self.origname, whichmodule(2))) self.fromfile(self.cfile) self.origdir = ddir or getdatadir() self.setcfile(ddir or getdatadir(), filename) self.init() if self.owner: logging.info("owner is %s" % self.owner) if not self.has_key("uuid"): self.setuuid() if not self.has_key("cfile"): self.cfile = self.setcfile(self.origdir, self.origname) assert self.cfile if not self.origdir in self.cfile: raise WrongFileName("%s not in %s" % (self.origdir, self.cfile))
def bind(self, bot=None, user=None, chan=None, force=False, dolog=None): """ bind event.bot event.user and event.chan to execute a command on it. """ #if self.nodispatch: logging.debug("nodispatch is set on event . .not binding"); return dolog = dolog or 'TICK' not in self.cbtype if dolog and not force and self.dontbind: logging.debug("dontbind is set on event . .not binding"); return if not force and self.bonded and (bot and not bot.isgae): logging.debug("already bonded") ; return dolog and logging.debug("starting bind on %s - %s" % (self.userhost, self.txt)) target = self.auth or self.userhost bot = bot or self.bot if not self.chan: if chan: self.chan = chan elif self.channel: self.chan = ChannelBase(self.channel, bot.cfg.name) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.cfg.name) if self.chan: #self.debug = self.chan.data.debug or False dolog and logging.debug("channel bonded - %s" % self.chan.data.id) self.prepare(bot) if not target: self.bonded = True ; return if not self.user and target and not self.nodispatch: if user: u = user else: u = bot.users.getuser(target) if not u: cfg = getmainconfig() if cfg.auto_register and self.iscommand: u = bot.users.addguest(target, self.nick) if u: logging.warn("auto_register applied") else: logging.error("can't add %s to users database" % target) if u: msg = "!! %s -=- %s -=- %s -=- (%s) !!" % (u.data.name, self.usercmnd or "none", self.cbtype, self.bot.cfg.name) dolog and logging.warn(msg) self.user = u if self.user: dolog and logging.debug("user bonded from %s" % whichmodule()) if not self.user and target: dolog and self.iscommand and logging.warn("no %s user found" % target) ; self.nodispatch = True if self.bot: self.inchan = self.channel in self.bot.state.data.joinedchannels self.bonded = True return self
def __init__(self, id, botname=None, type="notset"): if not id: raise NoChannelSet() if not botname: Persist.__init__(self, getdatadir() + os.sep + 'channels' + os.sep + stripname(id)) else: Persist.__init__(self, getdatadir() + os.sep + 'fleet' + os.sep + botname + os.sep + 'channels' + os.sep + stripname(id)) self.id = id self.type = type self.lastmodified = time.time() self.data.id = id self.data.silentcommands = self.data.silentcommands or [] self.data.allowcommands = self.data.allowcommands or [] self.data.feeds = self.data.feeds or [] self.data.forwards = self.data.forwards or [] self.data.allowwatch = self.data.allowwatch or [] self.data.watched = self.data.watched or [] self.data.passwords = self.data.passwords or {} self.data.cc = self.data.cc or "!" self.data.nick = self.data.nick or "jsb" self.data.key = self.data.key or "" self.data.denyplug = self.data.denyplug or [] self.data.createdfrom = whichmodule() self.data.cacheindex = 0 self.data.tokens = self.data.tokens or [] self.data.webchannels = self.data.webchannels or [] logging.debug("channelbase - created channel %s" % id)
def wrapper(*args, **kw): job = JobAt(start, interval, repeat, function, *args, **kw) job.group = group job.description = whichmodule() periodical.jobs.append(job)
def register(self, cb, modname=None, cbtype=None, *args, **kwargs): """ register a sink callback. """ modname = modname or whichmodule(2) self.cbs.add(Sinker(cb, modname, cbtype, *args, **kwargs)) logging.warn("registered %s sink handler for the %s plugin" % (str(cb), modname))
def unregister(self, modname=None): """ unregister a sink callback. """ modname = modname or whichmodule(2) try: size = len(self.cbs[modname]) ; del self.cbs[modname] ; logging.warn("%s sink callbacks removed" % size) except KeyError: pass
def init(self): """ initialize the config object. """ if self.filename == 'mainconfig': self.comments["whitelist"] = "# - whitelist used to allow ips .. bot maintains this" self.setdefault("whitelist", []) self.comments["blacklist"] = "# - blacklist used to deny ips .. bot maintains this" self.setdefault("blacklist", []) self.setdefault('owner', []) self.comments["loglist"] = "# - loglist .. maintained by the bot." self.setdefault('loglist', []) self.comments["loglevel"] = "# - loglevel of all bots" self.setdefault('loglevel', "warn") self.comments["loadlist"] = "# - loadlist .. not used yet." self.setdefault('loadlist', []) self.comments["quitmsg"] = "# - message to send on quit" self.setdefault('quitmsg', "http://jsonbot.googlecode.com") self.comments["dotchars"] = "# - characters to used as seperator." self.setdefault('dotchars', ", ") self.comments["floodallow"] = "# - whether the bot is allowed to flood." self.setdefault('floodallow', 0) self.comments["auto_register"] = "# - enable automatic registration of new users." self.setdefault('auto_register', 0) self.comments["guestasuser"] = "******" self.setdefault('guestasuser', 0) self.comments["app_id"] = "# - application id used by appengine." self.setdefault('app_id', "jsonbot") self.comments["appname"] = "# - application name as used by the bot." self.setdefault('appname', "JSONBOT") self.comments["domain"] = "# - domain .. used for WAVE." self.setdefault('domain', "") self.comments["color"] = "# - color used in the webconsole." self.setdefault('color', "") self.comments["colors"] = "# - enable colors in logging." self.setdefault('colors', "") self.comments["memcached"] = "# - enable memcached." self.setdefault('memcached', 0) self['createdfrom'] = whichmodule() self.comments['datadir'] = "# - directory to store bot data in." self.comments["owner"] = "# - owner of the bot." self.comments["uuid"] = "# - bot generated uuid for this config file." self.comments["user"] = "******" self.comments["host"] = "# - host part of the user, derived from user var." self.comments["server"] = "# - server to connect to (only when different from users host)." self.comments["password"] = "******" self.comments["port"] = "# - port to connect to (IRC)." self.comments["ssl"] = "# - whether to enable ssl (set to 1 to enable)." self.comments["ipv6"] = "# - whether to enable ssl (set to 1 to enable)." self.comments["name"] = "# - the name of the bot." self.comments["disable"] = "# - set this to 0 to enable the bot." self.comments["followlist"] = "# - who to follow on the bot .. bot maintains this list." self.comments["networkname"] = "# - networkname .. not used right now." self.comments["type"] = "# - the bot's type." self.comments["nick"] = "# - the bot's nick." self.comments["channels"] = "# - channels to join." self.comments["cfile"] = "# - filename of this config file. edit this when you move this file." self.comments["createdfrom"] = "# - function that created this config file. bot generated" self.comments["dir"] = "# - directory in which this config file lives." self.comments["isdb"] = "# - whether this config file lives in the database and not on file." self.comments["filename"] = "# - filename of this config file." self.comments["username"] = "******" self.comments["fulljids"] = "# - use fulljids of bot users (used in non anonymous conferences."
def _raw(self, stanza): """ output a xml stanza to the socket. """ if not self.connection: return time.sleep(0.01) try: stanza = stanza.strip() if not stanza: logging.debug("%s - no stanze provided. called from: %s" % (self.name, whichmodule())) return what = jabberstrip(stanza) what = toenc(stanza) logging.debug("%s - out - %s" % (self.name, what)) if not what.endswith('>') or not what.startswith('<'): logging.error('%s - invalid stanza: %s' % (self.name, what)) return if what.startswith('<stream') or what.startswith('<message') or what.startswith('<presence') or what.startswith('<iq'): logging.debug(u"%s - sxmpp - out - %s" % (self.name, what)) try: self.connection.send(what + u"\r\n") except AttributeError: self.connection.write(what) else: logging.error('%s - invalid stanza: %s' % (self.name, what)) except socket.error, ex: if 'Broken pipe' in str(ex): logging.debug('%s - core - broken pipe .. ignoring' % self.name) return self.error = str(ex) handle_exception()
def bind(self, bot=None, user=None, chan=None): """ bind event.bot event.user and event.chan to execute a command on it. """ target = self.auth assert target bot = bot or self.bot assert bot if not self.user and target: cfg = Config() if cfg.auto_register: bot.users.addguest(target) self.user = user or bot.users.getuser(target) logging.info("eventbase - binding user - %s - from %s" % (str(self.user), whichmodule())) if not self.chan: if chan: self.chan = chan elif self.channel: self.chan = ChannelBase(self.channel, bot.botname) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.botname) logging.info("eventbase - binding channel - %s" % str(self.chan)) if not self.user: logging.info("eventbase - no %s user found .. setting nodispatch" % target) ; self.nodispatch = True self.prepare(bot) return self
def ready(self, finish=True): """ signal the event as ready - push None to all queues. """ if self.finished.isSet(): logging.debug("event is already finished.") ; return if self.type != "TICK": logging.info("%s.%s - %s - from %s - %s" % (self.bottype, self.cbtype, str(self.ctime), whichmodule(), self.txt)) for i in range(10): if not self.outqueue.empty(): break time.sleep(0.01) if self.closequeue and self.queues: for q in self.queues: q.put_nowait(None) if not self.dontclose: self.outqueue.put_nowait(None) self.resqueue.put_nowait(None) self.inqueue.put_nowait(None) for cb in self.cbs: try: cb(self.result) except Exception, ex: handle_exception() if finish: self.finished.set() for event in self.waiting: if event != self: event.ready()
def wrapper(*args, **kw): job = JobInterval(1, 0, function, *args, **kw) job.group = group job.description = whichmodule() periodical.jobs.append(job) logging.debug('new interval job %d running per second' % job.id())
def init(self): """ initialize the config object. """ if not self._comments: self._comments = {} if self.filename == 'mainconfig': self._comments["whitelist"] = "# - whitelist used to allow ips .. bot maintains this" self.setdefault("whitelist", []) self._comments["blacklist"] = "# - blacklist used to deny ips .. bot maintains this" self.setdefault("blacklist", []) self.setdefault('owner', []) self._comments["loglist"] = "# - loglist .. maintained by the bot." self.setdefault('loglist', []) self._comments["loglevel"] = "# - loglevel of all bots" self.setdefault('loglevel', "warn") self._comments["loadlist"] = "# - loadlist .. not used yet." self.setdefault('loadlist', []) self._comments["quitmsg"] = "# - message to send on quit" self.setdefault('quitmsg', "http://jsonbot.googlecode.com") self._comments["dotchars"] = "# - characters to used as seperator." self.setdefault('dotchars', ", ") self._comments["floodallow"] = "# - whether the bot is allowed to flood." self.setdefault('floodallow', 1) self._comments["auto_register"] = "# - enable automatic registration of new users." self.setdefault('auto_register', 0) self._comments["guestasuser"] = "******" self.setdefault('guestasuser', 0) self._comments["globalcc"] = "# - global control character" self.setdefault('globalcc', "") self._comments["app_id"] = "# - application id used by appengine." self.setdefault('app_id', "jsonbot") self._comments["appname"] = "# - application name as used by the bot." self.setdefault('appname', "JSONBOT") self._comments["domain"] = "# - domain .. used for WAVE." self.setdefault('domain', "") self._comments["color"] = "# - color used in the webconsole." self.setdefault('color', "") self._comments["colors"] = "# - enable colors in logging." self.setdefault('colors', "") self._comments["memcached"] = "# - enable memcached." self.setdefault('memcached', 0) self._comments["allowrc"] = "# - allow execution of rc files." self.setdefault('allowrc', 0) self._comments["allowremoterc"] = "# - allow execution of remote rc files." self.setdefault('allowremoterc', 0) self._comments['dbenable'] = "# - enable database support" self.setdefault('dbenable', 0) self._comments['dbtype'] = "# - type of database .. sqlite or mysql at this time." self.setdefault('dbtype', 'sqlite') self._comments['dbname'] = "# - database name" self.setdefault('dbname', "main.db") self._comments['dbhost'] = "# - database hostname" self.setdefault('dbhost', "localhost") self._comments['dbuser'] = "******" self.setdefault('dbuser', "bart") self._comments['dbpasswd'] = "# - database password" self.setdefault('dbpasswd', "mekker2") self._comments['ticksleep'] = "# - nr of seconds to sleep before creating a TICK event." self.setdefault('ticksleep', 1) self._comments['bindhost'] = "# - host to bind to" self.setdefault("bindhost", "") self['createdfrom'] = whichmodule() if 'xmpp' in self.cfile: self.setdefault('fulljids', 1) if 'fleet' in self.cfile: self.setdefault('disable', 1) self.setdefault("owner", []) self.setdefault("user", "") self.setdefault("host", "") self.setdefault("server", "") self.setdefault("ssl", 0) self.setdefault("ipv6", 0) self.setdefault("channels", []) self.setdefault("port", "") self.setdefault("password", "") self._comments['datadir'] = "# - directory to store bot data in." self._comments["owner"] = "# - owner of the bot." self._comments["uuid"] = "# - bot generated uuid for this config file." self._comments["user"] = "******" self._comments["host"] = "# - host part of the user, derived from user var." self._comments["server"] = "# - server to connect to (only when different from users host)." self._comments["password"] = "******" self._comments["port"] = "# - port to connect to (IRC)." self._comments["ssl"] = "# - whether to enable ssl (set to 1 to enable)." self._comments["ipv6"] = "# - whether to enable ssl (set to 1 to enable)." self._comments["name"] = "# - the name of the bot." self._comments["disable"] = "# - set this to 0 to enable the bot." self._comments["followlist"] = "# - who to follow on the bot .. bot maintains this list." self._comments["networkname"] = "# - networkname .. not used right now." self._comments["type"] = "# - the bot's type." self._comments["nick"] = "# - the bot's nick." self._comments["channels"] = "# - channels to join." self._comments["cfile"] = "# - filename of this config file. edit this when you move this file." self._comments["createdfrom"] = "# - function that created this config file. bot generated" self._comments["dir"] = "# - directory in which this config file lives." self._comments["isdb"] = "# - whether this config file lives in the database and not on file." self._comments["filename"] = "# - filename of this config file." self._comments["username"] = "******" self._comments["fulljids"] = "# - use fulljids of bot users (used in non anonymous conferences." self._comments["servermodes"] = "# - string of modes to send to the server after connect." self._comments["realname"] = "# - name used in the ident of the bot." self._comments["onconnect"] = "# - string to send to server after connect." self._comments["onconnectmode"] = "# - MODE string to send to server after connect." self._comments["realname"] = "# - mode string to send to the server after connect." self._comments["issaved"] = "# - whether this config file has been saved. " self._comments["origdir"] = "# - original datadir for this configfile. " self._comments["origname"] = "# - displayable name of the config file name. " return self
def wrapper(*args, **kw): job = JobInterval(86400, 0, function, *args, **kw) job.group = group job.description = whichmodule() periodical.jobs.append(job) logging.warb('new interval job %d running daily' % job.id())
class EventBase(LazyDict): """ basic event class. """ def __init__(self, input={}, bot=None): LazyDict.__init__(self) if bot: self.bot = bot self.threaded = False self.untildone = False self.ctime = time.time() self.speed = self.speed or 5 self.nrout = self.nrout or 0 if input: self.copyin(input) if not self.token: self.setup() def copyin(self, eventin): """ copy in an event. """ self.update(eventin) return self def setup(self): self.token = self.token or str(uuid.uuid4().hex) self.finished = threading.Condition() self.busy = deque() self.inqueue = deque() self.outqueue = deque() self.resqueue = deque() self.ok = threading.Event() return self def __deepcopy__(self, a): """ deepcopy an event. """ e = EventBase(self) return e def launched(self): logging.info(str(self)) self.ok.set() def startout(self): if not self.nodispatch and not self.token in self.busy: self.busy.append(self.token) def ready(self, what=None, force=False): """ signal the event as ready - push None to all queues. """ if self.threaded and self.untildone: return if self.nodispatch: return if not "TICK" in self.cbtype: logging.info(self.busy) try: self.busy.remove(self.token) except ValueError: pass if not self.busy or force: self.notify() def notify(self, p=None): self.finished.acquire() self.finished.notifyAll() self.finished.release() if not "TICK" in self.cbtype: logging.info("notified %s" % str(self)) def execwait(self, direct=False): from jsb.lib.commands import cmnds e = self.bot.put(self) if e: return e.wait() else: logging.info("no response for %s" % self.txt) ; return logging.info("%s wont dispatch" % self.txt) def wait(self, nr=1000): nr = int(nr) result = [] #if self.nodispatch: return if not self.busy: self.startout() self.finished.acquire() if self.threaded and self.untildone: logging.info("waiting until done") while 1: self.finished.wait(0.1) else: while nr > 0 and (self.busy and not self.dostop): self.finished.wait(0.1) ; nr -= 100 self.finished.release() if self.wait and self.thread: logging.warn("joining thread %s" % self.thread) ; self.thread.join(nr/1000) if not "TICK" in self.cbtype: logging.info(self.busy) if not self.resqueue: res = waitforqueue(self.resqueue, nr) else: res = self.resqueue return list(res) def waitandout(self, nr=1000): res = self.wait(nr) if res: for r in res: self.reply(r) def execute(self, direct=False, *args, **kwargs): """ dispatch event onto the cmnds object. this method needs both event.nodispatch = False amd event.iscommand = True set. """ logging.debug("execute %s" % self.cbtype) from jsb.lib.commands import cmnds res = self self.startout() self.bind(self.bot, force=True, dolog=True) if not self.pipelined and ' ! ' in self.txt: res = self.dopipe(direct, *args, **kwargs) else: try: res = cmnds.dispatch(self.bot, self, direct=direct, *args, **kwargs) except RequireError, ex: logging.error(str(ex)) except NoSuchCommand, ex: logging.error("we don't have a %s command" % str(ex)) ; self.ready() except NoSuchUser, ex: logging.error("we don't have user for %s" % str(ex)) except Exception , ex: handle_exception() return res def dopipe(self, direct=False, *args, **kwargs): """ split cmnds, create events for them, chain the queues and dispatch. """ direct = True logging.warn("starting pipeline") origout = self.outqueue events = [] self.pipelined = True splitted = self.txt.split(" ! ") counter = 1 for i in range(len(splitted)): t = splitted[i].strip() if not t: continue cc = self.getcc() if not t[0] in cc: t = cc[0] + t e = self.bot.make_event(self.userhost, self.channel, t, showall=self.showall) if self.sock: e.sock = self.sock e.nick = self.nick e.outqueue = deque() e.busy = deque() e.prev = None e.pipelined = True e.dontbind = False e.bind(self.bot) if not e.woulddispatch(): raise NoSuchCommand(e.txt) events.append(e) counter += 1 prev = None for i in range(len(events)): if i > 0: events[i].inqueue = events[i-1].outqueue events[i].prev = events[i-1] events[-1].pipelined = False events[-1].dontclose = False if self.sock and self.isdcc: events[-1].channel = self.sock for i in range(len(events)): if not direct: self.bot.put(events[i]) else: events[i].execute(direct) self.ready() return events[-1] def prepare(self, bot=None): """ prepare the event for dispatch. """ if bot: self.bot = bot or self.bot assert(self.bot) self.origin = self.channel self.bloh() self.makeargs() if not self.nolog: logging.debug("%s - prepared event - %s" % (self.auth, self.cbtype)) return self def bind(self, bot=None, user=None, chan=None, force=False, dolog=None, noraise=True): """ bind event.bot event.user and event.chan to execute a command on it. """ dolog = dolog or 'TICK' not in self.cbtype if self.cbtype == "PRESENCE" and not force: dolog and logging.info("presence from %s, not binding" % self.stripped or self.nick) ; return self if self.cbtype == "PING" and not force: logging.debug("not binding PING") ; return self if dolog and not force and self.dontbind: logging.debug("dontbind is set on event . .not binding"); return self if not force and self.bonded: logging.debug("already bonded") ; return self dolog and logging.debug("starting bind on %s - %s" % (self.userhost, self.txt)) if not self.options:self.makeoptions() target = self.auth or self.userhost bot = bot or self.bot dolog and target and logging.info("target is %s" % target) if not self.chan: if chan: self.chan = chan elif self.channelchanged: try: self.chan = ChannelBase(self.origchannel, bot.cfg.name, needexist=self.origchannel) except WrongFileName, ex: self.error = "no such channel %s" % self.channel logging.error(self.error) if not self.chan: if self.channel: self.chan = ChannelBase(self.channel, bot.cfg.name) elif self.userhost: self.chan = ChannelBase(self.userhost, bot.cfg.name) if self.chan: dolog and logging.debug("channel bonded - %s" % self.chan.data.id) self.chanid = self.chan.data.id self.prepare(bot) if not target: self.bonded = True ; return self if target.lower() in bot.state['ignore']: logging.warn("user %s is ignored .. not binding" % target) ; raise UserIgnored(target) if not self.user and target and not self.nodispatch: if user: u = user else: u = bot.users.getuser(target) if not u: cfg = getmainconfig() if cfg.auto_register and self.iscommand: u = bot.users.addguest(target, self.nick) if u: logging.warn("auto_register applied") else: logging.error("can't add %s to users database" % target) if u: msg = "!! %s -=- %s -=- %s -=- (%s) !!" % (u.data.name, self.usercmnd or "none", self.cbtype, self.bot.cfg.name) if self.cbtype in ["PING", ]: dolog and logging.info(msg) else: dolog and logging.warn(msg) self.user = u if self.user: dolog and logging.debug("user bonded from %s" % whichmodule()) if not self.user and target: dolog and self.iscommand and logging.warn("no %s user found" % target) ; self.nodispatch = True if self.bot: self.inchan = self.channel in self.bot.state.data.joinedchannels self.bonded = True return self
def _raw(self, stanza): """ output a xml stanza to the socket. """ if self.stopped or self.failure: logging.info("%s - bot is stopped .. not sending" % self.cfg.name) ; return try: stanza = stanza.strip() if not stanza: logging.debug("%s - no stanze provided. called from: %s" % (self.cfg.name, whichmodule())) return what = jabberstrip(stanza, allowed=["\n", ]) what = toenc(what) if not what.endswith('>') or not what.startswith('<'): logging.error('%s - invalid stanza: %s' % (self.cfg.name, what)) return start = what[:3] if start in ['<st', '<me', '<pr', '<iq', "<au", "<re", "<fa", "<ab"]: if start == "<pr": logging.info(u"> %s" % what) else: logging.info(u"> %s" % what) if not self.connection: self.sock.send(what) else: try: self.connection.send(what + u"\r\n") except AttributeError: try: self.connection.write(what) except AttributeError: self.sock.send(what) else: logging.error('%s - invalid stanza: %s' % (self.cfg.name, what)) if self.cfg.sleeptime: time.sleep(self.cfg.sleeptime) else: time.sleep(0.01) except socket.error, ex: if 'Broken pipe' in str(ex): logging.debug('%s - core - broken pipe .. ignoring' % self.cfg.name) return self.error = str(ex) handle_exception()
def makebot(self, type, name, config={}, domain="", showerror=False): """ create a bot .. use configuration if provided. """ if not name: logging.error(" name is not correct: %s" % name) ; return if not type: type = self.data.types.get(name) if not type: logging.error("no type found for %s bot" % name) ; return if config: logging.debug('making %s (%s) bot - %s - from: %s' % (type, name, config.tojson(), whichmodule())) bot = None if not config: cfg = Config('fleet' + os.sep + stripname(name) + os.sep + 'config') else: cfg = config cfg.init() if not cfg.name: cfg['name'] = name cfg['botname'] = cfg['name'] if cfg.disable: logging.info("%s bot is disabled. see %s" % (name, cfg.cfile)) return if not cfg.type and type: logging.debug("%s - setting type to %s" % (cfg.cfile, type)) cfg.type = type if not cfg['type']: try: self.data['names'].remove(name) self.save() except ValueError: pass raise Exception("no bot type specified") if not cfg.owner: logging.debug("%s - owner not set .. using global config." % cfg.name) cfg.owner = getmainconfig().owner if not cfg.domain and domain: cfg.domain = domain if not cfg: raise Exception("can't make config for %s" % name) #cfg.save() bot = BotFactory().create(type, cfg) return bot