diff --git a/sleekxmpp/basexmpp.py b/sleekxmpp/basexmpp.py
index cd7d251..0ff573f 100644
--- a/sleekxmpp/basexmpp.py
+++ b/sleekxmpp/basexmpp.py
@@ -110,6 +110,8 @@ class BaseXMPP(XMLStream):
self.boundjid = JID("")
self.plugin = {}
+ self.plugin_config = {}
+ self.plugin_whitelist = []
self.roster = {}
self.is_component = False
self.auto_authorize = True
diff --git a/sleekxmpp/plugins/xep_0030.py b/sleekxmpp/plugins/xep_0030.py
index c805080..59c60e6 100644
--- a/sleekxmpp/plugins/xep_0030.py
+++ b/sleekxmpp/plugins/xep_0030.py
@@ -71,11 +71,12 @@ class DiscoInfo(ElementBase):
for idXML in idsXML:
self.xml.remove(idXML)
- def addIdentity(self, category, id_type, name=''):
- idXML = ET.Element('{%s}identity' % self.namespace,
- {'category': category,
- 'type': id_type,
- 'name': name})
+ def addIdentity(self, category, itype, name=''):
+ idXML = ET.Element('{%s}identity' % self.namespace)
+ idXML.attrib['category'] = category
+ idXML.attrib['type'] = itype
+ if name:
+ idXML.attrib['name'] = name
self.xml.append(idXML)
def delIdentity(self, category, id_type, name=''):
@@ -213,8 +214,11 @@ class xep_0030(base.base_plugin):
self.xmpp.add_event_handler('disco_items_request', self.handle_disco_items)
self.xmpp.add_event_handler('disco_info_request', self.handle_disco_info)
+
+ self.nodes = {}
- self.nodes = {'main': DiscoNode('main')}
+ self.add_node('')
+ self.add_feature('http://jabber.org/protocol/disco#info', node='')
def add_node(self, node):
if node not in self.nodes:
@@ -258,14 +262,30 @@ class xep_0030(base.base_plugin):
return
node_name = iq['disco_info']['node']
- if not node_name:
- node_name = 'main'
-
log.debug("Using default handler for disco#info on node '%s'." % node_name)
if node_name in self.nodes:
node = self.nodes[node_name]
- iq.reply().setPayload(node.info.xml).send()
+ iq.reply()
+ iq['disco_info']['node'] = node_name
+
+ identities = node.info['identities']
+ if identities:
+ iq['disco_info']['identities'] = identities
+ else:
+ if self.xmpp.is_component:
+ iq['disco_info'].addIdentity(
+ category='component',
+ itype='generic')
+ else:
+ iq['disco_info'].addIdentity(
+ category='client',
+ itype='bot')
+ log.info("No identity found for node '%'," + \
+ "using default, generic identity")
+
+ iq['disco_info']['features'] = node.info['features']
+ iq.send()
else:
log.debug("Node %s requested, but does not exist." % node_name)
iq.reply().error().setPayload(iq['disco_info'].xml)
@@ -287,10 +307,7 @@ class xep_0030(base.base_plugin):
return
node_name = iq['disco_items']['node']
- if not node_name:
- node_name = 'main'
-
- log.debug("Using default handler for disco#items on node '%s'." % node_name)
+ log.debug("Using default handler for disco#items on node: '%s'." % node_name)
if node_name in self.nodes:
node = self.nodes[node_name]
@@ -321,17 +338,17 @@ class xep_0030(base.base_plugin):
iq['disco_items']['node'] = node
return iq.send()
- def add_feature(self, feature, node='main'):
+ def add_feature(self, feature, node=''):
self.add_node(node)
self.nodes[node].addFeature(feature)
- def add_identity(self, category='', itype='', name='', node='main'):
+ def add_identity(self, category='', itype='', name='', node=''):
self.add_node(node)
self.nodes[node].addIdentity(category=category,
id_type=itype,
name=name)
- def add_item(self, jid=None, name='', node='main', subnode=''):
+ def add_item(self, jid=None, name='', node='', subnode=''):
self.add_node(node)
self.add_node(subnode)
if jid is None:
diff --git a/sleekxmpp/test/sleektest.py b/sleekxmpp/test/sleektest.py
index 5e61cec..f1b5ef9 100644
--- a/sleekxmpp/test/sleektest.py
+++ b/sleekxmpp/test/sleektest.py
@@ -257,7 +257,7 @@ class SleekTest(unittest.TestCase):
def stream_start(self, mode='client', skip=True, header=None,
socket='mock', jid='tester@localhost',
password='test', server='localhost',
- port=5222):
+ port=5222, plugins=None):
"""
Initialize an XMPP client or component using a dummy XML stream.
@@ -277,6 +277,8 @@ class SleekTest(unittest.TestCase):
server -- The name of the XMPP server. Defaults to 'localhost'.
port -- The port to use when connecting to the server.
Defaults to 5222.
+ plugins -- List of plugins to register. By default, all plugins
+ are loaded.
"""
if mode == 'client':
self.xmpp = ClientXMPP(jid, password)
@@ -312,7 +314,11 @@ class SleekTest(unittest.TestCase):
else:
raise ValueError("Unknown socket type.")
- self.xmpp.register_plugins()
+ if plugins is None:
+ self.xmpp.register_plugins()
+ else:
+ for plugin in plugins:
+ self.xmpp.register_plugin(plugin)
self.xmpp.process(threaded=True)
if skip:
if socket != 'live':
diff --git a/tests/test_stream_xep_0030.py b/tests/test_stream_xep_0030.py
new file mode 100644
index 0000000..5efce78
--- /dev/null
+++ b/tests/test_stream_xep_0030.py
@@ -0,0 +1,83 @@
+import time
+from sleekxmpp.test import *
+
+
+class TestStreamDisco(SleekTest):
+ """
+ Test using the XEP-0030 plugin.
+ """
+
+ def tearDown(self):
+ self.stream_close()
+
+ def testInfoEmptyNode(self):
+ """
+ Info queries to a node MUST have at least one identity
+ and feature, namely http://jabber.org/protocol/disco#info.
+
+ Since the XEP-0030 plugin is loaded, a disco response should
+ be generated and not an error result.
+ """
+ self.stream_start(plugins=['xep_0030'])
+
+ self.recv("""
+
+
+
+ """)
+
+ self.send("""
+
+
+
+
+
+ """)
+
+ def testInfoEmptyNodeComponent(self):
+ """
+ Test requesting an empty node using a Component.
+ """
+ self.stream_start(mode='component',
+ plugins=['xep_0030'])
+
+ self.recv("""
+
+
+
+ """)
+
+ self.send("""
+
+
+
+
+
+ """)
+
+ def testInfoIncludeNode(self):
+ """
+ Results for info queries directed to a particular node MUST
+ include the node in the query response.
+ """
+ self.stream_start(plugins=['xep_0030'])
+
+ self.xmpp['xep_0030'].add_node('testing')
+
+ self.recv("""
+
+
+
+ """)
+
+ self.send("""
+
+
+
+ """,
+ method='mask')
+
+
+suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamDisco)