summaryrefslogtreecommitdiff
path: root/sleekxmpp/plugins/xep_0030
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2014-07-17 14:19:04 +0200
committerFlorent Le Coz <louiz@louiz.org>2014-07-17 14:19:04 +0200
commit5ab77c745270d7d5c016c1dc7ef2a82533a4b16e (patch)
tree259377cc666f8b9c7954fc4e7b8f7a912bcfe101 /sleekxmpp/plugins/xep_0030
parente5582694c07236e6830c20361840360a1dde37f3 (diff)
downloadslixmpp-5ab77c745270d7d5c016c1dc7ef2a82533a4b16e.tar.gz
slixmpp-5ab77c745270d7d5c016c1dc7ef2a82533a4b16e.tar.bz2
slixmpp-5ab77c745270d7d5c016c1dc7ef2a82533a4b16e.tar.xz
slixmpp-5ab77c745270d7d5c016c1dc7ef2a82533a4b16e.zip
Rename to slixmpp
Diffstat (limited to 'sleekxmpp/plugins/xep_0030')
-rw-r--r--sleekxmpp/plugins/xep_0030/__init__.py23
-rw-r--r--sleekxmpp/plugins/xep_0030/disco.py740
-rw-r--r--sleekxmpp/plugins/xep_0030/stanza/__init__.py10
-rw-r--r--sleekxmpp/plugins/xep_0030/stanza/info.py276
-rw-r--r--sleekxmpp/plugins/xep_0030/stanza/items.py152
-rw-r--r--sleekxmpp/plugins/xep_0030/static.py430
6 files changed, 0 insertions, 1631 deletions
diff --git a/sleekxmpp/plugins/xep_0030/__init__.py b/sleekxmpp/plugins/xep_0030/__init__.py
deleted file mode 100644
index 0d1de65b..00000000
--- a/sleekxmpp/plugins/xep_0030/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-from sleekxmpp.plugins.base import register_plugin
-
-from sleekxmpp.plugins.xep_0030 import stanza
-from sleekxmpp.plugins.xep_0030.stanza import DiscoInfo, DiscoItems
-from sleekxmpp.plugins.xep_0030.static import StaticDisco
-from sleekxmpp.plugins.xep_0030.disco import XEP_0030
-
-
-register_plugin(XEP_0030)
-
-# Retain some backwards compatibility
-xep_0030 = XEP_0030
-XEP_0030.getInfo = XEP_0030.get_info
-XEP_0030.getItems = XEP_0030.get_items
-XEP_0030.make_static = XEP_0030.restore_defaults
diff --git a/sleekxmpp/plugins/xep_0030/disco.py b/sleekxmpp/plugins/xep_0030/disco.py
deleted file mode 100644
index 8a397923..00000000
--- a/sleekxmpp/plugins/xep_0030/disco.py
+++ /dev/null
@@ -1,740 +0,0 @@
-"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-import logging
-
-from sleekxmpp import Iq
-from sleekxmpp.plugins import BasePlugin
-from sleekxmpp.xmlstream.handler import Callback
-from sleekxmpp.xmlstream.matcher import StanzaPath
-from sleekxmpp.xmlstream import register_stanza_plugin, JID
-from sleekxmpp.plugins.xep_0030 import stanza, DiscoInfo, DiscoItems
-from sleekxmpp.plugins.xep_0030 import StaticDisco
-
-
-log = logging.getLogger(__name__)
-
-
-class XEP_0030(BasePlugin):
-
- """
- XEP-0030: Service Discovery
-
- Service discovery in XMPP allows entities to discover information about
- other agents in the network, such as the feature sets supported by a
- client, or signposts to other, related entities.
-
- Also see <http://www.xmpp.org/extensions/xep-0030.html>.
-
- The XEP-0030 plugin works using a hierarchy of dynamic
- node handlers, ranging from global handlers to specific
- JID+node handlers. The default set of handlers operate
- in a static manner, storing disco information in memory.
- However, custom handlers may use any available backend
- storage mechanism desired, such as SQLite or Redis.
-
- Node handler hierarchy:
- JID | Node | Level
- ---------------------
- None | None | Global
- Given | None | All nodes for the JID
- None | Given | Node on self.xmpp.boundjid
- Given | Given | A single node
-
- Stream Handlers:
- Disco Info -- Any Iq stanze that includes a query with the
- namespace http://jabber.org/protocol/disco#info.
- Disco Items -- Any Iq stanze that includes a query with the
- namespace http://jabber.org/protocol/disco#items.
-
- Events:
- disco_info -- Received a disco#info Iq query result.
- disco_items -- Received a disco#items Iq query result.
- disco_info_query -- Received a disco#info Iq query request.
- disco_items_query -- Received a disco#items Iq query request.
-
- Attributes:
- stanza -- A reference to the module containing the
- stanza classes provided by this plugin.
- static -- Object containing the default set of
- static node handlers.
- default_handlers -- A dictionary mapping operations to the default
- global handler (by default, the static handlers).
- xmpp -- The main SleekXMPP object.
-
- Methods:
- set_node_handler -- Assign a handler to a JID/node combination.
- del_node_handler -- Remove a handler from a JID/node combination.
- get_info -- Retrieve disco#info data, locally or remote.
- get_items -- Retrieve disco#items data, locally or remote.
- set_identities --
- set_features --
- set_items --
- del_items --
- del_identity --
- del_feature --
- del_item --
- add_identity --
- add_feature --
- add_item --
- """
-
- name = 'xep_0030'
- description = 'XEP-0030: Service Discovery'
- dependencies = set()
- stanza = stanza
- default_config = {
- 'use_cache': True,
- 'wrap_results': False
- }
-
- def plugin_init(self):
- """
- Start the XEP-0030 plugin.
- """
- self.xmpp.register_handler(
- Callback('Disco Info',
- StanzaPath('iq/disco_info'),
- self._handle_disco_info))
-
- self.xmpp.register_handler(
- Callback('Disco Items',
- StanzaPath('iq/disco_items'),
- self._handle_disco_items))
-
- register_stanza_plugin(Iq, DiscoInfo)
- register_stanza_plugin(Iq, DiscoItems)
-
- self.static = StaticDisco(self.xmpp, self)
-
- self._disco_ops = [
- 'get_info', 'set_info', 'set_identities', 'set_features',
- 'get_items', 'set_items', 'del_items', 'add_identity',
- 'del_identity', 'add_feature', 'del_feature', 'add_item',
- 'del_item', 'del_identities', 'del_features', 'cache_info',
- 'get_cached_info', 'supports', 'has_identity']
-
- for op in self._disco_ops:
- self.api.register(getattr(self.static, op), op, default=True)
-
- def _add_disco_op(self, op, default_handler):
- self.api.register(default_handler, op)
- self.api.register_default(default_handler, op)
-
- def set_node_handler(self, htype, jid=None, node=None, handler=None):
- """
- Add a node handler for the given hierarchy level and
- handler type.
-
- Node handlers are ordered in a hierarchy where the
- most specific handler is executed. Thus, a fallback,
- global handler can be used for the majority of cases
- with a few node specific handler that override the
- global behavior.
-
- Node handler hierarchy:
- JID | Node | Level
- ---------------------
- None | None | Global
- Given | None | All nodes for the JID
- None | Given | Node on self.xmpp.boundjid
- Given | Given | A single node
-
- Handler types:
- get_info
- get_items
- set_identities
- set_features
- set_items
- del_items
- del_identities
- del_identity
- del_feature
- del_features
- del_item
- add_identity
- add_feature
- add_item
-
- Arguments:
- htype -- The operation provided by the handler.
- jid -- The JID the handler applies to. May be narrowed
- further if a node is given.
- node -- The particular node the handler is for. If no JID
- is given, then the self.xmpp.boundjid.full is
- assumed.
- handler -- The handler function to use.
- """
- self.api.register(handler, htype, jid, node)
-
- def del_node_handler(self, htype, jid, node):
- """
- Remove a handler type for a JID and node combination.
-
- The next handler in the hierarchy will be used if one
- exists. If removing the global handler, make sure that
- other handlers exist to process existing nodes.
-
- Node handler hierarchy:
- JID | Node | Level
- ---------------------
- None | None | Global
- Given | None | All nodes for the JID
- None | Given | Node on self.xmpp.boundjid
- Given | Given | A single node
-
- Arguments:
- htype -- The type of handler to remove.
- jid -- The JID from which to remove the handler.
- node -- The node from which to remove the handler.
- """
- self.api.unregister(htype, jid, node)
-
- def restore_defaults(self, jid=None, node=None, handlers=None):
- """
- Change all or some of a node's handlers to the default
- handlers. Useful for manually overriding the contents
- of a node that would otherwise be handled by a JID level
- or global level dynamic handler.
-
- The default is to use the built-in static handlers, but that
- may be changed by modifying self.default_handlers.
-
- Arguments:
- jid -- The JID owning the node to modify.
- node -- The node to change to using static handlers.
- handlers -- Optional list of handlers to change to the
- default version. If provided, only these
- handlers will be changed. Otherwise, all
- handlers will use the default version.
- """
- if handlers is None:
- handlers = self._disco_ops
- for op in handlers:
- self.api.restore_default(op, jid, node)
-
- def supports(self, jid=None, node=None, feature=None, local=False,
- cached=True, ifrom=None):
- """
- Check if a JID supports a given feature.
-
- Return values:
- True -- The feature is supported
- False -- The feature is not listed as supported
- None -- Nothing could be found due to a timeout
-
- Arguments:
- jid -- Request info from this JID.
- node -- The particular node to query.
- feature -- The name of the feature to check.
- local -- If true, then the query is for a JID/node
- combination handled by this Sleek instance and
- no stanzas need to be sent.
- Otherwise, a disco stanza must be sent to the
- remove JID to retrieve the info.
- cached -- If true, then look for the disco info data from
- the local cache system. If no results are found,
- send the query as usual. The self.use_cache
- setting must be set to true for this option to
- be useful. If set to false, then the cache will
- be skipped, even if a result has already been
- cached. Defaults to false.
- ifrom -- Specifiy the sender's JID.
- """
- data = {'feature': feature,
- 'local': local,
- 'cached': cached}
- return self.api['supports'](jid, node, ifrom, data)
-
- def has_identity(self, jid=None, node=None, category=None, itype=None,
- lang=None, local=False, cached=True, ifrom=None):
- """
- Check if a JID provides a given identity.
-
- Return values:
- True -- The identity is provided
- False -- The identity is not listed
- None -- Nothing could be found due to a timeout
-
- Arguments:
- jid -- Request info from this JID.
- node -- The particular node to query.
- category -- The category of the identity to check.
- itype -- The type of the identity to check.
- lang -- The language of the identity to check.
- local -- If true, then the query is for a JID/node
- combination handled by this Sleek instance and
- no stanzas need to be sent.
- Otherwise, a disco stanza must be sent to the
- remove JID to retrieve the info.
- cached -- If true, then look for the disco info data from
- the local cache system. If no results are found,
- send the query as usual. The self.use_cache
- setting must be set to true for this option to
- be useful. If set to false, then the cache will
- be skipped, even if a result has already been
- cached. Defaults to false.
- ifrom -- Specifiy the sender's JID.
- """
- data = {'category': category,
- 'itype': itype,
- 'lang': lang,
- 'local': local,
- 'cached': cached}
- return self.api['has_identity'](jid, node, ifrom, data)
-
- def get_info(self, jid=None, node=None, local=None,
- cached=None, **kwargs):
- """
- Retrieve the disco#info results from a given JID/node combination.
-
- Info may be retrieved from both local resources and remote agents;
- the local parameter indicates if the information should be gathered
- by executing the local node handlers, or if a disco#info stanza
- must be generated and sent.
-
- If requesting items from a local JID/node, then only a DiscoInfo
- stanza will be returned. Otherwise, an Iq stanza will be returned.
-
- Arguments:
- jid -- Request info from this JID.
- node -- The particular node to query.
- local -- If true, then the query is for a JID/node
- combination handled by this Sleek instance and
- no stanzas need to be sent.
- Otherwise, a disco stanza must be sent to the
- remove JID to retrieve the info.
- cached -- If true, then look for the disco info data from
- the local cache system. If no results are found,
- send the query as usual. The self.use_cache
- setting must be set to true for this option to
- be useful. If set to false, then the cache will
- be skipped, even if a result has already been
- cached. Defaults to false.
- ifrom -- Specifiy the sender's JID.
- block -- If true, block and wait for the stanzas' reply.
- timeout -- The time in seconds to block while waiting for
- a reply. If None, then wait indefinitely. The
- timeout value is only used when block=True.
- callback -- Optional callback to execute when a reply is
- received instead of blocking and waiting for
- the reply.
- timeout_callback -- Optional callback to execute when no result
- has been received in timeout seconds.
- """
- if local is None:
- if jid is not None and not isinstance(jid, JID):
- jid = JID(jid)
- if self.xmpp.is_component:
- if jid.domain == self.xmpp.boundjid.domain:
- local = True
- else:
- if str(jid) == str(self.xmpp.boundjid):
- local = True
- jid = jid.full
- elif jid in (None, ''):
- local = True
-
- if local:
- log.debug("Looking up local disco#info data " + \
- "for %s, node %s.", jid, node)
- info = self.api['get_info'](jid, node,
- kwargs.get('ifrom', None),
- kwargs)
- info = self._fix_default_info(info)
- return self._wrap(kwargs.get('ifrom', None), jid, info)
-
- if cached:
- log.debug("Looking up cached disco#info data " + \
- "for %s, node %s.", jid, node)
- info = self.api['get_cached_info'](jid, node,
- kwargs.get('ifrom', None),
- kwargs)
- if info is not None:
- return self._wrap(kwargs.get('ifrom', None), jid, info)
-
- iq = self.xmpp.Iq()
- # Check dfrom parameter for backwards compatibility
- iq['from'] = kwargs.get('ifrom', kwargs.get('dfrom', ''))
- iq['to'] = jid
- iq['type'] = 'get'
- iq['disco_info']['node'] = node if node else ''
- return iq.send(timeout=kwargs.get('timeout', None),
- block=kwargs.get('block', True),
- callback=kwargs.get('callback', None),
- timeout_callback=kwargs.get('timeout_callback', None))
-
- def set_info(self, jid=None, node=None, info=None):
- """
- Set the disco#info data for a JID/node based on an existing
- disco#info stanza.
- """
- if isinstance(info, Iq):
- info = info['disco_info']
- self.api['set_info'](jid, node, None, info)
-
- def get_items(self, jid=None, node=None, local=False, **kwargs):
- """
- Retrieve the disco#items results from a given JID/node combination.
-
- Items may be retrieved from both local resources and remote agents;
- the local parameter indicates if the items should be gathered by
- executing the local node handlers, or if a disco#items stanza must
- be generated and sent.
-
- If requesting items from a local JID/node, then only a DiscoItems
- stanza will be returned. Otherwise, an Iq stanza will be returned.
-
- Arguments:
- jid -- Request info from this JID.
- node -- The particular node to query.
- local -- If true, then the query is for a JID/node
- combination handled by this Sleek instance and
- no stanzas need to be sent.
- Otherwise, a disco stanza must be sent to the
- remove JID to retrieve the items.
- ifrom -- Specifiy the sender's JID.
- block -- If true, block and wait for the stanzas' reply.
- timeout -- The time in seconds to block while waiting for
- a reply. If None, then wait indefinitely.
- callback -- Optional callback to execute when a reply is
- received instead of blocking and waiting for
- the reply.
- iterator -- If True, return a result set iterator using
- the XEP-0059 plugin, if the plugin is loaded.
- Otherwise the parameter is ignored.
- timeout_callback -- Optional callback to execute when no result
- has been received in timeout seconds.
- """
- if local or local is None and jid is None:
- items = self.api['get_items'](jid, node,
- kwargs.get('ifrom', None),
- kwargs)
- return self._wrap(kwargs.get('ifrom', None), jid, items)
-
- iq = self.xmpp.Iq()
- # Check dfrom parameter for backwards compatibility
- iq['from'] = kwargs.get('ifrom', kwargs.get('dfrom', ''))
- iq['to'] = jid
- iq['type'] = 'get'
- iq['disco_items']['node'] = node if node else ''
- if kwargs.get('iterator', False) and self.xmpp['xep_0059']:
- return self.xmpp['xep_0059'].iterate(iq, 'disco_items')
- else:
- return iq.send(timeout=kwargs.get('timeout', None),
- block=kwargs.get('block', True),
- callback=kwargs.get('callback', None),
- timeout_callback=kwargs.get('timeout_callback', None))
-
- def set_items(self, jid=None, node=None, **kwargs):
- """
- Set or replace all items for the specified JID/node combination.
-
- The given items must be in a list or set where each item is a
- tuple of the form: (jid, node, name).
-
- Arguments:
- jid -- The JID to modify.
- node -- Optional node to modify.
- items -- A series of items in tuple format.
- """
- self.api['set_items'](jid, node, None, kwargs)
-
- def del_items(self, jid=None, node=None, **kwargs):
- """
- Remove all items from the given JID/node combination.
-
- Arguments:
- jid -- The JID to modify.
- node -- Optional node to modify.
- """
- self.api['del_items'](jid, node, None, kwargs)
-
- def add_item(self, jid='', name='', node=None, subnode='', ijid=None):
- """
- Add a new item element to the given JID/node combination.
-
- Each item is required to have a JID, but may also specify
- a node value to reference non-addressable entities.
-
- Arguments:
- jid -- The JID for the item.
- name -- Optional name for the item.
- node -- The node to modify.
- subnode -- Optional node for the item.
- ijid -- The JID to modify.
- """
- if not jid:
- jid = self.xmpp.boundjid.full
- kwargs = {'ijid': jid,
- 'name': name,
- 'inode': subnode}
- self.api['add_item'](ijid, node, None, kwargs)
-
- def del_item(self, jid=None, node=None, **kwargs):
- """
- Remove a single item from the given JID/node combination.
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- ijid -- The item's JID.
- inode -- The item's node.
- """
- self.api['del_item'](jid, node, None, kwargs)
-
- def add_identity(self, category='', itype='', name='',
- node=None, jid=None, lang=None):
- """
- Add a new identity to the given JID/node combination.
-
- Each identity must be unique in terms of all four identity
- components: category, type, name, and language.
-
- Multiple, identical category/type pairs are allowed only
- if the xml:lang values are different. Likewise, multiple
- category/type/xml:lang pairs are allowed so long as the
- names are different. A category and type is always required.
-
- Arguments:
- category -- The identity's category.
- itype -- The identity's type.
- name -- Optional name for the identity.
- lang -- Optional two-letter language code.
- node -- The node to modify.
- jid -- The JID to modify.
- """
- kwargs = {'category': category,
- 'itype': itype,
- 'name': name,
- 'lang': lang}
- self.api['add_identity'](jid, node, None, kwargs)
-
- def add_feature(self, feature, node=None, jid=None):
- """
- Add a feature to a JID/node combination.
-
- Arguments:
- feature -- The namespace of the supported feature.
- node -- The node to modify.
- jid -- The JID to modify.
- """
- kwargs = {'feature': feature}
- self.api['add_feature'](jid, node, None, kwargs)
-
- def del_identity(self, jid=None, node=None, **kwargs):
- """
- Remove an identity from the given JID/node combination.
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- category -- The identity's category.
- itype -- The identity's type value.
- name -- Optional, human readable name for the identity.
- lang -- Optional, the identity's xml:lang value.
- """
- self.api['del_identity'](jid, node, None, kwargs)
-
- def del_feature(self, jid=None, node=None, **kwargs):
- """
- Remove a feature from a given JID/node combination.
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- feature -- The feature's namespace.
- """
- self.api['del_feature'](jid, node, None, kwargs)
-
- def set_identities(self, jid=None, node=None, **kwargs):
- """
- Add or replace all identities for the given JID/node combination.
-
- The identities must be in a set where each identity is a tuple
- of the form: (category, type, lang, name)
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- identities -- A set of identities in tuple form.
- lang -- Optional, xml:lang value.
- """
- self.api['set_identities'](jid, node, None, kwargs)
-
- def del_identities(self, jid=None, node=None, **kwargs):
- """
- Remove all identities for a JID/node combination.
-
- If a language is specified, only identities using that
- language will be removed.
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- lang -- Optional. If given, only remove identities
- using this xml:lang value.
- """
- self.api['del_identities'](jid, node, None, kwargs)
-
- def set_features(self, jid=None, node=None, **kwargs):
- """
- Add or replace the set of supported features
- for a JID/node combination.
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- features -- The new set of supported features.
- """
- self.api['set_features'](jid, node, None, kwargs)
-
- def del_features(self, jid=None, node=None, **kwargs):
- """
- Remove all features from a JID/node combination.
-
- Arguments:
- jid -- The JID to modify.
- node -- The node to modify.
- """
- self.api['del_features'](jid, node, None, kwargs)
-
- def _run_node_handler(self, htype, jid, node=None, ifrom=None, data={}):
- """
- Execute the most specific node handler for the given
- JID/node combination.
-
- Arguments:
- htype -- The handler type to execute.
- jid -- The JID requested.
- node -- The node requested.
- data -- Optional, custom data to pass to the handler.
- """
- return self.api[htype](jid, node, ifrom, data)
-
- def _handle_disco_info(self, iq):
- """
- Process an incoming disco#info stanza. If it is a get
- request, find and return the appropriate identities
- and features. If it is an info result, fire the
- disco_info event.
-
- Arguments:
- iq -- The incoming disco#items stanza.
- """
- if iq['type'] == 'get':
- log.debug("Received disco info query from " + \
- "<%s> to <%s>.", iq['from'], iq['to'])
- info = self.api['get_info'](iq['to'],
- iq['disco_info']['node'],
- iq['from'],
- iq)
- if isinstance(info, Iq):
- info['id'] = iq['id']
- info.send()
- else:
- iq.reply()
- if info:
- info = self._fix_default_info(info)
- iq.set_payload(info.xml)
- iq.send()
- elif iq['type'] == 'result':
- log.debug("Received disco info result from " + \
- "<%s> to <%s>.", iq['from'], iq['to'])
- if self.use_cache:
- log.debug("Caching disco info result from " \
- "<%s> to <%s>.", iq['from'], iq['to'])
- if self.xmpp.is_component:
- ito = iq['to'].full
- else:
- ito = None
- self.api['cache_info'](iq['from'],
- iq['disco_info']['node'],
- ito,
- iq)
- self.xmpp.event('disco_info', iq)
-
- def _handle_disco_items(self, iq):
- """
- Process an incoming disco#items stanza. If it is a get
- request, find and return the appropriate items. If it
- is an items result, fire the disco_items event.
-
- Arguments:
- iq -- The incoming disco#items stanza.
- """
- if iq['type'] == 'get':
- log.debug("Received disco items query from " + \
- "<%s> to <%s>.", iq['from'], iq['to'])
- items = self.api['get_items'](iq['to'],
- iq['disco_items']['node'],
- iq['from'],
- iq)
- if isinstance(items, Iq):
- items.send()
- else:
- iq.reply()
- if items:
- iq.set_payload(items.xml)
- iq.send()
- elif iq['type'] == 'result':
- log.debug("Received disco items result from " + \
- "%s to %s.", iq['from'], iq['to'])
- self.xmpp.event('disco_items', iq)
-
- def _fix_default_info(self, info):
- """
- Disco#info results for a JID are required to include at least
- one identity and feature. As a default, if no other identity is
- provided, SleekXMPP will use either the generic component or the
- bot client identity. A the standard disco#info feature will also be
- added if no features are provided.
-
- Arguments:
- info -- The disco#info quest (not the full Iq stanza) to modify.
- """
- result = info
- if isinstance(info, Iq):
- info = info['disco_info']
- if not info['node']:
- if not info['identities']:
- if self.xmpp.is_component:
- log.debug("No identity found for this entity. " + \
- "Using default component identity.")
- info.add_identity('component', 'generic')
- else:
- log.debug("No identity found for this entity. " + \
- "Using default client identity.")
- info.add_identity('client', 'bot')
- if not info['features']:
- log.debug("No features found for this entity. " + \
- "Using default disco#info feature.")
- info.add_feature(info.namespace)
- return result
-
- def _wrap(self, ito, ifrom, payload, force=False):
- """
- Ensure that results are wrapped in an Iq stanza
- if self.wrap_results has been set to True.
-
- Arguments:
- ito -- The JID to use as the 'to' value
- ifrom -- The JID to use as the 'from' value
- payload -- The disco data to wrap
- force -- Force wrapping, regardless of self.wrap_results
- """
- if (force or self.wrap_results) and not isinstance(payload, Iq):
- iq = self.xmpp.Iq()
- # Since we're simulating a result, we have to treat
- # the 'from' and 'to' values opposite the normal way.
- iq['to'] = self.xmpp.boundjid if ito is None else ito
- iq['from'] = self.xmpp.boundjid if ifrom is None else ifrom
- iq['type'] = 'result'
- iq.append(payload)
- return iq
- return payload
diff --git a/sleekxmpp/plugins/xep_0030/stanza/__init__.py b/sleekxmpp/plugins/xep_0030/stanza/__init__.py
deleted file mode 100644
index 0d97cf3d..00000000
--- a/sleekxmpp/plugins/xep_0030/stanza/__init__.py
+++ /dev/null
@@ -1,10 +0,0 @@
-"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-from sleekxmpp.plugins.xep_0030.stanza.info import DiscoInfo
-from sleekxmpp.plugins.xep_0030.stanza.items import DiscoItems
diff --git a/sleekxmpp/plugins/xep_0030/stanza/info.py b/sleekxmpp/plugins/xep_0030/stanza/info.py
deleted file mode 100644
index 25d1d07f..00000000
--- a/sleekxmpp/plugins/xep_0030/stanza/info.py
+++ /dev/null
@@ -1,276 +0,0 @@
-"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-from sleekxmpp.xmlstream import ElementBase, ET
-
-
-class DiscoInfo(ElementBase):
-
- """
- XMPP allows for users and agents to find the identities and features
- supported by other entities in the XMPP network through service discovery,
- or "disco". In particular, the "disco#info" query type for <iq> stanzas is
- used to request the list of identities and features offered by a JID.
-
- An identity is a combination of a category and type, such as the 'client'
- category with a type of 'pc' to indicate the agent is a human operated
- client with a GUI, or a category of 'gateway' with a type of 'aim' to
- identify the agent as a gateway for the legacy AIM protocol. See
- <http://xmpp.org/registrar/disco-categories.html> for a full list of
- accepted category and type combinations.
-
- Features are simply a set of the namespaces that identify the supported
- features. For example, a client that supports service discovery will
- include the feature 'http://jabber.org/protocol/disco#info'.
-
- Since clients and components may operate in several roles at once, identity
- and feature information may be grouped into "nodes". If one were to write
- all of the identities and features used by a client, then node names would
- be like section headings.
-
- Example disco#info stanzas:
- <iq type="get">
- <query xmlns="http://jabber.org/protocol/disco#info" />
- </iq>
-
- <iq type="result">
- <query xmlns="http://jabber.org/protocol/disco#info">
- <identity category="client" type="bot" name="SleekXMPP Bot" />
- <feature var="http://jabber.org/protocol/disco#info" />
- <feature var="jabber:x:data" />
- <feature var="urn:xmpp:ping" />
- </query>
- </iq>
-
- Stanza Interface:
- node -- The name of the node to either
- query or return info from.
- identities -- A set of 4-tuples, where each tuple contains
- the category, type, xml:lang, and name
- of an identity.
- features -- A set of namespaces for features.
-
- Methods:
- add_identity -- Add a new, single identity.
- del_identity -- Remove a single identity.
- get_identities -- Return all identities in tuple form.
- set_identities -- Use multiple identities, each given in tuple form.
- del_identities -- Remove all identities.
- add_feature -- Add a single feature.
- del_feature -- Remove a single feature.
- get_features -- Return a list of all features.
- set_features -- Use a given list of features.
- del_features -- Remove all features.
- """
-
- name = 'query'
- namespace = 'http://jabber.org/protocol/disco#info'
- plugin_attrib = 'disco_info'
- interfaces = set(('node', 'features', 'identities'))
- lang_interfaces = set(('identities',))
-
- # Cache identities and features
- _identities = set()
- _features = set()
-
- def setup(self, xml=None):
- """
- Populate the stanza object using an optional XML object.
-
- Overrides ElementBase.setup
-
- Caches identity and feature information.
-
- Arguments:
- xml -- Use an existing XML object for the stanza's values.
- """
- ElementBase.setup(self, xml)
-
- self._identities = set([id[0:3] for id in self['identities']])
- self._features = self['features']
-
- def add_identity(self, category, itype, name=None, lang=None):
- """
- Add a new identity element. Each identity must be unique
- in terms of all four identity components.
-
- Multiple, identical category/type pairs are allowed only
- if the xml:lang values are different. Likewise, multiple
- category/type/xml:lang pairs are allowed so long as the names
- are different. In any case, a category and type are required.
-
- Arguments:
- category -- The general category to which the agent belongs.
- itype -- A more specific designation with the category.
- name -- Optional human readable name for this identity.
- lang -- Optional standard xml:lang value.
- """
- identity = (category, itype, lang)
- if identity not in self._identities:
- self._identities.add(identity)
- id_xml = ET.Element('{%s}identity' % self.namespace)
- id_xml.attrib['category'] = category
- id_xml.attrib['type'] = itype
- if lang:
- id_xml.attrib['{%s}lang' % self.xml_ns] = lang
- if name:
- id_xml.attrib['name'] = name
- self.xml.append(id_xml)
- return True
- return False
-
- def del_identity(self, category, itype, name=None, lang=None):
- """
- Remove a given identity.
-
- Arguments:
- category -- The general category to which the agent belonged.
- itype -- A more specific designation with the category.
- name -- Optional human readable name for this identity.
- lang -- Optional, standard xml:lang value.
- """
- identity = (category, itype, lang)
- if identity in self._identities:
- self._identities.remove(identity)
- for id_xml in self.findall('{%s}identity' % self.namespace):
- id = (id_xml.attrib['category'],
- id_xml.attrib['type'],
- id_xml.attrib.get('{%s}lang' % self.xml_ns, None))
- if id == identity:
- self.xml.remove(id_xml)
- return True
- return False
-
- def get_identities(self, lang=None, dedupe=True):
- """
- Return a set of all identities in tuple form as so:
- (category, type, lang, name)
-
- If a language was specified, only return identities using
- that language.
-
- Arguments:
- lang -- Optional, standard xml:lang value.
- dedupe -- If True, de-duplicate identities, otherwise
- return a list of all identities.
- """
- if dedupe:
- identities = set()
- else:
- identities = []
- for id_xml in self.findall('{%s}identity' % self.namespace):
- xml_lang = id_xml.attrib.get('{%s}lang' % self.xml_ns, None)
- if lang is None or xml_lang == lang:
- id = (id_xml.attrib['category'],
- id_xml.attrib['type'],
- id_xml.attrib.get('{%s}lang' % self.xml_ns, None),
- id_xml.attrib.get('name', None))
- if dedupe:
- identities.add(id)
- else:
- identities.append(id)
- return identities
-
- def set_identities(self, identities, lang=None):
- """
- Add or replace all identities. The identities must be a in set
- where each identity is a tuple of the form:
- (category, type, lang, name)
-
- If a language is specifified, any identities using that language
- will be removed to be replaced with the given identities.
-
- NOTE: An identity's language will not be changed regardless of
- the value of lang.
-
- Arguments:
- identities -- A set of identities in tuple form.
- lang -- Optional, standard xml:lang value.
- """
- self.del_identities(lang)
- for identity in identities:
- category, itype, lang, name = identity
- self.add_identity(category, itype, name, lang)
-
- def del_identities(self, lang=None):
- """
- Remove all identities. If a language was specified, only
- remove identities using that language.
-
- Arguments:
- lang -- Optional, standard xml:lang value.
- """
- for id_xml in self.findall('{%s}identity' % self.namespace):
- if lang is None:
- self.xml.remove(id_xml)
- elif id_xml.attrib.get('{%s}lang' % self.xml_ns, None) == lang:
- self._identities.remove((
- id_xml.attrib['category'],
- id_xml.attrib['type'],
- id_xml.attrib.get('{%s}lang' % self.xml_ns, None)))
- self.xml.remove(id_xml)
-
- def add_feature(self, feature):
- """
- Add a single, new feature.
-
- Arguments:
- feature -- The namespace of the supported feature.
- """
- if feature not in self._features:
- self._features.add(feature)
- feature_xml = ET.Element('{%s}feature' % self.namespace)
- feature_xml.attrib['var'] = feature
- self.xml.append(feature_xml)
- return True
- return False
-
- def del_feature(self, feature):
- """
- Remove a single feature.
-
- Arguments:
- feature -- The namespace of the removed feature.
- """
- if feature in self._features:
- self._features.remove(feature)
- for feature_xml in self.findall('{%s}feature' % self.namespace):
- if feature_xml.attrib['var'] == feature:
- self.xml.remove(feature_xml)
- return True
- return False
-
- def get_features(self, dedupe=True):
- """Return the set of all supported features."""
- if dedupe:
- features = set()
- else:
- features = []
- for feature_xml in self.findall('{%s}feature' % self.namespace):
- if dedupe:
- features.add(feature_xml.attrib['var'])
- else:
- features.append(feature_xml.attrib['var'])
- return features
-
- def set_features(self, features):
- """
- Add or replace the set of supported features.
-
- Arguments:
- features -- The new set of supported features.
- """
- self.del_features()
- for feature in features:
- self.add_feature(feature)
-
- def del_features(self):
- """Remove all features."""
- self._features = set()
- for feature_xml in self.findall('{%s}feature' % self.namespace):
- self.xml.remove(feature_xml)
diff --git a/sleekxmpp/plugins/xep_0030/stanza/items.py b/sleekxmpp/plugins/xep_0030/stanza/items.py
deleted file mode 100644
index 10458614..00000000
--- a/sleekxmpp/plugins/xep_0030/stanza/items.py
+++ /dev/null
@@ -1,152 +0,0 @@
-"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin
-
-
-class DiscoItems(ElementBase):
-
- """
- Example disco#items stanzas:
- <iq type="get">
- <query xmlns="http://jabber.org/protocol/disco#items" />
- </iq>
-
- <iq type="result">
- <query xmlns="http://jabber.org/protocol/disco#items">
- <item jid="chat.example.com"
- node="xmppdev"
- name="XMPP Dev" />
- <item jid="chat.example.com"
- node="sleekdev"
- name="SleekXMPP Dev" />
- </query>
- </iq>
-
- Stanza Interface:
- node -- The name of the node to either
- query or return info from.
- items -- A list of 3-tuples, where each tuple contains
- the JID, node, and name of an item.
-
- Methods:
- add_item -- Add a single new item.
- del_item -- Remove a single item.
- get_items -- Return all items.
- set_items -- Set or replace all items.
- del_items -- Remove all items.
- """
-
- name = 'query'
- namespace = 'http://jabber.org/protocol/disco#items'
- plugin_attrib = 'disco_items'
- interfaces = set(('node', 'items'))
-
- # Cache items
- _items = set()
-
- def setup(self, xml=None):
- """
- Populate the stanza object using an optional XML object.
-
- Overrides ElementBase.setup
-
- Caches item information.
-
- Arguments:
- xml -- Use an existing XML object for the stanza's values.
- """
- ElementBase.setup(self, xml)
- self._items = set([item[0:2] for item in self['items']])
-
- def add_item(self, jid, node=None, name=None):
- """
- Add a new item element. Each item is required to have a
- JID, but may also specify a node value to reference
- non-addressable entitities.
-
- Arguments:
- jid -- The JID for the item.
- node -- Optional additional information to reference
- non-addressable items.
- name -- Optional human readable name for the item.
- """
- if (jid, node) not in self._items:
- self._items.add((jid, node))
- item = DiscoItem(parent=self)
- item['jid'] = jid
- item['node'] = node
- item['name'] = name
- self.iterables.append(item)
- return True
- return False
-
- def del_item(self, jid, node=None):
- """
- Remove a single item.
-
- Arguments:
- jid -- JID of the item to remove.
- node -- Optional extra identifying information.
- """
- if (jid, node) in self._items:
- for item_xml in self.findall('{%s}item' % self.namespace):
- item = (item_xml.attrib['jid'],
- item_xml.attrib.get('node', None))
- if item == (jid, node):
- self.xml.remove(item_xml)
- return True
- return False
-
- def get_items(self):
- """Return all items."""
- items = set()
- for item in self['substanzas']:
- if isinstance(item, DiscoItem):
- items.add((item['jid'], item['node'], item['name']))
- return items
-
- def set_items(self, items):
- """
- Set or replace all items. The given items must be in a
- list or set where each item is a tuple of the form:
- (jid, node, name)
-
- Arguments:
- items -- A series of items in tuple format.
- """
- self.del_items()
- for item in items:
- jid, node, name = item
- self.add_item(jid, node, name)
-
- def del_items(self):
- """Remove all items."""
- self._items = set()
- items = [i for i in self.iterables if isinstance(i, DiscoItem)]
- for item in items:
- self.xml.remove(item.xml)
- self.iterables.remove(item)
-
-
-class DiscoItem(ElementBase):
- name = 'item'
- namespace = 'http://jabber.org/protocol/disco#items'
- plugin_attrib = name
- interfaces = set(('jid', 'node', 'name'))
-
- def get_node(self):
- """Return the item's node name or ``None``."""
- return self._get_attr('node', None)
-
- def get_name(self):
- """Return the item's human readable name, or ``None``."""
- return self._get_attr('name', None)
-
-
-register_stanza_plugin(DiscoItems, DiscoItem, iterable=True)
diff --git a/sleekxmpp/plugins/xep_0030/static.py b/sleekxmpp/plugins/xep_0030/static.py
deleted file mode 100644
index dd5317d1..00000000
--- a/sleekxmpp/plugins/xep_0030/static.py
+++ /dev/null
@@ -1,430 +0,0 @@
-"""
- SleekXMPP: The Sleek XMPP Library
- Copyright (C) 2010 Nathanael C. Fritz, Lance J.T. Stout
- This file is part of SleekXMPP.
-
- See the file LICENSE for copying permission.
-"""
-
-import logging
-import threading
-
-from sleekxmpp import Iq
-from sleekxmpp.exceptions import XMPPError, IqError, IqTimeout
-from sleekxmpp.xmlstream import JID
-from sleekxmpp.plugins.xep_0030 import DiscoInfo, DiscoItems
-
-
-log = logging.getLogger(__name__)
-
-
-class StaticDisco(object):
-
- """
- While components will likely require fully dynamic handling
- of service discovery information, most clients and simple bots
- only need to manage a few disco nodes that will remain mostly
- static.
-
- StaticDisco provides a set of node handlers that will store
- static sets of disco info and items in memory.
-
- Attributes:
- nodes -- A dictionary mapping (JID, node) tuples to a dict
- containing a disco#info and a disco#items stanza.
- xmpp -- The main SleekXMPP object.
- """
-
- def __init__(self, xmpp, disco):
- """
- Create a static disco interface. Sets of disco#info and
- disco#items are maintained for every given JID and node
- combination. These stanzas are used to store disco
- information in memory without any additional processing.
-
- Arguments:
- xmpp -- The main SleekXMPP object.
- """
- self.nodes = {}
- self.xmpp = xmpp
- self.disco = disco
- self.lock = threading.RLock()
-
- def add_node(self, jid=None, node=None, ifrom=None):
- """
- Create a new set of stanzas for the provided
- JID and node combination.
-
- Arguments:
- jid -- The JID that will own the new stanzas.
- node -- The node that will own the new stanzas.
- """
- with self.lock:
- if jid is None:
- jid = self.xmpp.boundjid.full
- if node is None:
- node = ''
- if ifrom is None:
- ifrom = ''
- if isinstance(ifrom, JID):
- ifrom = ifrom.full
- if (jid, node, ifrom) not in self.nodes:
- self.nodes[(jid, node, ifrom)] = {'info': DiscoInfo(),
- 'items': DiscoItems()}
- self.nodes[(jid, node, ifrom)]['info']['node'] = node
- self.nodes[(jid, node, ifrom)]['items']['node'] = node
-
- def get_node(self, jid=None, node=None, ifrom=None):
- with self.lock:
- if jid is None:
- jid = self.xmpp.boundjid.full
- if node is None:
- node = ''
- if ifrom is None:
- ifrom = ''
- if isinstance(ifrom, JID):
- ifrom = ifrom.full
- if (jid, node, ifrom) not in self.nodes:
- self.add_node(jid, node, ifrom)
- return self.nodes[(jid, node, ifrom)]
-
- def node_exists(self, jid=None, node=None, ifrom=None):
- with self.lock:
- if jid is None:
- jid = self.xmpp.boundjid.full
- if node is None:
- node = ''
- if ifrom is None:
- ifrom = ''
- if isinstance(ifrom, JID):
- ifrom = ifrom.full
- if (jid, node, ifrom) not in self.nodes:
- return False
- return True
-
- # =================================================================
- # Node Handlers
- #
- # Each handler accepts four arguments: jid, node, ifrom, and data.
- # The jid and node parameters together determine the set of info
- # and items stanzas that will be retrieved or added. Additionally,
- # the ifrom value allows for cached results when results vary based
- # on the requester's JID. The data parameter is a dictionary with
- # additional parameters that will be passed to other calls.
- #
- # This implementation does not allow different responses based on
- # the requester's JID, except for cached results. To do that,
- # register a custom node handler.
-
- def supports(self, jid, node, ifrom, data):
- """
- Check if a JID supports a given feature.
-
- The data parameter may provide:
- feature -- The feature to check for support.
- local -- If true, then the query is for a JID/node
- combination handled by this Sleek instance and
- no stanzas need to be sent.
- Otherwise, a disco stanza must be sent to the
- remove JID to retrieve the info.
- cached -- If true, then look for the disco info data from
- the local cache system. If no results are found,
- send the query as usual. The self.use_cache
- setting must be set to true for this option to
- be useful. If set to false, then the cache will
- be skipped, even if a result has already been
- cached. Defaults to false.
- """
- feature = data.get('feature', None)
-
- data = {'local': data.get('local', False),
- 'cached': data.get('cached', True)}
-
- if not feature:
- return False
-
- try:
- info = self.disco.get_info(jid=jid, node=node,
- ifrom=ifrom, **data)
- info = self.disco._wrap(ifrom, jid, info, True)
- features = info['disco_info']['features']
- return feature in features
- except IqError:
- return False
- except IqTimeout:
- return None
-
- def has_identity(self, jid, node, ifrom, data):
- """
- Check if a JID has a given identity.
-
- The data parameter may provide:
- category -- The category of the identity to check.
- itype -- The type of the identity to check.
- lang -- The language of the identity to check.
- local -- If true, then the query is for a JID/node
- combination handled by this Sleek instance and
- no stanzas need to be sent.
- Otherwise, a disco stanza must be sent to the
- remove JID to retrieve the info.
- cached -- If true, then look for the disco info data from
- the local cache system. If no results are found,
- send the query as usual. The self.use_cache
- setting must be set to true for this option to
- be useful. If set to false, then the cache will
- be skipped, even if a result has already been
- cached. Defaults to false.
- """
- identity = (data.get('category', None),
- data.get('itype', None),
- data.get('lang', None))
-
- data = {'local': data.get('local', False),
- 'cached': data.get('cached', True)}
-
- try:
- info = self.disco.get_info(jid=jid, node=node,
- ifrom=ifrom, **data)
- info = self.disco._wrap(ifrom, jid, info, True)
- trunc = lambda i: (i[0], i[1], i[2])
- return identity in map(trunc, info['disco_info']['identities'])
- except IqError:
- return False
- except IqTimeout:
- return None
-
- def get_info(self, jid, node, ifrom, data):
- """
- Return the stored info data for the requested JID/node combination.
-
- The data parameter is not used.
- """
- with self.lock:
- if not self.node_exists(jid, node):
- if not node:
- return DiscoInfo()
- else:
- raise XMPPError(condition='item-not-found')
- else:
- return self.get_node(jid, node)['info']
-
- def set_info(self, jid, node, ifrom, data):
- """
- Set the entire info stanza for a JID/node at once.
-
- The data parameter is a disco#info substanza.
- """
- with self.lock:
- self.add_node(jid, node)
- self.get_node(jid, node)['info'] = data
-
- def del_info(self, jid, node, ifrom, data):
- """
- Reset the info stanza for a given JID/node combination.
-
- The data parameter is not used.
- """
- with self.lock:
- if self.node_exists(jid, node):
- self.get_node(jid, node)['info'] = DiscoInfo()
-
- def get_items(self, jid, node, ifrom, data):
- """
- Return the stored items data for the requested JID/node combination.
-
- The data parameter is not used.
- """
- with self.lock:
- if not self.node_exists(jid, node):
- if not node:
- return DiscoItems()
- else:
- raise XMPPError(condition='item-not-found')
- else:
- return self.get_node(jid, node)['items']
-
- def set_items(self, jid, node, ifrom, data):
- """
- Replace the stored items data for a JID/node combination.
-
- The data parameter may provide:
- items -- A set of items in tuple format.
- """
- with self.lock:
- items = data.get('items', set())
- self.add_node(jid, node)
- self.get_node(jid, node)['items']['items'] = items
-
- def del_items(self, jid, node, ifrom, data):
- """
- Reset the items stanza for a given JID/node combination.
-
- The data parameter is not used.
- """
- with self.lock:
- if self.node_exists(jid, node):
- self.get_node(jid, node)['items'] = DiscoItems()
-
- def add_identity(self, jid, node, ifrom, data):
- """
- Add a new identity to te JID/node combination.
-
- The data parameter may provide:
- category -- The general category to which the agent belongs.
- itype -- A more specific designation with the category.
- name -- Optional human readable name for this identity.
- lang -- Optional standard xml:lang value.
- """
- with self.lock:
- self.add_node(jid, node)
- self.get_node(jid, node)['info'].add_identity(
- data.get('category', ''),
- data.get('itype', ''),
- data.get('name', None),
- data.get('lang', None))
-
- def set_identities(self, jid, node, ifrom, data):
- """
- Add or replace all identities for a JID/node combination.
-
- The data parameter should include:
- identities -- A list of identities in tuple form:
- (category, type, name, lang)
- """
- with self.lock:
- identities = data.get('identities', set())
- self.add_node(jid, node)
- self.get_node(jid, node)['info']['identities'] = identities
-
- def del_identity(self, jid, node, ifrom, data):
- """
- Remove an identity from a JID/node combination.
-
- The data parameter may provide:
- category -- The general category to which the agent belonged.
- itype -- A more specific designation with the category.
- name -- Optional human readable name for this identity.
- lang -- Optional, standard xml:lang value.
- """
- with self.lock:
- if self.node_exists(jid, node):
- self.get_node(jid, node)['info'].del_identity(
- data.get('category', ''),
- data.get('itype', ''),
- data.get('name', None),
- data.get('lang', None))
-
- def del_identities(self, jid, node, ifrom, data):
- """
- Remove all identities from a JID/node combination.
-
- The data parameter is not used.
- """
- with self.lock:
- if self.node_exists(jid, node):
- del self.get_node(jid, node)['info']['identities']
-
- def add_feature(self, jid, node, ifrom, data):
- """
- Add a feature to a JID/node combination.
-
- The data parameter should include:
- feature -- The namespace of the supported feature.
- """
- with self.lock:
- self.add_node(jid, node)
- self.get_node(jid, node)['info'].add_feature(
- data.get('feature', ''))
-
- def set_features(self, jid, node, ifrom, data):
- """
- Add or replace all features for a JID/node combination.
-
- The data parameter should include:
- features -- The new set of supported features.
- """
- with self.lock:
- features = data.get('features', set())
- self.add_node(jid, node)
- self.get_node(jid, node)['info']['features'] = features
-
- def del_feature(self, jid, node, ifrom, data):
- """
- Remove a feature from a JID/node combination.
-
- The data parameter should include:
- feature -- The namespace of the removed feature.
- """
- with self.lock:
- if self.node_exists(jid, node):
- self.get_node(jid, node)['info'].del_feature(
- data.get('feature', ''))
-
- def del_features(self, jid, node, ifrom, data):
- """
- Remove all features from a JID/node combination.
-
- The data parameter is not used.
- """
- with self.lock:
- if not self.node_exists(jid, node):
- return
- del self.get_node(jid, node)['info']['features']
-
- def add_item(self, jid, node, ifrom, data):
- """
- Add an item to a JID/node combination.
-
- The data parameter may include:
- ijid -- The JID for the item.
- inode -- Optional additional information to reference
- non-addressable items.
- name -- Optional human readable name for the item.
- """
- with self.lock:
- self.add_node(jid, node)
- self.get_node(jid, node)['items'].add_item(
- data.get('ijid', ''),
- node=data.get('inode', ''),
- name=data.get('name', ''))
-
- def del_item(self, jid, node, ifrom, data):
- """
- Remove an item from a JID/node combination.
-
- The data parameter may include:
- ijid -- JID of the item to remove.
- inode -- Optional extra identifying information.
- """
- with self.lock:
- if self.node_exists(jid, node):
- self.get_node(jid, node)['items'].del_item(
- data.get('ijid', ''),
- node=data.get('inode', None))
-
- def cache_info(self, jid, node, ifrom, data):
- """
- Cache disco information for an external JID.
-
- The data parameter is the Iq result stanza
- containing the disco info to cache, or
- the disco#info substanza itself.
- """
- with self.lock:
- if isinstance(data, Iq):
- data = data['disco_info']
-
- self.add_node(jid, node, ifrom)
- self.get_node(jid, node, ifrom)['info'] = data
-
- def get_cached_info(self, jid, node, ifrom, data):
- """
- Retrieve cached disco info data.
-
- The data parameter is not used.
- """
- with self.lock:
- if not self.node_exists(jid, node, ifrom):
- return None
- else:
- return self.get_node(jid, node, ifrom)['info']