diff options
Diffstat (limited to 'pyload/plugins/addons/XMPPInterface.py')
| -rw-r--r-- | pyload/plugins/addons/XMPPInterface.py | 276 | 
1 files changed, 276 insertions, 0 deletions
| diff --git a/pyload/plugins/addons/XMPPInterface.py b/pyload/plugins/addons/XMPPInterface.py new file mode 100644 index 000000000..40454f1c3 --- /dev/null +++ b/pyload/plugins/addons/XMPPInterface.py @@ -0,0 +1,276 @@ +# -*- coding: utf-8 -*- + +""" +    This program is free software; you can redistribute it and/or modify +    it under the terms of the GNU General Public License as published by +    the Free Software Foundation; either version 3 of the License, +    or (at your option) any later version. + +    This program is distributed in the hope that it will be useful, +    but WITHOUT ANY WARRANTY; without even the implied warranty of +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +    See the GNU General Public License for more details. + +    You should have received a copy of the GNU General Public License +    along with this program; if not, see <http://www.gnu.org/licenses/>. +     +    @author: RaNaN +    @interface-version: 0.2 +""" + +from pyxmpp import streamtls +from pyxmpp.all import JID, Message, Presence +from pyxmpp.jabber.client import JabberClient +from pyxmpp.interface import implements +from pyxmpp.interfaces import * + +from module.plugins.addons.IRCInterface import IRCInterface + +class XMPPInterface(IRCInterface, JabberClient): +    __name__ = "XMPPInterface" +    __version__ = "0.11" +    __description__ = """connect to jabber and let owner perform different tasks""" +    __config__ = [("activated", "bool", "Activated", "False"), +            ("jid", "str", "Jabber ID", "user@exmaple-jabber-server.org"), +            ("pw", "str", "Password", ""), +            ("tls", "bool", "Use TLS", False), +            ("owners", "str", "List of JIDs accepting commands from", "me@icq-gateway.org;some@msn-gateway.org"), +            ("info_file", "bool", "Inform about every file finished", "False"), +            ("info_pack", "bool", "Inform about every package finished", "True"), +            ("captcha", "bool", "Send captcha requests", "True")] +    __author_name__ = ("RaNaN") +    __author_mail__ = ("RaNaN@pyload.org") + +    implements(IMessageHandlersProvider) + +    def __init__(self, core, manager): +        IRCInterface.__init__(self, core, manager) + +        self.jid = JID(self.getConfig("jid")) +        password = self.getConfig("pw") + +        # if bare JID is provided add a resource -- it is required +        if not self.jid.resource: +            self.jid = JID(self.jid.node, self.jid.domain, "pyLoad") + +        if self.getConfig("tls"): +            tls_settings = streamtls.TLSSettings(require=True, verify_peer=False) +            auth = ("sasl:PLAIN", "sasl:DIGEST-MD5") +        else: +            tls_settings = None +            auth = ("sasl:DIGEST-MD5", "digest") + +        # setup client with provided connection information +        # and identity data +        JabberClient.__init__(self, self.jid, password, +                              disco_name="pyLoad XMPP Client", disco_type="bot", +                              tls_settings=tls_settings, auth_methods=auth) + +        self.interface_providers = [ +            VersionHandler(self), +            self, +            ] + +    def coreReady(self): +        self.new_package = {} + +        self.start() + +    def packageFinished(self, pypack): +        try: +            if self.getConfig("info_pack"): +                self.announce(_("Package finished: %s") % pypack.name) +        except: +            pass + +    def downloadFinished(self, pyfile): +        try: +            if self.getConfig("info_file"): +                self.announce( +                    _("Download finished: %(name)s @ %(plugin)s") % {"name": pyfile.name, "plugin": pyfile.pluginname}) +        except: +            pass + +    def run(self): +        # connect to IRC etc. +        self.connect() +        try: +            self.loop() +        except Exception, ex: +            self.logError("pyLoad XMPP: %s" % str(ex)) + +    def stream_state_changed(self, state, arg): +        """This one is called when the state of stream connecting the component +        to a server changes. This will usually be used to let the user +        know what is going on.""" +        self.logDebug("pyLoad XMPP: *** State changed: %s %r ***" % (state, arg)) + +    def disconnected(self): +        self.logDebug("pyLoad XMPP: Client was disconnected") + +    def stream_closed(self, stream): +        self.logDebug("pyLoad XMPP: Stream was closed | %s" % stream) + +    def stream_error(self, err): +        self.logDebug("pyLoad XMPP: Stream Error: %s" % err) + +    def get_message_handlers(self): +        """Return list of (message_type, message_handler) tuples. + +        The handlers returned will be called when matching message is received +        in a client session.""" +        return [ +                ("normal", self.message), +                ] + +    def presence_control(self, stanza): +        from_jid = unicode(stanza.get_from_jid()) +        stanza_type = stanza.get_type() +        self.log.debug("pyLoad XMPP: %s stanza from %s" % (stanza_type, +            from_jid)) + +        if from_jid in self.getConfig("owners"): +            return stanza.make_accept_response() + +        return stanza.make_deny_response() + +    def session_started(self): +        self.stream.send(Presence()) + +        self.stream.set_presence_handler("subscribe", self.presence_control) +        self.stream.set_presence_handler("subscribed", self.presence_control) +        self.stream.set_presence_handler("unsubscribe", self.presence_control) +        self.stream.set_presence_handler("unsubscribed", self.presence_control) + +    def message(self, stanza): +        """Message handler for the component.""" +        subject = stanza.get_subject() +        body = stanza.get_body() +        t = stanza.get_type() +        self.logDebug(u'pyLoad XMPP: Message from %s received.' % (unicode(stanza.get_from(), ))) +        self.logDebug(u'pyLoad XMPP: Body: %s Subject: %s Type: %s' % (body, subject, t)) + +        if t == "headline": +            # 'headline' messages should never be replied to +            return True +        if subject: +            subject = u"Re: " + subject + +        to_jid = stanza.get_from() +        from_jid = stanza.get_to() + +        #j = JID() +        to_name = to_jid.as_utf8() +        from_name = from_jid.as_utf8() + +        names = self.getConfig("owners").split(";") + +        if to_name in names or to_jid.node + "@" + to_jid.domain in names: +            messages = [] + +            trigger = "pass" +            args = None + +            try: +                temp = body.split() +                trigger = temp[0] +                if len(temp) > 1: +                    args = temp[1:] +            except: +                pass + +            handler = getattr(self, "event_%s" % trigger, self.event_pass) +            try: +                res = handler(args) +                for line in res: +                    m = Message( +                        to_jid=to_jid, +                        from_jid=from_jid, +                        stanza_type=stanza.get_type(), +                        subject=subject, +                        body=line) + +                    messages.append(m) +            except Exception, e: +                self.logError("pyLoad XMPP: " + repr(e)) + +            return messages + +        else: +            return True + +    def response(self, msg, origin=""): +        return self.announce(msg) + +    def announce(self, message): +        """ send message to all owners""" +        for user in self.getConfig("owners").split(";"): +            self.logDebug("pyLoad XMPP: Send message to %s" % user) + +            to_jid = JID(user) + +            m = Message(from_jid=self.jid, +                        to_jid=to_jid, +                        stanza_type="chat", +                        body=message) + +            stream = self.get_stream() +            if not stream: +                self.connect() +                stream = self.get_stream() + +            stream.send(m) + +    def beforeReconnecting(self, ip): +        self.disconnect() + +    def afterReconnecting(self, ip): +        self.connect() + + +class VersionHandler(object): +    """Provides handler for a version query. +     +    This class will answer version query and announce 'jabber:iq:version' namespace +    in the client's disco#info results.""" + +    implements(IIqHandlersProvider, IFeaturesProvider) + +    def __init__(self, client): +        """Just remember who created this.""" +        self.client = client + +    def get_features(self): +        """Return namespace which should the client include in its reply to a +        disco#info query.""" +        return ["jabber:iq:version"] + +    def get_iq_get_handlers(self): +        """Return list of tuples (element_name, namespace, handler) describing +        handlers of <iq type='get'/> stanzas""" +        return [ +                ("query", "jabber:iq:version", self.get_version), +                                                                ] + +    def get_iq_set_handlers(self): +        """Return empty list, as this class provides no <iq type='set'/> stanza handler.""" +        return [] + +    def get_version(self, iq): +        """Handler for jabber:iq:version queries. + +        jabber:iq:version queries are not supported directly by PyXMPP, so the +        XML node is accessed directly through the libxml2 API.  This should be +        used very carefully!""" +        iq = iq.make_result_response() +        q = iq.new_query("jabber:iq:version") +        q.newTextChild(q.ns(), "name", "Echo component") +        q.newTextChild(q.ns(), "version", "1.0") +        return iq + +    def unload(self): +        self.log.debug("pyLoad XMPP: unloading") +        self.disconnect() + +    def deactivate(self): +        self.unload() | 
