Compare commits
	
		
			126 Commits
		
	
	
		
			xep-446-co
			...
			sleek-merg
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4512248901 | ||
| 
						 | 
					4305eddb4f | ||
| 
						 | 
					c2dc44cfd1 | ||
| 
						 | 
					5fc14de32e | ||
| 
						 | 
					d245558fd5 | ||
| 
						 | 
					9d45370e8a | ||
| 
						 | 
					cc1cc61d36 | ||
| 
						 | 
					c6740a4908 | ||
| 
						 | 
					55114bcffe | ||
| 
						 | 
					4fa5dedc47 | ||
| 
						 | 
					5525ef2285 | ||
| 
						 | 
					a7ac969215 | ||
| 
						 | 
					329cb5a9f8 | ||
| 
						 | 
					d9b47b33f5 | ||
| 
						 | 
					3582ac9941 | ||
| 
						 | 
					2a127a57a7 | ||
| 
						 | 
					7059400020 | ||
| 
						 | 
					0b14ef82d4 | ||
| 
						 | 
					83953af53d | ||
| 
						 | 
					110cf25c6d | ||
| 
						 | 
					f2bf6072ec | ||
| 
						 | 
					5f9abe2e0e | ||
| 
						 | 
					ea65b672e7 | ||
| 
						 | 
					93c705fb31 | ||
| 
						 | 
					0724f623bb | ||
| 
						 | 
					ffb2b6bc04 | ||
| 
						 | 
					4a24f58be2 | ||
| 
						 | 
					da14ce16ec | ||
| 
						 | 
					18e5abb9dd | ||
| 
						 | 
					1a75b76916 | ||
| 
						 | 
					53b56899a0 | ||
| 
						 | 
					a366482551 | ||
| 
						 | 
					abcec1e2d3 | ||
| 
						 | 
					eeab646bfa | ||
| 
						 | 
					2c69144189 | ||
| 
						 | 
					f54ebec654 | ||
| 
						 | 
					2042e1a4d5 | ||
| 
						 | 
					be14f0cc52 | ||
| 
						 | 
					edd9199be8 | ||
| 
						 | 
					bb094cc649 | ||
| 
						 | 
					dbaa6ed952 | ||
| 
						 | 
					8c94d894ab | ||
| 
						 | 
					ffc7eac4dc | ||
| 
						 | 
					555fd6d926 | ||
| 
						 | 
					c024ac8f0b | ||
| 
						 | 
					f00177c0cf | ||
| 
						 | 
					224d7ae133 | ||
| 
						 | 
					9b25a7cf77 | ||
| 
						 | 
					7a908ac07b | ||
| 
						 | 
					92901637ec | ||
| 
						 | 
					3590b663ed | ||
| 
						 | 
					a33bde9cc3 | ||
| 
						 | 
					ac50fdccfc | ||
| 
						 | 
					a0c6bf15e9 | ||
| 
						 | 
					a8ac115310 | ||
| 
						 | 
					1345b7c1d0 | ||
| 
						 | 
					d60a652259 | ||
| 
						 | 
					61a7cecb31 | ||
| 
						 | 
					192b7e0349 | ||
| 
						 | 
					80b60fc048 | ||
| 
						 | 
					842157a6cc | ||
| 
						 | 
					a63cc01482 | ||
| 
						 | 
					1bbb6f3ff9 | ||
| 
						 | 
					93894247a4 | ||
| 
						 | 
					16bb5e2537 | ||
| 
						 | 
					d19a6e05b2 | ||
| 
						 | 
					86e85f9835 | ||
| 
						 | 
					cc145d20b0 | ||
| 
						 | 
					881d9040c4 | ||
| 
						 | 
					1e77ea0944 | ||
| 
						 | 
					140f0885b2 | ||
| 
						 | 
					83f71a6610 | ||
| 
						 | 
					271343a32d | ||
| 
						 | 
					48857b0030 | ||
| 
						 | 
					1fe7f5f4e6 | ||
| 
						 | 
					81b7b2c190 | ||
| 
						 | 
					460de7d301 | ||
| 
						 | 
					69022c6db7 | ||
| 
						 | 
					9044807121 | ||
| 
						 | 
					24264d3a07 | ||
| 
						 | 
					8bc70264ef | ||
| 
						 | 
					c16b862200 | ||
| 
						 | 
					a96f608469 | ||
| 
						 | 
					e1f25604ec | ||
| 
						 | 
					0fe057b5c3 | ||
| 
						 | 
					be76dda21d | ||
| 
						 | 
					ecd124dd06 | ||
| 
						 | 
					4a8951c4ee | ||
| 
						 | 
					8afba7de85 | ||
| 
						 | 
					1ce42d3a2f | ||
| 
						 | 
					2f4d811db4 | ||
| 
						 | 
					61127f521d | ||
| 
						 | 
					063e73c0d2 | ||
| 
						 | 
					d261318e1a | ||
| 
						 | 
					d33cc00fe9 | ||
| 
						 | 
					27582f6fd2 | ||
| 
						 | 
					e328ff4833 | ||
| 
						 | 
					403462fdb8 | ||
| 
						 | 
					f22d8e67b4 | ||
| 
						 | 
					35f33f1614 | ||
| 
						 | 
					c9f8ddff65 | ||
| 
						 | 
					f5ae98aaf1 | ||
| 
						 | 
					073e85381a | ||
| 
						 | 
					afc939708f | ||
| 
						 | 
					aabec8b993 | ||
| 
						 | 
					e5e2fbb16b | ||
| 
						 | 
					3dd379cdf1 | ||
| 
						 | 
					a20582aba4 | ||
| 
						 | 
					09cdbf1b76 | ||
| 
						 | 
					ca306e7cec | ||
| 
						 | 
					1bf34f7fe6 | ||
| 
						 | 
					4144d60017 | ||
| 
						 | 
					7265682a4d | ||
| 
						 | 
					08c62a6bf1 | ||
| 
						 | 
					d61f1cd035 | ||
| 
						 | 
					1063feb33b | ||
| 
						 | 
					79f3c1ac8f | ||
| 
						 | 
					a5c03b763a | ||
| 
						 | 
					3670d82f1c | ||
| 
						 | 
					e94a73553d | ||
| 
						 | 
					577fd71472 | ||
| 
						 | 
					ef1c4368d0 | ||
| 
						 | 
					48def71d0c | ||
| 
						 | 
					c8c20fff71 | ||
| 
						 | 
					75a18b5ffe | ||
| 
						 | 
					ea3d39b50e | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -12,3 +12,4 @@ slixmpp.egg-info/
 | 
			
		||||
*~
 | 
			
		||||
.baboon/
 | 
			
		||||
.DS_STORE
 | 
			
		||||
.idea/
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.travis.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
language: python
 | 
			
		||||
python:
 | 
			
		||||
  - "2.6"
 | 
			
		||||
  - "2.7"
 | 
			
		||||
  - "3.2"
 | 
			
		||||
  - "3.3"
 | 
			
		||||
  - "3.4"
 | 
			
		||||
install:
 | 
			
		||||
  - "pip install ."
 | 
			
		||||
script: testall.py
 | 
			
		||||
@@ -8,7 +8,6 @@ Slixmpp's goals is to only rewrite the core of the library (the low level
 | 
			
		||||
socket handling, the timers, the events dispatching) in order to remove all
 | 
			
		||||
threads.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Documentation and Testing
 | 
			
		||||
-------------------------
 | 
			
		||||
Documentation can be found both inline in the code, and as a Sphinx project in ``/docs``.
 | 
			
		||||
 
 | 
			
		||||
@@ -161,7 +161,7 @@ item itself, and the JID and node that will own the item.
 | 
			
		||||
    In this case, the owning JID and node are provided with the
 | 
			
		||||
    parameters ``ijid`` and ``node``.
 | 
			
		||||
 | 
			
		||||
Peforming Disco Queries
 | 
			
		||||
Performing Disco Queries
 | 
			
		||||
-----------------------
 | 
			
		||||
The methods ``get_info()`` and ``get_items()`` are used to query remote JIDs
 | 
			
		||||
and their nodes for disco information. Since these methods are wrappers for
 | 
			
		||||
@@ -172,11 +172,10 @@ the `XEP-0059 <http://xmpp.org/extensions/xep-0059.html>`_ plug-in.
 | 
			
		||||
 | 
			
		||||
.. code-block:: python
 | 
			
		||||
 | 
			
		||||
    info = self['xep_0030'].get_info(jid='foo@example.com',
 | 
			
		||||
                                     node='bar',
 | 
			
		||||
                                     ifrom='baz@mycomponent.example.com',
 | 
			
		||||
                                     block=True,
 | 
			
		||||
                                     timeout=30)
 | 
			
		||||
    info = yield from self['xep_0030'].get_info(jid='foo@example.com',
 | 
			
		||||
                                                node='bar',
 | 
			
		||||
                                                ifrom='baz@mycomponent.example.com',
 | 
			
		||||
                                                timeout=30)
 | 
			
		||||
 | 
			
		||||
    items = self['xep_0030'].get_info(jid='foo@example.com',
 | 
			
		||||
                                      node='bar',
 | 
			
		||||
 
 | 
			
		||||
@@ -160,9 +160,9 @@ if __name__ == '__main__':
 | 
			
		||||
 | 
			
		||||
        myDevice = TheDevice(args.nodeid);
 | 
			
		||||
        # myDevice._add_field(name="Relay", typename="numeric", unit="Bool");
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="C");
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="C")
 | 
			
		||||
        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
 | 
			
		||||
 | 
			
		||||
        xmpp['xep_0323'].register_node(nodeId=args.nodeid, device=myDevice, commTimeout=10);
 | 
			
		||||
        xmpp.beClientOrServer(server=True)
 | 
			
		||||
 
 | 
			
		||||
@@ -76,10 +76,6 @@ class Disco(slixmpp.ClientXMPP):
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            if self.get in self.info_types:
 | 
			
		||||
                # By using block=True, the result stanza will be
 | 
			
		||||
                # returned. Execution will block until the reply is
 | 
			
		||||
                # received. Non-blocking options would be to listen
 | 
			
		||||
                # for the disco_info event, or passing a handler
 | 
			
		||||
                # function using the callback parameter.
 | 
			
		||||
                info = yield from self['xep_0030'].get_info(jid=self.target_jid,
 | 
			
		||||
                                                            node=self.target_node)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										97
									
								
								examples/http_over_xmpp.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								examples/http_over_xmpp.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp import ClientXMPP
 | 
			
		||||
 | 
			
		||||
from optparse import OptionParser
 | 
			
		||||
import logging
 | 
			
		||||
