# mad/xmpp.py
#
#
""" XMPP bot class. """
from .bot import Bot
from .event import Event
from .utils import stripped
import logging
import time
import os
[docs]def init(event):
bot = XMPP()
try:
bot.start()
except UnboundLocalError:
logging.error("# missing sleekxmpp")
return
return bot
[docs]class XMPP(Bot):
cc = ""
[docs] def announce(self, txt):
for channel in self.channels:
self.say(channel, txt)
[docs] def connect(self, user="", pw=""):
fn = os.path.expanduser("~/.sleekpass")
pww = ""
f = open(fn, "r")
pww = f.read()
f.close()
self._connect(user or self.cfg.user, pw or pww)
[docs] def connected(self, data):
self._connected.ready()
[docs] def disconnected(self, data):
self._connected.clear()
pass
[docs] def event(self):
e = self._queue.get()
if e:
e.btype = self.type
return e
[docs] def exception(self, data):
self._error = data
[docs] def failedauth(self, data):
logging.error("# failed auth %s" % data)
[docs] def failure(self, data):
logging.error("# failure %s" % data)
self._error = data
[docs] def invalid_cert(self, data):
logging.debug("# invalid cert")
[docs] def iqed(self, data):
logging.warn("# Iq %s:%s %s" % (self.cfg.server, self.cfg.port, data))
[docs] def messaged(self, data):
from .space import kernel
logging.debug("< %s" % data)
m = Event()
m.update(data)
if m.type == "error":
logging.error("^ %s" % m.error)
return
m.cc = ""
m["from"] = str(m["from"])
if self.cfg.user in m["from"]:
logging.debug("! ignore %s %s" % (m.type, m["from"]))
return
m.origin = m["from"]
m.btype = self.type
m.server = self.cfg.server
m.channel = m.origin
m.to = m.origin
m.element = "message"
m.txt = m["body"]
if '<delay xmlns="urn:xmpp:delay"' in str(data):
logging.debug("! ignore %s" % m.origin)
return
logging.info("< %s %s" % (stripped(m.origin), m.txt))
kernel.put(m)
[docs] def pinged(self, event):
self._connected.ready()
[docs] def presenced(self, data):
from .space import kernel
logging.debug("< %s" % data)
o = Event()
o.cc = ""
o.update(data)
o.id = self.id()
o.origin = o["from"]
if "txt" not in o:
o.txt = ""
o.element = "presence"
username = stripped(o.origin)
if o.type == 'subscribe':
pres = Event({'to': o["from"], 'type': 'subscribed'})
self.client.send_presence(dict(pres))
pres = Event({'to': o["from"], 'type': 'subscribe'})
self.client.send_presence(dict(pres))
elif o.type == "unavailable" and username != self.cfg.username and username in self.channels:
self.channels.remove(username)
elif o.origin != self.cfg.user and username != self.cfg.username and username not in self.channels:
self.channels.append(username)
o.txt = o.type
logging.info("< presence %s" % stripped(o.origin))
kernel.put(o)
[docs] def register(self, key, value):
self.client.add_event_handler(key, value)
[docs] def say(self, jid, txt):
txt = str(txt)
self.client.send_message(jid, txt)
logging.info("%s %s" % (stripped(jid), txt))
[docs] def session_start(self, data):
self.client.send_presence()
[docs] def start(self, *args, **kwargs):
self.launch(self.sleek)
try:
self.connect()
except FileNotFoundError:
print("# no ~/.sleekpass file found.")
return
super().start(*args, **kwargs)
[docs] def stop(self):
self._connected.ready()
self._queue.put(None)
if "client" in self and self.client:
self.client.disconnect()
super().stop()
[docs] def sleek(self):
self._connected.wait()
if "client" in self and self.client:
self.client.process(block=True)
[docs] def _connect(self, user, pw):
self.makeclient(user, pw)
self.client.reconnect_max_attempts = 2
logging.warn("# connect %s" % self.cfg.user)
if self.cfg.openfire:
self.client.connect((self.cfg.server, self.cfg.port), use_ssl=True)
else:
self.client.connect((self.cfg.server, self.cfg.port))
if self.cfg.noresolver:
self.client.configure_dns(None)
self.register_fd(self.client.socket)
[docs] def makeclient(self, jid, password):
try:
import sleekxmpp.clientxmpp
import sleekxmpp
except ImportError:
logging.warn("sleekxmpp is not installed")
self.client = sleekxmpp.clientxmpp.ClientXMPP(jid, password)
self.register("session_start", self.session_start)
self.register("message", self.messaged)
self.register("iq", self.iqed)
self.register("ssl_invalid_cert", self.invalid_cert)
self.register('disconnected', self.disconnected)
self.register('connected', self.connected)
self.register('presence_available', self.presenced)
self.register('presence_dnd', self.presenced)
self.register('presence_xa', self.presenced)
self.register('presence_chat', self.presenced)
self.register('presence_away', self.presenced)
self.register('presence_unavailable', self.presenced)
self.register('presence_subscribe', self.presenced)
self.register('presence_subscribed', self.presenced)
self.register('presence_unsubscribe', self.presenced)
self.register('presence_unsubscribed', self.presenced)
self.register('groupchat_message', self.messaged)
self.register('groupchat_presence', self.presenced)
self.register('groupchat_subject', self.presenced)
self.register('failed_auth', self.failedauth)
self.client.exception = self.exception
self.client.use_signals()