mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-24 03:00:15 +00:00
Merge branch 'develop' into roster
This commit is contained in:
commit
756c4c032f
9 changed files with 336 additions and 72 deletions
1
setup.py
1
setup.py
|
@ -52,6 +52,7 @@ packages = [ 'sleekxmpp',
|
||||||
'sleekxmpp/plugins/xep_0059',
|
'sleekxmpp/plugins/xep_0059',
|
||||||
'sleekxmpp/plugins/xep_0085',
|
'sleekxmpp/plugins/xep_0085',
|
||||||
'sleekxmpp/plugins/xep_0092',
|
'sleekxmpp/plugins/xep_0092',
|
||||||
|
'sleekxmpp/plugins/xep_0128',
|
||||||
'sleekxmpp/plugins/xep_0199',
|
'sleekxmpp/plugins/xep_0199',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -60,9 +60,12 @@ class xep_0030(base_plugin):
|
||||||
disco_items_query -- Received a disco#items Iq query request.
|
disco_items_query -- Received a disco#items Iq query request.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
stanza -- A reference to the module containing the stanza classes
|
stanza -- A reference to the module containing the
|
||||||
provided by this plugin.
|
stanza classes provided by this plugin.
|
||||||
static -- Object containing the default set of static node handlers.
|
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.
|
xmpp -- The main SleekXMPP object.
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
@ -110,11 +113,10 @@ class xep_0030(base_plugin):
|
||||||
'add_identity', 'del_identity', 'add_feature',
|
'add_identity', 'del_identity', 'add_feature',
|
||||||
'del_feature', 'add_item', 'del_item',
|
'del_feature', 'add_item', 'del_item',
|
||||||
'del_identities', 'del_features']
|
'del_identities', 'del_features']
|
||||||
|
self.default_handlers = {}
|
||||||
self._handlers = {}
|
self._handlers = {}
|
||||||
for op in self._disco_ops:
|
for op in self._disco_ops:
|
||||||
self._handlers[op] = {'global': getattr(self.static, op),
|
self._add_disco_op(op, getattr(self.static, op))
|
||||||
'jid': {},
|
|
||||||
'node': {}}
|
|
||||||
|
|
||||||
def post_init(self):
|
def post_init(self):
|
||||||
"""Handle cross-plugin dependencies."""
|
"""Handle cross-plugin dependencies."""
|
||||||
|
@ -123,6 +125,12 @@ class xep_0030(base_plugin):
|
||||||
register_stanza_plugin(DiscoItems,
|
register_stanza_plugin(DiscoItems,
|
||||||
self.xmpp['xep_0059'].stanza.Set)
|
self.xmpp['xep_0059'].stanza.Set)
|
||||||
|
|
||||||
|
def _add_disco_op(self, op, default_handler):
|
||||||
|
self.default_handlers[op] = default_handler
|
||||||
|
self._handlers[op] = {'global': default_handler,
|
||||||
|
'jid': {},
|
||||||
|
'node': {}}
|
||||||
|
|
||||||
def set_node_handler(self, htype, jid=None, node=None, handler=None):
|
def set_node_handler(self, htype, jid=None, node=None, handler=None):
|
||||||
"""
|
"""
|
||||||
Add a node handler for the given hierarchy level and
|
Add a node handler for the given hierarchy level and
|
||||||
|
@ -205,26 +213,29 @@ class xep_0030(base_plugin):
|
||||||
"""
|
"""
|
||||||
self.set_node_handler(htype, jid, node, None)
|
self.set_node_handler(htype, jid, node, None)
|
||||||
|
|
||||||
def make_static(self, jid=None, node=None, handlers=None):
|
def restore_defaults(self, jid=None, node=None, handlers=None):
|
||||||
"""
|
"""
|
||||||
Change all of a node's handlers to the default static
|
Change all or some of a node's handlers to the default
|
||||||
handlers. Useful for manually overriding the contents
|
handlers. Useful for manually overriding the contents
|
||||||
of a node that would otherwise be handled by a JID level
|
of a node that would otherwise be handled by a JID level
|
||||||
or global level dynamic handler.
|
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:
|
Arguments:
|
||||||
jid -- The JID owning the node to modify.
|
jid -- The JID owning the node to modify.
|
||||||
node -- The node to change to using static handlers.
|
node -- The node to change to using static handlers.
|
||||||
handlers -- Optional list of handlers to change to the
|
handlers -- Optional list of handlers to change to the
|
||||||
static version. If provided, only these
|
default version. If provided, only these
|
||||||
handlers will be changed. Otherwise, all
|
handlers will be changed. Otherwise, all
|
||||||
handlers will use the static version.
|
handlers will use the default version.
|
||||||
"""
|
"""
|
||||||
if handlers is None:
|
if handlers is None:
|
||||||
handlers = self._disco_ops
|
handlers = self._disco_ops
|
||||||
for op in handlers:
|
for op in handlers:
|
||||||
self.del_node_handler(op, jid, node)
|
self.del_node_handler(op, jid, node)
|
||||||
self.set_node_handler(op, jid, node, getattr(self.static, op))
|
self.set_node_handler(op, jid, node, self.default_handlers[op])
|
||||||
|
|
||||||
def get_info(self, jid=None, node=None, local=False, **kwargs):
|
def get_info(self, jid=None, node=None, local=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
@ -609,3 +620,4 @@ class xep_0030(base_plugin):
|
||||||
# Retain some backwards compatibility
|
# Retain some backwards compatibility
|
||||||
xep_0030.getInfo = xep_0030.get_info
|
xep_0030.getInfo = xep_0030.get_info
|
||||||
xep_0030.getItems = xep_0030.get_items
|
xep_0030.getItems = xep_0030.get_items
|
||||||
|
xep_0030.make_static = xep_0030.restore_defaults
|
||||||
|
|
|
@ -120,7 +120,8 @@ class StaticDisco(object):
|
||||||
"""
|
"""
|
||||||
Replace the stored items data for a JID/node combination.
|
Replace the stored items data for a JID/node combination.
|
||||||
|
|
||||||
The data parameter is not used.
|
The data parameter may provided:
|
||||||
|
items -- A set of items in tuple format.
|
||||||
"""
|
"""
|
||||||
items = data.get('items', set())
|
items = data.get('items', set())
|
||||||
self.add_node(jid, node)
|
self.add_node(jid, node)
|
||||||
|
|
|
@ -1,51 +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 . import base
|
|
||||||
from .. xmlstream.handler.callback import Callback
|
|
||||||
from .. xmlstream.matcher.xpath import MatchXPath
|
|
||||||
from .. xmlstream.stanzabase import registerStanzaPlugin, ElementBase, ET, JID
|
|
||||||
from .. stanza.iq import Iq
|
|
||||||
from . xep_0030 import DiscoInfo, DiscoItems
|
|
||||||
from . xep_0004 import Form
|
|
||||||
|
|
||||||
|
|
||||||
class xep_0128(base.base_plugin):
|
|
||||||
"""
|
|
||||||
XEP-0128 Service Discovery Extensions
|
|
||||||
"""
|
|
||||||
|
|
||||||
def plugin_init(self):
|
|
||||||
self.xep = '0128'
|
|
||||||
self.description = 'Service Discovery Extensions'
|
|
||||||
|
|
||||||
registerStanzaPlugin(DiscoInfo, Form)
|
|
||||||
registerStanzaPlugin(DiscoItems, Form)
|
|
||||||
|
|
||||||
def extend_info(self, node, data=None):
|
|
||||||
if data is None:
|
|
||||||
data = {}
|
|
||||||
node = self.xmpp['xep_0030'].nodes.get(node, None)
|
|
||||||
if node is None:
|
|
||||||
self.xmpp['xep_0030'].add_node(node)
|
|
||||||
|
|
||||||
info = node.info
|
|
||||||
info['form']['type'] = 'result'
|
|
||||||
info['form'].setFields(data, default=None)
|
|
||||||
|
|
||||||
def extend_items(self, node, data=None):
|
|
||||||
if data is None:
|
|
||||||
data = {}
|
|
||||||
node = self.xmpp['xep_0030'].nodes.get(node, None)
|
|
||||||
if node is None:
|
|
||||||
self.xmpp['xep_0030'].add_node(node)
|
|
||||||
|
|
||||||
items = node.items
|
|
||||||
items['form']['type'] = 'result'
|
|
||||||
items['form'].setFields(data, default=None)
|
|
10
sleekxmpp/plugins/xep_0128/__init__.py
Normal file
10
sleekxmpp/plugins/xep_0128/__init__.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
"""
|
||||||
|
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_0128.static import StaticExtendedDisco
|
||||||
|
from sleekxmpp.plugins.xep_0128.extended_disco import xep_0128
|
101
sleekxmpp/plugins/xep_0128/extended_disco.py
Normal file
101
sleekxmpp/plugins/xep_0128/extended_disco.py
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
"""
|
||||||
|
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 sleekxmpp
|
||||||
|
from sleekxmpp import Iq
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.plugins.base import base_plugin
|
||||||
|
from sleekxmpp.plugins.xep_0004 import Form
|
||||||
|
from sleekxmpp.plugins.xep_0030 import DiscoInfo
|
||||||
|
from sleekxmpp.plugins.xep_0128 import StaticExtendedDisco
|
||||||
|
|
||||||
|
|
||||||
|
class xep_0128(base_plugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0128: Service Discovery Extensions
|
||||||
|
|
||||||
|
Allow the use of data forms to add additional identity
|
||||||
|
information to disco#info results.
|
||||||
|
|
||||||
|
Also see <http://www.xmpp.org/extensions/xep-0128.html>.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
disco -- A reference to the XEP-0030 plugin.
|
||||||
|
static -- Object containing the default set of static
|
||||||
|
node handlers.
|
||||||
|
xmpp -- The main SleekXMPP object.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
set_extended_info -- Set extensions to a disco#info result.
|
||||||
|
add_extended_info -- Add an extension to a disco#info result.
|
||||||
|
del_extended_info -- Remove all extensions from a disco#info result.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
"""Start the XEP-0128 plugin."""
|
||||||
|
self.xep = '0128'
|
||||||
|
self.description = 'Service Discovery Extensions'
|
||||||
|
|
||||||
|
self._disco_ops = ['set_extended_info',
|
||||||
|
'add_extended_info',
|
||||||
|
'del_extended_info']
|
||||||
|
|
||||||
|
register_stanza_plugin(DiscoInfo, Form, iterable=True)
|
||||||
|
|
||||||
|
def post_init(self):
|
||||||
|
"""Handle cross-plugin dependencies."""
|
||||||
|
base_plugin.post_init(self)
|
||||||
|
self.disco = self.xmpp['xep_0030']
|
||||||
|
self.static = StaticExtendedDisco(self.disco.static)
|
||||||
|
|
||||||
|
self.disco.set_extended_info = self.set_extended_info
|
||||||
|
self.disco.add_extended_info = self.add_extended_info
|
||||||
|
self.disco.del_extended_info = self.del_extended_info
|
||||||
|
|
||||||
|
for op in self._disco_ops:
|
||||||
|
self.disco._add_disco_op(op, getattr(self.static, op))
|
||||||
|
|
||||||
|
def set_extended_info(self, jid=None, node=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Set additional, extended identity information to a node.
|
||||||
|
|
||||||
|
Replaces any existing extended information.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
jid -- The JID to modify.
|
||||||
|
node -- The node to modify.
|
||||||
|
data -- Either a form, or a list of forms to use
|
||||||
|
as extended information, replacing any
|
||||||
|
existing extensions.
|
||||||
|
"""
|
||||||
|
self.disco._run_node_handler('set_extended_info', jid, node, kwargs)
|
||||||
|
|
||||||
|
def add_extended_info(self, jid=None, node=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Add additional, extended identity information to a node.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
jid -- The JID to modify.
|
||||||
|
node -- The node to modify.
|
||||||
|
data -- Either a form, or a list of forms to add
|
||||||
|
as extended information.
|
||||||
|
"""
|
||||||
|
self.disco._run_node_handler('add_extended_info', jid, node, kwargs)
|
||||||
|
|
||||||
|
def del_extended_info(self, jid=None, node=None, **kwargs):
|
||||||
|
"""
|
||||||
|
Remove all extended identity information to a node.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
jid -- The JID to modify.
|
||||||
|
node -- The node to modify.
|
||||||
|
"""
|
||||||
|
self.disco._run_node_handler('del_extended_info', jid, node, kwargs)
|
72
sleekxmpp/plugins/xep_0128/static.py
Normal file
72
sleekxmpp/plugins/xep_0128/static.py
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
"""
|
||||||
|
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 sleekxmpp
|
||||||
|
from sleekxmpp.plugins.xep_0030 import StaticDisco
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class StaticExtendedDisco(object):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Extend the default StaticDisco implementation to provide
|
||||||
|
support for extended identity information.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, static):
|
||||||
|
"""
|
||||||
|
Augment the default XEP-0030 static handler object.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
static -- The default static XEP-0030 handler object.
|
||||||
|
"""
|
||||||
|
self.static = static
|
||||||
|
|
||||||
|
def set_extended_info(self, jid, node, data):
|
||||||
|
"""
|
||||||
|
Replace the extended identity data for a JID/node combination.
|
||||||
|
|
||||||
|
The data parameter may provide:
|
||||||
|
data -- Either a single data form, or a list of data forms.
|
||||||
|
"""
|
||||||
|
self.del_extended_info(jid, node, data)
|
||||||
|
self.add_extended_info(jid, node, data)
|
||||||
|
|
||||||
|
def add_extended_info(self, jid, node, data):
|
||||||
|
"""
|
||||||
|
Add additional extended identity data for a JID/node combination.
|
||||||
|
|
||||||
|
The data parameter may provide:
|
||||||
|
data -- Either a single data form, or a list of data forms.
|
||||||
|
"""
|
||||||
|
self.static.add_node(jid, node)
|
||||||
|
|
||||||
|
forms = data.get('data', [])
|
||||||
|
if not isinstance(forms, list):
|
||||||
|
forms = [forms]
|
||||||
|
|
||||||
|
for form in forms:
|
||||||
|
self.static.nodes[(jid, node)]['info'].append(form)
|
||||||
|
|
||||||
|
def del_extended_info(self, jid, node, data):
|
||||||
|
"""
|
||||||
|
Replace the extended identity data for a JID/node combination.
|
||||||
|
|
||||||
|
The data parameter is not used.
|
||||||
|
"""
|
||||||
|
if (jid, node) not in self.static.nodes:
|
||||||
|
return
|
||||||
|
|
||||||
|
info = self.static.nodes[(jid, node)]['info']
|
||||||
|
|
||||||
|
for form in info['substanza']:
|
||||||
|
info.xml.remove(form.xml)
|
|
@ -40,6 +40,7 @@ def register_stanza_plugin(stanza, plugin, iterable=False):
|
||||||
stanza.plugin_attrib_map[plugin.plugin_attrib] = plugin
|
stanza.plugin_attrib_map[plugin.plugin_attrib] = plugin
|
||||||
stanza.plugin_tag_map[tag] = plugin
|
stanza.plugin_tag_map[tag] = plugin
|
||||||
if iterable:
|
if iterable:
|
||||||
|
stanza.plugin_iterables = stanza.plugin_iterables.copy()
|
||||||
stanza.plugin_iterables.add(plugin)
|
stanza.plugin_iterables.add(plugin)
|
||||||
|
|
||||||
|
|
||||||
|
@ -206,7 +207,7 @@ class ElementBase(object):
|
||||||
plugin_attrib_map = {}
|
plugin_attrib_map = {}
|
||||||
plugin_iterables = set()
|
plugin_iterables = set()
|
||||||
plugin_tag_map = {}
|
plugin_tag_map = {}
|
||||||
subitem = None
|
subitem = set()
|
||||||
is_extension = False
|
is_extension = False
|
||||||
xml_ns = 'http://www.w3.org/XML/1998/namespace'
|
xml_ns = 'http://www.w3.org/XML/1998/namespace'
|
||||||
|
|
||||||
|
@ -231,6 +232,10 @@ class ElementBase(object):
|
||||||
ElementBase.values = property(ElementBase._get_stanza_values,
|
ElementBase.values = property(ElementBase._get_stanza_values,
|
||||||
ElementBase._set_stanza_values)
|
ElementBase._set_stanza_values)
|
||||||
|
|
||||||
|
if self.subitem is not None:
|
||||||
|
for sub in self.subitem:
|
||||||
|
self.plugin_iterables.add(sub)
|
||||||
|
|
||||||
if self.setup(xml):
|
if self.setup(xml):
|
||||||
# If we generated our own XML, then everything is ready.
|
# If we generated our own XML, then everything is ready.
|
||||||
return
|
return
|
||||||
|
@ -240,9 +245,6 @@ class ElementBase(object):
|
||||||
if child.tag in self.plugin_tag_map:
|
if child.tag in self.plugin_tag_map:
|
||||||
plugin = self.plugin_tag_map[child.tag]
|
plugin = self.plugin_tag_map[child.tag]
|
||||||
self.plugins[plugin.plugin_attrib] = plugin(child, self)
|
self.plugins[plugin.plugin_attrib] = plugin(child, self)
|
||||||
if self.subitem is not None:
|
|
||||||
for sub in self.subitem:
|
|
||||||
self.plugin_iterables.add(sub)
|
|
||||||
for sub in self.plugin_iterables:
|
for sub in self.plugin_iterables:
|
||||||
if child.tag == "{%s}%s" % (sub.namespace, sub.name):
|
if child.tag == "{%s}%s" % (sub.namespace, sub.name):
|
||||||
self.iterables.append(sub(child, self))
|
self.iterables.append(sub(child, self))
|
||||||
|
@ -333,11 +335,20 @@ class ElementBase(object):
|
||||||
Plugin interfaces may accept a nested dictionary that
|
Plugin interfaces may accept a nested dictionary that
|
||||||
will be used recursively.
|
will be used recursively.
|
||||||
"""
|
"""
|
||||||
|
iterable_interfaces = [p.plugin_attrib for \
|
||||||
|
p in self.plugin_iterables]
|
||||||
|
|
||||||
for interface, value in values.items():
|
for interface, value in values.items():
|
||||||
if interface == 'substanzas':
|
if interface == 'substanzas':
|
||||||
|
# Remove existing substanzas
|
||||||
|
for stanza in self.iterables:
|
||||||
|
self.xml.remove(stanza.xml)
|
||||||
|
self.iterables = []
|
||||||
|
|
||||||
|
# Add new substanzas
|
||||||
for subdict in value:
|
for subdict in value:
|
||||||
if '__childtag__' in subdict:
|
if '__childtag__' in subdict:
|
||||||
for subclass in self.subitem:
|
for subclass in self.plugin_iterables:
|
||||||
child_tag = "{%s}%s" % (subclass.namespace,
|
child_tag = "{%s}%s" % (subclass.namespace,
|
||||||
subclass.name)
|
subclass.name)
|
||||||
if subdict['__childtag__'] == child_tag:
|
if subdict['__childtag__'] == child_tag:
|
||||||
|
@ -348,6 +359,7 @@ class ElementBase(object):
|
||||||
elif interface in self.interfaces:
|
elif interface in self.interfaces:
|
||||||
self[interface] = value
|
self[interface] = value
|
||||||
elif interface in self.plugin_attrib_map:
|
elif interface in self.plugin_attrib_map:
|
||||||
|
if interface not in iterable_interfaces:
|
||||||
if interface not in self.plugins:
|
if interface not in self.plugins:
|
||||||
self.init_plugin(interface)
|
self.init_plugin(interface)
|
||||||
self.plugins[interface].values = value
|
self.plugins[interface].values = value
|
||||||
|
|
106
tests/test_stream_xep_0128.py
Normal file
106
tests/test_stream_xep_0128.py
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
|
||||||
|
from sleekxmpp.test import *
|
||||||
|
from sleekxmpp.xmlstream import ElementBase
|
||||||
|
|
||||||
|
|
||||||
|
class TestStreamExtendedDisco(SleekTest):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Test using the XEP-0128 plugin.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
sys.excepthook = sys.__excepthook__
|
||||||
|
self.stream_close()
|
||||||
|
|
||||||
|
def testUsingExtendedInfo(self):
|
||||||
|
self.stream_start(mode='client',
|
||||||
|
jid='tester@localhost',
|
||||||
|
plugins=['xep_0030',
|
||||||
|
'xep_0004',
|
||||||
|
'xep_0128'])
|
||||||
|
|
||||||
|
form = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||||
|
form.addField(var='FORM_TYPE', ftype='hidden', value='testing')
|
||||||
|
|
||||||
|
info_ns = 'http://jabber.org/protocol/disco#info'
|
||||||
|
self.xmpp['xep_0030'].add_identity(node='test',
|
||||||
|
category='client',
|
||||||
|
itype='bot')
|
||||||
|
self.xmpp['xep_0030'].add_feature(node='test', feature=info_ns)
|
||||||
|
self.xmpp['xep_0128'].set_extended_info(node='test', data=form)
|
||||||
|
|
||||||
|
self.recv("""
|
||||||
|
<iq type="get" id="test" to="tester@localhost">
|
||||||
|
<query xmlns="http://jabber.org/protocol/disco#info"
|
||||||
|
node="test" />
|
||||||
|
</iq>
|
||||||
|
""")
|
||||||
|
|
||||||
|
self.send("""
|
||||||
|
<iq type="result" id="test">
|
||||||
|
<query xmlns="http://jabber.org/protocol/disco#info"
|
||||||
|
node="test">
|
||||||
|
<identity category="client" type="bot" />
|
||||||
|
<feature var="http://jabber.org/protocol/disco#info" />
|
||||||
|
<x xmlns="jabber:x:data" type="result">
|
||||||
|
<field var="FORM_TYPE" type="hidden">
|
||||||
|
<value>testing</value>
|
||||||
|
</field>
|
||||||
|
</x>
|
||||||
|
</query>
|
||||||
|
</iq>
|
||||||
|
""")
|
||||||
|
|
||||||
|
def testUsingMultipleExtendedInfo(self):
|
||||||
|
self.stream_start(mode='client',
|
||||||
|
jid='tester@localhost',
|
||||||
|
plugins=['xep_0030',
|
||||||
|
'xep_0004',
|
||||||
|
'xep_0128'])
|
||||||
|
|
||||||
|
form1 = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||||
|
form1.addField(var='FORM_TYPE', ftype='hidden', value='testing')
|
||||||
|
|
||||||
|
form2 = self.xmpp['xep_0004'].makeForm(ftype='result')
|
||||||
|
form2.addField(var='FORM_TYPE', ftype='hidden', value='testing_2')
|
||||||
|
|
||||||
|
info_ns = 'http://jabber.org/protocol/disco#info'
|
||||||
|
self.xmpp['xep_0030'].add_identity(node='test',
|
||||||
|
category='client',
|
||||||
|
itype='bot')
|
||||||
|
self.xmpp['xep_0030'].add_feature(node='test', feature=info_ns)
|
||||||
|
self.xmpp['xep_0128'].set_extended_info(node='test', data=[form1, form2])
|
||||||
|
|
||||||
|
self.recv("""
|
||||||
|
<iq type="get" id="test" to="tester@localhost">
|
||||||
|
<query xmlns="http://jabber.org/protocol/disco#info"
|
||||||
|
node="test" />
|
||||||
|
</iq>
|
||||||
|
""")
|
||||||
|
|
||||||
|
self.send("""
|
||||||
|
<iq type="result" id="test">
|
||||||
|
<query xmlns="http://jabber.org/protocol/disco#info"
|
||||||
|
node="test">
|
||||||
|
<identity category="client" type="bot" />
|
||||||
|
<feature var="http://jabber.org/protocol/disco#info" />
|
||||||
|
<x xmlns="jabber:x:data" type="result">
|
||||||
|
<field var="FORM_TYPE" type="hidden">
|
||||||
|
<value>testing</value>
|
||||||
|
</field>
|
||||||
|
</x>
|
||||||
|
<x xmlns="jabber:x:data" type="result">
|
||||||
|
<field var="FORM_TYPE" type="hidden">
|
||||||
|
<value>testing_2</value>
|
||||||
|
</field>
|
||||||
|
</x>
|
||||||
|
</query>
|
||||||
|
</iq>
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestStreamExtendedDisco)
|
Loading…
Reference in a new issue