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
|
||||
|
||||
class DiscoInfo(ElementBase):
|
||||
namespace = 'http://jabber.org/protocol/disco#info'
|
||||
name = 'query'
|
||||
plugin_attrib = 'disco_info'
|
||||
interfaces = set(('node', 'features', 'identities'))
|
||||
namespace = 'http://jabber.org/protocol/disco#info'
|
||||
name = 'query'
|
||||
plugin_attrib = 'disco_info'
|
||||
interfaces = set(('node', 'features', 'identities'))
|
||||
|
||||
def getFeatures(self):
|
||||
features = []
|
||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||
for feature in featuresXML:
|
||||
features.append(feature.attrib['var'])
|
||||
return features
|
||||
def getFeatures(self):
|
||||
features = []
|
||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||
for feature in featuresXML:
|
||||
features.append(feature.attrib['var'])
|
||||
return features
|
||||
|
||||
def setFeatures(self, features):
|
||||
self.delFeatures()
|
||||
for name in features:
|
||||
self.addFeature(name)
|
||||
def setFeatures(self, features):
|
||||
self.delFeatures()
|
||||
for name in features:
|
||||
self.addFeature(name)
|
||||
|
||||
def delFeatures(self):
|
||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||
for feature in featuresXML:
|
||||
self.xml.remove(feature)
|
||||
def delFeatures(self):
|
||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||
for feature in featuresXML:
|
||||
self.xml.remove(feature)
|
||||
|
||||
def addFeature(self, feature):
|
||||
featureXML = ET.Element('{%s}feature' % self.namespace,
|
||||
{'var': feature})
|
||||
self.xml.append(featureXML)
|
||||
def addFeature(self, feature):
|
||||
featureXML = ET.Element('{%s}feature' % self.namespace,
|
||||
{'var': feature})
|
||||
self.xml.append(featureXML)
|
||||
|
||||
def delFeature(self, feature):
|
||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||
for featureXML in featuresXML:
|
||||
if featureXML.attrib['var'] == feature:
|
||||
self.xml.remove(featureXML)
|
||||
def delFeature(self, feature):
|
||||
featuresXML = self.xml.findall('{%s}feature' % self.namespace)
|
||||
for featureXML in featuresXML:
|
||||
if featureXML.attrib['var'] == feature:
|
||||
self.xml.remove(featureXML)
|
||||
|
||||
def getIdentities(self):
|
||||
ids = []
|
||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||
for idXML in idsXML:
|
||||
idData = (idXML.attrib['category'],
|
||||
idXML.attrib['type'],
|
||||
idXML.attrib.get('name', ''))
|
||||
ids.append(idData)
|
||||
return ids
|
||||
def getIdentities(self):
|
||||
ids = []
|
||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||
for idXML in idsXML:
|
||||
idData = (idXML.attrib['category'],
|
||||
idXML.attrib['type'],
|
||||
idXML.attrib.get('name', ''))
|
||||
ids.append(idData)
|
||||
return ids
|
||||
|
||||
def setIdentities(self, ids):
|
||||
self.delIdentities()
|
||||
for idData in ids:
|
||||
self.addIdentity(*idData)
|
||||
def setIdentities(self, ids):
|
||||
self.delIdentities()
|
||||
for idData in ids:
|
||||
self.addIdentity(*idData)
|
||||
|
||||
def delIdentities(self):
|
||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||
for idXML in idsXML:
|
||||
self.xml.remove(idXML)
|
||||
def delIdentities(self):
|
||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||
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})
|
||||
self.xml.append(idXML)
|
||||
def addIdentity(self, category, id_type, name=''):
|
||||
idXML = ET.Element('{%s}identity' % self.namespace,
|
||||
{'category': category,
|
||||
'type': id_type,
|
||||
'name': name})
|
||||
self.xml.append(idXML)
|
||||
|
||||
def delIdentity(self, category, id_type, name=''):
|
||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||
for idXML in idsXML:
|
||||
idData = (idXML.attrib['category'],
|
||||
idXML.attrib['type'])
|
||||
delId = (category, id_type)
|
||||
if idData == delId:
|
||||
self.xml.remove(idXML)
|
||||
def delIdentity(self, category, id_type, name=''):
|
||||
idsXML = self.xml.findall('{%s}identity' % self.namespace)
|
||||
for idXML in idsXML:
|
||||
idData = (idXML.attrib['category'],
|
||||
idXML.attrib['type'])
|
||||
delId = (category, id_type)
|
||||
if idData == delId:
|
||||
self.xml.remove(idXML)
|
||||
|
||||
|
||||
class DiscoItems(ElementBase):
|
||||
namespace = 'http://jabber.org/protocol/disco#items'
|
||||
name = 'query'
|
||||
plugin_attrib = 'disco_items'
|
||||
interfaces = set(('node', 'items'))
|
||||
namespace = 'http://jabber.org/protocol/disco#items'
|
||||
name = 'query'
|
||||
plugin_attrib = 'disco_items'
|
||||
interfaces = set(('node', 'items'))
|
||||
|
||||
def getItems(self):
|
||||
items = []
|
||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||
for item in itemsXML:
|
||||
itemData = (item.attrib['jid'],
|
||||
item.attrib.get('node'),
|
||||
item.attrib.get('name'))
|
||||
items.append(itemData)
|
||||
return items
|
||||
def getItems(self):
|
||||
items = []
|
||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||
for item in itemsXML:
|
||||
itemData = (item.attrib['jid'],
|
||||
item.attrib.get('node'),
|
||||
item.attrib.get('name'))
|
||||
items.append(itemData)
|
||||
return items
|
||||
|
||||
def setItems(self, items):
|
||||
self.delItems()
|
||||
for item in items:
|
||||
self.addItem(*item)
|
||||
def setItems(self, items):
|
||||
self.delItems()
|
||||
for item in items:
|
||||
self.addItem(*item)
|
||||
|
||||
def delItems(self):
|
||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||
for item in itemsXML:
|
||||
self.xml.remove(item)
|
||||
def delItems(self):
|
||||
itemsXML = self.xml.findall('{%s}item' % self.namespace)
|
||||
for item in itemsXML:
|
||||
self.xml.remove(item)
|
||||
|
||||
def addItem(self, jid, node='', name=''):
|
||||
itemXML = ET.Element('{%s}item' % self.namespace, {'jid': jid})
|
||||
if name:
|
||||
itemXML.attrib['name'] = name
|
||||
if node:
|
||||
itemXML.attrib['node'] = node
|
||||
self.xml.append(itemXML)
|
||||
def addItem(self, jid, node='', name=''):
|
||||
itemXML = ET.Element('{%s}item' % self.namespace, {'jid': jid})
|
||||
if name:
|
||||
itemXML.attrib['name'] = name
|
||||
if node:
|
||||
itemXML.attrib['node'] = node
|
||||
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):
|
||||
"""
|
||||
Collection object for grouping info and item information
|
||||
into nodes.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.info = DiscoInfo()
|
||||
self.items = DiscoItems()
|
||||
"""
|
||||
Collection object for grouping info and item information
|
||||
into nodes.
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.info = DiscoInfo()
|
||||
self.items = DiscoItems()
|
||||
|
||||
self.info['node'] = name
|
||||
self.items['node'] = name
|
||||
self.info['node'] = name
|
||||
self.items['node'] = name
|
||||
|
||||
# This is a bit like poor man's inheritance, but
|
||||
# to simplify adding information to the node we
|
||||
# map node functions to either the info or items
|
||||
# stanza objects.
|
||||
#
|
||||
# We don't want to make DiscoNode inherit from
|
||||
# DiscoInfo and DiscoItems because DiscoNode is
|
||||
# not an actual stanza, and doing so would create
|
||||
# confusion and potential bugs.
|
||||
# This is a bit like poor man's inheritance, but
|
||||
# to simplify adding information to the node we
|
||||
# map node functions to either the info or items
|
||||
# stanza objects.
|
||||
#
|
||||
# We don't want to make DiscoNode inherit from
|
||||
# DiscoInfo and DiscoItems because DiscoNode is
|
||||
# not an actual stanza, and doing so would create
|
||||
# confusion and potential bugs.
|
||||
|
||||
self._map(self.items, 'items', ['get', 'set', 'del'])
|
||||
self._map(self.items, 'item', ['add', 'del'])
|
||||
self._map(self.info, 'identities', ['get', 'set', 'del'])
|
||||
self._map(self.info, 'identity', ['add', 'del'])
|
||||
self._map(self.info, 'features', ['get', 'set', 'del'])
|
||||
self._map(self.info, 'feature', ['add', 'del'])
|
||||
self._map(self.items, 'items', ['get', 'set', 'del'])
|
||||
self._map(self.items, 'item', ['add', 'del'])
|
||||
self._map(self.info, 'identities', ['get', 'set', 'del'])
|
||||
self._map(self.info, 'identity', ['add', 'del'])
|
||||
self._map(self.info, 'features', ['get', 'set', 'del'])
|
||||
self._map(self.info, 'feature', ['add', 'del'])
|
||||
|
||||
def isEmpty(self):
|
||||
"""
|
||||
Test if the node contains any information. Useful for
|
||||
determining if a node can be deleted.
|
||||
"""
|
||||
ids = self.getIdentities()
|
||||
features = self.getFeatures()
|
||||
items = self.getItems()
|
||||
def isEmpty(self):
|
||||
"""
|
||||
Test if the node contains any information. Useful for
|
||||
determining if a node can be deleted.
|
||||
"""
|
||||
ids = self.getIdentities()
|
||||
features = self.getFeatures()
|
||||
items = self.getItems()
|
||||
|
||||
if not ids and not features and not items:
|
||||
return True
|
||||
return False
|
||||
if not ids and not features and not items:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _map(self, obj, interface, access):
|
||||
"""
|
||||
Map functions of the form obj.accessInterface
|
||||
to self.accessInterface for each given access type.
|
||||
"""
|
||||
interface = interface.title()
|
||||
for access_type in access:
|
||||
method = access_type + interface
|
||||
if hasattr(obj, method):
|
||||
setattr(self, method, getattr(obj, method))
|
||||
def _map(self, obj, interface, access):
|
||||
"""
|
||||
Map functions of the form obj.accessInterface
|
||||
to self.accessInterface for each given access type.
|
||||
"""
|
||||
interface = interface.title()
|
||||
for access_type in access:
|
||||
method = access_type + interface
|
||||
if hasattr(obj, method):
|
||||
setattr(self, method, getattr(obj, method))
|
||||
|
||||
|
||||
class xep_0030(base.base_plugin):
|
||||
"""
|
||||
XEP-0030 Service Discovery
|
||||
"""
|
||||
|
||||
def plugin_init(self):
|
||||
self.xep = '0030'
|
||||
self.description = 'Service Discovery'
|
||||
"""
|
||||
XEP-0030 Service Discovery
|
||||
"""
|
||||
|
||||
self.xmpp.registerHandler(
|
||||
Callback('Disco Items',
|
||||
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
||||
DiscoItems.namespace)),
|
||||
self.handle_item_query))
|
||||
def plugin_init(self):
|
||||
self.xep = '0030'
|
||||
self.description = 'Service Discovery'
|
||||
|
||||
self.xmpp.registerHandler(
|
||||
Callback('Disco Info',
|
||||
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
||||
DiscoInfo.namespace)),
|
||||
self.handle_info_query))
|
||||
self.xmpp.registerHandler(
|
||||
Callback('Disco Items',
|
||||
MatchXPath('{%s}iq/{%s}query' % (self.xmpp.default_ns,
|
||||
DiscoItems.namespace)),
|
||||
self.handle_item_query))
|
||||
|
||||
registerStanzaPlugin(Iq, DiscoInfo)
|
||||
registerStanzaPlugin(Iq, DiscoItems)
|
||||
self.xmpp.registerHandler(
|
||||
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)
|
||||
self.xmpp.add_event_handler('disco_info_request', self.handle_disco_info)
|
||||
registerStanzaPlugin(Iq, DiscoInfo)
|
||||
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):
|
||||
if node not in self.nodes:
|
||||
self.nodes[node] = DiscoNode(node)
|
||||
self.nodes = {'main': DiscoNode('main')}
|
||||
|
||||
def del_node(self, node):
|
||||
if node in self.nodes:
|
||||
del self.nodes[node]
|
||||
def add_node(self, node):
|
||||
if node not in self.nodes:
|
||||
self.nodes[node] = DiscoNode(node)
|
||||
|
||||
def handle_item_query(self, iq):
|
||||
if iq['type'] == 'get':
|
||||
logging.debug("Items requested by %s" % iq['from'])
|
||||
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 del_node(self, node):
|
||||
if node in self.nodes:
|
||||
del self.nodes[node]
|
||||
|
||||
def handle_info_query(self, iq):
|
||||
if iq['type'] == 'get':
|
||||
logging.debug("Info requested by %s" % iq['from'])
|
||||
self.xmpp.event('disco_info_request', iq)
|
||||
elif iq['type'] == 'result':
|
||||
logging.debug("Info result from %s" % iq['from'])
|
||||
self.xmpp.event('disco_info', iq)
|
||||
def handle_item_query(self, iq):
|
||||
if iq['type'] == 'get':
|
||||
logging.debug("Items requested by %s" % iq['from'])
|
||||
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_disco_info(self, iq, forwarded=False):
|
||||
"""
|
||||
A default handler for disco#info requests. If another
|
||||
handler is registered, this one will defer and not run.
|
||||
"""
|
||||
handlers = self.xmpp.event_handlers['disco_info_request']
|
||||
if not forwarded and len(handlers) > 1:
|
||||
return
|
||||
def handle_info_query(self, iq):
|
||||
if iq['type'] == 'get':
|
||||
logging.debug("Info requested by %s" % iq['from'])
|
||||
self.xmpp.event('disco_info_request', iq)
|
||||
elif iq['type'] == 'result':
|
||||
logging.debug("Info result from %s" % iq['from'])
|
||||
self.xmpp.event('disco_info', iq)
|
||||
|
||||
node_name = iq['disco_info']['node']
|
||||
if not node_name:
|
||||
node_name = 'main'
|
||||
def handle_disco_info(self, iq, forwarded=False):
|
||||
"""
|
||||
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:
|
||||
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.
|
||||
logging.debug("Using default handler for disco#info 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.
|
||||
"""
|
||||
handlers = self.xmpp.event_handlers['disco_items_request']
|
||||
if not forwarded and len(handlers) > 1:
|
||||
return
|
||||
if node_name in self.nodes:
|
||||
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()
|
||||
|
||||
node_name = iq['disco_items']['node']
|
||||
if not node_name:
|
||||
node_name = 'main'
|
||||
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.
|
||||
|
||||
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 = self.nodes[node_name]
|
||||
iq.reply().setPayload(node.items.xml).send()
|
||||
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()
|
||||
node_name = iq['disco_items']['node']
|
||||
if not node_name:
|
||||
node_name = 'main'
|
||||
|
||||
# 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):
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq['to'] = jid
|
||||
iq['from'] = dfrom
|
||||
iq['disco_info']['node'] = node
|
||||
return iq.send()
|
||||
if node_name in self.nodes:
|
||||
node = self.nodes[node_name]
|
||||
iq.reply().setPayload(node.items.xml).send()
|
||||
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()
|
||||
|
||||
def getItems(self, jid, node='', dfrom=None):
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq['to'] = jid
|
||||
iq['from'] = dfrom
|
||||
iq['disco_items']['node'] = node
|
||||
return iq.send()
|
||||
|
||||
def add_feature(self, feature, node='main'):
|
||||
self.add_node(node)
|
||||
self.nodes[node].addFeature(feature)
|
||||
|
||||
def add_identity(self, category='', itype='', name='', node='main'):
|
||||
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)
|
||||
# Older interface methods for backwards compatibility
|
||||
|
||||
def getInfo(self, jid, node='', dfrom=None):
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq['to'] = jid
|
||||
iq['from'] = dfrom
|
||||
iq['disco_info']['node'] = node
|
||||
return iq.send()
|
||||
|
||||
def getItems(self, jid, node='', dfrom=None):
|
||||
iq = self.xmpp.Iq()
|
||||
iq['type'] = 'get'
|
||||
iq['to'] = jid
|
||||
iq['from'] = dfrom
|
||||
iq['disco_items']['node'] = node
|
||||
return iq.send()
|
||||
|
||||
def add_feature(self, feature, node='main'):
|
||||
self.add_node(node)
|
||||
self.nodes[node].addFeature(feature)
|
||||
|
||||
def add_identity(self, category='', itype='', name='', node='main'):
|
||||
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:
|
||||
logging.info("Negotiating TLS")
|
||||
logging.info("Using SSL version: %s" % str(self.ssl_version))
|
||||
ssl_socket = ssl.wrap_socket(self.socket,
|
||||
ssl_version=self.ssl_version,
|
||||
do_handshake_on_connect=False)
|
||||
|
@ -527,6 +528,17 @@ class XMLStream(object):
|
|||
self.__event_handlers[name] = filter(filter_pointers,
|
||||
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):
|
||||
"""
|
||||
Manually trigger a custom event.
|
||||
|
|
Loading…
Reference in a new issue