# bot/__init__.py
#
#
""" bot package. """
__version__ = 19
## IMPORTS
from bot.utils import *
from bot.log import datefmt
## BASIC IMPORTS
import collections
import threading
import logging
import getpass
import _thread
import socket
import queue
import types
import errno
import select
import fcntl
import uuid
import json
import time
import imp
import sys
import os
import re
try: import readline
except: error()
## ERRORS
[docs]class Error(BaseException): pass
[docs]class OverloadError(Error): pass
[docs]class MissingArgument(Error): pass
[docs]class MissingOutFunction(Error): pass
[docs]class NoText(Error): pass
[docs]class NoDate(Error): pass
[docs]class NoPath(Error): pass
[docs]class NoJSON(Error): pass
[docs]class NoFileName(Error): pass
[docs]class SignatureError(Error): pass
[docs]class NoSuchBotType(Error): pass
[docs]class NoEvent(Error): pass
[docs]class RemoteDisconnect(Error): pass
[docs]class NotOne(Error): pass
[docs]class TargetMissing(Error): pass
## BOOT
[docs]def boot(*args, **kwargs):
global kernel
cfg = args[0]
kernel.cfg.update(cfg)
if cfg.shell: hello("BOTJE")
set_workdir(kernel.cfg.workdir)
if not kernel.cfg.loglevel: cfg.loglevel = "error"
from bot.log import log_config
log_config(cfg.loglevel)
if kernel.cfg.loglevel:
logging.warn("E G G S")
logging.warn("")
show_eggs()
if kernel.cfg.loglevel:
logging.warn("")
logging.warn("C O N F I G")
logging.warn("")
for line in kernel.cfg.show(): logging.warn(line)
if kernel.cfg.loglevel:
logging.warn("")
logging.warn("B O O T")
logging.warn("")
return kernel
## WORKDIR
[docs]def set_workdir(*args, **kwargs):
global kernel
workdir = args[0]
if not workdir: workdir = "bot.workdir"
wd = workdir.split(os.sep)[-1]
if not wd: wd = workdir.split(os.sep)[-2]
if not kernel.cfg.workdir: kernel.cfg.workdir = j(os.getcwd(), wd)
kernel.cfg.rootlist = []
kernel.cfg.rootlist.append(kernel.cfg.workdir)
kernel.cfg.rootlist.append(j("backups", day(), ""))
make_dir(kernel.cfg.workdir)
## BASE
[docs]class Object(dict):
def __getattribute__(zelf, *args, **kwargs):
name = args[0]
result = ""
if name == "date": return zelf.Date or zelf.added or ""
if name == "what": result = get_cls(zelf)
if name == "modname": result = get_modname(zelf)
if name == "plugname": result = get_plugname(3)
if name == "func": result = get_func(5)
if name == "how": result = get_how(2)
if name == "kind": result = mj(zelf.modname, zelf.what, zelf.func)
if name == "stdin": return sys.stdin
if name == "stdout": return sys.stdout
if result: zelf[name] = result ; return zelf[name]
return dict.__getattribute__(zelf, *args, **kwargs)
def __getattr__(zelf, name):
try: return zelf[name]
except KeyError:
if name == "timed": zelf["timed"] = short_date(zelf.Date or zelf.date or zelf.published) or to_time(zelf.added)
if name == "_result": zelf["_result"] = Object()
if name == "_status": zelf["_status"] = Object()
if name == "_ready": zelf["_ready"] = threading.Event()
try: return zelf[name]
except KeyError: return ""
def __setattr__(zelf, name, value): return dict.__setitem__(zelf, name, value)
def __exists__(zelf, a):
try: return zelf[a]
except KeyError: False
def __lt__(zelf, a): return time_stamp(zelf.ddate) < time_stamp(a.ddate)
## TOUCH
[docs] def touch(zelf, *args, **kwargs):
try: res = getattr(zelf, args[0])
except (TypeError, AttributeError): res = None
return res
## LOCATORS
[docs] def get_root(zelf, *args, **kwargs): return j(os.path.expanduser("~"), *args)
[docs] def get_roots(zelf, *args, **kwargs):
result = []
return result
[docs] def get_target(zelf):
if "_target" in zelf: return zelf._target
return None
[docs] def get_all(zelf, *args, **kwargs):
attr = args[0]
result = []
for obj in zelf.objects():
if attr in obj and obj[attr]: result.append(obj)
return result
## OUTPUT
[docs] def make_json(zelf, *args, **kwargs): return json.dumps(zelf.reduced(*args, **kwargs), default=smooth, *args, **kwargs)
[docs] def make_full(zelf, *args, **kwargs): return json.dumps(zelf, default=smooth, *args, **kwargs)
[docs] def make_signature(zelf, sig=None): return str(hashlib.sha1(bytes(str(sig or zelf), "utf-8")).hexdigest())
[docs] def make_path(zelf, *args, **kwargs): path = zelf.get_path(*args, **kwargs) ; make_dir(path) ; return path
## INPUT
[docs] def load(zelf, *args, **kwargs):
if args: path = zelf.make_path(*args, **kwargs)
else: path = zelf.make_path()
return zelf.load_file(path)
[docs] def load_file(zelf, *args, **kwargs):
path = args[0]
logging.debug("load_file %s" % " ".join(args))
ondisk = zelf.read(path)
fromdisk = json.loads(ondisk)
if "data" in fromdisk: zelf.update(fromdisk["data"])
return zelf
[docs] def load_json(zelf, *args, **kwargs): zelf.update(json.loads(args[0]))
[docs] def read(zelf, *args, **kwargs):
logging.debug("read %s" % " ".join(args))
path = args[0]
try: f = open(path, "r")
except IOError as ex:
if ex.errno == errno.ENOENT: return "{}"
raise
if zelf.do_test: f.line_buffering = False
res = ""
for line in f:
if not line.strip().startswith("#"): res += line
if not res.strip(): return "{}"
f.close()
return res
## PERSISTENCE
[docs] def dump(zelf, *args, **kwargs):
# object attributes settins before save
path = args[0]
zelf.path = path
todisk = Object()
todisk.data = zelf.reduced()
todisk.how = zelf.how
todisk.create_type = zelf.what
todisk.stime = time.ctime(time.time())
todisk.modname = zelf.modname
todisk.version = __version__
todisk.signature = zelf.make_signature()
try: result = todisk.make_json(indent=2, ensure_ascii=False)
except TypeError: raise NoJSON()
return result
[docs] def save(zelf, *args, **kwargs):
if not args: t = rtime()
else: t = args[0]
for path in kernel.cfg.rootlist:
root = zelf.get_root(path, t)
make_dir(root)
zelf.sync(root)
[docs] def sync(zelf, *args, **kwargs):
# syn the object to disk
try: path = args[0]
except IndexError: path = zelf.path
logging.info("save %s" % " ".join(args))
fn = path.split(os.sep)[-1]
todisk = zelf.dump(path, **kwargs)
datafile = open(path + ".tmp", 'w')
fcntl.flock(datafile, fcntl.LOCK_EX | fcntl.LOCK_NB)
datafile.write(headertxt % (fn, __version__, "%s characters" % len(todisk)))
datafile.write(todisk)
datafile.write("\n")
fcntl.flock(datafile, fcntl.LOCK_UN)
datafile.close()
os.rename(path + ".tmp", path)
logging.warn("saved %s" % path)
return zelf
## STATE
[docs] def register(zelf, *args, **kwargs):
name = args[0]
obj = args[1]
zelf[name] = obj
[docs] def reduced(zelf, *args, **kwargs):
res = Object()
for key in zelf.keys():
k = str(key)
if k.startswith("_"): continue
if k in ["args", "rest", "first",]: continue
if args and k in args[0]: continue
res[k] = zelf[k]
return res
[docs] def pretty(zelf): return json.dumps(zelf, indent=2)
## OBJECTORS
[docs] def objects(zelf, *args, **kwargs):
path = zelf.get_root(kernel.cfg.workdir, *args, **kwargs)
flist = list_files(path, **kwargs)
res = []
for fnn in flist:
try: obj = Object().load_file(fnn)
except ValueError: logging.warn("no json in %s" % fnn) ; continue
if "key" in kwargs and kwargs["key"] not in obj: continue
res.append(obj)
logging.debug("%s objects found" % len(res))
return res
[docs] def has_obj(zelf, *args, **kwargs):
key, value = args
for obj in zelf.objects():
if key in obj and value in obj[key]: return True
return False
## RESULT
[docs] def parse(zelf, *args, **kwargs):
try: zelf.ucmnd, zelf.rest = zelf.txt.split(" ", 1)
except: zelf.ucmnd = zelf.txt ; zelf.rest = ""
if zelf.ucmnd and zelf.ucmnd[0] == ".": zelf.ucmnd = zelf.ucmnd[1:]
return zelf
[docs] def prepare(zelf, *args, **kwargs):
zelf.opts = get_opts(zelf.txt)
zelf.args = get_args(zelf.txt)
zelf.knobs = get_knobs(zelf.txt)
zelf.parse()
return zelf
[docs] def ready(zelf): zelf._ready.set()
[docs] def wait(zelf, sec=180.0):
try: zelf._ready.wait(sec)
except: pass
[docs] def add(zelf, *args, **kwargs): zelf._result[time.time()] = args[0]
[docs] def reply(zelf, *args, **kwargs):
if zelf.outer: zelf.outer.write(str(args[0]) + "\n") ; zelf.outer.flush() ; return
zelf.say(zelf.channel, args[0])
[docs] def say(zelf, *args, **kwargs): zelf._target.say(args[0], args[1])
[docs] def show(zelf): return ["%s=%s" % (a, b) for a, b in zelf.items() if b]
[docs] def display(zelf, *args, **kwargs):
for res in sorted(zelf._result.keys()):
d = zelf._result[res]
zelf.say(zelf.channel or "", d)
## TASKS
[docs]class Runner(threading.Thread):
def __init__(zelf, *args, **kwargs):
threading.Thread.__init__(zelf, None, zelf._loop, "thread.%s" % str(time.time()), args, kwargs)
zelf.setDaemon(True)
zelf._queue = queue.Queue()
zelf._outqueue = queue.Queue()
zelf._state = "idle"
def _loop(zelf):
logging.info("start %s" % str(zelf))
while zelf._state in ["running", "once", ]:
args, kwargs = zelf._queue.get()
if zelf._state == "stop": break
func = args[0]
try: func(*args[1:], **kwargs)
except: error()
time.sleep(0.001)
logging.warn("stop %s" % str(zelf))
[docs] def stop(zelf, *args, **kwargs): zelf._state = "stop"
[docs] def put(zelf, *args, **kwargs): zelf._queue.put((args, kwargs))
## DISPATCH
[docs]class Dispatcher(Object):
max = 50
runners = collections.deque()
[docs] def register(zelf, cbtype, cb, *args, **kwargs):
logging.debug("register %s" % cbtype)
if cbtype not in zelf: zelf[cbtype] = []
zelf[cbtype].append(cb)
[docs] def dispatch(zelf, *args, **kwargs):
event = args[0]
event.prepare()
logging.info("event %s" % str(event))
if event.etype:
try:
for func in zelf[event.etype]: func(event)
except KeyError: pass
if event.ucmnd:
if event.ucmnd not in kernel: return
try:
for func in zelf[event.ucmnd]: func(event)
except KeyError: pass
except: error()
[docs] def stop(zelf, name=None):
for runner in zelf.runners:
if name and name not in runner.name: continue
runner.stop()
[docs] def put(zelf, *args, **kwargs):
target = zelf.make_new()
target.put(*args, **kwargs)
return target
[docs] def make_new(zelf, *args, **kwargs):
if len(zelf._runners) < zelf.max:
runner = Runner(*args, **kwargs)
runner.start()
zelf.runners.append(runner)
else: runner = random.choice(zelf._runners)
return runner
[docs] def cleanup(zelf, dojoin=False):
todo = []
for runner in zelf.runners:
if runner.stopped or not len(runner.queue): todo.append(runner)
for runner in todo: runner.stop() ; zelf.runners.remove(runner)
## PLUGINS
[docs]class Plugins(Object):
[docs] def get_names(zelf, plugsdir): return [x[:-3] for x in os.listdir(plugsdir) if x.endswith(".py")]
[docs] def load_plugs(zelf, path):
logging.warn("plugs %s" % path)
for plugname in zelf.get_names(path):
if "__" in plugname: continue
try: zelf[plugname] = zelf.load_mod(plugname, path, force=True)
except: error() ; continue
[docs] def load_package(zelf, modname):
mod = __import__(modname)
path, fn = os.path.split(mod.__file__)
path += os.sep + "plugs"
zelf.load_plugs(path)
[docs] def load_mod(zelf, plugname, pdir="", force=False):
logging.info("load %s - %s" % (zelf.what.lower(), plugname))
if plugname in zelf:
if not force: return zelf[plugname]
zelf[plugname] = imp.reload(zelf[plugname])
else:
if not pdir: pdir = j(zelf.root, "plugs")
search = imp.find_module(plugname, [pdir,])
zelf[plugname] = imp.load_module(plugname, *search)
zelf.plug_exec(plugname, "init")
return zelf[plugname]
[docs] def plug_exec(zelf, plugname, item):
try: todo = getattr(zelf[plugname], item) ; todo() ; logging.info("exec %s" % get_name(todo))
except AttributeError: pass
[docs] def exit(zelf, *args, **kwargs):
for plugname in zelf.reduced():
try: zelf.plug_exec(plugname, "shutdown") ; del zelf[plugname]
except KeyError: pass
[docs] def reload(zelf, plugname, force=False):
zelf.unload(plugname)
mod = zelf.load_mod(plugname, force)
return mod
## BOTS
[docs]class Bot(Dispatcher):
[docs] def exit(zelf, *args, **kwargs): pass
[docs] def begin(zelf, *args, **kwargs):
if zelf not in kernel.fleet: kernel.fleet.append(zelf)
zelf.connect()
if not zelf._state: zelf._state = "running"
while zelf._state in ["running", "once"]:
time.sleep(0.01)
zelf.do_one()
if zelf._state == "once": break
[docs] def do_one(zelf, *args, **kwargs): pass
[docs] def get_prompt(zelf, *args, **kwargs): return ""
[docs] def connect(zelf, *args, **kwargs): pass
[docs] def announce(zelf, *args, **kwargs):
if zelf.channels:
for channel in zelf.channels: zelf.say(channel, args[0], **kwargs)
else: zelf.say(*args, **kwargs)
## CONSOLE
[docs]class ConsoleBot(Bot):
def _raw(zelf, *args, **kwargs):
txt = args[0]
try: sys.stdout.write(txt) ; sys.stdout.write("\n") ; sys.stdout.flush()
except Exception as ex: logging.warn(str(ex))
[docs] def say(zelf, *args, **kwargs):
try: txt = args[1]
except IndexError: txt = args[0]
zelf._raw(txt)
[docs] def get_prompt(zelf, *args, **kwargs): return "%s -=- %s%s<%s " % (time.strftime(datefmt), BOLD, YELLOW, ENDC)
[docs] def do_one(zelf, *args, **kwargs):
o = Object()
if not kernel.cfg.shell: o.txt = " ".join(kernel.cfg.runargs) ; zelf._state = "once"
else: o.txt = input(zelf.get_prompt())
o._target = zelf
o.prepare()
kernel.dispatch(o)
return o
## IRC
[docs]class IRCBot(Bot):
marker = "\r\n"
cc = "."
def __init__(zelf, *args, **kwargs):
Bot.__init__(zelf, *args, **kwargs)
zelf.connected = threading.Event()
#zelf.register("250", zelf._onconnect)
zelf.register("001", zelf._onconnect)
zelf.register("513", zelf.handle_513)
zelf.register("433", zelf.handle_433)
zelf.register("PING", zelf.handle_ping)
zelf.register("INVITE", zelf.handle_invite)
zelf.register("PRIVMSG", zelf.handle_privmsg)
zelf._lock = _thread.allocate_lock()
zelf._buffer = []
zelf._lastline = ""
zelf.encoding = "utf-8"
zelf.server = zelf.server or "localhost"
zelf.port = zelf.port or 6667
zelf.nick = zelf.nick or "bot"
if not zelf.channels: zelf.channels = []
if zelf.channel and zelf.channel not in zelf.channels: zelf.channels.append(zelf.channel)
def _raw(zelf, txt):
logging.warn("> %s" % txt)
if not txt.endswith(zelf.marker): txt += zelf.marker
txt = bytes(txt, zelf.encoding)
if 'ssl' in zelf and zelf.ssl: zelf.sock.write(txt)
else: zelf.sock.send(txt[:512])
def _connect(zelf):
zelf.stopped = False
if zelf.ipv6: zelf.oldsock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
else: zelf.oldsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
zelf.server = zelf.bind()
logging.warn('connect %s - %s (%s)' % (zelf.server, zelf.port, zelf.name))
zelf.oldsock.settimeout(60)
zelf.oldsock.connect((zelf.server, int(str(zelf.port or 6667))))
zelf.blocking = 1
zelf.oldsock.setblocking(zelf.blocking)
logging.warn('connection made to %s (%s)' % (zelf.server, zelf.name))
zelf.fsock = zelf.oldsock.makefile("r")
if zelf.blocking: zelf.oldsock.settimeout(301.0)
if 'ssl' in zelf and zelf['ssl']: zelf.sock = socket.ssl(zelf.oldsock)
else: zelf.sock = zelf.oldsock
zelf.connecttime = time.time()
return True
def _onconnect(zelf, *args, **kwargs):
logging.warn("logged on !!")
if "onconnect" in zelf: time.sleep(2) ; zelf._raw(zelf.onconnect)
if "servermodes" in zelf: zelf._raw("MODE %s %s" % (zelf.nick, zelf.servermodes))
zelf.join_channels(*args, **kwargs)
zelf.ready()
def _dodcc(zelf, event, s):
s.send(bytes('Welcome to BOTJE ' + event.nick + " !!\n", zelf.encoding))
_thread.start_new_thread(zelf._dccloop, (event, s))
def _dccloop(zelf, event, s):
sockfile = s.makefile('rw')
s.setblocking(True)
while 1:
try:
res = sockfile.readline()
if not res: break
res = res.rstrip()
logging.warn("< DCC %s" % res)
o = Object(_target=zelf, txt=res)
o.outer = sockfile
o.prepare()
kernel.dispatch(o)
except socket.timeout: time.sleep(0.01)
except socket.error as ex:
if ex.errno in [EAGAIN, ]: continue
else: raise
except Exception as ex: error()
sockfile.close()
def _dccconnect(zelf, event):
try:
addr = event.args[3] ; port = event.args[4][:-1]
port = int(port)
if re.search(':', addr): s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
else: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((addr, port))
except Exception as ex: error() ; return
zelf._dodcc(event, s)
[docs] def do_one(zelf, *args, **kwargs):
if not zelf._buffer: zelf.read_some()
try: line = zelf._buffer.pop(0)
except IndexError: return Object()
e = Object()
e._target = zelf
o = irc_parse(e, line.rstrip())
o.prepare()
zelf.dispatch(o)
[docs] def read_some(zelf, *args, **kwargs):
try:
if "ssl" in zelf and zelf.ssl: inbytes = zelf.sock.read()
else: inbytes = zelf.sock.recv(512)
except Exception as ex: error()
try: txt = str(inbytes, zelf.encoding)
except UnicodeDecodeError: txt = " "
if txt == "": raise RemoteDisconnect()
zelf._lastline += txt
splitted = zelf._lastline.split(zelf.marker)
for s in splitted[:-1]: logging.warn("< %s" % s) ; zelf._buffer.append(s)
zelf._lastline = splitted[-1]
[docs] def send(zelf, txt): zelf._raw(txt) ; time.sleep(3.0)
[docs] def bind(zelf):
server = zelf.server
try: zelf.oldsock.bind((server, 0))
except socket.error:
if not server:
try: socket.inet_pton(socket.AF_INET6, zelf.server)
except socket.error: pass
else: server = zelf.server
if not server:
try: socket.inet_pton(socket.AF_INET, zelf.server)
except socket.error: pass
else: server = zelf.server
if not server:
ips = []
try:
for item in socket.getaddrinfo(zelf.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
[docs] def logon(zelf):
if "password" in zelf: zelf._raw("PASS %s" % zelf.password)
logging.warn('logging in on %s - this may take a while' % zelf.server)
zelf._raw("NICK %s" % zelf.nick or "bot")
zelf._raw("USER %s localhost %s :%s" % (zelf.username or "botje", zelf.server or "localhost", zelf.realname or "botje"))
[docs] def say(zelf, *args, **kwargs):
try: channel, txt = args
except ValueError: channel = zelf.channel ; txt = args[0]
zelf.privmsg(channel, txt)
[docs] def join_channels(zelf, *args, **kwargs):
for channel in zelf.channels: zelf.join(channel)
[docs] def broadcast(zelf, txt):
for i in zelf.channels: zelf.say(i, txt)
[docs] def connect(zelf, reconnect=True):
try: res = zelf._connect()
except: error() ; return
if res: time.sleep(1) ; zelf.logon()
return res
[docs] def close(zelf):
if 'ssl' in zelf and zelf['ssl']: zelf.oldsock.shutdown(2) ; zelf.oldsock.close()
else: zelf.sock.shutdown(2) ; zelf.sock.close()
zelf.fsock.close()
[docs] def handle_ping(zelf, event): zelf.pongcheck = True ; zelf.pong()
[docs] def handle_433(zelf, event): zelf.donick(event.arguments[1] + "_")
[docs] def handle_invite(zelf, event): zelf.join(event.channel)
[docs] def handle_privmsg(zelf, event):
if event.txt.startswith("\001DCC"): zelf._dccconnect(event) ; return
if event.txt and event.txt[0] == zelf.cc:
event.prepare()
kernel.dispatch(event)
[docs] def handle_513(zelf, event): zelf._raw("PONG %s" % event.arguments[6])
[docs] def handle_ctcp(zelf, event):
if event.txt and event.txt[0] == zelf.cc: resolve(event)
[docs] def donick(zelf, nick, setorig=False, save=False, whois=False): zelf.send('NICK %s\n' % nick[:16])
[docs] def join(zelf, channel, password=None):
if password: zelf._raw('JOIN %s %s' % (channel, password))
else: zelf._raw('JOIN %s' % channel)
[docs] def part(zelf, channel):
zelf.send('PART %s' % channel)
if channel in zelf.channels: zelf.channels.remove(channel) ; zelf.save()
[docs] def who(zelf, who): zelf.send('WHO %s' % who.strip())
[docs] def names(zelf, channel): zelf.send('NAMES %s' % channel)
[docs] def whois(zelf, who): zelf.send('WHOIS %s' % who)
[docs] def privmsg(zelf, printto, what): zelf.send('PRIVMSG %s :%s' % (printto, what))
[docs] def voice(zelf, channel, who): zelf.send('MODE %s +v %s' % (channel, who))
[docs] def doop(zelf, channel, who): zelf.send('MODE %s +o %s' % (channel, who))
[docs] def delop(zelf, channel, who): zelf.send('MODE %s -o %s' % (channel, who))
[docs] def quit(zelf, reason='https://pikacode.com/milla/botje'): zelf.send('QUIT :%s' % reason)
[docs] def notice(zelf, printto, what): zelf.send('NOTICE %s :%s' % (printto, what))
[docs] def ctcp(zelf, printto, what): zelf.send("PRIVMSG %s :\001%s\001" % (printto, what))
[docs] def ctcpreply(zelf, printto, what): zelf.send("NOTICE %s :\001%s\001" % (printto, what))
[docs] def action(zelf, printto, what, event=None, *args, **kwargs): zelf.send("PRIVMSG %s :\001ACTION %s\001" % (printto, what))
[docs] def getchannelmode(zelf, channel): zelf.send('MODE %s' % channel)
[docs] def settopic(zelf, channel, txt): zelf.send('TOPIC %s :%s' % (channel, txt))
[docs] def ping(zelf, *args, **kwargs): zelf.send('PING :%s' % zelf.server)
[docs] def pong(zelf, *args, **kwargs): zelf.send('PONG :%s' % zelf.server)
## irc_parse function
[docs]def irc_parse(obj, *args, **kwargs):
rawstr = str(args[0])
zelf = obj
zelf.servermsg = False
splitted = re.split('\s+', rawstr)
if not rawstr[0] == ':': zelf.servermsg = True
zelf.prefix = splitted[0]
if zelf.servermsg: zelf.etype = zelf.prefix
else: zelf.etype = splitted[1]
try:
nickuser = zelf.prefix.split('!')
zelf.origin = nickuser[1]
zelf.nick = nickuser[0][1:]
except IndexError: zelf.origin = zelf.prefix ; zelf.servermsg = True
if zelf.etype in pfc:
zelf.arguments = splitted[2:pfc[zelf.etype]+2]
txtsplit = re.split('\s+', rawstr, pfc[zelf.etype]+2)
zelf.txt = txtsplit[-1]
else: zelf.arguments = splitted[2:]
if zelf.arguments: zelf.target = zelf.arguments[0]
zelf.postfix = ' '.join(zelf.arguments)
if not "txt" in zelf: zelf.txt = rawstr.rsplit(":")[-1]
if zelf.txt.startswith(":"): zelf.txt = zelf.txt[1:]
if not "channel" in zelf:
for c in zelf.arguments + [zelf.txt, ]:
if c.startswith("#"): zelf.channel = c
if zelf.servermsg:
zelf.origin = zelf.origin[1:-1]
zelf.channel = zelf.origin
if not "origin" in zelf: zelf.origin = zelf.channel
if not "target" in zelf: zelf.target = zelf.channel or zelf.origin
return obj
## XMPP
[docs]class XMPPBot(Bot):
def __init__(zelf, *args, **kwargs):
import sleekxmpp
from sleekxmpp import clientxmpp
Bot.__init__(zelf, *args, **kwargs)
zelf.port = zelf.port or 5222
logging.warn("creating xmpp %s" % str(zelf))
zelf.queue = queue.Queue()
zelf.xmpp = clientxmpp.ClientXMPP(zelf.user, getpass.getpass())
zelf.xmpp.add_event_handler("session_start", zelf.session_start)
zelf.xmpp.add_event_handler("message", zelf.handle_message)
zelf.xmpp.add_event_handler('disconnected', zelf.handle_disconnected)
zelf.xmpp.add_event_handler('connected', zelf.handle_connected)
zelf.xmpp.add_event_handler('presence_available', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_dnd', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_xa', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_chat', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_away', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_unavailable', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_subscribe', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_subscribed', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_unsubscribe', zelf.handle_presence)
zelf.xmpp.add_event_handler('presence_unsubscribed', zelf.handle_presence)
zelf.xmpp.add_event_handler('groupchat_message', zelf.handle_message)
zelf.xmpp.add_event_handler('groupchat_presence', zelf.handle_presence)
zelf.xmpp.add_event_handler('groupchat_subject', zelf.handle_presence)
zelf.xmpp.add_event_handler('failed_auth', zelf.handle_failedauth)
zelf.xmpp.exception = zelf.exception
zelf.xmpp.use_signals()
zelf.openfire = False
if zelf.openfire:
import ssl
zelf.xmpp.ssl_version = ssl.PROTOCOL_SSLv3
zelf._connected = threading.Event()
zelf.channels = []
def _raw(zelf, txt): zelf.xmpp.send_raw(txt)
[docs] def connect(zelf):
try: zelf.xmpp.connect((zelf.server, zelf.port or 5222), use_ssl=zelf.openfire)
except: zelf.xmpp.connect((zelf.server, zelf.port or 5222), )
[docs] def session_start(zelf, event): zelf.xmpp.send_presence()
[docs] def exception(zelf, ex): logging.error(str(ex))
[docs] def handle_failedauth(zelf, error, *args): logging.warn(error)
[docs] def handle_failure(zelf, ex, *args, **kwargs): logging.error(str(ex))
[docs] def handle_disconnected(zelf, *args, **kwargs): zelf._connected.clear() ; logging.error("disconnected")
[docs] def handle_connected(zelf, *args, **kwargs): zelf._connected.set() ; logging.warn("connected!")
[docs] def loop(zelf, *args, **kwargs): zelf.xmpp.process()
[docs] def say(zelf, *args, **kwargs):
try: channel, txt = args
except ValueError: channel = zelf.jid ; txt = args[0]
zelf.xmpp.send_message(channel, txt)
[docs] def get_one(zelf, *args, **kwargs): return zelf.queue.get()
[docs] def handle_message(zelf, data, *args, **kwargs):
if '<delay xmlns="urn:xmpp:delay"' in str(data): logging.debug("ignoring delayed message") ; return
logging.warn("< %s" % data)
m = Object(**data)
if m.type == "error": logging.warn("error %s" % m.make_json()) ; return
m.origin = stripped(str(m["from"]))
if not m.origin in zelf.channels: zelf.channels.append(m.origin)
m.channel = m.origin
m.to = m.origin
m.element = "message"
try: m.txt = m["body"]
except KeyError: pass
m._target = zelf
kernel.dispatch(m)
[docs] def handle_presence(zelf, data, *args, **kwargs):
logging.info("< %s" % data)
p = Object(**data)
if "from" in p and p["from"]:
p.origin = stripped(str(p["from"]))
p.to = p.origin
else: p.origin = "" ; p.to = ""
p.element = "presence"
if p.type == 'subscribe':
pres = Object({'to': p["from"], 'type': 'subscribed'})
zelf.send(pres)
pres = Object({'to': p["from"], 'type': 'subscribe'})
zelf.send(pres)
else:
try: zelf.channels.remove(p.origin)
except ValueError: pass
p.no_dispatch = True
p._target = zelf
kernel.dispatch(p)
## VARS
kernel = Dispatcher()
kernel.plugs = Plugins()
kernel.run = Object()
kernel.cfg = Object()
kernel.fleet = []