import getpass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HTTPOverXMPPClient(ClientXMPP):
 | 
			
		||||
    def __init__(self, jid, password):
 | 
			
		||||
        ClientXMPP.__init__(self, jid, password)
 | 
			
		||||
        self.register_plugin('xep_0332')    # HTTP over XMPP Transport
 | 
			
		||||
        self.add_event_handler(
 | 
			
		||||
            'session_start', self.session_start, threaded=True
 | 
			
		||||
        )
 | 
			
		||||
        self.add_event_handler('http_request', self.http_request_received)
 | 
			
		||||
        self.add_event_handler('http_response', self.http_response_received)
 | 
			
		||||
 | 
			
		||||
    def http_request_received(self, iq):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def http_response_received(self, iq):
 | 
			
		||||
        print('HTTP Response Received : %s' % iq)
 | 
			
		||||
        print('From    : %s' %  iq['from'])
 | 
			
		||||
        print('To      : %s' % iq['to'])
 | 
			
		||||
        print('Type    : %s' % iq['type'])
 | 
			
		||||
        print('Headers : %s' % iq['resp']['headers'])
 | 
			
		||||
        print('Code    : %s' % iq['resp']['code'])
 | 
			
		||||
        print('Message : %s' % iq['resp']['message'])
 | 
			
		||||
        print('Data    : %s' % iq['resp']['data'])
 | 
			
		||||
 | 
			
		||||
    def session_start(self, event):
 | 
			
		||||
        # TODO: Fill in the blanks
 | 
			
		||||
        self['xep_0332'].send_request(
 | 
			
		||||
            to='?', method='?', resource='?', headers={}
 | 
			
		||||
        )
 | 
			
		||||
        self.disconnect()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
 | 
			
		||||
    #
 | 
			
		||||
    # NOTE: To run this example, fill up the blanks in session_start() and
 | 
			
		||||
    #       use the following command.
 | 
			
		||||
    #
 | 
			
		||||
    # ./http_over_xmpp.py -J <jid> -P <pwd> -i <ip> -p <port> [-v]
 | 
			
		||||
    #
 | 
			
		||||
 | 
			
		||||
    parser = OptionParser()
 | 
			
		||||
 | 
			
		||||
    # Output verbosity options.
 | 
			
		||||
    parser.add_option(
 | 
			
		||||
        '-v', '--verbose', help='set logging to DEBUG', action='store_const',
 | 
			
		||||
        dest='loglevel', const=logging.DEBUG, default=logging.ERROR
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # JID and password options.
 | 
			
		||||
    parser.add_option('-J', '--jid', dest='jid', help='JID')
 | 
			
		||||
    parser.add_option('-P', '--password', dest='password', help='Password')
 | 
			
		||||
 | 
			
		||||
    # XMPP server ip and port options.
 | 
			
		||||
    parser.add_option(
 | 
			
		||||
        '-i', '--ipaddr', dest='ipaddr',
 | 
			
		||||
        help='IP Address of the XMPP server', default=None
 | 
			
		||||
    )
 | 
			
		||||
    parser.add_option(
 | 
			
		||||
        '-p', '--port', dest='port',
 | 
			
		||||
        help='Port of the XMPP server', default=None
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    opts, args = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
    # Setup logging.
 | 
			
		||||
    logging.basicConfig(level=opts.loglevel,
 | 
			
		||||
                        format='%(levelname)-8s %(message)s')
 | 
			
		||||
 | 
			
		||||
    if opts.jid is None:
 | 
			
		||||
        opts.jid = input('Username: ')
 | 
			
		||||
    if opts.password is None:
 | 
			
		||||
        opts.password = getpass.getpass('Password: ')
 | 
			
		||||
 | 
			
		||||
    xmpp = HTTPOverXMPPClient(opts.jid, opts.password)
 | 
			
		||||
    xmpp.connect()
 | 
			
		||||
    xmpp.process()
 | 
			
		||||
 | 
			
		||||
@@ -100,7 +100,7 @@ def on_session2(event):
 | 
			
		||||
        new_xmpp.update_roster(jid,
 | 
			
		||||
                name = item['name'],
 | 
			
		||||
                groups = item['groups'])
 | 
			
		||||
        new_xmpp.disconnect()
 | 
			
		||||
    new_xmpp.disconnect()
 | 
			
		||||
new_xmpp.add_event_handler('session_start', on_session2)
 | 
			
		||||
 | 
			
		||||
new_xmpp.connect()
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ class RosterBrowser(slixmpp.ClientXMPP):
 | 
			
		||||
            self.get_roster(callback=callback)
 | 
			
		||||
            yield from future
 | 
			
		||||
        except IqError as err:
 | 
			
		||||
            print('Error: %' % err.iq['error']['condition'])
 | 
			
		||||
            print('Error: %s' % err.iq['error']['condition'])
 | 
			
		||||
        except IqTimeout:
 | 
			
		||||
            print('Error: Request timed out')
 | 
			
		||||
        self.send_presence()
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@ from slixmpp.exceptions import IqError, IqTimeout
 | 
			
		||||
from slixmpp.stanza import Message, Presence, Iq, StreamError
 | 
			
		||||
from slixmpp.stanza.roster import Roster
 | 
			
		||||
from slixmpp.stanza.nick import Nick
 | 
			
		||||
from slixmpp.stanza.htmlim import HTMLIM
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import XMLStream, JID
 | 
			
		||||
from slixmpp.xmlstream import ET, register_stanza_plugin
 | 
			
		||||
@@ -46,8 +45,8 @@ class BaseXMPP(XMLStream):
 | 
			
		||||
                       is used during initialization.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, jid='', default_ns='jabber:client'):
 | 
			
		||||
        XMLStream.__init__(self)
 | 
			
		||||
    def __init__(self, jid='', default_ns='jabber:client', **kwargs):
 | 
			
		||||
        XMLStream.__init__(self, **kwargs)
 | 
			
		||||
 | 
			
		||||
        self.default_ns = default_ns
 | 
			
		||||
        self.stream_ns = 'http://etherx.jabber.org/streams'
 | 
			
		||||
@@ -221,7 +220,7 @@ class BaseXMPP(XMLStream):
 | 
			
		||||
                    self.plugin[name].post_init()
 | 
			
		||||
                self.plugin[name].post_inited = True
 | 
			
		||||
 | 
			
		||||
    def register_plugin(self, plugin, pconfig={}, module=None):
 | 
			
		||||
    def register_plugin(self, plugin, pconfig=None, module=None):
 | 
			
		||||
        """Register and configure  a plugin for use in this stream.
 | 
			
		||||
 | 
			
		||||
        :param plugin: The name of the plugin class. Plugin names must
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,6 @@ class ClientXMPP(BaseXMPP):
 | 
			
		||||
 | 
			
		||||
    :param jid: The JID of the XMPP user account.
 | 
			
		||||
    :param password: The password for the XMPP user account.
 | 
			
		||||
    :param ssl: **Deprecated.**
 | 
			
		||||
    :param plugin_config: A dictionary of plugin configurations.
 | 
			
		||||
    :param plugin_whitelist: A list of approved plugins that
 | 
			
		||||
                    will be loaded when calling
 | 
			
		||||
@@ -58,9 +57,15 @@ class ClientXMPP(BaseXMPP):
 | 
			
		||||
    :param escape_quotes: **Deprecated.**
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, jid, password, plugin_config={}, plugin_whitelist=[],
 | 
			
		||||
                 escape_quotes=True, sasl_mech=None, lang='en'):
 | 
			
		||||
        BaseXMPP.__init__(self, jid, 'jabber:client')
 | 
			
		||||
    def __init__(self, jid, password, plugin_config=None,
 | 
			
		||||
                 plugin_whitelist=None, escape_quotes=True, sasl_mech=None,
 | 
			
		||||
                 lang='en', **kwargs):
 | 
			
		||||
        if not plugin_whitelist:
 | 
			
		||||
            plugin_whitelist = []
 | 
			
		||||
        if not plugin_config:
 | 
			
		||||
            plugin_config = {}
 | 
			
		||||
 | 
			
		||||
        BaseXMPP.__init__(self, jid, 'jabber:client', **kwargs)
 | 
			
		||||
 | 
			
		||||
        self.escape_quotes = escape_quotes
 | 
			
		||||
        self.plugin_config = plugin_config
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,13 @@ class ComponentXMPP(BaseXMPP):
 | 
			
		||||
                      Defaults to ``False``.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, jid, secret, host=None, port=None,
 | 
			
		||||
                 plugin_config={}, plugin_whitelist=[], use_jc_ns=False):
 | 
			
		||||
    def __init__(self, jid, secret, host=None, port=None, plugin_config=None, plugin_whitelist=None, use_jc_ns=False):
 | 
			
		||||
 | 
			
		||||
        if not plugin_whitelist:
 | 
			
		||||
            plugin_whitelist = []
 | 
			
		||||
        if not plugin_config:
 | 
			
		||||
            plugin_config = {}
 | 
			
		||||
 | 
			
		||||
        if use_jc_ns:
 | 
			
		||||
            default_ns = 'jabber:client'
 | 
			
		||||
        else:
 | 
			
		||||
 
 | 
			
		||||
@@ -190,14 +190,14 @@ class FeatureMechanisms(BasePlugin):
 | 
			
		||||
        except sasl.SASLCancelled:
 | 
			
		||||
            self.attempted_mechs.add(self.mech.name)
 | 
			
		||||
            self._send_auth()
 | 
			
		||||
        except sasl.SASLFailed:
 | 
			
		||||
            self.attempted_mechs.add(self.mech.name)
 | 
			
		||||
            self._send_auth()
 | 
			
		||||
        except sasl.SASLMutualAuthFailed:
 | 
			
		||||
            log.error("Mutual authentication failed! " + \
 | 
			
		||||
                      "A security breach is possible.")
 | 
			
		||||
            self.attempted_mechs.add(self.mech.name)
 | 
			
		||||
            self.xmpp.disconnect()
 | 
			
		||||
        except sasl.SASLFailed:
 | 
			
		||||
            self.attempted_mechs.add(self.mech.name)
 | 
			
		||||
            self._send_auth()
 | 
			
		||||
        else:
 | 
			
		||||
            resp.send()
 | 
			
		||||
 | 
			
		||||
@@ -210,13 +210,13 @@ class FeatureMechanisms(BasePlugin):
 | 
			
		||||
            resp['value'] = self.mech.process(stanza['value'])
 | 
			
		||||
        except sasl.SASLCancelled:
 | 
			
		||||
            self.stanza.Abort(self.xmpp).send()
 | 
			
		||||
        except sasl.SASLFailed:
 | 
			
		||||
            self.stanza.Abort(self.xmpp).send()
 | 
			
		||||
        except sasl.SASLMutualAuthFailed:
 | 
			
		||||
            log.error("Mutual authentication failed! " + \
 | 
			
		||||
                      "A security breach is possible.")
 | 
			
		||||
            self.attempted_mechs.add(self.mech.name)
 | 
			
		||||
            self.xmpp.disconnect()
 | 
			
		||||
        except sasl.SASLFailed:
 | 
			
		||||
            self.stanza.Abort(self.xmpp).send()
 | 
			
		||||
        else:
 | 
			
		||||
            if resp.get_value() == '':
 | 
			
		||||
                resp.del_value()
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ __all__ = [
 | 
			
		||||
    'xep_0108',  # User Activity
 | 
			
		||||
    'xep_0115',  # Entity Capabilities
 | 
			
		||||
    'xep_0118',  # User Tune
 | 
			
		||||
    'xep_0122',  # Data Forms Validation
 | 
			
		||||
    'xep_0128',  # Extended Service Discovery
 | 
			
		||||
    'xep_0131',  # Standard Headers and Internet Metadata
 | 
			
		||||
    'xep_0133',  # Service Administration
 | 
			
		||||
@@ -83,4 +84,5 @@ __all__ = [
 | 
			
		||||
    'xep_0319',  # Last User Interaction in Presence
 | 
			
		||||
    'xep_0323',  # IoT Systems Sensor Data
 | 
			
		||||
    'xep_0325',  # IoT Systems Control
 | 
			
		||||
    'xep_0332',  # HTTP Over XMPP Transport
 | 
			
		||||
]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										47
									
								
								slixmpp/plugins/google/auth/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								slixmpp/plugins/google/auth/stanza.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase, ET
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GoogleAuth(ElementBase):
 | 
			
		||||
    name = 'auth'
 | 
			
		||||
    namespace = 'http://www.google.com/talk/protocol/auth'
 | 
			
		||||
    plugin_attrib = 'google'
 | 
			
		||||
    interfaces = set(['client_uses_full_bind_result', 'service'])
 | 
			
		||||
 | 
			
		||||
    discovery_attr= '{%s}client-uses-full-bind-result' % namespace
 | 
			
		||||
    service_attr= '{%s}service' % namespace
 | 
			
		||||
 | 
			
		||||
    def setup(self, xml):
 | 
			
		||||
        """Don't create XML for the plugin."""
 | 
			
		||||
        self.xml = ET.Element('')
 | 
			
		||||
 | 
			
		||||
    def get_client_uses_full_bind_result(self):
 | 
			
		||||
        return self.parent()._get_attr(self.discovery_attr) == 'true'
 | 
			
		||||
 | 
			
		||||
    def set_client_uses_full_bind_result(self, value):
 | 
			
		||||
        if value in (True, 'true'):
 | 
			
		||||
            self.parent()._set_attr(self.discovery_attr, 'true')
 | 
			
		||||
        else:
 | 
			
		||||
            self.parent()._del_attr(self.discovery_attr)
 | 
			
		||||
 | 
			
		||||
    def del_client_uses_full_bind_result(self):
 | 
			
		||||
        self.parent()._del_attr(self.discovery_attr)
 | 
			
		||||
 | 
			
		||||
    def get_service(self):
 | 
			
		||||
        return self.parent()._get_attr(self.service_attr, '')
 | 
			
		||||
 | 
			
		||||
    def set_service(self, value):
 | 
			
		||||
        if value:
 | 
			
		||||
            self.parent()._set_attr(self.service_attr, value)
 | 
			
		||||
        else:
 | 
			
		||||
            self.parent()._del_attr(self.service_attr)
 | 
			
		||||
 | 
			
		||||
    def del_service(self):
 | 
			
		||||
        self.parent()._del_attr(self.service_attr)
 | 
			
		||||
							
								
								
									
										90
									
								
								slixmpp/plugins/google/gmail/notifications.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								slixmpp/plugins/google/gmail/notifications.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from slixmpp.stanza import Iq
 | 
			
		||||
from slixmpp.xmlstream.handler import Callback
 | 
			
		||||
from slixmpp.xmlstream.matcher import MatchXPath
 | 
			
		||||
from slixmpp.xmlstream import register_stanza_plugin
 | 
			
		||||
from slixmpp.plugins import BasePlugin
 | 
			
		||||
from slixmpp.plugins.google.gmail import stanza
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Gmail(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    Google: Gmail Notifications
 | 
			
		||||
 | 
			
		||||
    Also see <https://developers.google.com/talk/jep_extensions/gmail>.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'gmail'
 | 
			
		||||
    description = 'Google: Gmail Notifications'
 | 
			
		||||
    dependencies = set()
 | 
			
		||||
    stanza = stanza
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
        register_stanza_plugin(Iq, stanza.GmailQuery)
 | 
			
		||||
        register_stanza_plugin(Iq, stanza.MailBox)
 | 
			
		||||
        register_stanza_plugin(Iq, stanza.NewMail)
 | 
			
		||||
 | 
			
		||||
        self.xmpp.register_handler(
 | 
			
		||||
                Callback('Gmail New Mail',
 | 
			
		||||
                    MatchXPath('{%s}iq/{%s}%s' % (
 | 
			
		||||
                        self.xmpp.default_ns,
 | 
			
		||||
                        stanza.NewMail.namespace,
 | 
			
		||||
                        stanza.NewMail.name)),
 | 
			
		||||
                    self._handle_new_mail))
 | 
			
		||||
 | 
			
		||||
        self._last_result_time = None
 | 
			
		||||
        self._last_result_tid = None
 | 
			
		||||
 | 
			
		||||
    def plugin_end(self):
 | 
			
		||||
        self.xmpp.remove_handler('Gmail New Mail')
 | 
			
		||||
 | 
			
		||||
    def _handle_new_mail(self, iq):
 | 
			
		||||
        log.info('Gmail: New email!')
 | 
			
		||||
        iq.reply().send()
 | 
			
		||||
        self.xmpp.event('gmail_notification')
 | 
			
		||||
 | 
			
		||||
    def check(self, timeout=None, callback=None):
 | 
			
		||||
        last_time = self._last_result_time
 | 
			
		||||
        last_tid = self._last_result_tid
 | 
			
		||||
 | 
			
		||||
        callback = lambda iq: self._update_last_results(iq, callback)
 | 
			
		||||
 | 
			
		||||
        return self.search(newer_time=last_time,
 | 
			
		||||
                           newer_tid=last_tid,
 | 
			
		||||
                           timeout=timeout,
 | 
			
		||||
                           callback=callback)
 | 
			
		||||
 | 
			
		||||
    def _update_last_results(self, iq, callback=None):
 | 
			
		||||
        self._last_result_time = iq['gmail_messages']['result_time']
 | 
			
		||||
        threads = iq['gmail_messages']['threads']
 | 
			
		||||
        if threads:
 | 
			
		||||
            self._last_result_tid = threads[0]['tid']
 | 
			
		||||
        if callback:
 | 
			
		||||
            callback(iq)
 | 
			
		||||
 | 
			
		||||
    def search(self, query=None, newer_time=None, newer_tid=None,
 | 
			
		||||
                     timeout=None, callback=None):
 | 
			
		||||
        if not query:
 | 
			
		||||
            log.info('Gmail: Checking for new email')
 | 
			
		||||
        else:
 | 
			
		||||
            log.info('Gmail: Searching for emails matching: "%s"', query)
 | 
			
		||||
        iq = self.xmpp.Iq()
 | 
			
		||||
        iq['type'] = 'get'
 | 
			
		||||
        iq['to'] = self.xmpp.boundjid.bare
 | 
			
		||||
        iq['gmail']['search'] = query
 | 
			
		||||
        iq['gmail']['newer_than_time'] = newer_time
 | 
			
		||||
        iq['gmail']['newer_than_tid'] = newer_tid
 | 
			
		||||
        return iq.send(timeout=timeout, callback=callback)
 | 
			
		||||
							
								
								
									
										59
									
								
								slixmpp/plugins/google/nosave/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								slixmpp/plugins/google/nosave/stanza.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.jid import JID
 | 
			
		||||
from slixmpp.xmlstream import ElementBase, register_stanza_plugin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NoSave(ElementBase):
 | 
			
		||||
    name = 'x'
 | 
			
		||||
    namespace = 'google:nosave'
 | 
			
		||||
    plugin_attrib = 'google_nosave'
 | 
			
		||||
    interfaces = set(['value'])
 | 
			
		||||
 | 
			
		||||
    def get_value(self):
 | 
			
		||||
        return self._get_attr('value', '') == 'enabled'
 | 
			
		||||
 | 
			
		||||
    def set_value(self, value):
 | 
			
		||||
        self._set_attr('value', 'enabled' if value else 'disabled')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NoSaveQuery(ElementBase):
 | 
			
		||||
    name = 'query'
 | 
			
		||||
    namespace = 'google:nosave'
 | 
			
		||||
    plugin_attrib = 'google_nosave'
 | 
			
		||||
    interfaces = set()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Item(ElementBase):
 | 
			
		||||
    name = 'item'
 | 
			
		||||
    namespace = 'google:nosave'
 | 
			
		||||
    plugin_attrib = 'item'
 | 
			
		||||
    plugin_multi_attrib = 'items'
 | 
			
		||||
    interfaces = set(['jid', 'source', 'value'])
 | 
			
		||||
 | 
			
		||||
    def get_value(self):
 | 
			
		||||
        return self._get_attr('value', '') == 'enabled'
 | 
			
		||||
 | 
			
		||||
    def set_value(self, value):
 | 
			
		||||
        self._set_attr('value', 'enabled' if value else 'disabled')
 | 
			
		||||
 | 
			
		||||
    def get_jid(self):
 | 
			
		||||
        return JID(self._get_attr('jid', ''))
 | 
			
		||||
 | 
			
		||||
    def set_jid(self, value):
 | 
			
		||||
        self._set_attr('jid', str(value))
 | 
			
		||||
 | 
			
		||||
    def get_source(self):
 | 
			
		||||
        return JID(self._get_attr('source', ''))
 | 
			
		||||
 | 
			
		||||
    def set_source(self, value):
 | 
			
		||||
        self._set_attr('source', str(value))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register_stanza_plugin(NoSaveQuery, Item)
 | 
			
		||||
							
								
								
									
										63
									
								
								slixmpp/plugins/google/settings/settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								slixmpp/plugins/google/settings/settings.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Copyright (C) 2013 Nathanael C. Fritz, Lance J.T. Stout
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.stanza import Iq
 | 
			
		||||
from slixmpp.xmlstream.handler import Callback
 | 
			
		||||
from slixmpp.xmlstream.matcher import StanzaPath
 | 
			
		||||
from slixmpp.xmlstream import register_stanza_plugin
 | 
			
		||||
from slixmpp.plugins import BasePlugin
 | 
			
		||||
from slixmpp.plugins.google.settings import stanza
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GoogleSettings(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    Google: Gmail Notifications
 | 
			
		||||
 | 
			
		||||
    Also see <https://developers.google.com/talk/jep_extensions/usersettings>.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'google_settings'
 | 
			
		||||
    description = 'Google: User Settings'
 | 
			
		||||
    dependencies = set()
 | 
			
		||||
    stanza = stanza
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
        register_stanza_plugin(Iq, stanza.UserSettings)
 | 
			
		||||
 | 
			
		||||
        self.xmpp.register_handler(
 | 
			
		||||
                Callback('Google Settings',
 | 
			
		||||
                    StanzaPath('iq@type=set/google_settings'),
 | 
			
		||||
                    self._handle_settings_change))
 | 
			
		||||
 | 
			
		||||
    def plugin_end(self):
 | 
			
		||||
        self.xmpp.remove_handler('Google Settings')
 | 
			
		||||
 | 
			
		||||
    def get(self, timeout=None, callback=None):
 | 
			
		||||
        iq = self.xmpp.Iq()
 | 
			
		||||
        iq['type'] = 'get'
 | 
			
		||||
        iq.enable('google_settings')
 | 
			
		||||
        return iq.send(timeout=timeout, callback=callback)
 | 
			
		||||
 | 
			
		||||
    def update(self, settings, timeout=None, callback=None):
 | 
			
		||||
        iq = self.xmpp.Iq()
 | 
			
		||||
        iq['type'] = 'set'
 | 
			
		||||
        iq.enable('google_settings')
 | 
			
		||||
 | 
			
		||||
        for setting, value in settings.items():
 | 
			
		||||
            iq['google_settings'][setting] = value
 | 
			
		||||
 | 
			
		||||
        return iq.send(timeout=timeout, callback=callback)
 | 
			
		||||
 | 
			
		||||
    def _handle_settings_change(self, iq):
 | 
			
		||||
        reply = self.xmpp.Iq()
 | 
			
		||||
        reply['type'] = 'result'
 | 
			
		||||
        reply['id'] = iq['id']
 | 
			
		||||
        reply['to'] = iq['from']
 | 
			
		||||
        reply.send()
 | 
			
		||||
        self.xmpp.event('google_settings_change', iq)
 | 
			
		||||
@@ -13,8 +13,9 @@ class FormField(ElementBase):
 | 
			
		||||
    namespace = 'jabber:x:data'
 | 
			
		||||
    name = 'field'
 | 
			
		||||
    plugin_attrib = 'field'
 | 
			
		||||
    plugin_multi_attrib = 'fields'
 | 
			
		||||
    interfaces = set(('answer', 'desc', 'required', 'value',
 | 
			
		||||
                      'options', 'label', 'type', 'var'))
 | 
			
		||||
                      'label', 'type', 'var'))
 | 
			
		||||
    sub_interfaces = set(('desc',))
 | 
			
		||||
    plugin_tag_map = {}
 | 
			
		||||
    plugin_attrib_map = {}
 | 
			
		||||
@@ -165,6 +166,7 @@ class FieldOption(ElementBase):
 | 
			
		||||
    plugin_attrib = 'option'
 | 
			
		||||
    interfaces = set(('label', 'value'))
 | 
			
		||||
    sub_interfaces = set(('value',))
 | 
			
		||||
    plugin_multi_attrib = 'options'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FormField.addOption = FormField.add_option
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import copy
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from collections import OrderedDict
 | 
			
		||||
from slixmpp.thirdparty import OrderedSet
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase, ET
 | 
			
		||||
from slixmpp.plugins.xep_0004.stanza import FormField
 | 
			
		||||
@@ -22,8 +23,7 @@ class Form(ElementBase):
 | 
			
		||||
    namespace = 'jabber:x:data'
 | 
			
		||||
    name = 'x'
 | 
			
		||||
    plugin_attrib = 'form'
 | 
			
		||||
    interfaces = set(('fields', 'instructions', 'items',
 | 
			
		||||
                      'reported', 'title', 'type', 'values'))
 | 
			
		||||
    interfaces = OrderedSet(('instructions', 'reported', 'title', 'type', 'items', ))
 | 
			
		||||
    sub_interfaces = set(('title',))
 | 
			
		||||
    form_types = set(('cancel', 'form', 'result', 'submit'))
 | 
			
		||||
 | 
			
		||||
@@ -43,12 +43,12 @@ class Form(ElementBase):
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def field(self):
 | 
			
		||||
        return self['fields']
 | 
			
		||||
        return self.get_fields()
 | 
			
		||||
 | 
			
		||||
    def set_type(self, ftype):
 | 
			
		||||
        self._set_attr('type', ftype)
 | 
			
		||||
        if ftype == 'submit':
 | 
			
		||||
            fields = self['fields']
 | 
			
		||||
            fields = self.get_fields()
 | 
			
		||||
            for var in fields:
 | 
			
		||||
                field = fields[var]
 | 
			
		||||
                del field['type']
 | 
			
		||||
@@ -74,7 +74,8 @@ class Form(ElementBase):
 | 
			
		||||
            field['desc'] = desc
 | 
			
		||||
            field['required'] = required
 | 
			
		||||
            if options is not None:
 | 
			
		||||
                field['options'] = options
 | 
			
		||||
                for option in options:
 | 
			
		||||
                    field.add_option(**option)
 | 
			
		||||
        else:
 | 
			
		||||
            del field['type']
 | 
			
		||||
        self.append(field)
 | 
			
		||||
@@ -151,7 +152,6 @@ class Form(ElementBase):
 | 
			
		||||
        return fields
 | 
			
		||||
 | 
			
		||||
    def get_instructions(self):
 | 
			
		||||
        instructions = ''
 | 
			
		||||
        instsXML = self.xml.findall('{%s}instructions' % self.namespace)
 | 
			
		||||
        return "\n".join([instXML.text for instXML in instsXML])
 | 
			
		||||
 | 
			
		||||
@@ -170,7 +170,7 @@ class Form(ElementBase):
 | 
			
		||||
    def get_reported(self):
 | 
			
		||||
        fields = OrderedDict()
 | 
			
		||||
        xml = self.xml.findall('{%s}reported/{%s}field' % (self.namespace,
 | 
			
		||||
                                     FormField.namespace))
 | 
			
		||||
                                                           FormField.namespace))
 | 
			
		||||
        for field in xml:
 | 
			
		||||
            field = FormField(xml=field)
 | 
			
		||||
            fields[field['var']] = field
 | 
			
		||||
