mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-27 19:19:54 +00:00
Fix bug in XEP-0030 plugin.
xep_0030 still referenced event_handlers. Added the method event_handled which will return the number of registered handlers for an event to resolve the issue.
This commit is contained in:
parent
973890e2c9
commit
9e248bb852
2 changed files with 272 additions and 262 deletions
|
@ -14,314 +14,312 @@ from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID
|
||||||
from .. stanza.iq import Iq
|
from .. stanza.iq import Iq
|
||||||
|
|
||||||
class DiscoInfo(ElementBase):
|
class DiscoInfo(ElementBase):
|
||||||
namespace = 'http://jabber.org/protocol/disco#info'
|
namespace = 'http://jabber.org/protocol/disco#info'
|
||||||
name = 'query'
|
name = 'query'
|
||||||
plugin_attrib = 'disco_info'
|
plugin_attrib = 'disco_info'
|
||||||
interfaces = set(('node', 'features', 'identities'))
|
interfaces = set(('node', 'features', 'identities'))
|
||||||
|
|
||||||
def getFeatures(self):
|
def getFeatures(self):
|
||||||
features = []
|
features = []
|
||||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||||
for feature in featuresXML:
|
for feature in featuresXML:
|
||||||
features.append(feature.attrib['var'])
|
features.append(feature.attrib['var'])
|
||||||
return features
|
return features
|
||||||
|
|
||||||
def setFeatures(self, features):
|
def setFeatures(self, features):
|
||||||
self.delFeatures()
|
self.delFeatures()
|
||||||
for name in features:
|
for name in features:
|
||||||
self.addFeature(name)
|
self.addFeature(name)
|
||||||
|
|
||||||
def delFeatures(self):
|
def delFeatures(self):
|
||||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||||
for feature in featuresXML:
|
for feature in featuresXML:
|
||||||
self.xml.remove(feature)
|
self.xml.remove(feature)
|
||||||
|
|
||||||
def addFeature(self, feature):
|
def addFeature(self, feature):
|
||||||
featureXML = ET.Element('{%s}feature' % self.namespace,
|
featureXML = ET.Element('{%s}feature' % self.namespace,
|
||||||
{'var': feature})
|
{'var': feature})
|
||||||
self.xml.append(featureXML)
|
self.xml.append(featureXML)
|
||||||
|
|
||||||
def delFeature(self, feature):
|
def delFeature(self, feature):
|
||||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||||
for featureXML in featuresXML:
|
for featureXML in featuresXML:
|
||||||
if featureXML.attrib['var'] == feature:
|
if featureXML.attrib['var'] == feature:
|
||||||
self.xml.remove(featureXML)
|
self.xml.remove(featureXML)
|
||||||
|
|
||||||
def getIdentities(self):
|
def getIdentities(self):
|
||||||
ids = []
|
ids = []
|
||||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||||
for idXML in idsXML:
|
for idXML in idsXML:
|
||||||
idData = (idXML.attrib['category'],
|
idData = (idXML.attrib['category'],
|
||||||
idXML.attrib['type'],
|
idXML.attrib['type'],
|
||||||
idXML.attrib.get('name', ''))
|
idXML.attrib.get('name', ''))
|
||||||
ids.append(idData)
|
ids.append(idData)
|
||||||
return ids
|
return ids
|
||||||
|
|
||||||
def setIdentities(self, ids):
|
def setIdentities(self, ids):
|
||||||
self.delIdentities()
|
self.delIdentities()
|
||||||
for idData in ids:
|
for idData in ids:
|
||||||
self.addIdentity(*idData)
|
self.addIdentity(*idData)
|
||||||
|
|
||||||
def delIdentities(self):
|
def delIdentities(self):
|
||||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||||
for idXML in idsXML:
|
for idXML in idsXML:
|
||||||
self.xml.remove(idXML)
|
self.xml.remove(idXML)
|
||||||
|
|
||||||
def addIdentity(self, category, id_type, name=''):
|
def addIdentity(self, category, id_type, name=''):
|
||||||
idXML = ET.Element('{%s}identity' % self.namespace,
|
idXML = ET.Element('{%s}identity' % self.namespace,
|
||||||
{'category': category,
|
{'category': category,
|
||||||
'type': id_type,
|
'type': id_type,
|
||||||
'name': name})
|
'name': name})
|
||||||
self.xml.append(idXML)
|
self.xml.append(idXML)
|
||||||
|
|
||||||
def delIdentity(self, category, id_type, name=''):
|
def delIdentity(self, category, id_type, name=''):
|
||||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||||
for idXML in idsXML:
|
for idXML in idsXML:
|
||||||
idData = (idXML.attrib['category'],
|
idData = (idXML.attrib['category'],
|
||||||
idXML.attrib['type'])
|
idXML.attrib['type'])
|
||||||
delId = (category, id_type)
|
delId = (category, id_type)
|
||||||
if idData == delId:
|
if idData == delId:
|
||||||
self.xml.remove(idXML)
|
self.xml.remove(idXML)
|
||||||
|
|
||||||
|
|
||||||
class DiscoItems(ElementBase):
|
class DiscoItems(ElementBase):
|
||||||
namespace = 'http://jabber.org/protocol/disco#items'
|
namespace = 'http://jabber.org/protocol/disco#items'
|
||||||
name = 'query'
|
name = 'query'
|
||||||
plugin_attrib = 'disco_items'
|
plugin_attrib = 'disco_items'
|
||||||
interfaces = set(('node', 'items'))
|
interfaces = set(('node', 'items'))
|
||||||
|
|
||||||
def getItems(self):
|
def getItems(self):
|
||||||
items = []
|
items = []
|
||||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||||
for item in itemsXML:
|
for item in itemsXML:
|
||||||
itemData = (item.attrib['jid'],
|
itemData = (item.attrib['jid'],
|
||||||
item.attrib.get('node'),
|
item.attrib.get('node'),
|
||||||
item.attrib.get('name'))
|
item.attrib.get('name'))
|
||||||
items.append(itemData)
|
items.append(itemData)
|
||||||
return items
|
return items
|
||||||
|
|
||||||
def setItems(self, items):
|
def setItems(self, items):
|
||||||
self.delItems()
|
self.delItems()
|
||||||
for item in items:
|
for item in items:
|
||||||
self.addItem(*item)
|
self.addItem(*item)
|
||||||
|
|
||||||
def delItems(self):
|
def delItems(self):
|
||||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||||
for item in itemsXML:
|
for item in itemsXML:
|
||||||
self.xml.remove(item)
|
self.xml.remove(item)
|
||||||
|
|
||||||
def addItem(self, jid, node='', name=''):
|
def addItem(self, jid, node='', name=''):
|
||||||
itemXML = ET.Element('{%s}item' % self.namespace, {'jid': jid})
|
itemXML = ET.Element('{%s}item' % self.namespace, {'jid': jid})
|
||||||
if name:
|
if name:
|
||||||
itemXML.attrib['name'] = name
|
itemXML.attrib['name'] = name
|
||||||
if node:
|
if node:
|
||||||
itemXML.attrib['node'] = node
|
itemXML.attrib['node'] = node
|
||||||
self.xml.append(itemXML)
|
self.xml.append(itemXML)
|
||||||
|
|
||||||
|
def delItem(self, jid, node=''):
|
||||||
|
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||||
|
for itemXML in itemsXML:
|
||||||
|
itemData = (itemXML.attrib['jid'],
|
||||||
|
itemXML.attrib.get('node', ''))
|
||||||
|
itemDel = (jid, node)
|
||||||
|
if itemData == itemDel:
|
||||||
|
self.xml.remove(itemXML)
|
||||||
|
|
||||||
def delItem(self, jid, node=''):
|
|
||||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
|
||||||
for itemXML in itemsXML:
|
|
||||||
itemData = (itemXML.attrib['jid'],
|
|
||||||
itemXML.attrib.get('node', ''))
|
|
||||||
itemDel = (jid, node)
|
|
||||||
if itemData == itemDel:
|
|
||||||
self.xml.remove(itemXML)
|
|
||||||
|
|
||||||
|
|
||||||
class DiscoNode(object):
|
class DiscoNode(object):
|
||||||
"""
|
"""
|
||||||
Collection object for grouping info and item information
|
Collection object for grouping info and item information
|
||||||
into nodes.
|
into nodes.
|
||||||
"""
|
"""
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.info = DiscoInfo()
|
self.info = DiscoInfo()
|
||||||
self.items = DiscoItems()
|
self.items = DiscoItems()
|
||||||
|
|
||||||
self.info['node'] = name
|
self.info['node'] = name
|
||||||
self.items['node'] = name
|
self.items['node'] = name
|
||||||
|
|
||||||
# This is a bit like poor man's inheritance, but
|
# This is a bit like poor man's inheritance, but
|
||||||
# to simplify adding information to the node we
|
# to simplify adding information to the node we
|
||||||
# map node functions to either the info or items
|
# map node functions to either the info or items
|
||||||
# stanza objects.
|
# stanza objects.
|
||||||
#
|
#
|
||||||
# We don't want to make DiscoNode inherit from
|
# We don't want to make DiscoNode inherit from
|
||||||
# DiscoInfo and DiscoItems because DiscoNode is
|
# DiscoInfo and DiscoItems because DiscoNode is
|
||||||
# not an actual stanza, and doing so would create
|
# not an actual stanza, and doing so would create
|
||||||
# confusion and potential bugs.
|
# confusion and potential bugs.
|
||||||
|
|
||||||
self._map(self.items, 'items', ['get', 'set', 'del'])
|
self._map(self.items, 'items', ['get', 'set', 'del'])
|
||||||
self._map(self.items, 'item', ['add', 'del'])
|
self._map(self.items, 'item', ['add', 'del'])
|
||||||
self._map(self.info, 'identities', ['get', 'set', 'del'])
|
self._map(self.info, 'identities', ['get', 'set', 'del'])
|
||||||
self._map(self.info, 'identity', ['add', 'del'])
|
self._map(self.info, 'identity', ['add', 'del'])
|
||||||
self._map(self.info, 'features', ['get', 'set', 'del'])
|
self._map(self.info, 'features', ['get', 'set', 'del'])
|
||||||
self._map(self.info, 'feature', ['add', 'del'])
|
self._map(self.info, 'feature', ['add', 'del'])
|
||||||
|
|
||||||
def isEmpty(self):
|
def isEmpty(self):
|
||||||
"""
|
"""
|
||||||
Test if the node contains any information. Useful for
|
Test if the node contains any information. Useful for
|
||||||
determining if a node can be deleted.
|
determining if a node can be deleted.
|
||||||
"""
|
"""
|
||||||
ids = self.getIdentities()
|
ids = self.getIdentities()
|
||||||
features = self.getFeatures()
|
features = self.getFeatures()
|
||||||
items = self.getItems()
|
items = self.getItems()
|
||||||
|
|
||||||
if not ids and not features and not items:
|
if not ids and not features and not items:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _map(self, obj, interface, access):
|
def _map(self, obj, interface, access):
|
||||||
"""
|
"""
|
||||||
Map functions of the form obj.accessInterface
|
Map functions of the form obj.accessInterface
|
||||||
to self.accessInterface for each given access type.
|
to self.accessInterface for each given access type.
|
||||||
"""
|
"""
|
||||||
interface = interface.title()
|
interface = interface.title()
|
||||||
for access_type in access:
|
for access_type in access:
|
||||||
method = access_type + interface
|
method = access_type + interface
|
||||||
if hasattr(obj, method):
|
if hasattr(obj, method):
|
||||||
setattr(self, method, getattr(obj, method))
|
setattr(self, method, getattr(obj, method))
|
||||||
|
|
||||||
|
|
||||||
class xep_0030(base.base_plugin):
|
class xep_0030(base.base_plugin):
|
||||||
"""
|
"""
|
||||||
XEP-0030 Service Discovery
|
XEP-0030 Service Discovery
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def plugin_init(self):
|
|
||||||
self.xep = '0030'
|
|
||||||
self.description = 'Service Discovery'
|
|
||||||
|
|
||||||
self.xmpp.registerHandler(
|
def plugin_init(self):
|
||||||
Callback('Disco Items',
|
self.xep = '0030'
|
||||||
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
self.description = 'Service Discovery'
|
||||||
DiscoItems.namespace)),
|
|
||||||
self.handle_item_query))
|
|
||||||
|
|
||||||
self.xmpp.registerHandler(
|
self.xmpp.registerHandler(
|
||||||
Callback('Disco Info',
|
Callback('Disco Items',
|
||||||
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
||||||
DiscoInfo.namespace)),
|
DiscoItems.namespace)),
|
||||||
self.handle_info_query))
|
self.handle_item_query))
|
||||||
|
|
||||||
registerStanzaPlugin(Iq, DiscoInfo)
|
self.xmpp.registerHandler(
|
||||||
registerStanzaPlugin(Iq, DiscoItems)
|
Callback('Disco Info',
|
||||||
|
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
||||||
|
DiscoInfo.namespace)),
|
||||||
|
self.handle_info_query))
|
||||||
|
|
||||||
self.xmpp.add_event_handler('disco_items_request', self.handle_disco_items)
|
registerStanzaPlugin(Iq, DiscoInfo)
|
||||||
self.xmpp.add_event_handler('disco_info_request', self.handle_disco_info)
|
registerStanzaPlugin(Iq, DiscoItems)
|
||||||
|
|
||||||
self.nodes = {'main': DiscoNode('main')}
|
self.xmpp.add_event_handler('disco_items_request', self.handle_disco_items)
|
||||||
|
self.xmpp.add_event_handler('disco_info_request', self.handle_disco_info)
|
||||||
|
|
||||||
def add_node(self, node):
|
self.nodes = {'main': DiscoNode('main')}
|
||||||
if node not in self.nodes:
|
|
||||||
self.nodes[node] = DiscoNode(node)
|
|
||||||
|
|
||||||
def del_node(self, node):
|
def add_node(self, node):
|
||||||
if node in self.nodes:
|
if node not in self.nodes:
|
||||||
del self.nodes[node]
|
self.nodes[node] = DiscoNode(node)
|
||||||
|
|
||||||
def handle_item_query(self, iq):
|
def del_node(self, node):
|
||||||
if iq['type'] == 'get':
|
if node in self.nodes:
|
||||||
logging.debug("Items requested by %s" % iq['from'])
|
del self.nodes[node]
|
||||||
self.xmpp.event('disco_items_request', iq)
|
|
||||||
elif iq['type'] == 'result':
|
|
||||||
logging.debug("Items result from %s" % iq['from'])
|
|
||||||
self.xmpp.event('disco_items', iq)
|
|
||||||
|
|
||||||
def handle_info_query(self, iq):
|
def handle_item_query(self, iq):
|
||||||
if iq['type'] == 'get':
|
if iq['type'] == 'get':
|
||||||
logging.debug("Info requested by %s" % iq['from'])
|
logging.debug("Items requested by %s" % iq['from'])
|
||||||
self.xmpp.event('disco_info_request', iq)
|
self.xmpp.event('disco_items_request', iq)
|
||||||
elif iq['type'] == 'result':
|
elif iq['type'] == 'result':
|
||||||
logging.debug("Info result from %s" % iq['from'])
|
logging.debug("Items result from %s" % iq['from'])
|
||||||
self.xmpp.event('disco_info', iq)
|
self.xmpp.event('disco_items', iq)
|
||||||
|
|
||||||
def handle_disco_info(self, iq, forwarded=False):
|
def handle_info_query(self, iq):
|
||||||
"""
|
if iq['type'] == 'get':
|
||||||
A default handler for disco#info requests. If another
|
logging.debug("Info requested by %s" % iq['from'])
|
||||||
handler is registered, this one will defer and not run.
|
self.xmpp.event('disco_info_request', iq)
|
||||||
"""
|
elif iq['type'] == 'result':
|
||||||
handlers = self.xmpp.event_handlers['disco_info_request']
|
logging.debug("Info result from %s" % iq['from'])
|
||||||
if not forwarded and len(handlers) > 1:
|
self.xmpp.event('disco_info', iq)
|
||||||
return
|
|
||||||
|
|
||||||
node_name = iq['disco_info']['node']
|
def handle_disco_info(self, iq, forwarded=False):
|
||||||
if not node_name:
|
"""
|
||||||
node_name = 'main'
|
A default handler for disco#info requests. If another
|
||||||
|
handler is registered, this one will defer and not run.
|
||||||
|
"""
|
||||||
|
if not forwarded and self.xmpp.event_handled('disco_info_request'):
|
||||||
|
return
|
||||||
|
|
||||||
logging.debug("Using default handler for disco#info on node '%s'." % node_name)
|
node_name = iq['disco_info']['node']
|
||||||
|
if not node_name:
|
||||||
|
node_name = 'main'
|
||||||
|
|
||||||
if node_name in self.nodes:
|
logging.debug("Using default handler for disco#info on node '%s'." % node_name)
|
||||||
node = self.nodes[node_name]
|
|
||||||
iq.reply().setPayload(node.info.xml).send()
|
|
||||||
else:
|
|
||||||
logging.debug("Node %s requested, but does not exist." % node_name)
|
|
||||||
iq.reply().error().setPayload(iq['disco_info'].xml)
|
|
||||||
iq['error']['code'] = '404'
|
|
||||||
iq['error']['type'] = 'cancel'
|
|
||||||
iq['error']['condition'] = 'item-not-found'
|
|
||||||
iq.send()
|
|
||||||
|
|
||||||
def handle_disco_items(self, iq, forwarded=False):
|
|
||||||
"""
|
|
||||||
A default handler for disco#items requests. If another
|
|
||||||
handler is registered, this one will defer and not run.
|
|
||||||
|
|
||||||
If this handler is called by your own custom handler with
|
if node_name in self.nodes:
|
||||||
forwarded set to True, then it will run as normal.
|
node = self.nodes[node_name]
|
||||||
"""
|
iq.reply().setPayload(node.info.xml).send()
|
||||||
handlers = self.xmpp.event_handlers['disco_items_request']
|
else:
|
||||||
if not forwarded and len(handlers) > 1:
|
logging.debug("Node %s requested, but does not exist." % node_name)
|
||||||
return
|
iq.reply().error().setPayload(iq['disco_info'].xml)
|
||||||
|
iq['error']['code'] = '404'
|
||||||
|
iq['error']['type'] = 'cancel'
|
||||||
|
iq['error']['condition'] = 'item-not-found'
|
||||||
|
iq.send()
|
||||||
|
|
||||||
node_name = iq['disco_items']['node']
|
def handle_disco_items(self, iq, forwarded=False):
|
||||||
if not node_name:
|
"""
|
||||||
node_name = 'main'
|
A default handler for disco#items requests. If another
|
||||||
|
handler is registered, this one will defer and not run.
|
||||||
|
|
||||||
logging.debug("Using default handler for disco#items on node '%s'." % node_name)
|
If this handler is called by your own custom handler with
|
||||||
|
forwarded set to True, then it will run as normal.
|
||||||
|
"""
|
||||||
|
if not forwarded and self.xmpp.event_handled('disco_items_request'):
|
||||||
|
return
|
||||||
|
|
||||||
if node_name in self.nodes:
|
node_name = iq['disco_items']['node']
|
||||||
node = self.nodes[node_name]
|
if not node_name:
|
||||||
iq.reply().setPayload(node.items.xml).send()
|
node_name = 'main'
|
||||||
else:
|
|
||||||
logging.debug("Node %s requested, but does not exist." % node_name)
|
|
||||||
iq.reply().error().setPayload(iq['disco_items'].xml)
|
|
||||||
iq['error']['code'] = '404'
|
|
||||||
iq['error']['type'] = 'cancel'
|
|
||||||
iq['error']['condition'] = 'item-not-found'
|
|
||||||
iq.send()
|
|
||||||
|
|
||||||
# Older interface methods for backwards compatibility
|
logging.debug("Using default handler for disco#items on node '%s'." % node_name)
|
||||||
|
|
||||||
def getInfo(self, jid, node='', dfrom=None):
|
if node_name in self.nodes:
|
||||||
iq = self.xmpp.Iq()
|
node = self.nodes[node_name]
|
||||||
iq['type'] = 'get'
|
iq.reply().setPayload(node.items.xml).send()
|
||||||
iq['to'] = jid
|
else:
|
||||||
iq['from'] = dfrom
|
logging.debug("Node %s requested, but does not exist." % node_name)
|
||||||
iq['disco_info']['node'] = node
|
iq.reply().error().setPayload(iq['disco_items'].xml)
|
||||||
return iq.send()
|
iq['error']['code'] = '404'
|
||||||
|
iq['error']['type'] = 'cancel'
|
||||||
|
iq['error']['condition'] = 'item-not-found'
|
||||||
|
iq.send()
|
||||||
|
|
||||||
def getItems(self, jid, node='', dfrom=None):
|
# Older interface methods for backwards compatibility
|
||||||
iq = self.xmpp.Iq()
|
|
||||||
iq['type'] = 'get'
|
def getInfo(self, jid, node='', dfrom=None):
|
||||||
iq['to'] = jid
|
iq = self.xmpp.Iq()
|
||||||
iq['from'] = dfrom
|
iq['type'] = 'get'
|
||||||
iq['disco_items']['node'] = node
|
iq['to'] = jid
|
||||||
return iq.send()
|
iq['from'] = dfrom
|
||||||
|
iq['disco_info']['node'] = node
|
||||||
def add_feature(self, feature, node='main'):
|
return iq.send()
|
||||||
self.add_node(node)
|
|
||||||
self.nodes[node].addFeature(feature)
|
def getItems(self, jid, node='', dfrom=None):
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
def add_identity(self, category='', itype='', name='', node='main'):
|
iq['type'] = 'get'
|
||||||
self.add_node(node)
|
iq['to'] = jid
|
||||||
self.nodes[node].addIdentity(category=category,
|
iq['from'] = dfrom
|
||||||
id_type=itype,
|
iq['disco_items']['node'] = node
|
||||||
name=name)
|
return iq.send()
|
||||||
|
|
||||||
def add_item(self, jid=None, name='', node='main', subnode=''):
|
def add_feature(self, feature, node='main'):
|
||||||
self.add_node(node)
|
self.add_node(node)
|
||||||
self.add_node(subnode)
|
self.nodes[node].addFeature(feature)
|
||||||
if jid is None:
|
|
||||||
jid = self.xmpp.fulljid
|
def add_identity(self, category='', itype='', name='', node='main'):
|
||||||
self.nodes[node].addItem(jid=jid, name=name, node=subnode)
|
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=''):
|
||||||
|
self.add_node(node)
|
||||||
|
self.add_node(subnode)
|
||||||
|
if jid is None:
|
||||||
|
jid = self.xmpp.fulljid
|
||||||
|
self.nodes[node].addItem(jid=jid, name=name, node=subnode)
|
||||||
|
|
|
@ -379,6 +379,7 @@ class XMLStream(object):
|
||||||
"""
|
"""
|
||||||
if self.ssl_support:
|
if self.ssl_support:
|
||||||
logging.info("Negotiating TLS")
|
logging.info("Negotiating TLS")
|
||||||
|
logging.info("Using SSL version: %s" % str(self.ssl_version))
|
||||||
ssl_socket = ssl.wrap_socket(self.socket,
|
ssl_socket = ssl.wrap_socket(self.socket,
|
||||||
ssl_version=self.ssl_version,
|
ssl_version=self.ssl_version,
|
||||||
do_handshake_on_connect=False)
|
do_handshake_on_connect=False)
|
||||||
|
@ -527,6 +528,17 @@ class XMLStream(object):
|
||||||
self.__event_handlers[name] = filter(filter_pointers,
|
self.__event_handlers[name] = filter(filter_pointers,
|
||||||
self.__event_handlers[name])
|
self.__event_handlers[name])
|
||||||
|
|
||||||
|
def event_handled(self, name):
|
||||||
|
"""
|
||||||
|
Indicates if an event has any associated handlers.
|
||||||
|
|
||||||
|
Returns the number of registered handlers.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
name -- The name of the event to check.
|
||||||
|
"""
|
||||||
|
return len(self.__event_handlers.get(name, []))
|
||||||
|
|
||||||
def event(self, name, data={}, direct=False):
|
def event(self, name, data={}, direct=False):
|
||||||
"""
|
"""
|
||||||
Manually trigger a custom event.
|
Manually trigger a custom event.
|
||||||
|
|
Loading…
Reference in a new issue