Skip to content
Back to top

# Source code for slixmpp.plugins.xep_0066.oob

    # Slixmpp: The Slick XMPP Library
    # Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
    # This file is part of Slixmpp.
    # See the file LICENSE for copying permission.
    import logging

    from slixmpp.stanza import Message, Presence, Iq
    from slixmpp.exceptions import XMPPError
    from slixmpp.xmlstream import register_stanza_plugin
    from slixmpp.xmlstream.handler import Callback
    from slixmpp.xmlstream.matcher import StanzaPath
    from slixmpp.plugins import BasePlugin
    from slixmpp.plugins.xep_0066 import stanza

    log = logging.getLogger(__name__)

    class XEP_0066(BasePlugin):

        """
        XEP-0066: Out of Band Data

        Out of Band Data is a basic method for transferring files between
        XMPP agents. The URL of the resource in question is sent to the receiving
        entity, which then downloads the resource before responding to the OOB
        request. OOB is also used as a generic means to transmit URLs in other
        stanzas to indicate where to find additional information.

        Also see <http://www.xmpp.org/extensions/xep-0066.html>.

        Events:
            oob_transfer -- Raised when a request to download a resource
                            has been received.
        """

        name = 'xep_0066'
        description = 'XEP-0066: Out of Band Data'
        dependencies = {'xep_0030'}
        stanza = stanza

        def plugin_init(self):
            """Start the XEP-0066 plugin."""

            self.url_handlers = {'global': self._default_handler,
                                 'jid': {}}

            register_stanza_plugin(Iq, stanza.OOBTransfer)
            register_stanza_plugin(Message, stanza.OOB)
            register_stanza_plugin(Presence, stanza.OOB)

            self.xmpp.register_handler(
                    Callback('OOB Transfer',
                             StanzaPath('iq@type=set/oob_transfer'),
                             self._handle_transfer))

        def plugin_end(self):
            self.xmpp.remove_handler('OOB Transfer')
            self.xmpp.plugin['xep_0030'].del_feature(feature=stanza.OOBTransfer.namespace)
            self.xmpp.plugin['xep_0030'].del_feature(feature=stanza.OOB.namespace)

        def session_bind(self, jid):
            self.xmpp.plugin['xep_0030'].add_feature(stanza.OOBTransfer.namespace)
            self.xmpp.plugin['xep_0030'].add_feature(stanza.OOB.namespace)

        def register_url_handler(self, jid=None, handler=None):
            """
            Register a handler to process download requests, either for all
            JIDs or a single JID.

            :param jid: If None, then set the handler as a global default.
            :param handler: If None, then remove the existing handler for the
                            given JID, or reset the global handler if the JID
                            is None.
            """
            if jid is None:
                if handler is not None:
                    self.url_handlers['global'] = handler
                else:
                    self.url_handlers['global'] = self._default_handler
            else:
                if handler is not None:
                    self.url_handlers['jid'][jid] = handler
                else:
                    del self.url_handlers['jid'][jid]

        def send_oob(self, to, url, desc=None, ifrom=None, **iqargs):
            """
            Initiate a basic file transfer by sending the URL of
            a file or other resource.

            :param url: The URL of the resource to transfer.
            :param desc: An optional human readable description of the item
                         that is to be transferred.
            """
            iq = self.xmpp.Iq()
            iq['type'] = 'set'
            iq['to'] = to
            iq['from'] = ifrom
            iq['oob_transfer']['url'] = url
            iq['oob_transfer']['desc'] = desc
            return iq.send(**iqargs)

        def _run_url_handler(self, iq):
            """
            Execute the appropriate handler for a transfer request.

            :param iq: The Iq stanza containing the OOB transfer request.
            """
            if iq['to'] in self.url_handlers['jid']:
                return self.url_handlers['jid'][iq['to']](iq)
            else:
                if self.url_handlers['global']:
                    self.url_handlers['global'](iq)
                else:
                    raise XMPPError('service-unavailable')

        def _default_handler(self, iq):
            """
            As a safe default, don't actually download files.

            Register a new handler using self.register_url_handler to
            screen requests and download files.

            :param iq: The Iq stanza containing the OOB transfer request.
            """
            raise XMPPError('service-unavailable')

        def _handle_transfer(self, iq):
            """
            Handle receiving an out-of-band transfer request.

            :param iq: An Iq stanza containing an OOB transfer request.
            """
            log.debug('Received out-of-band data request for %s from %s:' % (
                iq['oob_transfer']['url'], iq['from']))
            self._run_url_handler(iq)
            iq.reply().send()