@@ -178,7 +178,7 @@ class Form(ElementBase):
 | 
			
		||||
 | 
			
		||||
    def get_values(self):
 | 
			
		||||
        values = OrderedDict()
 | 
			
		||||
        fields = self['fields']
 | 
			
		||||
        fields = self.get_fields()
 | 
			
		||||
        for var in fields:
 | 
			
		||||
            values[var] = fields[var]['value']
 | 
			
		||||
        return values
 | 
			
		||||
@@ -195,7 +195,14 @@ class Form(ElementBase):
 | 
			
		||||
            fields = fields.items()
 | 
			
		||||
        for var, field in fields:
 | 
			
		||||
            field['var'] = var
 | 
			
		||||
            self.add_field(**field)
 | 
			
		||||
            self.add_field(
 | 
			
		||||
                var = field.get('var'),
 | 
			
		||||
                label = field.get('label'),
 | 
			
		||||
                desc = field.get('desc'),
 | 
			
		||||
                required = field.get('required'),
 | 
			
		||||
                value = field.get('value'),
 | 
			
		||||
                options = field.get('options'),
 | 
			
		||||
                type = field.get('type'))
 | 
			
		||||
 | 
			
		||||
    def set_instructions(self, instructions):
 | 
			
		||||
        del self['instructions']
 | 
			
		||||
@@ -213,17 +220,33 @@ class Form(ElementBase):
 | 
			
		||||
            self.add_item(item)
 | 
			
		||||
 | 
			
		||||
    def set_reported(self, reported):
 | 
			
		||||
        """
 | 
			
		||||
        This either needs a dictionary or dictionaries or a dictionary of form fields.
 | 
			
		||||
        :param reported:
 | 
			
		||||
        :return:
 | 
			
		||||
        """
 | 
			
		||||
        for var in reported:
 | 
			
		||||
            field = reported[var]
 | 
			
		||||
            field['var'] = var
 | 
			
		||||
            self.add_reported(var, **field)
 | 
			
		||||
 | 
			
		||||
            if isinstance(field, dict):
 | 
			
		||||
                self.add_reported(**field)
 | 
			
		||||
            else:
 | 
			
		||||
                reported = self.xml.find('{%s}reported' % self.namespace)
 | 
			
		||||
                if reported is None:
 | 
			
		||||
                    reported = ET.Element('{%s}reported' % self.namespace)
 | 
			
		||||
                    self.xml.append(reported)
 | 
			
		||||
 | 
			
		||||
                fieldXML = ET.Element('{%s}field' % FormField.namespace)
 | 
			
		||||
                reported.append(fieldXML)
 | 
			
		||||
                new_field = FormField(xml=fieldXML)
 | 
			
		||||
                new_field.values = field.values
 | 
			
		||||
 | 
			
		||||
    def set_values(self, values):
 | 
			
		||||
        fields = self['fields']
 | 
			
		||||
        fields = self.get_fields()
 | 
			
		||||
        for field in values:
 | 
			
		||||
            if field not in fields:
 | 
			
		||||
            if field not in self.get_fields():
 | 
			
		||||
                fields[field] = self.add_field(var=field)
 | 
			
		||||
            fields[field]['value'] = values[field]
 | 
			
		||||
            self.get_fields()[field]['value'] = values[field]
 | 
			
		||||
 | 
			
		||||
    def merge(self, other):
 | 
			
		||||
        new = copy.copy(self)
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from binding import py2xml, xml2py, xml2fault, fault2xml
 | 
			
		||||
from slixmpp.plugins.xep_0009.binding import py2xml, xml2py, xml2fault, fault2xml
 | 
			
		||||
from threading import RLock
 | 
			
		||||
import abc
 | 
			
		||||
import inspect
 | 
			
		||||
@@ -18,6 +18,38 @@ import traceback
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
def _isstr(obj):
 | 
			
		||||
    return isinstance(obj, str)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Class decorator to declare a metaclass to a class in a way compatible with Python 2 and 3.
 | 
			
		||||
# This decorator is copied from 'six' (https://bitbucket.org/gutworth/six):
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2010-2015 Benjamin Peterson
 | 
			
		||||
#
 | 
			
		||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
# of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
# in the Software without restriction, including without limitation the rights
 | 
			
		||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
# copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
# furnished to do so, subject to the following conditions:
 | 
			
		||||
#
 | 
			
		||||
# The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
# copies or substantial portions of the Software.
 | 
			
		||||
def _add_metaclass(metaclass):
 | 
			
		||||
    def wrapper(cls):
 | 
			
		||||
        orig_vars = cls.__dict__.copy()
 | 
			
		||||
        slots = orig_vars.get('__slots__')
 | 
			
		||||
        if slots is not None:
 | 
			
		||||
            if isinstance(slots, str):
 | 
			
		||||
                slots = [slots]
 | 
			
		||||
            for slots_var in slots:
 | 
			
		||||
                orig_vars.pop(slots_var)
 | 
			
		||||
        orig_vars.pop('__dict__', None)
 | 
			
		||||
        orig_vars.pop('__weakref__', None)
 | 
			
		||||
        return metaclass(cls.__name__, cls.__bases__, orig_vars)
 | 
			
		||||
    return wrapper
 | 
			
		||||
 | 
			
		||||
def _intercept(method, name, public):
 | 
			
		||||
    def _resolver(instance, *args, **kwargs):
 | 
			
		||||
        log.debug("Locally calling %s.%s with arguments %s.", instance.FQN(), method.__name__, args)
 | 
			
		||||
@@ -68,7 +100,7 @@ def remote(function_argument, public = True):
 | 
			
		||||
    if hasattr(function_argument, '__call__'):
 | 
			
		||||
        return _intercept(function_argument, None, public)
 | 
			
		||||
    else:
 | 
			
		||||
        if not isinstance(function_argument, basestring):
 | 
			
		||||
        if not _isstr(function_argument):
 | 
			
		||||
            if not isinstance(function_argument, bool):
 | 
			
		||||
                raise Exception('Expected an RPC method name or visibility modifier!')
 | 
			
		||||
            else:
 | 
			
		||||
@@ -222,12 +254,11 @@ class TimeoutException(Exception):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@_add_metaclass(abc.ABCMeta)
 | 
			
		||||
class Callback(object):
 | 
			
		||||
    '''
 | 
			
		||||
    A base class for callback handlers.
 | 
			
		||||
    '''
 | 
			
		||||
    __metaclass__ = abc.ABCMeta
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    @abc.abstractproperty
 | 
			
		||||
    def set_value(self, value):
 | 
			
		||||
@@ -291,7 +322,7 @@ class Future(Callback):
 | 
			
		||||
        self._event.set()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@_add_metaclass(abc.ABCMeta)
 | 
			
		||||
