def handle_adminreloadconfig(bot, event): """ no arguments - reload bot config and mainconfig files. """ try: bot.cfg.reload() getmainconfig().reload() except Exception as ex: handle_exception() event.done()
def handle_rc(bot, event): """ arguments: <file>|<url> - execute a .tl resource file with bot commands. """ if not event.rest: event.missing("<file>|<url>") ; return if not getmainconfig().allowrc: event.reply("rc mode is not enabled") ; return teller = 0 t = event.rest waiting = [] try: try: if getmainconfig().allowremoterc and t.startswith("http"): data = geturl2(t) else: data = open(t, 'r').read() except IOError as ex: event.reply("I/O error: %s" % str(ex)) ; return if not data: event.reply("can't get data from %s" % event.rest) ; return for d in data.split("\n"): i = d.strip() if not i: continue if i.startswith("#"): continue e = cpy(event) e.txt = "%s" % i.strip() e.direct = True bot.put(e) waiting.append(e) teller += 1 event.reply("%s commands executed" % teller) except Exception as ex: event.reply("an error occured: %s" % str(ex)) ; handle_exception()
def handle_adminsave(bot, ievent): """ no arguments - boot the bot .. do some initialisation. """ ievent.reply("saving mainconfig") getmainconfig().save() ievent.reply("saving fleet bots") getfleet().save() ievent.reply("saving all plugins") plugs.save() ievent.done()
def checkevent(self, event, dobind=True): if not event.iscommand: return False if getmainconfig().floodallow: return False if dobind: event.bind() if not event.user: got = False else: got = True t = got and event.user.data.floodtime or 60 if t < 60: t = 60 threshold = got and event.user.data.floodthreshold or 20 if threshold < 20: threshold = 20 wait = got and event.user.data.floodwait or 120 if wait < 120: wait = 120 floodrate = got and event.user.data.floodrate or 0.1 if floodrate < 0.1: floodrate = 0.1 if not self.check(event.userhost, t, threshold, wait, floodrate): return False if event.user and "OPER" in event.user.data.perms: return False logging.warn("floodcontrol block on %s" % event.userhost) if event.userhost not in self.warned: logging.warn("floodcontrol block on %s" % event.userhost) event.reply("floodcontrol enabled (%s seconds)" % wait) self.warned[event.userhost] = time.time() return True
def do_opts(type="console", args=[], *argslist, **kwargs): from tl.version import getversion if not args: args = sys.argv if type != "console": print("TIMELINE %s" % getversion(type.upper())) cfg = None if type == "irc": target = api_opts + bot_opts + irc_opts elif type == "xmpp": target = api_opts + bot_opts + xmpp_opts elif type == "fleet": target = api_opts + fleet_opts elif type == "init": target = [] elif type == "console": target = bot_opts + console_opts else: target = [] opts = make_opts(args, target, *argslist, **kwargs) if type == "console": ll = "error" else: ll = "warn" if opts.datadir: setdatadir(opts.datadir) else: setdatadir(homedir + os.sep + ".tl") setloglevel(opts.loglevel or ll) if opts.bork: tl.utils.exception.bork = True ; logging.warn("bork mode enabled") if opts.nourl: tl.utils.url.enabled = False ; logging.warn("url fetching disabled") if opts.nocolors: tl.utils.log.docolor = False ; logging.warn("colors in logging is disabled") from tl.lib.users import getusers u = getusers() if opts.owner and u: u.make_owner(opts.owner) from tl.lib.config import getmainconfig maincfg = getmainconfig(opts.datadir) if type == "irc": cfg = makeircconfig(opts, opts.name) elif type == "xmpp" or type == "xmpp": cfg = makexmppconfig(opts, opts.name) elif type == "console": cfg = makeconsoleconfig(opts, opts.name) else: cfg = makedefaultconfig(opts, opts.name) if opts.anon: cfg.auto_register = True ; cfg.guestasuser = True else: cfg.auto_register = False if maincfg.dbtype: logging.warn("database type is %s" % maincfg.dbtype) return (opts, cfg)
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. """ 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: 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: dolog and logging.debug("channel bonded - %s" % self.chan.data.id) if not target: self.prepare(bot) ; 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: u = bot.users.by_uid(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 self.prepare(bot) if self.bot: self.inchan = self.channel in self.bot.cfg.channels if not self.auth: self.auth = self.userhost self.bonded = True return self
def bind(self): server = self.cfg.server elite = self.cfg['bindhost'] or getmainconfig()['bindhost'] if elite: logging.warn("trying to bind to %s" % elite) try: self.oldsock.bind((elite, 0)) except socket.gaierror: logging.debug("%s - can't bind to %s" % (self.cfg.name, elite)) if not server: try: socket.inet_pton(socket.AF_INET6, self.cfg.server) except socket.error: pass else: server = self.cfg.server if not server: try: socket.inet_pton(socket.AF_INET, self.cfg.server) except socket.error: pass else: server = self.cfg.server if not server: ips = [] try: for item in socket.getaddrinfo(self.cfg.server, None): if item[0] in [socket.AF_INET, socket.AF_INET6] and item[1] == socket.SOCK_STREAM: ip = item[4][0] if ip not in ips: ips.append(ip) except socket.error: pass else: server = random.choice(ips) return server
def sendmail(user, to, subject, text, attach, server=None, port=None): msg = MIMEMultipart() msg['From'] = user msg['To'] = to msg['Subject'] = subject msg.attach(MIMEText(text)) part = MIMEBase('application', 'octet-stream') part.set_payload(open(attach, 'rb').read()) encoders.encode_base64(part) part.add_header('Content-Disposition','attachment; filename="%s"' % os.path.basename(attach)) msg.attach(part) from tl.lib.config import getmainconfig cfg = getmainconfig() mailServer = smtplib.SMTP(server or mainconfig.emailserver or "localhost", 25 or mainconfig.emailport) mailServer.ehlo() mailServer.starttls() mailServer.ehlo() mailServer.login(user or mainconfig.emailfrom, pwd or mainconfig.emailpwd or "") result = mailServer.sendmail(user, to, msg.as_string()) # Should be mailServer.quit(), but that crashes... mailServer.close() return result
def handle_loglevel(bot, event): """ arguments: <loglevel> - change loglevel of the bot. loglevel is on of debug, info, warn or error. """ if not event.rest: event.reply("loglevel is %s" % getloglevel()) ; return from tl.lib.config import getmainconfig mainconfig = getmainconfig() mainconfig.loglevel = event.rest mainconfig.save() #mainhandler.put(4, setloglevel, event.rest) setloglevel(event.rest) event.done()
def getcc(self): if self.chan: cc = self.chan.data.cc else: cc = "" if not cc: cfg = getmainconfig() if cfg.globalcc and not cfg.globalcc in cc: cc += cfg.globalcc if not cc: cc = "!;" if not ";" in cc: cc += ";" logging.debug("cc is %s" % cc) return cc
def handle_cfgset(bot, event): if len(event.args) != 3: event.missing("<configname> <variable> <value>") ; return name, var, value = event.args if not var in allowset: event.reply("setting %s is not allowed" % var) ; return if name == "main": if not getusers().allowed(event.userhost, "OPER"): event.reply("you need to have OPER permissions to edit the mainconfig.") ; return mcfg = getmainconfig() try: mcfg[var] = int(value) except ValueError: mcfg[var] = value mcfg.save() event.done() else: event.reply('we current only support editing the "main" config.') ; return
def getmaindb(): try: from tl.lib.config import getmainconfig cfg = getmainconfig() if cfg.dbenable: if "sqlite" in cfg.dbtype and not gotsqlite(): logging.error("sqlite is not found.") return global db if db: return db from .direct import Db return Db() else: raise Exception("db not enabled in %s" % cfg._cfile) except Exception as ex: handle_exception()
def getfullversion(txt="", repo=False): v = str(version) from tl.lib.config import getmainconfig cfg = getmainconfig() if cfg.dbenable: v += " -=- " + cfg.dbtype.upper() tip = None if repo: try: from mercurial import context, hg, node, repo, ui repository = hg.repository(ui.ui(), '.') ctx = context.changectx(repository) tip = str(ctx.rev()) except: tip = None if tip: version2 = v + " -=- HG " + tip else: version2 = v return "T I M E L I N E -=- %s -=- %s" % (txt, version2)
def handle(self): """ send TICK events to callback. """ self.counter += 1 event = EventBase() event.nolog = True event.nobind = True if self.counter % 60 == 0: event.type = event.cbtype = 'TICK60' callbacks.check(self.bot, event) if self.counter % 10 == 0: event.type = event.cbtype = 'TICK10' callbacks.check(self.bot, event) maincfg = getmainconfig() t = maincfg.ticksleep or 1 if self.counter % t == 0: event.type = event.cbtype = 'TICK' callbacks.check(self.bot, event)
def __init__(self, dbname=None, dbhost=None, dbuser=None, dbpasswd=None, dbtype=None, ddir=None, doconnect=True): self.datadir = ddir or getdatadir() self.datadir = self.datadir + os.sep + "db" + os.sep if hasattr(os, 'mkdir'): if not os.path.isdir(self.datadir): try: os.mkdir(self.datadir) except OSError: pass cfg = getmainconfig() self.dbname = dbname or cfg.dbname if not self.dbname: raise Exception("no db name") self.dbhost = dbhost or cfg.dbhost or "" self.dbuser = dbuser or cfg.dbuser or "" self.dbpasswd = dbpasswd or cfg.dbpasswd or "" self.connection = None self.timeout = 15 self.dbtype = dbtype or cfg.dbtype or 'sqlite' if doconnect: self.connect()
def handle_cfg(bot, event): if len(event.args) != 1: event.missing("<configname>") ; return name = event.args[0] if name == "main": if not getusers().allowed(event.userhost, "OPER"): event.reply("you need to have OPER permissions to edit the mainconfig.") ; return event.reply(getmainconfig().fordisplay())
def handle_datamain(bot, event): """ no arguments - dump bot as json dict. """ event.reply(getmainconfig().fordisplay())
def boot(ddir=None, force=False, encoding="utf-8", umask=None, saveperms=True, fast=False, clear=False, loadall=False): """ initialize the bot. """ global plugin_packages try: if os.getuid() == 0: print("don't run the bot as root") ; os._exit(1) except AttributeError: pass from tl.lib.datadir import getdatadir, setdatadir if ddir: setdatadir(ddir) origdir = ddir ddir = getdatadir() if not ddir: logging.error("can't determine datadir to boot from") ; raise Exception("can't determine datadir") logging.warn("starting !!") if not ddir in sys.path: sys.path.append(ddir) makedirs(ddir) try: rundir = ddir + os.sep + "run" k = open(rundir + os.sep + 'tl.pid','w') k.write(str(os.getpid())) k.close() except IOError: pass try: if not umask: checkpermissions(getdatadir(), 0o700) else: checkpermissions(getdatadir(), umask) except: handle_exception() from tl.lib.plugins import plugs global loaded global cmndtable global retable global plugins global callbacktable global shorttable global cmndperms global timestamps if not retable: retable = Persist(rundir + os.sep + 'retable') if clear: retable.data = {} if not cmndtable: cmndtable = Persist(rundir + os.sep + 'cmndtable') if clear: cmndtable.data = {} if not plugins: plugins = Persist(rundir + os.sep + 'plugins') if clear: plugins.data = {} if not plugins.data.available: plugins.data.available = [] if not plugins.data.refused: plugins.data.refused = [] if not plugins.data.allowed: plugins.data.allowed = [] if not callbacktable: callbacktable = Persist(rundir + os.sep + 'callbacktable') if clear: callbacktable.data = {} if not shorttable: shorttable = Persist(rundir + os.sep + 'shorttable') if clear: shorttable.data = {} if not timestamps: timestamps = Persist(rundir + os.sep + 'timestamps') if not cmndperms: cmndperms = Config('cmndperms', ddir=ddir) changed = [] gotlocal = False dosave = clear or False maincfg = getmainconfig(ddir=ddir) logging.warn("mainconfig used is %s" % maincfg.cfile) packages = find_packages(ddir + os.sep + "myplugs") for p in packages: if p not in plugin_packages: plugin_packages.append(p) packages = find_packages("tl" + os.sep + "plugs") for p in packages: if p not in plugin_packages: plugin_packages.append(p) if os.path.isdir('tl'): gotlocal = True changed = scandir('tl-myplugs') if changed: logging.warn("tl-myplugs has changed -=- %s" % ", ".join(changed)) dosave = True for plug in default_plugins: plugs.reload(plug, showerror=True, force=True) changed = scandir(ddir + os.sep + 'myplugs') if changed: logging.warn("myplugs has changed -=- %s" % ', '.join(changed)) dosave = True configchanges = checkconfig() if configchanges: logging.info("there are configuration changes: %s" % ', '.join(configchanges)) for f in configchanges: if 'mainconfig' in f: force = True ; dosave = True if os.path.isdir('tl'): coreplugs = scandir("tl" + os.sep + "plugs") if coreplugs: logging.warn("core changed -=- %s" % ", ".join(coreplugs)) dosave = True try: from tl.db import getmaindb from tl.db.tables import tablestxt db = getmaindb() if db: db.define(tablestxt) except Exception as ex: logging.warn("could not initialize database %s" % str(ex)) if force or dosave or not cmndtable.data or len(cmndtable.data) < 100: logging.debug("using target %s" % str(plugin_packages)) plugs.loadall(plugin_packages, force=True) savecmndtable(saveperms=saveperms) saveplugins() savecallbacktable() savealiases() logging.warn(getfullversion(getdatadir())) logging.warn("READY")