diff --git a/sleekxmpp/basexmpp.py b/sleekxmpp/basexmpp.py
index edb20d08..2548934e 100644
--- a/sleekxmpp/basexmpp.py
+++ b/sleekxmpp/basexmpp.py
@@ -26,6 +26,14 @@ from sleekxmpp.xmlstream.matcher import *
from sleekxmpp.xmlstream.handler import *
+# Flag indicating if DNS SRV records are available for use.
+SRV_SUPPORT = True
+try:
+ import dns.resolver
+except:
+ SRV_SUPPORT = False
+
+
# In order to make sure that Unicode is handled properly
# in Python 2.x, reset the default encoding.
if sys.version_info < (3, 0):
diff --git a/sleekxmpp/componentxmpp.py b/sleekxmpp/componentxmpp.py
old mode 100755
new mode 100644
index 00e52528..abb20d95
--- a/sleekxmpp/componentxmpp.py
+++ b/sleekxmpp/componentxmpp.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-
"""
SleekXMPP: The Sleek XMPP Library
Copyright (C) 2010 Nathanael C. Fritz
@@ -7,72 +5,132 @@
See the file LICENSE for copying permission.
"""
-from __future__ import absolute_import
-from . basexmpp import BaseXMPP
-from xml.etree import cElementTree as ET
-from . xmlstream.xmlstream import XMLStream
-from . xmlstream.xmlstream import RestartStream
-from . xmlstream.matcher.xmlmask import MatchXMLMask
-from . xmlstream.matcher.xpath import MatchXPath
-from . xmlstream.matcher.many import MatchMany
-from . xmlstream.handler.callback import Callback
-from . xmlstream.stanzabase import StanzaBase
-from . xmlstream import xmlstream as xmlstreammod
-import time
+from __future__ import absolute_import
+
import logging
import base64
import sys
-import random
-import copy
-from . import plugins
-from . import stanza
import hashlib
-srvsupport = True
-try:
- import dns.resolver
-except ImportError:
- srvsupport = False
+
+from sleekxmpp import plugins
+from sleekxmpp import stanza
+from sleekxmpp.basexmpp import BaseXMPP, SRV_SUPPORT
+from sleekxmpp.xmlstream import XMLStream, RestartStream
+from sleekxmpp.xmlstream.matcher import *
+from sleekxmpp.xmlstream.handler import *
+from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET
-class ComponentXMPP(basexmpp, XMLStream):
- """SleekXMPP's client class. Use only for good, not evil."""
+class ComponentXMPP(BaseXMPP):
- def __init__(self, jid, secret, host, port, plugin_config = {}, plugin_whitelist=[], use_jc_ns=False):
- if use_jc_ns:
- default_ns = 'jabber:client'
- else:
- default_ns = 'jabber:component:accept'
- BaseXMPP.__init__(self, default_ns)
- self.auto_authorize = None
- self.stream_header = "" % jid
- self.stream_footer = ""
- self.server_host = host
- self.server_port = port
- self.set_jid(jid)
- self.secret = secret
- self.is_component = True
- self.registerHandler(Callback('Handshake', MatchXPath('{jabber:component:accept}handshake'), self._handleHandshake))
+ """
+ SleekXMPP's basic XMPP server component.
- def incoming_filter(self, xmlobj):
- if xmlobj.tag.startswith('{jabber:client}'):
- xmlobj.tag = xmlobj.tag.replace('jabber:client', self.default_ns)
- for sub in xmlobj:
- self.incoming_filter(sub)
- return xmlobj
+ Use only for good, not for evil.
- def start_stream_handler(self, xml):
- sid = xml.get('id', '')
- handshake = ET.Element('{jabber:component:accept}handshake')
- if sys.version_info < (3,0):
- handshake.text = hashlib.sha1("%s%s" % (sid, self.secret)).hexdigest().lower()
- else:
- handshake.text = hashlib.sha1(bytes("%s%s" % (sid, self.secret), 'utf-8')).hexdigest().lower()
- self.sendXML(handshake)
+ Methods:
+ connect -- Overrides XMLStream.connect.
+ incoming_filter -- Overrides XMLStream.incoming_filter.
+ start_stream_handler -- Overrides XMLStream.start_stream_handler.
+ """
- def _handleHandshake(self, xml):
- self.event("session_start")
+ def __init__(self, jid, secret, host, port,
+ plugin_config={}, plugin_whitelist=[], use_jc_ns=False):
+ """
+ Arguments:
+ jid -- The JID of the component.
+ secret -- The secret or password for the component.
+ host -- The server accepting the component.
+ port -- The port used to connect to the server.
+ plugin_config -- A dictionary of plugin configurations.
+ plugin_whitelist -- A list of desired plugins to load
+ when using register_plugins.
+ use_js_ns -- Indicates if the 'jabber:client' namespace
+ should be used instead of the standard
+ 'jabber:component:accept' namespace.
+ Defaults to False.
+ """
+ if use_jc_ns:
+ default_ns = 'jabber:client'
+ else:
+ default_ns = 'jabber:component:accept'
+ BaseXMPP.__init__(self, default_ns)
- def connect(self):
- logging.debug("Connecting to %s:%s" % (self.server_host, self.server_port))
- return xmlstreammod.XMLStream.connect(self, self.server_host, self.server_port)
+ self.auto_authorize = None
+ self.stream_header = "" % (
+ 'xmlns="jabber:component:accept"',
+ 'xmlns:stream="http://etherx.jabber.org/streams"',
+ jid)
+ self.stream_footer = ""
+ self.server_host = host
+ self.server_port = port
+ self.set_jid(jid)
+ self.secret = secret
+ self.is_component = True
+
+ self.register_handler(
+ Callback('Handshake',
+ MatchXPath('{jabber:component:accept}handshake'),
+ self._handle_handshake))
+
+ def connect(self):
+ """
+ Connect to the server.
+
+ Overrides XMLStream.connect.
+ """
+ logging.debug("Connecting to %s:%s" % (self.server_host,
+ self.server_port))
+ return XMLStream.connect(self, self.server_host,
+ self.server_port)
+
+ def incoming_filter(self, xml):
+ """
+ Pre-process incoming XML stanzas by converting any 'jabber:client'
+ namespaced elements to the component's default namespace.
+
+ Overrides XMLStream.incoming_filter.
+
+ Arguments:
+ xml -- The XML stanza to pre-process.
+ """
+ if xml.tag.startswith('{jabber:client}'):
+ xml.tag = xml.tag.replace('jabber:client', self.default_ns)
+
+ # The incoming_filter call is only made on top level stanza
+ # elements. So we manually continue filtering on sub-elements.
+ for sub in xml:
+ self.incoming_filter(sub)
+
+ return xml
+
+ def start_stream_handler(self, xml):
+ """
+ Once the streams are established, attempt to handshake
+ with the server to be accepted as a component.
+
+ Overrides XMLStream.start_stream_handler.
+
+ Arguments:
+ xml -- The incoming stream's root element.
+ """
+ # Construct a hash of the stream ID and the component secret.
+ sid = xml.get('id', '')
+ pre_hash = '%s%s' % (sid, self.secret)
+ if sys.version_info >= (3, 0):
+ # Handle Unicode byte encoding in Python 3.
+ pre_hash = bytes(pre_hash, 'utf-8')
+
+ handshake = ET.Element('{jabber:component:accept}handshake')
+ handshake.text = hashlib.sha1(pre_hash).hexdigest().lower()
+ self.send_xml(handshake)
+
+ def _handle_handshake(self, xml):
+ """
+ The handshake has been accepted.
+
+ Arguments:
+ xml -- The reply handshake stanza.
+ """
+ self.event("session_start")