class Endpoint(object):
 | 
			
		||||
    '''
 | 
			
		||||
    The Endpoint class is an abstract base class for all objects
 | 
			
		||||
@@ -303,8 +334,6 @@ class Endpoint(object):
 | 
			
		||||
    which specifies which object an RPC call refers to. It is the
 | 
			
		||||
    first part in a RPC method name '<fqn>.<method>'.
 | 
			
		||||
    '''
 | 
			
		||||
    __metaclass__ = abc.ABCMeta
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def __init__(self, session, target_jid):
 | 
			
		||||
        '''
 | 
			
		||||
@@ -491,7 +520,7 @@ class RemoteSession(object):
 | 
			
		||||
 | 
			
		||||
    def _find_key(self, dict, value):
 | 
			
		||||
        """return the key of dictionary dic given the value"""
 | 
			
		||||
        search = [k for k, v in dict.iteritems() if v == value]
 | 
			
		||||
        search = [k for k, v in dict.items() if v == value]
 | 
			
		||||
        if len(search) == 0:
 | 
			
		||||
            return None
 | 
			
		||||
        else:
 | 
			
		||||
@@ -547,7 +576,7 @@ class RemoteSession(object):
 | 
			
		||||
            result = handler_cls(*args, **kwargs)
 | 
			
		||||
            Endpoint.__init__(result, self, self._client.boundjid.full)
 | 
			
		||||
        method_dict = result.get_methods()
 | 
			
		||||
        for method_name, method in method_dict.iteritems():
 | 
			
		||||
        for method_name, method in method_dict.items():
 | 
			
		||||
            #!!! self._client.plugin['xep_0009'].register_call(result.FQN(), method, method_name)
 | 
			
		||||
            self._register_call(result.FQN(), method, method_name)
 | 
			
		||||
        self._register_acl(result.FQN(), acl)
 | 
			
		||||
@@ -569,11 +598,11 @@ class RemoteSession(object):
 | 
			
		||||
            self._register_callback(pid, callback)
 | 
			
		||||
            iq.send()
 | 
			
		||||
 | 
			
		||||
    def close(self):
 | 
			
		||||
    def close(self, wait=False):
 | 
			
		||||
        '''
 | 
			
		||||
        Closes this session.
 | 
			
		||||
        '''
 | 
			
		||||
        self._client.disconnect(False)
 | 
			
		||||
        self._client.disconnect(wait=wait)
 | 
			
		||||
        self._session_close_callback()
 | 
			
		||||
 | 
			
		||||
    def _on_jabber_rpc_method_call(self, iq):
 | 
			
		||||
@@ -697,7 +726,8 @@ class Remote(object):
 | 
			
		||||
            if(client.boundjid.bare in cls._sessions):
 | 
			
		||||
                raise RemoteException("There already is a session associated with these credentials!")
 | 
			
		||||
            else:
 | 
			
		||||
                cls._sessions[client.boundjid.bare] = client;
 | 
			
		||||
                cls._sessions[client.boundjid.bare] = client
 | 
			
		||||
 | 
			
		||||
        def _session_close_callback():
 | 
			
		||||
            with Remote._lock:
 | 
			
		||||
                del cls._sessions[client.boundjid.bare]
 | 
			
		||||
 
 | 
			
		||||
@@ -220,3 +220,4 @@ class XEP_0009(BasePlugin):
 | 
			
		||||
    def _extract_method(self, stanza):
 | 
			
		||||
        xml = ET.fromstring("%s" % stanza)
 | 
			
		||||
        return xml.find("./methodCall/methodName").text
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -609,7 +609,7 @@ class XEP_0030(BasePlugin):
 | 
			
		||||
        """
 | 
			
		||||
        self.api['del_features'](jid, node, None, kwargs)
 | 
			
		||||
 | 
			
		||||
    def _run_node_handler(self, htype, jid, node=None, ifrom=None, data={}):
 | 
			
		||||
    def _run_node_handler(self, htype, jid, node=None, ifrom=None, data=None):
 | 
			
		||||
        """
 | 
			
		||||
        Execute the most specific node handler for the given
 | 
			
		||||
        JID/node combination.
 | 
			
		||||
@@ -620,6 +620,9 @@ class XEP_0030(BasePlugin):
 | 
			
		||||
            node  -- The node requested.
 | 
			
		||||
            data  -- Optional, custom data to pass to the handler.
 | 
			
		||||
        """
 | 
			
		||||
        if not data:
 | 
			
		||||
            data = {}
 | 
			
		||||
 | 
			
		||||
        return self.api[htype](jid, node, ifrom, data)
 | 
			
		||||
 | 
			
		||||
    def _handle_disco_info(self, iq):
 | 
			
		||||
 
 | 
			
		||||
@@ -403,6 +403,16 @@ class XEP_0045(BasePlugin):
 | 
			
		||||
            return None
 | 
			
		||||
        return self.rooms[room].keys()
 | 
			
		||||
 | 
			
		||||
    def getUsersByAffiliation(cls, room, affiliation='member', ifrom=None):
 | 
			
		||||
        if affiliation not in ('outcast', 'member', 'admin', 'owner', 'none'):
 | 
			
		||||
            raise TypeError
 | 
			
		||||
        query = ET.Element('{http://jabber.org/protocol/muc#admin}query')
 | 
			
		||||
        item = ET.Element('{http://jabber.org/protocol/muc#admin}item', {'affiliation': affiliation})
 | 
			
		||||
        query.append(item)
 | 
			
		||||
        iq = cls.xmpp.Iq(sto=room, sfrom=ifrom, stype='get')
 | 
			
		||||
        iq.append(query)
 | 
			
		||||
        return iq.send()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
xep_0045 = XEP_0045
 | 
			
		||||
register_plugin(XEP_0045)
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ class XEP_0050(BasePlugin):
 | 
			
		||||
                         self._handle_command))
 | 
			
		||||
 | 
			
		||||
        register_stanza_plugin(Iq, Command)
 | 
			
		||||
        register_stanza_plugin(Command, Form)
 | 
			
		||||
        register_stanza_plugin(Command, Form, iterable=True)
 | 
			
		||||
 | 
			
		||||
        self.xmpp.add_event_handler('command_execute',
 | 
			
		||||
                                    self._handle_command_start)
 | 
			
		||||
@@ -415,12 +415,26 @@ class XEP_0050(BasePlugin):
 | 
			
		||||
 | 
			
		||||
            del self.sessions[sessionid]
 | 
			
		||||
 | 
			
		||||
            payload = session['payload']
 | 
			
		||||
            if payload is None:
 | 
			
		||||
                payload = []
 | 
			
		||||
            if not isinstance(payload, list):
 | 
			
		||||
                payload = [payload]
 | 
			
		||||
 | 
			
		||||
            for item in payload:
 | 
			
		||||
                register_stanza_plugin(Command, item.__class__, iterable=True)
 | 
			
		||||
 | 
			
		||||
            iq = iq.reply()
 | 
			
		||||
 | 
			
		||||
            iq['command']['node'] = node
 | 
			
		||||
            iq['command']['sessionid'] = sessionid
 | 
			
		||||
            iq['command']['actions'] = []
 | 
			
		||||
            iq['command']['status'] = 'completed'
 | 
			
		||||
            iq['command']['notes'] = session['notes']
 | 
			
		||||
 | 
			
		||||
            for item in payload:
 | 
			
		||||
                iq['command'].append(item)
 | 
			
		||||
 | 
			
		||||
            iq.send()
 | 
			
		||||
        else:
 | 
			
		||||
            raise XMPPError('item-not-found')
 | 
			
		||||
 
 | 
			
		||||
@@ -128,7 +128,8 @@ class Telephone(ElementBase):
 | 
			
		||||
 | 
			
		||||
    def setup(self, xml=None):
 | 
			
		||||
        super(Telephone, self).setup(xml=xml)
 | 
			
		||||
        self._set_sub_text('NUMBER', '', keep=True)
 | 
			
		||||
        ## this blanks out numbers received from server
 | 
			
		||||
        ##self._set_sub_text('NUMBER', '', keep=True)
 | 
			
		||||
 | 
			
		||||
    def set_number(self, value):
 | 
			
		||||
        self._set_sub_text('NUMBER', value, keep=True)
 | 
			
		||||
 
 | 
			
		||||
@@ -251,7 +251,6 @@ class XEP_0065(BasePlugin):
 | 
			
		||||
        host : The hostname or the IP of the proxy. <str>
 | 
			
		||||
        port : The port of the proxy. <str> or <int>
 | 
			
		||||
        """
 | 
			
		||||
 | 
			
		||||
        factory = lambda: Socks5Protocol(dest, 0, self.xmpp.event)
 | 
			
		||||
        return self.xmpp.loop.create_connection(factory, proxy, proxy_port)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@ class XEP_0096(BasePlugin):
 | 
			
		||||
        data['size'] = size
 | 
			
		||||
        data['date'] = date
 | 
			
		||||
        data['desc'] = desc
 | 
			
		||||
        data['hash'] = hash
 | 
			
		||||
        if allow_ranged:
 | 
			
		||||
            data.enable('range')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								slixmpp/plugins/xep_0122/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								slixmpp/plugins/xep_0122/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
 | 
			
		||||
from slixmpp.plugins.base import register_plugin
 | 
			
		||||
from slixmpp.plugins.xep_0122.stanza import FormValidation
 | 
			
		||||
from slixmpp.plugins.xep_0122.data_validation import XEP_0122
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register_plugin(XEP_0122)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Retain some backwards compatibility
 | 
			
		||||
xep_0122 = XEP_0122
 | 
			
		||||
							
								
								
									
										19
									
								
								slixmpp/plugins/xep_0122/data_validation.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								slixmpp/plugins/xep_0122/data_validation.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
from slixmpp.xmlstream import register_stanza_plugin
 | 
			
		||||
from slixmpp.plugins import BasePlugin
 | 
			
		||||
from slixmpp.plugins.xep_0004 import stanza
 | 
			
		||||
from slixmpp.plugins.xep_0004.stanza import FormField
 | 
			
		||||
from slixmpp.plugins.xep_0122.stanza import FormValidation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XEP_0122(BasePlugin):
 | 
			
		||||
    """
 | 
			
		||||
    XEP-0122: Data Forms
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'xep_0122'
 | 
			
		||||
    description = 'XEP-0122: Data Forms Validation'
 | 
			
		||||
    dependencies = set(['xep_0004'])
 | 
			
		||||
    stanza = stanza
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
        register_stanza_plugin(FormField, FormValidation)
 | 
			
		||||
							
								
								
									
										93
									
								
								slixmpp/plugins/xep_0122/stanza.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								slixmpp/plugins/xep_0122/stanza.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
			
		||||
from slixmpp.xmlstream import ElementBase, ET
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class FormValidation(ElementBase):
 | 
			
		||||
    """
 | 
			
		||||
    Validation values for form fields.
 | 
			
		||||
 | 
			
		||||
    Example:
 | 
			
		||||
 | 
			
		||||
    <field var='evt.date' type='text-single' label='Event Date/Time'>
 | 
			
		||||
      <validate xmlns='http://jabber.org/protocol/xdata-validate'
 | 
			
		||||
                datatype='xs:dateTime'/>
 | 
			
		||||
      <value>2003-10-06T11:22:00-07:00</value>
 | 
			
		||||
    </field>
 | 
			
		||||
 | 
			
		||||
    Questions:
 | 
			
		||||
      Should this look at the datatype value and convert the range values as appropriate?
 | 
			
		||||
      Should this stanza provide a pass/fail for a value from the field, or convert field value to datatype?
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    namespace = 'http://jabber.org/protocol/xdata-validate'
 | 
			
		||||
    name = 'validate'
 | 
			
		||||
    plugin_attrib = 'validate'
 | 
			
		||||
    interfaces = {'datatype', 'basic', 'open', 'range', 'regex', }
 | 
			
		||||
    sub_interfaces = {'basic', 'open', 'range', 'regex', }
 | 
			
		||||
    plugin_attrib_map = {}
 | 
			
		||||
    plugin_tag_map = {}
 | 
			
		||||
 | 
			
		||||
    def _add_field(self, name):
 | 
			
		||||
        self.remove_all()
 | 
			
		||||
        item_xml = ET.Element('{%s}%s' % (self.namespace, name))
 | 
			
		||||
        self.xml.append(item_xml)
 | 
			
		||||
        return item_xml
 | 
			
		||||
 | 
			
		||||
    def set_basic(self, value):
 | 
			
		||||
        if value:
 | 
			
		||||
            self._add_field('basic')
 | 
			
		||||
        else:
 | 
			
		||||
            del self['basic']
 | 
			
		||||
 | 
			
		||||
    def set_open(self, value):
 | 
			
		||||
        if value:
 | 
			
		||||
            self._add_field('open')
 | 
			
		||||
        else:
 | 
			
		||||
            del self['open']
 | 
			
		||||
 | 
			
		||||
    def set_regex(self, regex):
 | 
			
		||||
        if regex:
 | 
			
		||||
            _regex = self._add_field('regex')
 | 
			
		||||
            _regex.text = regex
 | 
			
		||||
        else:
 | 
			
		||||
            del self['regex']
 | 
			
		||||
 | 
			
		||||
    def set_range(self, value, minimum=None, maximum=None):
 | 
			
		||||
        if value:
 | 
			
		||||
            _range = self._add_field('range')
 | 
			
		||||
            _range.attrib['min'] = str(minimum)
 | 
			
		||||
            _range.attrib['max'] = str(maximum)
 | 
			
		||||
        else:
 | 
			
		||||
            del self['range']
 | 
			
		||||
 | 
			
		||||
    def remove_all(self, except_tag=None):
 | 
			
		||||
        for a in self.sub_interfaces:
 | 
			
		||||
            if a != except_tag:
 | 
			
		||||
                del self[a]
 | 
			
		||||
 | 
			
		||||
    def get_basic(self):
 | 
			
		||||
        present = self.xml.find('{%s}basic' % self.namespace)
 | 
			
		||||
        return present is not None
 | 
			
		||||
 | 
			
		||||
    def get_open(self):
 | 
			
		||||
        present = self.xml.find('{%s}open' % self.namespace)
 | 
			
		||||
        return present is not None
 | 
			
		||||
 | 
			
		||||
    def get_regex(self):
 | 
			
		||||
        present = self.xml.find('{%s}regex' % self.namespace)
 | 
			
		||||
        if present is not None:
 | 
			
		||||
            return present.text
 | 
			
		||||
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def get_range(self):
 | 
			
		||||
        present = self.xml.find('{%s}range' % self.namespace)
 | 
			
		||||
        if present is not None:
 | 
			
		||||
            attributes = present.attrib
 | 
			
		||||
            return_value = dict()
 | 
			
		||||
            if 'min' in attributes:
 | 
			
		||||
                return_value['minimum'] = attributes['min']
 | 
			
		||||
            if 'max' in attributes:
 | 
			
		||||
                return_value['maximum'] = attributes['max']
 | 
			
		||||
            return return_value
 | 
			
		||||
 | 
			
		||||
        return False
 | 
			
		||||
							
								
								
									
										145
									
								
								slixmpp/plugins/xep_0138.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								slixmpp/plugins/xep_0138.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,145 @@
 | 
			
		||||
"""
 | 
			
		||||
    slixmpp: The Slick XMPP Library
 | 
			
		||||
    Copyright (C) 2011  Nathanael C. Fritz
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import zlib
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from slixmpp.stanza import StreamFeatures
 | 
			
		||||
from slixmpp.xmlstream import RestartStream, register_stanza_plugin, ElementBase, StanzaBase
 | 
			
		||||
from slixmpp.xmlstream.matcher import *
 | 
			
		||||
from slixmpp.xmlstream.handler import *
 | 
			
		||||
from slixmpp.plugins import BasePlugin, register_plugin
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Compression(ElementBase):
 | 
			
		||||
    name = 'compression'
 | 
			
		||||
    namespace = 'http://jabber.org/features/compress'
 | 
			
		||||
    interfaces = set(('methods',))
 | 
			
		||||
    plugin_attrib = 'compression'
 | 
			
		||||
    plugin_tag_map = {}
 | 
			
		||||
    plugin_attrib_map = {}
 | 
			
		||||
 | 
			
		||||
    def get_methods(self):
 | 
			
		||||
        methods = []
 | 
			
		||||
        for method in self.xml.findall('{%s}method' % self.namespace):
 | 
			
		||||
            methods.append(method.text)
 | 
			
		||||
        return methods
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Compress(StanzaBase):
 | 
			
		||||
    name = 'compress'
 | 
			
		||||
    namespace = 'http://jabber.org/protocol/compress'
 | 
			
		||||
    interfaces = set(('method',))
 | 
			
		||||
    sub_interfaces = interfaces
 | 
			
		||||
    plugin_attrib = 'compress'
 | 
			
		||||
    plugin_tag_map = {}
 | 
			
		||||
    plugin_attrib_map = {}
 | 
			
		||||
 | 
			
		||||
    def setup(self, xml):
 | 
			
		||||
        StanzaBase.setup(self, xml)
 | 
			
		||||
        self.xml.tag = self.tag_name()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Compressed(StanzaBase):
 | 
			
		||||
    name = 'compressed'
 | 
			
		||||
    namespace = 'http://jabber.org/protocol/compress'
 | 
			
		||||
    interfaces = set()
 | 
			
		||||
    plugin_tag_map = {}
 | 
			
		||||
    plugin_attrib_map = {}
 | 
			
		||||
 | 
			
		||||
    def setup(self, xml):
 | 
			
		||||
        StanzaBase.setup(self, xml)
 | 
			
		||||
        self.xml.tag = self.tag_name()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ZlibSocket(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, socketobj):
 | 
			
		||||
        self.__socket = socketobj
 | 
			
		||||
        self.compressor = zlib.compressobj()
 | 
			
		||||
        self.decompressor = zlib.decompressobj(zlib.MAX_WBITS)
 | 
			
		||||
 | 
			
		||||
    def __getattr__(self, name):
 | 
			
		||||
        return getattr(self.__socket, name)
 | 
			
		||||
 | 
			
		||||
    def send(self, data):
 | 
			
		||||
        sentlen = len(data)
 | 
			
		||||
        data = self.compressor.compress(data)
 | 
			
		||||
        data += self.compressor.flush(zlib.Z_SYNC_FLUSH)
 | 
			
		||||
        log.debug(b'>>> (compressed)' + (data.encode("hex")))
 | 
			
		||||
        #return self.__socket.send(data)
 | 
			
		||||
        sentactuallen = self.__socket.send(data)
 | 
			
		||||
        assert(sentactuallen == len(data))
 | 
			
		||||
 | 
			
		||||
        return sentlen
 | 
			
		||||
 | 
			
		||||
    def recv(self, *args, **kwargs):
 | 
			
		||||
        data = self.__socket.recv(*args, **kwargs)
 | 
			
		||||
        log.debug(b'<<< (compressed)' + data.encode("hex"))
 | 
			
		||||
        return self.decompressor.decompress(self.decompressor.unconsumed_tail + data)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XEP_0138(BasePlugin):
 | 
			
		||||
    """
 | 
			
		||||
    XEP-0138: Compression
 | 
			
		||||
    """
 | 
			
		||||
    name = "xep_0138"
 | 
			
		||||
    description = "XEP-0138: Compression"
 | 
			
		||||
    dependencies = set(["xep_0030"])
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
        self.xep = '0138'
 | 
			
		||||
        self.description = 'Stream Compression (Generic)'
 | 
			
		||||
 | 
			
		||||
        self.compression_methods = {'zlib': True}
 | 
			
		||||
 | 
			
		||||
        register_stanza_plugin(StreamFeatures, Compression)
 | 
			
		||||
        self.xmpp.register_stanza(Compress)
 | 
			
		||||
        self.xmpp.register_stanza(Compressed)
 | 
			
		||||
 | 
			
		||||
        self.xmpp.register_handler(
 | 
			
		||||
                Callback('Compressed',
 | 
			
		||||
                    StanzaPath('compressed'),
 | 
			
		||||
                    self._handle_compressed,
 | 
			
		||||
                    instream=True))
 | 
			
		||||
 | 
			
		||||
        self.xmpp.register_feature('compression',
 | 
			
		||||
                self._handle_compression,
 | 
			
		||||
                restart=True,
 | 
			
		||||
                order=self.config.get('order', 5))
 | 
			
		||||
 | 
			
		||||
    def register_compression_method(self, name, handler):
 | 
			
		||||
        self.compression_methods[name] = handler
 | 
			
		||||
 | 
			
		||||
    def _handle_compression(self, features):
 | 
			
		||||
        for method in features['compression']['methods']:
 | 
			
		||||
            if method in self.compression_methods:
 | 
			
		||||
                log.info('Attempting to use %s compression' % method)
 | 
			
		||||
                c = Compress(self.xmpp)
 | 
			
		||||
                c['method'] = method
 | 
			
		||||
                c.send(now=True)
 | 
			
		||||
                return True
 | 
			
		||||
        return False
 | 
			
		||||
 | 
			
		||||
    def _handle_compressed(self, stanza):
 | 
			
		||||
        self.xmpp.features.add('compression')
 | 
			
		||||
        log.debug('Stream Compressed!')
 | 
			
		||||
        compressed_socket = ZlibSocket(self.xmpp.socket)
 | 
			
		||||
        self.xmpp.set_socket(compressed_socket)
 | 
			
		||||
        raise RestartStream()
 | 
			
		||||
 | 
			
		||||
    def _handle_failure(self, stanza):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
xep_0138 = XEP_0138
 | 
			
		||||
register_plugin(XEP_0138)
 | 
			
		||||
@@ -96,3 +96,4 @@ class XEP_0202(BasePlugin):
 | 
			
		||||
        iq['from'] = ifrom
 | 
			
		||||
        iq.enable('entity_time')
 | 
			
		||||
        return iq.send(**iqargs)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,10 @@ class Device(object):
 | 
			
		||||
          request_fields
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, nodeId, fields={}):
 | 
			
		||||
    def __init__(self, nodeId, fields=None):
 | 
			
		||||
        if not fields:
 | 
			
		||||
            fields = {}
 | 
			
		||||
 | 
			
		||||
        self.nodeId = nodeId
 | 
			
		||||
        self.fields = fields # see fields described below
 | 
			
		||||
        # {'type':'numeric',
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,6 @@ from slixmpp.plugins.base import BasePlugin
 | 
			
		||||
from slixmpp.plugins.xep_0323 import stanza
 | 
			
		||||
from slixmpp.plugins.xep_0323.stanza import Sensordata
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -108,7 +107,6 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    default_config = {
 | 
			
		||||
        'threaded': True
 | 
			
		||||
#        'session_db': None
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
@@ -161,11 +159,11 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
        self.last_seqnr = 0
 | 
			
		||||
        self.seqnr_lock = Lock()
 | 
			
		||||
 | 
			
		||||
        ## For testning only
 | 
			
		||||
        ## For testing only
 | 
			
		||||
        self.test_authenticated_from = ""
 | 
			
		||||
 | 
			
		||||
    def post_init(self):
 | 
			
		||||
        """ Init complete. Register our features in Serivce discovery. """
 | 
			
		||||
        """ Init complete. Register our features in Service discovery. """
 | 
			
		||||
        BasePlugin.post_init(self)
 | 
			
		||||
        self.xmpp['xep_0030'].add_feature(Sensordata.namespace)
 | 
			
		||||
        self.xmpp['xep_0030'].set_items(node=Sensordata.namespace, items=tuple())
 | 
			
		||||
@@ -301,8 +299,6 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
            self.sessions[session]["commTimers"] = {}
 | 
			
		||||
            self.sessions[session]["nodeDone"] = {}
 | 
			
		||||
 | 
			
		||||
            #print("added session: " + str(self.sessions))
 | 
			
		||||
 | 
			
		||||
            iq = iq.reply()
 | 
			
		||||
            iq['accepted']['seqnr'] = seqnr
 | 
			
		||||
            if not request_delay_sec is None:
 | 
			
		||||
@@ -319,10 +315,8 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            if self.threaded:
 | 
			
		||||
                #print("starting thread")
 | 
			
		||||
                tr_req = Thread(target=self._threaded_node_request, args=(session, process_fields, req_flags))
 | 
			
		||||
                tr_req.start()
 | 
			
		||||
                #print("started thread")
 | 
			
		||||
            else:
 | 
			
		||||
                self._threaded_node_request(session, process_fields, req_flags)
 | 
			
		||||
 | 
			
		||||
@@ -349,7 +343,6 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
        for node in self.sessions[session]["node_list"]:
 | 
			
		||||
            timer = TimerReset(self.nodes[node]['commTimeout'], self._event_comm_timeout, args=(session, node))
 | 
			
		||||
            self.sessions[session]["commTimers"][node] = timer
 | 
			
		||||
            #print("Starting timer " + str(timer) + ", timeout: " + str(self.nodes[node]['commTimeout']))
 | 
			
		||||
            timer.start()
 | 
			
		||||
            self.nodes[node]['device'].request_fields(process_fields, flags=flags, session=session, callback=self._device_field_request_callback)
 | 
			
		||||
 | 
			
		||||
@@ -377,7 +370,6 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
            msg['failure']['done'] = 'true'
 | 
			
		||||
        msg.send()
 | 
			
		||||
        # The session is complete, delete it
 | 
			
		||||
        #print("del session " + session + " due to timeout")
 | 
			
		||||
        del self.sessions[session]
 | 
			
		||||
 | 
			
		||||
    def _event_delayed_req(self, session, process_fields, req_flags):
 | 
			
		||||
@@ -404,7 +396,7 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    def _all_nodes_done(self, session):
 | 
			
		||||
        """
 | 
			
		||||
        Checks wheter all devices are done replying to the readout.
 | 
			
		||||
        Checks whether all devices are done replying to the readout.
 | 
			
		||||
 | 
			
		||||
        Arguments:
 | 
			
		||||
            session         -- The request session id
 | 
			
		||||
@@ -448,7 +440,7 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
                                Error details when a request failed.
 | 
			
		||||
        """
 | 
			
		||||
        if not session in self.sessions:
 | 
			
		||||
            # This can happend if a session was deleted, like in a cancellation. Just drop the data.
 | 
			
		||||
            # This can happen if a session was deleted, like in a cancellation. Just drop the data.
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if result == "error":
 | 
			
		||||
@@ -467,7 +459,6 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
            if (self._all_nodes_done(session)):
 | 
			
		||||
                msg['failure']['done'] = 'true'
 | 
			
		||||
                # The session is complete, delete it
 | 
			
		||||
                # print("del session " + session + " due to error")
 | 
			
		||||
                del self.sessions[session]
 | 
			
		||||
            msg.send()
 | 
			
		||||
        else:
 | 
			
		||||
@@ -491,11 +482,10 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
            if result == "done":
 | 
			
		||||
                self.sessions[session]["commTimers"][nodeId].cancel()
 | 
			
		||||
                self.sessions[session]["nodeDone"][nodeId] = True
 | 
			
		||||
                msg['fields']['done'] = 'true'
 | 
			
		||||
                if (self._all_nodes_done(session)):
 | 
			
		||||
                    # The session is complete, delete it
 | 
			
		||||
                    # print("del session " + session + " due to complete")
 | 
			
		||||
                    del self.sessions[session]
 | 
			
		||||
                    msg['fields']['done'] = 'true'
 | 
			
		||||
            else:
 | 
			
		||||
                # Restart comm timer
 | 
			
		||||
                self.sessions[session]["commTimers"][nodeId].reset()
 | 
			
		||||
@@ -531,19 +521,19 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
        iq['rejected']['error'] = "Cancel request received, no matching request is active."
 | 
			
		||||
        iq.send()
 | 
			
		||||
 | 
			
		||||
    # =================================================================
 | 
			
		||||
        # =================================================================
 | 
			
		||||
    # Client side (data retriever) API
 | 
			
		||||
 | 
			
		||||
    def request_data(self, from_jid, to_jid, callback, nodeIds=None, fields=None, flags=None):
 | 
			
		||||
        """
 | 
			
		||||
        Called on the client side to initiade a data readout.
 | 
			
		||||
        Called on the client side to initiate a data readout.
 | 
			
		||||
        Composes a message with the request and sends it to the device(s).
 | 
			
		||||
        Does not block, the callback will be called when data is available.
 | 
			
		||||
 | 
			
		||||
        Arguments:
 | 
			
		||||
            from_jid        -- The jid of the requester
 | 
			
		||||
            to_jid          -- The jid of the device(s)
 | 
			
		||||
            callback        -- The callback function to call when data is availble.
 | 
			
		||||
            callback        -- The callback function to call when data is available.
 | 
			
		||||
 | 
			
		||||
                            The callback function must support the following arguments:
 | 
			
		||||
 | 
			
		||||
@@ -636,7 +626,7 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
    def _get_new_seqnr(self):
 | 
			
		||||
        """ Returns a unique sequence number (unique across threads) """
 | 
			
		||||
        self.seqnr_lock.acquire()
 | 
			
		||||
        self.last_seqnr = self.last_seqnr + 1
 | 
			
		||||
        self.last_seqnr += 1
 | 
			
		||||
        self.seqnr_lock.release()
 | 
			
		||||
        return str(self.last_seqnr)
 | 
			
		||||
 | 
			
		||||
@@ -664,7 +654,6 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
        Received Iq with cancelled - this is a cancel confirm.
 | 
			
		||||
        Delete the session.
 | 
			
		||||
        """
 | 
			
		||||
        #print("Got cancelled")
 | 
			
		||||
        seqnr = iq['cancelled']['seqnr']
 | 
			
		||||
        callback = self.sessions[seqnr]["callback"]
 | 
			
		||||
        callback(from_jid=iq['from'], result="cancelled")
 | 
			
		||||
@@ -673,7 +662,7 @@ class XEP_0323(BasePlugin):
 | 
			
		||||
 | 
			
		||||
    def _handle_event_fields(self, msg):
 | 
			
		||||
        """
 | 
			
		||||
        Received Msg with fields - this is a data reponse to a request.
 | 
			
		||||
        Received Msg with fields - this is a data response to a request.
 | 
			
		||||
        If this is the last data block, issue a "done" callback.
 | 
			
		||||
        """
 | 
			
		||||
        seqnr = msg['fields']['seqnr']
 | 
			
		||||
 
 | 
			
		||||
@@ -23,7 +23,12 @@ class _TimerReset(Thread):
 | 
			
		||||
    t.cancel() # stop the timer's action if it's still waiting
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, interval, function, args=[], kwargs={}):
 | 
			
		||||
    def __init__(self, interval, function, args=None, kwargs=None):
 | 
			
		||||
        if not kwargs:
 | 
			
		||||
            kwargs = {}
 | 
			
		||||
        if not args:
 | 
			
		||||
            args = []
 | 
			
		||||
 | 
			
		||||
        Thread.__init__(self)
 | 
			
		||||
        self.interval = interval
 | 
			
		||||
        self.function = function
 | 
			
		||||
 
 | 
			
		||||
@@ -223,7 +223,6 @@ class XEP_0325(BasePlugin):
 | 
			
		||||
            error_msg = "Access denied"
 | 
			
		||||
 | 
			
		||||
        # Nodes
 | 
			
		||||
        process_nodes = []
 | 
			
		||||
        if len(iq['set']['nodes']) > 0:
 | 
			
		||||
            for n in iq['set']['nodes']:
 | 
			
		||||
                if not n['nodeId'] in self.nodes:
 | 
			
		||||
@@ -286,7 +285,6 @@ class XEP_0325(BasePlugin):
 | 
			
		||||
        req_ok = True
 | 
			
		||||
 | 
			
		||||
        # Nodes
 | 
			
		||||
        process_nodes = []
 | 
			
		||||
        if len(msg['set']['nodes']) > 0:
 | 
			
		||||
            for n in msg['set']['nodes']:
 | 
			
		||||
                if not n['nodeId'] in self.nodes:
 | 
			
		||||
@@ -548,4 +546,3 @@ class XEP_0325(BasePlugin):
 | 
			
		||||
        callback = self.sessions[seqnr]["callback"]
 | 
			
		||||
        callback(from_jid=from_jid, result=result, nodeIds=nodeIds, fields=fields, error_msg=error_msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								slixmpp/plugins/xep_0332/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								slixmpp/plugins/xep_0332/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.plugins.base import register_plugin
 | 
			
		||||
 | 
			
		||||
from slixmpp.plugins.xep_0332 import stanza
 | 
			
		||||
from slixmpp.plugins.xep_0332.http import XEP_0332
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
register_plugin(XEP_0332)
 | 
			
		||||
							
								
								
									
										159
									
								
								slixmpp/plugins/xep_0332/http.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										159
									
								
								slixmpp/plugins/xep_0332/http.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,159 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from slixmpp import Iq
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import register_stanza_plugin
 | 
			
		||||
from slixmpp.xmlstream.handler import Callback
 | 
			
		||||
from slixmpp.xmlstream.matcher import StanzaPath
 | 
			
		||||
 | 
			
		||||
from slixmpp.plugins.base import BasePlugin
 | 
			
		||||
from slixmpp.plugins.xep_0332.stanza import (
 | 
			
		||||
    HTTPRequest, HTTPResponse, HTTPData
 | 
			
		||||
)
 | 
			
		||||
from slixmpp.plugins.xep_0131.stanza import Headers
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class XEP_0332(BasePlugin):
 | 
			
		||||
    """
 | 
			
		||||
    XEP-0332: HTTP over XMPP transport
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'xep_0332'
 | 
			
		||||
    description = 'XEP-0332: HTTP over XMPP transport'
 | 
			
		||||
 | 
			
		||||
    #: xep_0047 not included.
 | 
			
		||||
    #: xep_0001, 0137 and 0166 are missing
 | 
			
		||||
    dependencies = set(['xep_0030', 'xep_0131'])
 | 
			
		||||
 | 
			
		||||
    #: TODO: Do we really need to mention the supported_headers?!
 | 
			
		||||
    default_config = {
 | 
			
		||||
        'supported_headers': set([
 | 
			
		||||
            'Content-Length', 'Transfer-Encoding', 'DateTime',
 | 
			
		||||
            'Accept-Charset', 'Location', 'Content-ID', 'Description',
 | 
			
		||||
            'Content-Language', 'Content-Transfer-Encoding', 'Timestamp',
 | 
			
		||||
            'Expires', 'User-Agent', 'Host', 'Proxy-Authorization', 'Date',
 | 
			
		||||
            'WWW-Authenticate', 'Accept-Encoding', 'Server', 'Error-Info',
 | 
			
		||||
            'Identifier', 'Content-Location', 'Content-Encoding', 'Distribute',
 | 
			
		||||
            'Accept', 'Proxy-Authenticate', 'ETag', 'Expect', 'Content-Type'
 | 
			
		||||
        ])
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def plugin_init(self):
 | 
			
		||||
        self.xmpp.register_handler(
 | 
			
		||||
            Callback(
 | 
			
		||||
                'HTTP Request',
 | 
			
		||||
                StanzaPath('iq/http-req'),
 | 
			
		||||
                self._handle_request
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        self.xmpp.register_handler(
 | 
			
		||||
            Callback(
 | 
			
		||||
                'HTTP Response',
 | 
			
		||||
                StanzaPath('iq/http-resp'),
 | 
			
		||||
                self._handle_response
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
        register_stanza_plugin(Iq, HTTPRequest, iterable=True)
 | 
			
		||||
        register_stanza_plugin(Iq, HTTPResponse, iterable=True)
 | 
			
		||||
        register_stanza_plugin(HTTPRequest, Headers, iterable=True)
 | 
			
		||||
        register_stanza_plugin(HTTPRequest, HTTPData, iterable=True)
 | 
			
		||||
        register_stanza_plugin(HTTPResponse, Headers, iterable=True)
 | 
			
		||||
        register_stanza_plugin(HTTPResponse, HTTPData, iterable=True)
 | 
			
		||||
        # TODO: Should we register any api's here? self.api.register()
 | 
			
		||||
 | 
			
		||||
    def plugin_end(self):
 | 
			
		||||
        self.xmpp.remove_handler('HTTP Request')
 | 
			
		||||
        self.xmpp.remove_handler('HTTP Response')
 | 
			
		||||
        self.xmpp['xep_0030'].del_feature('urn:xmpp:http')
 | 
			
		||||
        for header in self.supported_headers:
 | 
			
		||||
            self.xmpp['xep_0030'].del_feature(
 | 
			
		||||
                feature='%s#%s' % (Headers.namespace, header)
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def session_bind(self, jid):
 | 
			
		||||
        self.xmpp['xep_0030'].add_feature('urn:xmpp:http')
 | 
			
		||||
        for header in self.supported_headers:
 | 
			
		||||
            self.xmpp['xep_0030'].add_feature(
 | 
			
		||||
                '%s#%s' % (Headers.namespace, header)
 | 
			
		||||
            )
 | 
			
		||||
            # TODO: Do we need to add the supported headers to xep_0131?
 | 
			
		||||
            # self.xmpp['xep_0131'].supported_headers.add(header)
 | 
			
		||||
 | 
			
		||||
    def _handle_request(self, iq):
 | 
			
		||||
        self.xmpp.event('http_request', iq)
 | 
			
		||||
 | 
			
		||||
    def _handle_response(self, iq):
 | 
			
		||||
        self.xmpp.event('http_response', iq)
 | 
			
		||||
 | 
			
		||||
    def send_request(self, to=None, method=None, resource=None, headers=None,
 | 
			
		||||
                     data=None, **kwargs):
 | 
			
		||||
        iq = self.xmpp.Iq()
 | 
			
		||||
        iq['from'] = self.xmpp.boundjid
 | 
			
		||||
        iq['to'] = to
 | 
			
		||||
        iq['type'] = 'set'
 | 
			
		||||
        iq['http-req']['headers'] = headers
 | 
			
		||||
        iq['http-req']['method'] = method
 | 
			
		||||
        iq['http-req']['resource'] = resource
 | 
			
		||||
        iq['http-req']['version'] = '1.1'        # TODO: set this implicitly
 | 
			
		||||
        if 'id' in kwargs:
 | 
			
		||||
            iq['id'] = kwargs["id"]
 | 
			
		||||
        if data is not None:
 | 
			
		||||
            iq['http-req']['data'] = data
 | 
			
		||||
        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 send_response(self, to=None, code=None, message=None, headers=None,
 | 
			
		||||
                      data=None, **kwargs):
 | 
			
		||||
        iq = self.xmpp.Iq()
 | 
			
		||||
        iq['from'] = self.xmpp.boundjid
 | 
			
		||||
        iq['to'] = to
 | 
			
		||||
        iq['type'] = 'result'
 | 
			
		||||
        iq['http-resp']['headers'] = headers
 | 
			
		||||
        iq['http-resp']['code'] = code
 | 
			
		||||
        iq['http-resp']['message'] = message
 | 
			
		||||
        iq['http-resp']['version'] = '1.1'       # TODO: set this implicitly
 | 
			
		||||
        if 'id' in kwargs:
 | 
			
		||||
            iq['id'] = kwargs["id"]
 | 
			
		||||
        if data is not None:
 | 
			
		||||
            iq['http-resp']['data'] = data
 | 
			
		||||
        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 send_error(self, to=None, ecode='500', etype='wait',
 | 
			
		||||
                   econd='internal-server-error', **kwargs):
 | 
			
		||||
        iq = self.xmpp.Iq()
 | 
			
		||||
        iq['from'] = self.xmpp.boundjid
 | 
			
		||||
        iq['to'] = to
 | 
			
		||||
        iq['type'] = 'error'
 | 
			
		||||
        iq['error']['code'] = ecode
 | 
			
		||||
        iq['error']['type'] = etype
 | 
			
		||||
        iq['error']['condition'] = econd
 | 
			
		||||
        if 'id' in kwargs:
 | 
			
		||||
            iq['id'] = kwargs["id"]
 | 
			
		||||
        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)
 | 
			
		||||
        )
 | 
			
		||||
							
								
								
									
										13
									
								
								slixmpp/plugins/xep_0332/stanza/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								slixmpp/plugins/xep_0332/stanza/__init__.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.plugins.xep_0332.stanza.request import HTTPRequest
 | 
			
		||||
from slixmpp.plugins.xep_0332.stanza.response import HTTPResponse
 | 
			
		||||
from slixmpp.plugins.xep_0332.stanza.data import HTTPData
 | 
			
		||||
							
								
								
									
										30
									
								
								slixmpp/plugins/xep_0332/stanza/data.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								slixmpp/plugins/xep_0332/stanza/data.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HTTPData(ElementBase):
 | 
			
		||||
    """
 | 
			
		||||
    The data element.
 | 
			
		||||
    """
 | 
			
		||||
    name = 'data'
 | 
			
		||||
    namespace = 'urn:xmpp:http'
 | 
			
		||||
    interfaces = set(['data'])
 | 
			
		||||
    plugin_attrib = 'data'
 | 
			
		||||
    is_extension = True
 | 
			
		||||
 | 
			
		||||
    def get_data(self, encoding='text'):
 | 
			
		||||
        data = self._get_sub_text(encoding, None)
 | 
			
		||||
        return str(data) if data is not None else data
 | 
			
		||||
 | 
			
		||||
    def set_data(self, data, encoding='text'):
 | 
			
		||||
        self._set_sub_text(encoding, text=data)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								slixmpp/plugins/xep_0332/stanza/request.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								slixmpp/plugins/xep_0332/stanza/request.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
			
		||||
"""
 | 
			
		||||
    slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HTTPRequest(ElementBase):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    All HTTP communication is done using the `Request`/`Response` paradigm.
 | 
			
		||||
    Each HTTP Request is made sending an `iq` stanza containing a `req`
 | 
			
		||||
    element to the server. Each `iq` stanza sent is of type `set`.
 | 
			
		||||
 | 
			
		||||
    Examples:
 | 
			
		||||
    <iq type='set' from='a@b.com/browser' to='x@y.com' id='1'>
 | 
			
		||||
        <req xmlns='urn:xmpp:http'
 | 
			
		||||
             method='GET'
 | 
			
		||||
             resource='/api/users'
 | 
			
		||||
             version='1.1'>
 | 
			
		||||
            <headers xmlns='http://jabber.org/protocol/shim'>
 | 
			
		||||
                <header name='Host'>b.com</header>
 | 
			
		||||
            </headers>
 | 
			
		||||
        </req>
 | 
			
		||||
    </iq>
 | 
			
		||||
 | 
			
		||||
    <iq type='set' from='a@b.com/browser' to='x@y.com' id='2'>
 | 
			
		||||
        <req xmlns='urn:xmpp:http'
 | 
			
		||||
             method='PUT'
 | 
			
		||||
             resource='/api/users'
 | 
			
		||||
             version='1.1'>
 | 
			
		||||
            <headers xmlns='http://jabber.org/protocol/shim'>
 | 
			
		||||
                <header name='Host'>b.com</header>
 | 
			
		||||
                <header name='Content-Type'>text/html</header>
 | 
			
		||||
                <header name='Content-Length'>...</header>
 | 
			
		||||
            </headers>
 | 
			
		||||
            <data>
 | 
			
		||||
                <text>...</text>
 | 
			
		||||
            </data>
 | 
			
		||||
        </req>
 | 
			
		||||
    </iq>
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'request'
 | 
			
		||||
    namespace = 'urn:xmpp:http'
 | 
			
		||||
    interfaces = set(['method', 'resource', 'version'])
 | 
			
		||||
    plugin_attrib = 'http-req'
 | 
			
		||||
 | 
			
		||||
    def get_method(self):
 | 
			
		||||
        return self._get_attr('method', None)
 | 
			
		||||
 | 
			
		||||
    def set_method(self, method):
 | 
			
		||||
        self._set_attr('method', method)
 | 
			
		||||
 | 
			
		||||
    def get_resource(self):
 | 
			
		||||
        return self._get_attr('resource', None)
 | 
			
		||||
 | 
			
		||||
    def set_resource(self, resource):
 | 
			
		||||
        self._set_attr('resource', resource)
 | 
			
		||||
 | 
			
		||||
    def get_version(self):
 | 
			
		||||
        return self._get_attr('version', None)
 | 
			
		||||
 | 
			
		||||
    def set_version(self, version='1.1'):
 | 
			
		||||
        self._set_attr('version', version)
 | 
			
		||||
							
								
								
									
										66
									
								
								slixmpp/plugins/xep_0332/stanza/response.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								slixmpp/plugins/xep_0332/stanza/response.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
"""
 | 
			
		||||
    Slixmpp: The Slick XMPP Library
 | 
			
		||||
    Implementation of HTTP over XMPP transport
 | 
			
		||||
    http://xmpp.org/extensions/xep-0332.html
 | 
			
		||||
    Copyright (C) 2015 Riptide IO, sangeeth@riptideio.com
 | 
			
		||||
    This file is part of slixmpp.
 | 
			
		||||
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HTTPResponse(ElementBase):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    When the HTTP Server responds, it does so by sending an `iq` stanza
 | 
			
		||||
    response (type=`result`) back to the client containing the `resp` element.
 | 
			
		||||
    Since response are asynchronous, and since multiple requests may be active
 | 
			
		||||
    at the same time, responses may be returned in a different order than the
 | 
			
		||||
    in which the original requests were made.
 | 
			
		||||
 | 
			
		||||
    Examples:
 | 
			
		||||
    <iq type='result'
 | 
			
		||||
        from='httpserver@clayster.com'
 | 
			
		||||
        to='httpclient@clayster.com/browser' id='2'>
 | 
			
		||||
        <resp xmlns='urn:xmpp:http'
 | 
			
		||||
              version='1.1'
 | 
			
		||||
              statusCode='200'
 | 
			
		||||
              statusMessage='OK'>
 | 
			
		||||
            <headers xmlns='http://jabber.org/protocol/shim'>
 | 
			
		||||
                <header name='Date'>Fri, 03 May 2013 16:39:54GMT-4</header>
 | 
			
		||||
                <header name='Server'>Clayster</header>
 | 
			
		||||
                <header name='Content-Type'>text/turtle</header>
 | 
			
		||||
                <header name='Content-Length'>...</header>
 | 
			
		||||
                <header name='Connection'>Close</header>
 | 
			
		||||
            </headers>
 | 
			
		||||
            <data>
 | 
			
		||||
                <text>
 | 
			
		||||
                    ...
 | 
			
		||||
                </text>
 | 
			
		||||
            </data>
 | 
			
		||||
        </resp>
 | 
			
		||||
    </iq>
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'response'
 | 
			
		||||
    namespace = 'urn:xmpp:http'
 | 
			
		||||
    interfaces = set(['code', 'message', 'version'])
 | 
			
		||||
    plugin_attrib = 'http-resp'
 | 
			
		||||
 | 
			
		||||
    def get_code(self):
 | 
			
		||||
        code = self._get_attr('statusCode', None)
 | 
			
		||||
        return int(code) if code is not None else code
 | 
			
		||||
 | 
			
		||||
    def set_code(self, code):
 | 
			
		||||
        self._set_attr('statusCode', str(code))
 | 
			
		||||
 | 
			
		||||
    def get_message(self):
 | 
			
		||||
        return self._get_attr('statusMessage', '')
 | 
			
		||||
 | 
			
		||||
    def set_message(self, message):
 | 
			
		||||
        self._set_attr('statusMessage', message)
 | 
			
		||||
 | 
			
		||||
    def set_version(self, version='1.1'):
 | 
			
		||||
        self._set_attr('version', version)
 | 
			
		||||
@@ -254,6 +254,9 @@ class RosterNode(object):
 | 
			
		||||
            callback     -- Optional reference to a stream handler function.
 | 
			
		||||
                            Will be executed when the roster is received.
 | 
			
		||||
        """
 | 
			
		||||
        if not groups:
 | 
			
		||||
            groups = []
 | 
			
		||||
 | 
			
		||||
        self[jid]['name'] = name
 | 
			
		||||
        self[jid]['groups'] = groups
 | 
			
		||||
        self[jid].save()
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,7 @@
 | 
			
		||||
    See the file LICENSE for copying permission.
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase
 | 
			
		||||
 | 
			
		||||
from slixmpp.xmlstream import ElementBase, register_stanza_plugin
 | 
			
		||||
 | 
			
		||||
class AtomEntry(ElementBase):
 | 
			
		||||
 | 
			
		||||
@@ -22,5 +21,23 @@ class AtomEntry(ElementBase):
 | 
			
		||||
    namespace = 'http://www.w3.org/2005/Atom'
 | 
			
		||||
    name = 'entry'
 | 
			
		||||
    plugin_attrib = 'entry'
 | 
			
		||||
    interfaces = set(('title', 'summary'))
 | 
			
		||||
    sub_interfaces = set(('title', 'summary'))
 | 
			
		||||
    interfaces = set(('title', 'summary', 'id', 'published', 'updated'))
 | 
			
		||||
    sub_interfaces = set(('title', 'summary', 'id', 'published',
 | 
			
		||||
                          'updated'))
 | 
			
		||||
 | 
			
		||||
class AtomAuthor(ElementBase):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    An Atom author.
 | 
			
		||||
 | 
			
		||||
    Stanza Interface:
 | 
			
		||||
        name -- The printable author name
 | 
			
		||||
        uri  -- The bare jid of the author
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    name = 'author'
 | 
			
		||||
    plugin_attrib = 'author'
 | 
			
		||||
    interfaces = set(('name', 'uri'))
 | 
			
		||||
    sub_interfaces = set(('name', 'uri'))
 | 
			
		||||
 | 
			
		||||
register_stanza_plugin(AtomEntry, AtomAuthor)
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,9 @@ class RootStanza(StanzaBase):
 | 
			
		||||
            reply.send()
 | 
			
		||||
        elif isinstance(e, XMPPError):
 | 
			
		||||
            # We raised this deliberately
 | 
			
		||||
            keep_id = self['id']
 | 
			
		||||
            reply = self.reply(clear=e.clear)
 | 
			
		||||
            reply['id'] = keep_id
 | 
			
		||||
            reply['error']['condition'] = e.condition
 | 
			
		||||
            reply['error']['text'] = e.text
 | 
			
		||||
            reply['error']['type'] = e.etype
 | 
			
		||||
@@ -72,7 +74,9 @@ class RootStanza(StanzaBase):
 | 
			
		||||
            reply.send()
 | 
			
		||||
        else:
 | 
			
		||||
            # We probably didn't raise this on purpose, so send an error stanza
 | 
			
		||||
            keep_id = self['id']
 | 
			
		||||
            reply = self.reply()
 | 
			
		||||
            reply['id'] = keep_id
 | 
			
		||||
            reply['error']['condition'] = 'undefined-condition'
 | 
			
		||||
            reply['error']['text'] = "Slixmpp got into trouble."
 | 
			
		||||
            reply['error']['type'] = 'cancel'
 | 
			
		||||
 
 | 
			
		||||
@@ -319,6 +319,9 @@ class SlixTest(unittest.TestCase):
 | 
			
		||||
            plugins  -- List of plugins to register. By default, all plugins
 | 
			
		||||
                        are loaded.
 | 
			
		||||
        """
 | 
			
		||||
        if not plugin_config:
 | 
			
		||||
            plugin_config = {}
 | 
			
		||||
 | 
			
		||||
        if mode == 'client':
 | 
			
		||||
            self.xmpp = ClientXMPP(jid, password,
 | 
			
		||||
                                   sasl_mech=sasl_mech,
 | 
			
		||||
@@ -402,8 +405,7 @@ class SlixTest(unittest.TestCase):
 | 
			
		||||
        parts.append('xmlns="%s"' % default_ns)
 | 
			
		||||
        return header % ' '.join(parts)
 | 
			
		||||
 | 
			
		||||
    def recv(self, data, defaults=[], method='exact',
 | 
			
		||||
             use_values=True, timeout=1):
 | 
			
		||||
    def recv(self, data, defaults=None, method='exact', use_values=True, timeout=1):
 | 
			
		||||
        """
 | 
			
		||||
        Pass data to the dummy XMPP client as if it came from an XMPP server.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								slixmpp/thirdparty/__init__.py
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								slixmpp/thirdparty/__init__.py
									
									
									
									
										vendored
									
									
								
							@@ -4,3 +4,4 @@ except:
 | 
			
		||||
    from slixmpp.thirdparty.gnupg import GPG
 | 
			
		||||
 | 
			
		||||
from slixmpp.thirdparty.mini_dateutil import tzutc, tzoffset, parse_iso
 | 
			
		||||
from slixmpp.thirdparty.orderedset import OrderedSet
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								slixmpp/thirdparty/orderedset.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								slixmpp/thirdparty/orderedset.py
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
# Copyright (c) 2009 Raymond Hettinger
 | 
			
		||||
#
 | 
			
		||||
# Permission is hereby granted, free of charge, to any person
 | 
			
		||||
# obtaining a copy of this software and associated documentation files
 | 
			
		||||
# (the "Software"), to deal in the Software without restriction,
 | 
			
		||||
# including without limitation the rights to use, copy, modify, merge,
 | 
			
		||||
# publish, distribute, sublicense, and/or sell copies of the Software,
 | 
			
		||||
# and to permit persons to whom the Software is furnished to do so,
 | 
			
		||||
# subject to the following conditions:
 | 
			
		||||
#
 | 
			
		||||
#     The above copyright notice and this permission notice shall be
 | 
			
		||||
#     included in all copies or substantial portions of the Software.
 | 
			
		||||
#
 | 
			
		||||
#     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
			
		||||
#     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 | 
			
		||||
#     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | 
			
		||||
#     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 | 
			
		||||
#     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 | 
			
		||||
#     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
			
		||||
#     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
			
		||||
#     OTHER DEALINGS IN THE SOFTWARE.
 | 
			
		||||
 | 
			
		||||
import collections
 | 
			
		||||
 | 
			
		||||
class OrderedSet(collections.MutableSet):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, iterable=None):
 | 
			
		||||
        self.end = end = []
 | 
			
		||||
        end += [None, end, end]         # sentinel node for doubly linked list
 | 
			
		||||
        self.map = {}                   # key --> [key, prev, next]
 | 
			
		||||
        if iterable is not None:
 | 
			
		||||
            self |= iterable
 | 
			
		||||
 | 
			
		||||
    def __len__(self):
 | 
			
		||||
        return len(self.map)
 | 
			
		||||
 | 
			
		||||
    def __contains__(self, key):
 | 
			
		||||
        return key in self.map
 | 
			
		||||
 | 
			
		||||
    def add(self, key):
 | 
			
		||||
        if key not in self.map:
 | 
			
		||||
            end = self.end
 | 
			
		||||
            curr = end[1]
 | 
			
		||||
            curr[2] = end[1] = self.map[key] = [key, curr, end]
 | 
			
		||||
 | 
			
		||||
    def discard(self, key):
 | 
			
		||||
        if key in self.map:
 | 
			
		||||
            key, prev, next = self.map.pop(key)
 | 
			
		||||
            prev[2] = next
 | 
			
		||||
            next[1] = prev
 | 
			
		||||
 | 
			
		||||
    def __iter__(self):
 | 
			
		||||
        end = self.end
 | 
			
		||||
        curr = end[2]
 | 
			
		||||
        while curr is not end:
 | 
			
		||||
            yield curr[0]
 | 
			
		||||
            curr = curr[2]
 | 
			
		||||
 | 
			
		||||
    def __reversed__(self):
 | 
			
		||||
        end = self.end
 | 
			
		||||
        curr = end[1]
 | 
			
		||||
        while curr is not end:
 | 
			
		||||
            yield curr[0]
 | 
			
		||||
            curr = curr[1]
 | 
			
		||||
 | 
			
		||||
    def pop(self, last=True):
 | 
			
		||||
        if not self:
 | 
			
		||||
            raise KeyError('set is empty')
 | 
			
		||||
        key = self.end[1][0] if last else self.end[2][0]
 | 
			
		||||
        self.discard(key)
 | 
			
		||||
        return key
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        if not self:
 | 
			
		||||
            return '%s()' % (self.__class__.__name__,)
 | 
			
		||||
        return '%s(%r)' % (self.__class__.__name__, list(self))
 | 
			
		||||
 | 
			
		||||
    def __eq__(self, other):
 | 
			
		||||
        if isinstance(other, OrderedSet):
 | 
			
		||||
            return len(self) == len(other) and list(self) == list(other)
 | 
			
		||||
        return set(self) == set(other)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    s = OrderedSet('abracadaba')
 | 
			
		||||
    t = OrderedSet('simsalabim')
 | 
			
		||||
    print(s | t)
 | 
			
		||||
    print(s & t)
 | 
			
		||||
    print(s - t)
 | 
			
		||||
@@ -181,4 +181,4 @@ def verify(expected, raw_cert):
 | 
			
		||||
            return True
 | 
			
		||||
 | 
			
		||||
    raise CertificateError(
 | 
			
		||||
            'Could not match certficate against hostname: %s' % expected)
 | 
			
		||||
            'Could not match certificate against hostname: %s' % expected)
 | 
			
		||||
 
 | 
			
		||||
@@ -558,10 +558,13 @@ class ElementBase(object):
 | 
			
		||||
 | 
			
		||||
        .. versionadded:: 1.0-Beta1
 | 
			
		||||
        """
 | 
			
		||||
        values = {}
 | 
			
		||||
        values = OrderedDict()
 | 
			
		||||
        values['lang'] = self['lang']
 | 
			
		||||
        for interface in self.interfaces:
 | 
			
		||||
            values[interface] = self[interface]
 | 
			
		||||
            if isinstance(self[interface], JID):
 | 
			
		||||
                values[interface] = self[interface].jid
 | 
			
		||||
            else:
 | 
			
		||||
                values[interface] = self[interface]
 | 
			
		||||
            if interface in self.lang_interfaces:
 | 
			
		||||
                values['%s|*' % interface] = self['%s|*' % interface]
 | 
			
		||||
        for plugin, stanza in self.plugins.items():
 | 
			
		||||
@@ -672,6 +675,8 @@ class ElementBase(object):
 | 
			
		||||
        if lang and attrib in self.lang_interfaces:
 | 
			
		||||
            kwargs['lang'] = lang
 | 
			
		||||
 | 
			
		||||
        kwargs = OrderedDict(kwargs)
 | 
			
		||||
 | 
			
		||||
        if attrib == 'substanzas':
 | 
			
		||||
            return self.iterables
 | 
			
		||||
        elif attrib in self.interfaces or attrib == 'lang':
 | 
			
		||||
@@ -748,6 +753,8 @@ class ElementBase(object):
 | 
			
		||||
        if lang and attrib in self.lang_interfaces:
 | 
			
		||||
            kwargs['lang'] = lang
 | 
			
		||||
 | 
			
		||||
        kwargs = OrderedDict(kwargs)
 | 
			
		||||
 | 
			
		||||
        if attrib in self.interfaces or attrib == 'lang':
 | 
			
		||||
            if value is not None:
 | 
			
		||||
                set_method = "set_%s" % attrib.lower()
 | 
			
		||||
@@ -834,6 +841,8 @@ class ElementBase(object):
 | 
			
		||||
        if lang and attrib in self.lang_interfaces:
 | 
			
		||||
            kwargs['lang'] = lang
 | 
			
		||||
 | 
			
		||||
        kwargs = OrderedDict(kwargs)
 | 
			
		||||
 | 
			
		||||
        if attrib in self.interfaces or attrib == 'lang':
 | 
			
		||||
            del_method = "del_%s" % attrib.lower()
 | 
			
		||||
            del_method2 = "del%s" % attrib.title()
 | 
			
		||||
 
 | 
			
		||||
@@ -385,7 +385,7 @@ class TestElementBase(SlixTest):
 | 
			
		||||
            interfaces = set(('bar', 'baz'))
 | 
			
		||||
 | 
			
		||||
            def setBar(self, value):
 | 
			
		||||
                self._set_sub_text("path/to/only/bar", value);
 | 
			
		||||
                self._set_sub_text("path/to/only/bar", value)
 | 
			
		||||
 | 
			
		||||
            def getBar(self):
 | 
			
		||||
                return self._get_sub_text("path/to/only/bar")
 | 
			
		||||
@@ -394,7 +394,7 @@ class TestElementBase(SlixTest):
 | 
			
		||||
                self._del_sub("path/to/only/bar")
 | 
			
		||||
 | 
			
		||||
            def setBaz(self, value):
 | 
			
		||||
                self._set_sub_text("path/to/just/baz", value);
 | 
			
		||||
                self._set_sub_text("path/to/just/baz", value)
 | 
			
		||||
 | 
			
		||||
            def getBaz(self):
 | 
			
		||||
                return self._get_sub_text("path/to/just/baz")
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,8 @@ class TestDataForms(SlixTest):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        register_stanza_plugin(Message, xep_0004.Form)
 | 
			
		||||
        register_stanza_plugin(xep_0004.Form, xep_0004.FormField)
 | 
			
		||||
        register_stanza_plugin(xep_0004.FormField, xep_0004.FieldOption)
 | 
			
		||||
        register_stanza_plugin(xep_0004.Form, xep_0004.FormField, iterable=True)
 | 
			
		||||
        register_stanza_plugin(xep_0004.FormField, xep_0004.FieldOption, iterable=True)
 | 
			
		||||
 | 
			
		||||
    def testMultipleInstructions(self):
 | 
			
		||||
        """Testing using multiple instructions elements in a data form."""
 | 
			
		||||
@@ -68,7 +68,7 @@ class TestDataForms(SlixTest):
 | 
			
		||||
                                     'value': 'cool'},
 | 
			
		||||
                                    {'label': 'Urgh!',
 | 
			
		||||
                                     'value': 'urgh'}]}
 | 
			
		||||
        form['fields'] = fields
 | 
			
		||||
        form.set_fields(fields)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
@@ -141,13 +141,13 @@ class TestDataForms(SlixTest):
 | 
			
		||||
                                     'value': 'cool'},
 | 
			
		||||
                                    {'label': 'Urgh!',
 | 
			
		||||
                                     'value': 'urgh'}]}
 | 
			
		||||
        form['fields'] = fields
 | 
			
		||||
        form.set_fields(fields)
 | 
			
		||||
 | 
			
		||||
        form['type'] = 'submit'
 | 
			
		||||
        form['values'] = {'f1': 'username',
 | 
			
		||||
        form.set_values({'f1': 'username',
 | 
			
		||||
                          'f2': 'hunter2',
 | 
			
		||||
                          'f3': 'A long\nmultiline\nmessage',
 | 
			
		||||
                          'f4': 'cool'}
 | 
			
		||||
                          'f4': 'cool'})
 | 
			
		||||
 | 
			
		||||
        self.check(form, """
 | 
			
		||||
          <x xmlns="jabber:x:data" type="submit">
 | 
			
		||||
@@ -189,7 +189,7 @@ class TestDataForms(SlixTest):
 | 
			
		||||
                                     'value': 'cool'},
 | 
			
		||||
                                    {'label': 'Urgh!',
 | 
			
		||||
                                     'value': 'urgh'}]}
 | 
			
		||||
        form['fields'] = fields
 | 
			
		||||
        form.set_fields(fields)
 | 
			
		||||
 | 
			
		||||
        form['type'] = 'cancel'
 | 
			
		||||
 | 
			
		||||
@@ -197,5 +197,52 @@ class TestDataForms(SlixTest):
 | 
			
		||||
          <x xmlns="jabber:x:data" type="cancel" />
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
    def testReported(self):
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        form['type'] = 'result'
 | 
			
		||||
 | 
			
		||||
        form.add_reported(var='f1', ftype='text-single', label='Username')
 | 
			
		||||
 | 
			
		||||
        form.add_item({'f1': 'username@example.org'})
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="result">
 | 
			
		||||
              <reported>
 | 
			
		||||
                <field var="f1" type="text-single" label="Username" />
 | 
			
		||||
              </reported>
 | 
			
		||||
              <item>
 | 
			
		||||
                <field var="f1">
 | 
			
		||||
                  <value>username@example.org</value>
 | 
			
		||||
                </field>
 | 
			
		||||
              </item>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
    def testSetReported(self):
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        form['type'] = 'result'
 | 
			
		||||
 | 
			
		||||
        reported = {'f1': {
 | 
			
		||||
            'var': 'f1',
 | 
			
		||||
            'type': 'text-single',
 | 
			
		||||
            'label': 'Username'
 | 
			
		||||
        }}
 | 
			
		||||
 | 
			
		||||
        form.set_reported(reported)
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="result">
 | 
			
		||||
              <reported>
 | 
			
		||||
                <field var="f1" type="text-single" label="Username" />
 | 
			
		||||
              </reported>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestDataForms)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										189
									
								
								tests/test_stanza_xep_0122.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								tests/test_stanza_xep_0122.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,189 @@
 | 
			
		||||
import unittest
 | 
			
		||||
 | 
			
		||||
from slixmpp import Message
 | 
			
		||||
from slixmpp.test import SlixTest
 | 
			
		||||
import slixmpp.plugins.xep_0004 as xep_0004
 | 
			
		||||
import slixmpp.plugins.xep_0122 as xep_0122
 | 
			
		||||
from slixmpp.xmlstream import register_stanza_plugin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestDataForms(SlixTest):
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        register_stanza_plugin(Message, xep_0004.Form)
 | 
			
		||||
        register_stanza_plugin(xep_0004.Form, xep_0004.FormField, iterable=True)
 | 
			
		||||
        register_stanza_plugin(xep_0004.FormField, xep_0004.FieldOption, iterable=True)
 | 
			
		||||
        register_stanza_plugin(xep_0004.FormField, xep_0122.FormValidation)
 | 
			
		||||
 | 
			
		||||
    def test_basic_validation(self):
 | 
			
		||||
        """Testing basic validation setting and getting."""
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        field = form.add_field(var='f1',
 | 
			
		||||
                               ftype='text-single',
 | 
			
		||||
                               label='Text',
 | 
			
		||||
                               desc='A text field',
 | 
			
		||||
                               required=True,
 | 
			
		||||
                               value='Some text!')
 | 
			
		||||
 | 
			
		||||
        validation = field['validate']
 | 
			
		||||
        validation['datatype'] = 'xs:string'
 | 
			
		||||
        validation.set_basic(True)
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="form">
 | 
			
		||||
              <field var="f1" type="text-single" label="Text">
 | 
			
		||||
                <desc>A text field</desc>
 | 
			
		||||
                <required />
 | 
			
		||||
                <value>Some text!</value>
 | 
			
		||||
                <validate xmlns="http://jabber.org/protocol/xdata-validate" datatype="xs:string">
 | 
			
		||||
                    <basic/>
 | 
			
		||||
                </validate>
 | 
			
		||||
              </field>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertTrue(validation.get_basic())
 | 
			
		||||
        self.assertFalse(validation.get_open())
 | 
			
		||||
        self.assertFalse(validation.get_range())
 | 
			
		||||
        self.assertFalse(validation.get_regex())
 | 
			
		||||
 | 
			
		||||
    def test_open_validation(self):
 | 
			
		||||
        """Testing open validation setting and getting."""
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        field = form.add_field(var='f1',
 | 
			
		||||
                               ftype='text-single',
 | 
			
		||||
                               label='Text',
 | 
			
		||||
                               desc='A text field',
 | 
			
		||||
                               required=True,
 | 
			
		||||
                               value='Some text!')
 | 
			
		||||
 | 
			
		||||
        validation = field['validate']
 | 
			
		||||
        validation.set_open(True)
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="form">
 | 
			
		||||
              <field var="f1" type="text-single" label="Text">
 | 
			
		||||
                <desc>A text field</desc>
 | 
			
		||||
                <required />
 | 
			
		||||
                <value>Some text!</value>
 | 
			
		||||
                <validate xmlns="http://jabber.org/protocol/xdata-validate">
 | 
			
		||||
                    <open />
 | 
			
		||||
                </validate>
 | 
			
		||||
              </field>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertFalse(validation.get_basic())
 | 
			
		||||
        self.assertTrue(validation.get_open())
 | 
			
		||||
        self.assertFalse(validation.get_range())
 | 
			
		||||
        self.assertFalse(validation.get_regex())
 | 
			
		||||
 | 
			
		||||
    def test_regex_validation(self):
 | 
			
		||||
        """Testing regex validation setting and getting."""
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        field = form.add_field(var='f1',
 | 
			
		||||
                               ftype='text-single',
 | 
			
		||||
                               label='Text',
 | 
			
		||||
                               desc='A text field',
 | 
			
		||||
                               required=True,
 | 
			
		||||
                               value='Some text!')
 | 
			
		||||
 | 
			
		||||
        regex_value = '[0-9]+'
 | 
			
		||||
 | 
			
		||||
        validation = field['validate']
 | 
			
		||||
        validation.set_regex(regex_value)
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="form">
 | 
			
		||||
              <field var="f1" type="text-single" label="Text">
 | 
			
		||||
                <desc>A text field</desc>
 | 
			
		||||
                <required />
 | 
			
		||||
                <value>Some text!</value>
 | 
			
		||||
                <validate xmlns="http://jabber.org/protocol/xdata-validate">
 | 
			
		||||
                    <regex>[0-9]+</regex>
 | 
			
		||||
                </validate>
 | 
			
		||||
              </field>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertFalse(validation.get_basic())
 | 
			
		||||
        self.assertFalse(validation.get_open())
 | 
			
		||||
        self.assertFalse(validation.get_range())
 | 
			
		||||
        self.assertTrue(validation.get_regex())
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(regex_value, validation.get_regex())
 | 
			
		||||
 | 
			
		||||
    def test_range_validation(self):
 | 
			
		||||
        """Testing range validation setting and getting."""
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        field = form.add_field(var='f1',
 | 
			
		||||
                               ftype='text-single',
 | 
			
		||||
                               label='Text',
 | 
			
		||||
                               desc='A text field',
 | 
			
		||||
                               required=True,
 | 
			
		||||
                               value='Some text!')
 | 
			
		||||
 | 
			
		||||
        validation = field['validate']
 | 
			
		||||
        validation.set_range(True, minimum=0, maximum=10)
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="form">
 | 
			
		||||
              <field var="f1" type="text-single" label="Text">
 | 
			
		||||
                <desc>A text field</desc>
 | 
			
		||||
                <required />
 | 
			
		||||
                <value>Some text!</value>
 | 
			
		||||
                <validate xmlns="http://jabber.org/protocol/xdata-validate">
 | 
			
		||||
                    <range min="0" max="10" />
 | 
			
		||||
                </validate>
 | 
			
		||||
              </field>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
        self.assertDictEqual(dict(minimum=str(0), maximum=str(10)), validation.get_range())
 | 
			
		||||
 | 
			
		||||
    def test_reported_field_validation(self):
 | 
			
		||||
        """
 | 
			
		||||
        Testing adding validation to the field when it's stored in the reported.
 | 
			
		||||
        :return:
 | 
			
		||||
        """
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        form = msg['form']
 | 
			
		||||
        field = form.add_reported(var='f1', ftype='text-single', label='Text')
 | 
			
		||||
        validation = field['validate']
 | 
			
		||||
        validation.set_basic(True)
 | 
			
		||||
 | 
			
		||||
        form.add_item({'f1': 'Some text!'})
 | 
			
		||||
 | 
			
		||||
        self.check(msg, """
 | 
			
		||||
          <message>
 | 
			
		||||
            <x xmlns="jabber:x:data" type="form">
 | 
			
		||||
              <reported>
 | 
			
		||||
                <field var="f1" type="text-single" label="Text">
 | 
			
		||||
                  <validate xmlns="http://jabber.org/protocol/xdata-validate">
 | 
			
		||||
                    <basic />
 | 
			
		||||
                  </validate>
 | 
			
		||||
                </field>
 | 
			
		||||
              </reported>
 | 
			
		||||
              <item>
 | 
			
		||||
                <field var="f1">
 | 
			
		||||
                  <value>Some text!</value>
 | 
			
		||||
                </field>
 | 
			
		||||
              </item>
 | 
			
		||||
            </x>
 | 
			
		||||
          </message>
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestDataForms)
 | 
			
		||||
@@ -7,7 +7,6 @@ namespace='sn'
 | 
			
		||||
 | 
			
		||||
class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        pass
 | 
			
		||||
        #register_stanza_plugin(Iq, xep_0323.stanza.Request)
 | 
			
		||||
@@ -59,8 +58,8 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
        iq['req']['momentary'] = 'true'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        iq['req'].add_node("Device02", "Source02", "CacheType");
 | 
			
		||||
        iq['req'].add_node("Device44");
 | 
			
		||||
        iq['req'].add_node("Device02", "Source02", "CacheType")
 | 
			
		||||
        iq['req'].add_node("Device44")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -75,7 +74,7 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
        """
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        iq['req'].del_node("Device02");
 | 
			
		||||
        iq['req'].del_node("Device02")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -89,7 +88,7 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
        """
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        iq['req'].del_nodes();
 | 
			
		||||
        iq['req'].del_nodes()
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -115,8 +114,8 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
        iq['req']['momentary'] = 'true'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        iq['req'].add_field("Top temperature");
 | 
			
		||||
        iq['req'].add_field("Bottom temperature");
 | 
			
		||||
        iq['req'].add_field("Top temperature")
 | 
			
		||||
        iq['req'].add_field("Bottom temperature")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -237,12 +236,12 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
        msg['to'] = 'master@clayster.com/amr'
 | 
			
		||||
        msg['fields']['seqnr'] = '1'
 | 
			
		||||
 | 
			
		||||
        node = msg['fields'].add_node("Device02");
 | 
			
		||||
        ts = node.add_timestamp("2013-03-07T16:24:30");
 | 
			
		||||
        node = msg['fields'].add_node("Device02")
 | 
			
		||||
        ts = node.add_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
 | 
			
		||||
        data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K');
 | 
			
		||||
        data['momentary'] = 'true';
 | 
			
		||||
        data['automaticReadout'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K')
 | 
			
		||||
        data['momentary'] = 'true'
 | 
			
		||||
        data['automaticReadout'] = 'true'
 | 
			
		||||
 | 
			
		||||
        self.check(msg,"""
 | 
			
		||||
            <message from='device@clayster.com'
 | 
			
		||||
@@ -258,10 +257,9 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
                       """
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        node = msg['fields'].add_node("EmptyDevice");
 | 
			
		||||
        node = msg['fields'].add_node("Device04");
 | 
			
		||||
        ts = node.add_timestamp("EmptyTimestamp");
 | 
			
		||||
 | 
			
		||||
        node = msg['fields'].add_node("EmptyDevice")
 | 
			
		||||
        node = msg['fields'].add_node("Device04")
 | 
			
		||||
        ts = node.add_timestamp("EmptyTimestamp")
 | 
			
		||||
 | 
			
		||||
        self.check(msg,"""
 | 
			
		||||
            <message from='device@clayster.com'
 | 
			
		||||
@@ -281,32 +279,32 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
                       """
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        node = msg['fields'].add_node("Device77");
 | 
			
		||||
        ts = node.add_timestamp("2013-05-03T12:00:01");
 | 
			
		||||
        data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K');
 | 
			
		||||
        data['historicalDay'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="numeric", name="Speed", value="312.42", unit='km/h');
 | 
			
		||||
        data['historicalWeek'] = 'false';
 | 
			
		||||
        data = ts.add_data(typename="string", name="Temperature name", value="Bottom oil");
 | 
			
		||||
        data['historicalMonth'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="string", name="Speed name", value="Top speed");
 | 
			
		||||
        data['historicalQuarter'] = 'false';
 | 
			
		||||
        data = ts.add_data(typename="dateTime", name="T1", value="1979-01-01T00:00:00");
 | 
			
		||||
        data['historicalYear'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="dateTime", name="T2", value="2000-01-01T01:02:03");
 | 
			
		||||
        data['historicalOther'] = 'false';
 | 
			
		||||
        data = ts.add_data(typename="timeSpan", name="TS1", value="P5Y");
 | 
			
		||||
        data['missing'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="timeSpan", name="TS2", value="PT2M1S");
 | 
			
		||||
        data['manualEstimate'] = 'false';
 | 
			
		||||
        data = ts.add_data(typename="enum", name="top color", value="red", dataType="string");
 | 
			
		||||
        data['invoiced'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="enum", name="bottom color", value="black", dataType="string");
 | 
			
		||||
        data['powerFailure'] = 'false';
 | 
			
		||||
        data = ts.add_data(typename="boolean", name="Temperature real", value="false");
 | 
			
		||||
        data['historicalDay'] = 'true';
 | 
			
		||||
        data = ts.add_data(typename="boolean", name="Speed real", value="true");
 | 
			
		||||
        data['historicalWeek'] = 'false';
 | 
			
		||||
        node = msg['fields'].add_node("Device77")
 | 
			
		||||
        ts = node.add_timestamp("2013-05-03T12:00:01")
 | 
			
		||||
        data = ts.add_data(typename="numeric", name="Temperature", value="-12.42", unit='K')
 | 
			
		||||
        data['historicalDay'] = 'true'
 | 
			
		||||
        data = ts.add_data(typename="numeric", name="Speed", value="312.42", unit='km/h')
 | 
			
		||||
        data['historicalWeek'] = 'false'
 | 
			
		||||
        data = ts.add_data(typename="string", name="Temperature name", value="Bottom oil")
 | 
			
		||||
        data['historicalMonth'] = 'true'
 | 
			
		||||
        data = ts.add_data(typename="string", name="Speed name", value="Top speed")
 | 
			
		||||
        data['historicalQuarter'] = 'false'
 | 
			
		||||
        data = ts.add_data(typename="dateTime", name="T1", value="1979-01-01T00:00:00")
 | 
			
		||||
        data['historicalYear'] = 'true'
 | 
			
		||||
        data = ts.add_data(typename="dateTime", name="T2", value="2000-01-01T01:02:03")
 | 
			
		||||
        data['historicalOther'] = 'false'
 | 
			
		||||
        data = ts.add_data(typename="timeSpan", name="TS1", value="P5Y")
 | 
			
		||||
        data['missing'] = 'true'
 | 
			
		||||
        data = ts.add_data(typename="timeSpan", name="TS2", value="PT2M1S")
 | 
			
		||||
        data['manualEstimate'] = 'false'
 | 
			
		||||
        data = ts.add_data(typename="enum", name="top color", value="red", dataType="string")
 | 
			
		||||
        data['invoiced'] = 'true'
 | 
			
		||||
        data = ts.add_data(typename="enum", name="bottom color", value="black", dataType="string")
 | 
			
		||||
        data['powerFailure'] = 'false'
 | 
			
		||||
        data = ts.add_data(typename="boolean", name="Temperature real", value="false")
 | 
			
		||||
        data['historicalDay'] = 'true'
 | 
			
		||||
        data = ts.add_data(typename="boolean", name="Speed real", value="true")
 | 
			
		||||
        data['historicalWeek'] = 'false'
 | 
			
		||||
 | 
			
		||||
        self.check(msg,"""
 | 
			
		||||
            <message from='device@clayster.com'
 | 
			
		||||
@@ -344,19 +342,17 @@ class TestSensorDataStanzas(SlixTest):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def testTimestamp(self):
 | 
			
		||||
        msg = self.Message();
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
 | 
			
		||||
        msg['from'] = 'device@clayster.com'
 | 
			
		||||
        msg['to'] = 'master@clayster.com/amr'
 | 
			
		||||
        msg['fields']['seqnr'] = '1'
 | 
			
		||||
 | 
			
		||||
        node = msg['fields'].add_node("Device02");
 | 
			
		||||
        node = msg['fields'].add_node("Device03");
 | 
			
		||||
 | 
			
		||||
        ts = node.add_timestamp("2013-03-07T16:24:30");
 | 
			
		||||
        ts = node.add_timestamp("2013-03-07T16:24:31");
 | 
			
		||||
 | 
			
		||||
        node = msg['fields'].add_node("Device02")
 | 
			
		||||
        node = msg['fields'].add_node("Device03")
 | 
			
		||||
 | 
			
		||||
        ts = node.add_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
        ts = node.add_timestamp("2013-03-07T16:24:31")
 | 
			
		||||
 | 
			
		||||
        self.check(msg,"""
 | 
			
		||||
            <message from='device@clayster.com'
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,6 @@ namespace='sn'
 | 
			
		||||
 | 
			
		||||
class TestControlStanzas(SlixTest):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
@@ -29,8 +28,8 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        iq['from'] = 'master@clayster.com/amr'
 | 
			
		||||
        iq['to'] = 'device@clayster.com'
 | 
			
		||||
        iq['id'] = '1'
 | 
			
		||||
        iq['set'].add_node("Device02", "Source02", "MyCacheType");
 | 
			
		||||
        iq['set'].add_node("Device15");
 | 
			
		||||
        iq['set'].add_node("Device02", "Source02", "MyCacheType")
 | 
			
		||||
        iq['set'].add_node("Device15")
 | 
			
		||||
        iq['set'].add_data("Tjohej", "boolean", "true")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
@@ -47,7 +46,7 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        """
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        iq['set'].del_node("Device02");
 | 
			
		||||
        iq['set'].del_node("Device02")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -62,7 +61,7 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        """
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        iq['set'].del_nodes();
 | 
			
		||||
        iq['set'].del_nodes()
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -84,8 +83,8 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        msg = self.Message()
 | 
			
		||||
        msg['from'] = 'master@clayster.com/amr'
 | 
			
		||||
        msg['to'] = 'device@clayster.com'
 | 
			
		||||
        msg['set'].add_node("Device02");
 | 
			
		||||
        msg['set'].add_node("Device15");
 | 
			
		||||
        msg['set'].add_node("Device02")
 | 
			
		||||
        msg['set'].add_node("Device15")
 | 
			
		||||
        msg['set'].add_data("Tjohej", "boolean", "true")
 | 
			
		||||
 | 
			
		||||
        self.check(msg,"""
 | 
			
		||||
@@ -111,7 +110,7 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        iq['from'] = 'master@clayster.com/amr'
 | 
			
		||||
        iq['to'] = 'device@clayster.com'
 | 
			
		||||
        iq['id'] = '8'
 | 
			
		||||
        iq['setResponse']['responseCode'] = "OK";
 | 
			
		||||
        iq['setResponse']['responseCode'] = "OK"
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='result'
 | 
			
		||||
@@ -128,10 +127,9 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        iq['from'] = 'master@clayster.com/amr'
 | 
			
		||||
        iq['to'] = 'device@clayster.com'
 | 
			
		||||
        iq['id'] = '9'
 | 
			
		||||
        iq['setResponse']['responseCode'] = "OtherError";
 | 
			
		||||
        iq['setResponse']['error']['var'] = "Output";
 | 
			
		||||
        iq['setResponse']['error']['text'] = "Test of other error.!";
 | 
			
		||||
 | 
			
		||||
        iq['setResponse']['responseCode'] = "OtherError"
 | 
			
		||||
        iq['setResponse']['error']['var'] = "Output"
 | 
			
		||||
        iq['setResponse']['error']['text'] = "Test of other error.!"
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='error'
 | 
			
		||||
@@ -150,11 +148,10 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        iq['from'] = 'master@clayster.com/amr'
 | 
			
		||||
        iq['to'] = 'device@clayster.com'
 | 
			
		||||
        iq['id'] = '9'
 | 
			
		||||
        iq['setResponse']['responseCode'] = "NotFound";
 | 
			
		||||
        iq['setResponse'].add_node("Device17", "Source09");
 | 
			
		||||
        iq['setResponse'].add_node("Device18", "Source09");
 | 
			
		||||
        iq['setResponse'].add_data("Tjohopp");
 | 
			
		||||
 | 
			
		||||
        iq['setResponse']['responseCode'] = "NotFound"
 | 
			
		||||
        iq['setResponse'].add_node("Device17", "Source09")
 | 
			
		||||
        iq['setResponse'].add_node("Device18", "Source09")
 | 
			
		||||
        iq['setResponse'].add_data("Tjohopp")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='error'
 | 
			
		||||
@@ -179,38 +176,38 @@ class TestControlStanzas(SlixTest):
 | 
			
		||||
        iq['from'] = 'master@clayster.com/amr'
 | 
			
		||||
        iq['to'] = 'device@clayster.com'
 | 
			
		||||
        iq['id'] = '1'
 | 
			
		||||
        iq['set'].add_node("Device02", "Source02", "MyCacheType");
 | 
			
		||||
        iq['set'].add_node("Device15");
 | 
			
		||||
        iq['set'].add_node("Device02", "Source02", "MyCacheType")
 | 
			
		||||
        iq['set'].add_node("Device15")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("Tjohej", "boolean", "true");
 | 
			
		||||
        iq['set'].add_data("Tjohej2", "boolean", "false");
 | 
			
		||||
        iq['set'].add_data("Tjohej", "boolean", "true")
 | 
			
		||||
        iq['set'].add_data("Tjohej2", "boolean", "false")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejC", "color", "FF00FF");
 | 
			
		||||
        iq['set'].add_data("TjohejC2", "color", "00FF00");
 | 
			
		||||
        iq['set'].add_data("TjohejC", "color", "FF00FF")
 | 
			
		||||
        iq['set'].add_data("TjohejC2", "color", "00FF00")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejS", "string", "String1");
 | 
			
		||||
        iq['set'].add_data("TjohejS2", "string", "String2");
 | 
			
		||||
        iq['set'].add_data("TjohejS", "string", "String1")
 | 
			
		||||
        iq['set'].add_data("TjohejS2", "string", "String2")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejDate", "date", "2012-01-01");
 | 
			
		||||
        iq['set'].add_data("TjohejDate2", "date", "1900-12-03");
 | 
			
		||||
        iq['set'].add_data("TjohejDate", "date", "2012-01-01")
 | 
			
		||||
        iq['set'].add_data("TjohejDate2", "date", "1900-12-03")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejDateT4", "dateTime", "1900-12-03 12:30");
 | 
			
		||||
        iq['set'].add_data("TjohejDateT2", "dateTime", "1900-12-03 11:22");
 | 
			
		||||
        iq['set'].add_data("TjohejDateT4", "dateTime", "1900-12-03 12:30")
 | 
			
		||||
        iq['set'].add_data("TjohejDateT2", "dateTime", "1900-12-03 11:22")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejDouble2", "double", "200.22");
 | 
			
		||||
        iq['set'].add_data("TjohejDouble3", "double", "-12232131.3333");
 | 
			
		||||
        iq['set'].add_data("TjohejDouble2", "double", "200.22")
 | 
			
		||||
        iq['set'].add_data("TjohejDouble3", "double", "-12232131.3333")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejDur", "duration", "P5Y");
 | 
			
		||||
        iq['set'].add_data("TjohejDur2", "duration", "PT2M1S");
 | 
			
		||||
        iq['set'].add_data("TjohejDur", "duration", "P5Y")
 | 
			
		||||
        iq['set'].add_data("TjohejDur2", "duration", "PT2M1S")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejInt", "int", "1");
 | 
			
		||||
        iq['set'].add_data("TjohejInt2", "int", "-42");
 | 
			
		||||
        iq['set'].add_data("TjohejInt", "int", "1")
 | 
			
		||||
        iq['set'].add_data("TjohejInt2", "int", "-42")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejLong", "long", "123456789098");
 | 
			
		||||
        iq['set'].add_data("TjohejLong2", "long", "-90983243827489374");
 | 
			
		||||
        iq['set'].add_data("TjohejLong", "long", "123456789098")
 | 
			
		||||
        iq['set'].add_data("TjohejLong2", "long", "-90983243827489374")
 | 
			
		||||
 | 
			
		||||
        iq['set'].add_data("TjohejTime", "time", "23:59");
 | 
			
		||||
        iq['set'].add_data("TjohejTime2", "time", "12:00");
 | 
			
		||||
        iq['set'].add_data("TjohejTime", "time", "23:59")
 | 
			
		||||
        iq['set'].add_data("TjohejTime2", "time", "12:00")
 | 
			
		||||
 | 
			
		||||
        self.check(iq,"""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
 
 | 
			
		||||
@@ -119,7 +119,8 @@ class TestAdHocCommands(SlixTest):
 | 
			
		||||
        def handle_command(iq, session):
 | 
			
		||||
 | 
			
		||||
            def handle_form(form, session):
 | 
			
		||||
                results.append(form['values']['foo'])
 | 
			
		||||
                results.append(form.get_values()['foo'])
 | 
			
		||||
                session['payload'] = None
 | 
			
		||||
 | 
			
		||||
            form = self.xmpp['xep_0004'].makeForm('form')
 | 
			
		||||
            form.addField(var='foo', ftype='text-single', label='Foo')
 | 
			
		||||
@@ -191,10 +192,11 @@ class TestAdHocCommands(SlixTest):
 | 
			
		||||
        def handle_command(iq, session):
 | 
			
		||||
 | 
			
		||||
            def handle_step2(form, session):
 | 
			
		||||
                results.append(form['values']['bar'])
 | 
			
		||||
                results.append(form.get_values()['bar'])
 | 
			
		||||
                session['payload'] = None
 | 
			
		||||
 | 
			
		||||
            def handle_step1(form, session):
 | 
			
		||||
                results.append(form['values']['foo'])
 | 
			
		||||
                results.append(form.get_values()['foo'])
 | 
			
		||||
 | 
			
		||||
                form = self.xmpp['xep_0004'].makeForm('form')
 | 
			
		||||
                form.addField(var='bar', ftype='text-single', label='Bar')
 | 
			
		||||
@@ -426,7 +428,8 @@ class TestAdHocCommands(SlixTest):
 | 
			
		||||
 | 
			
		||||
            def handle_form(forms, session):
 | 
			
		||||
                for form in forms:
 | 
			
		||||
                    results.append(form['values']['FORM_TYPE'])
 | 
			
		||||
                    results.append(form.get_values()['FORM_TYPE'])
 | 
			
		||||
                session['payload'] = None
 | 
			
		||||
 | 
			
		||||
            form1 = self.xmpp['xep_0004'].makeForm('form')
 | 
			
		||||
            form1.addField(var='FORM_TYPE', ftype='hidden', value='form_1')
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def _time_now(self):
 | 
			
		||||
        return datetime.datetime.now().replace(microsecond=0).isoformat();
 | 
			
		||||
        return datetime.datetime.now().replace(microsecond=0).isoformat()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        self.stream_close()
 | 
			
		||||
@@ -29,12 +29,12 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
 | 
			
		||||
        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -73,7 +73,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323']._set_authenticated("darth@deathstar.com");
 | 
			
		||||
        self.xmpp['xep_0323']._set_authenticated("darth@deathstar.com")
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -101,8 +101,8 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -157,11 +157,11 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -236,15 +236,15 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field(name='Current', typename="numeric", unit="A");
 | 
			
		||||
        myDevice._add_field(name='Height', typename="string");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field(name='Current', typename="numeric", unit="A")
 | 
			
		||||
        myDevice._add_field(name='Height', typename="string")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -308,15 +308,15 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field(name='Current', typename="numeric", unit="A");
 | 
			
		||||
        myDevice._add_field(name='Height', typename="string");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.4", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field(name='Current', typename="numeric", unit="A")
 | 
			
		||||
        myDevice._add_field(name='Height', typename="string")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.6", timestamp="2000-01-01T01:01:02")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Height", value="115 m", timestamp="2000-01-01T01:01:02", flags={"invoiced": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -379,7 +379,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", callback=None);
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", callback=None)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -390,7 +390,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=None);
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=None)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -404,7 +404,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", fields=['Temperature', 'Voltage'], callback=None);
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", fields=['Temperature', 'Voltage'], callback=None)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -424,13 +424,13 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        results = []
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
 | 
			
		||||
            if (result == "rejected") and (error_msg == "Invalid device Device22"):
 | 
			
		||||
                results.append("rejected");
 | 
			
		||||
                results.append("rejected")
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback);
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -456,7 +456,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.failUnless(results == ["rejected"],
 | 
			
		||||
                "Rejected callback was not properly executed");
 | 
			
		||||
                "Rejected callback was not properly executed")
 | 
			
		||||
 | 
			
		||||
    def testRequestAcceptedAPI(self):
 | 
			
		||||
 | 
			
		||||
@@ -464,12 +464,12 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        results = []
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback);
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33', 'Device22'], callback=my_callback)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -493,7 +493,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.failUnless(results == ["accepted"],
 | 
			
		||||
                "Accepted callback was not properly executed");
 | 
			
		||||
                "Accepted callback was not properly executed")
 | 
			
		||||
 | 
			
		||||
    def testRequestFieldsAPI(self):
 | 
			
		||||
 | 
			
		||||
@@ -501,17 +501,17 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        callback_data = {};
 | 
			
		||||
        results = []
 | 
			
		||||
        callback_data = {}
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
            if result == "fields":
 | 
			
		||||
                callback_data["nodeId"] = nodeId;
 | 
			
		||||
                callback_data["timestamp"] = timestamp;
 | 
			
		||||
                callback_data["error_msg"] = error_msg;
 | 
			
		||||
                callback_data["nodeId"] = nodeId
 | 
			
		||||
                callback_data["timestamp"] = timestamp
 | 
			
		||||
                callback_data["error_msg"] = error_msg
 | 
			
		||||
                for f in fields:
 | 
			
		||||
                    callback_data["field_" + f['name']] = f;
 | 
			
		||||
                    callback_data["field_" + f['name']] = f
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost",
 | 
			
		||||
                                            to_jid="you@google.com",
 | 
			
		||||
@@ -560,24 +560,24 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            </message>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.failUnlessEqual(results, ["accepted","fields","done"]);
 | 
			
		||||
        self.failUnlessEqual(results, ["accepted","fields","done"])
 | 
			
		||||
        # self.assertIn("nodeId", callback_data);
 | 
			
		||||
        self.assertTrue("nodeId" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["nodeId"], "Device33");
 | 
			
		||||
        self.failUnlessEqual(callback_data["nodeId"], "Device33")
 | 
			
		||||
        # self.assertIn("timestamp", callback_data);
 | 
			
		||||
        self.assertTrue("timestamp" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02");
 | 
			
		||||
        self.assertTrue("timestamp" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02")
 | 
			
		||||
        #self.assertIn("field_Voltage", callback_data);
 | 
			
		||||
        self.assertTrue("field_Voltage" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}});
 | 
			
		||||
        self.assertTrue("field_Voltage" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}})
 | 
			
		||||
        #self.assertIn("field_TestBool", callback_data);
 | 
			
		||||
        self.assertTrue("field_TestBool" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" });
 | 
			
		||||
        self.assertTrue("field_TestBool" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" })
 | 
			
		||||
 | 
			
		||||
    def testServiceDiscoveryClient(self):
 | 
			
		||||
        self.stream_start(mode='client',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323']);
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
        <iq type='get'
 | 
			
		||||
@@ -602,7 +602,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
    def testServiceDiscoveryComponent(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323']);
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
        <iq type='get'
 | 
			
		||||
@@ -631,21 +631,20 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        callback_data = {};
 | 
			
		||||
        results = []
 | 
			
		||||
        callback_data = {}
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeId=None, timestamp=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
            if result == "failure":
 | 
			
		||||
                callback_data["nodeId"] = nodeId;
 | 
			
		||||
                callback_data["timestamp"] = timestamp;
 | 
			
		||||
                callback_data["error_msg"] = error_msg;
 | 
			
		||||
                callback_data["nodeId"] = nodeId
 | 
			
		||||
                callback_data["timestamp"] = timestamp
 | 
			
		||||
                callback_data["error_msg"] = error_msg
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost",
 | 
			
		||||
                                           to_jid="you@google.com",
 | 
			
		||||
                                           nodeIds=['Device33'],
 | 
			
		||||
                                           callback=my_callback)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
                from='tester@localhost'
 | 
			
		||||
@@ -677,26 +676,26 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
 | 
			
		||||
        self.failUnlessEqual(results, ["accepted","failure"]);
 | 
			
		||||
        # self.assertIn("nodeId", callback_data);
 | 
			
		||||
        self.assertTrue("nodeId" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["nodeId"], "Device33");
 | 
			
		||||
        self.assertTrue("nodeId" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["nodeId"], "Device33")
 | 
			
		||||
        # self.assertIn("timestamp", callback_data);
 | 
			
		||||
        self.assertTrue("timestamp" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["timestamp"], "2013-03-07T17:13:30");
 | 
			
		||||
        self.assertTrue("timestamp" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["timestamp"], "2013-03-07T17:13:30")
 | 
			
		||||
        # self.assertIn("error_msg", callback_data);
 | 
			
		||||
        self.assertTrue("error_msg" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["error_msg"], "Timeout.");
 | 
			
		||||
        self.assertTrue("error_msg" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["error_msg"], "Timeout.")
 | 
			
		||||
 | 
			
		||||
    def testDelayedRequest(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
 | 
			
		||||
        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        dtnow = datetime.datetime.now()
 | 
			
		||||
        ts_2sec = datetime.timedelta(0,2)
 | 
			
		||||
@@ -748,12 +747,12 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
 | 
			
		||||
        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        dtnow = datetime.datetime.now()
 | 
			
		||||
        ts_2sec = datetime.timedelta(0,2)
 | 
			
		||||
@@ -809,13 +808,13 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -879,13 +878,13 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -949,13 +948,13 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device44");
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V");
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"});
 | 
			
		||||
        myDevice = Device("Device44")
 | 
			
		||||
        myDevice._add_field(name='Voltage', typename="numeric", unit="V")
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.1", timestamp="2000-01-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.2", timestamp="2000-02-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
        myDevice._add_field_timestamp_data(name="Voltage", value="230.3", timestamp="2000-03-01T00:01:02", flags={"invoiced": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node('Device44', myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        print("."),
 | 
			
		||||
 | 
			
		||||
@@ -1005,17 +1004,17 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        callback_data = {};
 | 
			
		||||
        results = []
 | 
			
		||||
        callback_data = {}
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
            if result == "fields":
 | 
			
		||||
                callback_data["nodeId"] = nodeId;
 | 
			
		||||
                callback_data["timestamp"] = timestamp;
 | 
			
		||||
                callback_data["error_msg"] = error_msg;
 | 
			
		||||
                callback_data["nodeId"] = nodeId
 | 
			
		||||
                callback_data["timestamp"] = timestamp
 | 
			
		||||
                callback_data["error_msg"] = error_msg
 | 
			
		||||
                for f in fields:
 | 
			
		||||
                    callback_data["field_" + f['name']] = f;
 | 
			
		||||
                    callback_data["field_" + f['name']] = f
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].request_data(from_jid="tester@localhost",
 | 
			
		||||
                                           to_jid="you@google.com",
 | 
			
		||||
@@ -1073,17 +1072,17 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
 | 
			
		||||
        self.failUnlessEqual(results, ["queued","started","fields","done"]);
 | 
			
		||||
        # self.assertIn("nodeId", callback_data);
 | 
			
		||||
        self.assertTrue("nodeId" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["nodeId"], "Device33");
 | 
			
		||||
        self.assertTrue("nodeId" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["nodeId"], "Device33")
 | 
			
		||||
        # self.assertIn("timestamp", callback_data);
 | 
			
		||||
        self.assertTrue("timestamp" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02");
 | 
			
		||||
        self.assertTrue("timestamp" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["timestamp"], "2000-01-01T00:01:02")
 | 
			
		||||
        # self.assertIn("field_Voltage", callback_data);
 | 
			
		||||
        self.assertTrue("field_Voltage" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}});
 | 
			
		||||
        self.assertTrue("field_Voltage" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_Voltage"], {"name": "Voltage", "value": "230.4", "typename": "numeric", "unit": "V", "flags": {"invoiced": "true"}})
 | 
			
		||||
        # self.assertIn("field_TestBool", callback_data);
 | 
			
		||||
        self.assertTrue("field_TestBool" in callback_data);
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" });
 | 
			
		||||
        self.assertTrue("field_TestBool" in callback_data)
 | 
			
		||||
        self.failUnlessEqual(callback_data["field_TestBool"], {"name": "TestBool", "value": "true", "typename": "boolean" })
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def testRequestFieldsCancelAPI(self):
 | 
			
		||||
@@ -1092,12 +1091,12 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        results = []
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeId=None, timestamp=None, fields=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
 | 
			
		||||
        session = self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback);
 | 
			
		||||
        session = self.xmpp['xep_0323'].request_data(from_jid="tester@localhost", to_jid="you@google.com", nodeIds=['Device33'], callback=my_callback)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -1119,7 +1118,7 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].cancel_request(session=session);
 | 
			
		||||
        self.xmpp['xep_0323'].cancel_request(session=session)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='get'
 | 
			
		||||
@@ -1139,19 +1138,19 @@ class TestStreamSensorData(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.failUnlessEqual(results, ["accepted","cancelled"]);
 | 
			
		||||
        self.failUnlessEqual(results, ["accepted","cancelled"])
 | 
			
		||||
 | 
			
		||||
    def testDelayedRequestCancel(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0323'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_field(name="Temperature", typename="numeric", unit="°C")
 | 
			
		||||
        myDevice._set_momentary_timestamp("2013-03-07T16:24:30")
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"});
 | 
			
		||||
        myDevice._add_field_momentary_data("Temperature", "23.4", flags={"automaticReadout": "true"})
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0323'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        dtnow = datetime.datetime.now()
 | 
			
		||||
        ts_2sec = datetime.timedelta(0,2)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def _time_now(self):
 | 
			
		||||
        return datetime.datetime.now().replace(microsecond=0).isoformat();
 | 
			
		||||
        return datetime.datetime.now().replace(microsecond=0).isoformat()
 | 
			
		||||
 | 
			
		||||
    def tearDown(self):
 | 
			
		||||
        self.stream_close()
 | 
			
		||||
@@ -38,10 +38,10 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15")
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -63,23 +63,23 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "17");
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "17")
 | 
			
		||||
 | 
			
		||||
    def testRequestSetMulti(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15");
 | 
			
		||||
        myDevice._add_control_field(name="Startup", typename="date", value="2013-01-03");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15")
 | 
			
		||||
        myDevice._add_control_field(name="Startup", typename="date", value="2013-01-03")
 | 
			
		||||
 | 
			
		||||
        myDevice2 = Device("Device23");
 | 
			
		||||
        myDevice2._add_control_field(name="Temperature", typename="int", value="19");
 | 
			
		||||
        myDevice2._add_control_field(name="Startup", typename="date", value="2013-01-09");
 | 
			
		||||
        myDevice2 = Device("Device23")
 | 
			
		||||
        myDevice2._add_control_field(name="Temperature", typename="int", value="19")
 | 
			
		||||
        myDevice2._add_control_field(name="Startup", typename="date", value="2013-01-09")
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice2, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice2, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -102,8 +102,8 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "17");
 | 
			
		||||
        self.assertEqual(myDevice2._get_field_value("Temperature"), "19");
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "17")
 | 
			
		||||
        self.assertEqual(myDevice2._get_field_value("Temperature"), "19")
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -128,20 +128,20 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "20");
 | 
			
		||||
        self.assertEqual(myDevice2._get_field_value("Temperature"), "20");
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Startup"), "2013-02-01");
 | 
			
		||||
        self.assertEqual(myDevice2._get_field_value("Startup"), "2013-02-01");
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "20")
 | 
			
		||||
        self.assertEqual(myDevice2._get_field_value("Temperature"), "20")
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Startup"), "2013-02-01")
 | 
			
		||||
        self.assertEqual(myDevice2._get_field_value("Startup"), "2013-02-01")
 | 
			
		||||
 | 
			
		||||
    def testRequestSetFail(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device23");
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15");
 | 
			
		||||
        myDevice = Device("Device23")
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15")
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device23", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -166,18 +166,18 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "15");
 | 
			
		||||
        self.assertFalse(myDevice.has_control_field("Voltage", "int"));
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "15")
 | 
			
		||||
        self.assertFalse(myDevice.has_control_field("Voltage", "int"))
 | 
			
		||||
 | 
			
		||||
    def testDirectSetOk(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15")
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <message
 | 
			
		||||
@@ -191,17 +191,17 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
 | 
			
		||||
        time.sleep(0.5)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "17");
 | 
			
		||||
        self.assertEqual(myDevice._get_field_value("Temperature"), "17")
 | 
			
		||||
 | 
			
		||||
    def testDirectSetFail(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        myDevice = Device("Device22");
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15");
 | 
			
		||||
        myDevice = Device("Device22")
 | 
			
		||||
        myDevice._add_control_field(name="Temperature", typename="int", value="15")
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5);
 | 
			
		||||
        self.xmpp['xep_0325'].register_node(nodeId="Device22", device=myDevice, commTimeout=0.5)
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
            <message
 | 
			
		||||
@@ -223,16 +223,16 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        results = []
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
 | 
			
		||||
        fields = []
 | 
			
		||||
        fields.append(("Temperature", "double", "20.5"))
 | 
			
		||||
        fields.append(("TemperatureAlarmSetting", "string", "High"))
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback);
 | 
			
		||||
        self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -265,16 +265,16 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        results = [];
 | 
			
		||||
        results = []
 | 
			
		||||
 | 
			
		||||
        def my_callback(from_jid, result, nodeIds=None, fields=None, error_msg=None):
 | 
			
		||||
            results.append(result);
 | 
			
		||||
            results.append(result)
 | 
			
		||||
 | 
			
		||||
        fields = []
 | 
			
		||||
        fields.append(("Temperature", "double", "20.5"))
 | 
			
		||||
        fields.append(("TemperatureAlarmSetting", "string", "High"))
 | 
			
		||||
 | 
			
		||||
        self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback);
 | 
			
		||||
        self.xmpp['xep_0325'].set_request(from_jid="tester@localhost", to_jid="you@google.com", fields=fields, nodeIds=['Device33', 'Device22'], callback=my_callback)
 | 
			
		||||
 | 
			
		||||
        self.send("""
 | 
			
		||||
            <iq type='set'
 | 
			
		||||
@@ -301,12 +301,12 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
            </iq>
 | 
			
		||||
            """)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(results, ["OtherError"]);
 | 
			
		||||
        self.assertEqual(results, ["OtherError"])
 | 
			
		||||
 | 
			
		||||
    def testServiceDiscoveryClient(self):
 | 
			
		||||
        self.stream_start(mode='client',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325']);
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
        <iq type='get'
 | 
			
		||||
@@ -331,7 +331,7 @@ class TestStreamControl(SlixTest):
 | 
			
		||||
    def testServiceDiscoveryComponent(self):
 | 
			
		||||
        self.stream_start(mode='component',
 | 
			
		||||
                          plugins=['xep_0030',
 | 
			
		||||
                                   'xep_0325']);
 | 
			
		||||
                                   'xep_0325'])
 | 
			
		||||
 | 
			
		||||
        self.recv("""
 | 
			
		||||
        <iq type='get'
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user