Compare commits

...

126 Commits

Author SHA1 Message Date
mathieui
4512248901
Merge branch 'develop' of https://github.com/fritzy/SleekXMPP into sleek-merge
Conflicts:
	README.rst
	examples/IoT_TestDevice.py
	examples/disco_browser.py
	setup.py
	sleekxmpp/jid.py
	sleekxmpp/plugins/google/auth/stanza.py
	sleekxmpp/plugins/google/gmail/notifications.py
	sleekxmpp/plugins/google/nosave/stanza.py
	sleekxmpp/plugins/google/settings/settings.py
	sleekxmpp/thirdparty/__init__.py
	sleekxmpp/thirdparty/socks.py
	sleekxmpp/thirdparty/statemachine.py
	sleekxmpp/util/__init__.py
	sleekxmpp/xmlstream/xmlstream.py
	slixmpp/basexmpp.py
	slixmpp/plugins/xep_0004/stanza/form.py
	slixmpp/plugins/xep_0009/rpc.py
	slixmpp/plugins/xep_0050/adhoc.py
	slixmpp/plugins/xep_0065/proxy.py
	slixmpp/plugins/xep_0084/stanza.py
	slixmpp/plugins/xep_0202/time.py
	slixmpp/plugins/xep_0323/sensordata.py
	slixmpp/plugins/xep_0325/control.py
	slixmpp/plugins/xep_0325/stanza/control.py
	slixmpp/roster/single.py
	slixmpp/stanza/atom.py
	slixmpp/stanza/rootstanza.py
	slixmpp/test/slixtest.py
	slixmpp/util/sasl/mechanisms.py
	slixmpp/version.py
	slixmpp/xmlstream/stanzabase.py
	tests/test_stanza_xep_0323.py
	tests/test_stanza_xep_0325.py
	tests/test_stream_xep_0323.py
	tests/test_stream_xep_0325.py
2015-09-23 23:15:09 +02:00
Mike Taylor
4305eddb4f Merge pull request #397 from rerobins/xep_0050_updates
Xep 0050 updates
2015-09-18 16:18:41 -04:00
Robert Robinson
c2dc44cfd1 Merge branch 'develop' into xep_0050_updates
# Conflicts:
#	tests/test_stream_xep_0050.py
2015-09-18 13:35:28 -06:00
Robert Robinson
5fc14de32e Merge pull request #3 from fritzy/develop
Merge to fritzy_master
2015-09-18 13:30:30 -06:00
Mike Taylor
d245558fd5 Merge pull request #396 from rerobins/add_xep_0122
XEP_0122: Add support for form validation
2015-09-18 15:15:27 -04:00
Mike Taylor
9d45370e8a Merge pull request #393 from aalba6675/fix/time
Only send time if Iq type is get.
2015-09-18 15:15:01 -04:00
Mike Taylor
cc1cc61d36 Merge pull request #392 from aalba6675/fix/tel_number
Do not overwrite telephone numbers
2015-09-18 15:14:35 -04:00
Mike Taylor
c6740a4908 Merge pull request #389 from alexdraga/develop
Add get users by affiliation.
2015-09-18 15:13:54 -04:00
Mike Taylor
55114bcffe Merge pull request #384 from elya5/patch-1
Fix UnboundlocalError in disco_browser.py example
2015-09-18 15:13:30 -04:00
Mike Taylor
4fa5dedc47 Merge pull request #386 from jdowner/develop-iot
iot: only add the 'done' field when all devices are done
2015-09-18 15:13:07 -04:00
Mike Taylor
5525ef2285 Merge pull request #395 from rerobins/refactor_forms
XEP_0004: Data Forms use register_stanza_plugin
2015-09-18 15:11:47 -04:00
Robert Robinson
a7ac969215 register_Stanza_plugin shouldn't be iterable
Should not use iterable for registering the stanza plugins.
2015-09-17 16:21:54 -06:00
Robert Robinson
329cb5a9f8 Add 0122 to plugin/__init__.py __all__ 2015-09-17 16:21:13 -06:00
Robert Robinson
d9b47b33f5 Update __init__.py
changed xep_0121 to xep_0122
2015-09-15 10:20:37 -06:00
Robert Robinson
3582ac9941 Merge branch 'add_xep_0122' of https://github.com/rerobins/SleekXMPP into add_xep_0122 2015-09-15 10:12:50 -06:00
Robert Robinson
2a127a57a7 Add test case Reported->Data Form Validation
Add a test case that will verify that reported fields can contain data form validation data.
2015-09-15 10:09:06 -06:00
Robert Robinson
7059400020 Merge branch 'refactor_forms' into add_xep_0122 2015-09-15 10:07:34 -06:00
Robert Robinson
0b14ef82d4 Add test case for reported and items
Previous stanza test cases didn't have test cases for reported and item field types in forms.   This fixes that issue.

Modified stanzabase to use an ordered dict so that can guarentee the that 'items' in a form are added after reported.  Also updated the set of interfaces that are stored in Form to be a ordered set.  Used the order set implementation from:  https://code.activestate.com/recipes/576694/

The OrderedSet implementation is licensed under the MIT license and is developed by the same developer of the ordereddict.
2015-09-15 10:05:53 -06:00
Robert Robinson
83953af53d Missing xep_122 dir in setup.py 2015-09-14 20:28:55 -06:00
Robert Robinson
110cf25c6d Add plugin support 2015-09-14 17:06:07 -06:00
Robert Robinson
f2bf6072ec Add plugin
(cherry picked from commit 2296d56)
2015-09-14 17:04:43 -06:00
Robert Robinson
5f9abe2e0e Working through test case issues.
(cherry picked from commit 6b58cef)
2015-09-14 17:04:16 -06:00
Robert Robinson
ea65b672e7 Initial cut at getting the stanzas to work.
(cherry picked from commit 8c7df49)
2015-09-14 17:04:08 -06:00
Robert Robinson
93c705fb31 Fix xep_0050 changes after form refactor. 2015-09-14 17:00:53 -06:00
Robert Robinson
0724f623bb Force forms and fields to use plugin resolution
Instead of using the interface/subinterface code that was currently being implemented for the plugin.
(cherry picked from commit 1467ec7)
2015-09-14 16:46:36 -06:00
Robert Robinson
ffb2b6bc04 Update test_stream_xep_0050.py
Fix Unit Test for adhoc 50 stream.
2015-09-12 20:08:21 -06:00
Robert Robinson
4a24f58be2 XEP0050: Add support for payload in completed response
When sending the command to complete the task, the adhoc plugin does not provide the ability to send a payload from the _handle_command_complete method.
2015-09-03 10:15:41 -06:00
Mike Taylor
da14ce16ec Merge pull request #394 from sangeeths/misc_updates
adding 'id' to self['xep_0332'].send_request()
2015-08-27 13:00:34 -04:00
Sangeeth Saravanaraj
18e5abb9dd adding 'id' to self['xep_0332'].send_request() 2015-08-27 13:24:01 +05:30
Richard Chan
1a75b76916 Only send time if Iq type is get. 2015-08-25 18:21:58 +08:00
Richard Chan
53b56899a0 Do not overwrite telephone numbers; otherwise all TEL/NUMBER received
from a server will be blank.
2015-08-25 18:11:54 +08:00
Aleksandr Draga
a366482551 Add get users by affiliation. 2015-08-10 15:34:27 +03:00
Mike Taylor
abcec1e2d3 Merge pull request #388 from sangeeths/misc_updates
Retaining 'id' in the response and error stanzas
2015-08-01 14:04:22 -04:00
Sangeeth Saravanaraj
eeab646bfa Retaining 'id' in the response and error stanzas 2015-08-01 17:47:03 +05:30
Mike Taylor
2c69144189 Merge pull request #387 from mcella/378
Fixes #378: must acquire JID_CACHE_LOCK before adding to JID_CACHE
2015-07-31 11:21:01 -04:00
Michele Cella
f54ebec654 Fixes #378: must acquire JID_CACHE_LOCK before adding to JID_CACHE 2015-07-31 11:55:50 +02:00
Joshua Downer
2042e1a4d5 iot: only add the 'done' field when all devices are done 2015-07-20 17:34:09 -04:00
Robert Robinson
be14f0cc52 XEP_0050: Form not iterable in command
Cannot pass in a form into the initial command and have it show up in the payload of the session.  Line 344 makes this possible when following the standard workflow.
2015-07-15 20:52:06 -06:00
elya5
edd9199be8 Fix UnboundlocalError in disco_browser.py example
If self.get is in self.info_types and self.items_types, only self['xep_0030'].get_info is executed and not self['xep_0030'].get_items. So the condition in line 129 is successful but items is not assigned.
2015-07-09 17:15:36 +02:00
Mike Taylor
bb094cc649 Merge pull request #365 from jdowner/staging
Fixed imports
2015-07-05 15:46:04 -04:00
Mike Taylor
dbaa6ed952 Merge pull request #366 from jdowner/develop-iot-cleanup
Minor cleanup of IoT plugin
2015-07-05 15:45:47 -04:00
Mike Taylor
8c94d894ab Merge pull request #369 from stevenroose/patch-2
Change to roster migration e
2015-07-05 15:45:19 -04:00
Mike Taylor
ffc7eac4dc Merge pull request #370 from jdowner/develop-jid
Removed duplicate property
2015-07-05 15:44:58 -04:00
Mike Taylor
555fd6d926 Merge pull request #380 from anirudh-chhangani/XEP-0096-add-hash-param
add hash metadata for file transfer
2015-07-05 15:44:03 -04:00
Mike Taylor
c024ac8f0b Merge pull request #382 from sangeeths/initialize_certificate
Initialize certfile, keyfile and ca_certs in XMLStream. Added **kwargs to ClientXMPP, BaseXMPP and XMLStream.
2015-07-03 15:07:35 -04:00
Sangeeth Saravanaraj
f00177c0cf Added **kwargs to ClientXMPP, BaseXMPP and XMLStream so that certfile, keyfile and ca_certs can be initialized. 2015-07-03 10:47:06 +05:30
Anirudh
224d7ae133 add hash param to file metadata 2015-06-18 00:21:19 +05:30
Sangeeth Saravanaraj
9b25a7cf77 Fixed typo. 2015-06-05 12:25:41 +05:30
Joshua Downer
7a908ac07b Removed duplicate property 2015-05-28 09:35:50 -04:00
Steven Roose
92901637ec Change to roster migration example
I did have the chance to test the script yet, but it seems like that line should be outside the for loop.
2015-05-25 01:01:08 +02:00
Joshua Downer
3590b663ed xep-0323: removed deadcode 2015-05-14 06:27:59 -04:00
Joshua Downer
a33bde9cc3 xep-0323: spelling 2015-05-14 06:27:39 -04:00
Joshua Downer
ac50fdccfc xep-0323: unused import 2015-05-14 06:26:54 -04:00
Joshua Downer
a0c6bf15e9 Fixed imports
Removed unused modules/packages and added getpass, which was missing.
2015-05-13 17:24:06 -04:00
Mike Taylor
a8ac115310 Merge pull request #363 from sangeeths/xep_0332
XEP_332: Prefixed request and response with "http"
2015-05-01 12:50:06 -04:00
Sangeeth Saravanaraj
1345b7c1d0 Misc updates for send_error() 2015-05-01 15:34:53 +05:30
Sangeeth Saravanaraj
d60a652259 data need not be prefixed with http.. 2015-05-01 14:32:36 +05:30
Sangeeth Saravanaraj
61a7cecb31 Prefixed request, response and data with http. Avoided (plugin_attrib) name collision with other plugins. 2015-04-29 14:44:25 +05:30
Mike Taylor
192b7e0349 Merge pull request #345 from sangeeths/xep_0332
XEP-0332: HTTP over XMPP transport
2015-04-28 22:44:27 -04:00
Sangeeth Saravanaraj
80b60fc048 Merge remote-tracking branch 'origin/develop' into xep_0332 2015-04-28 16:53:40 +05:30
Mike Taylor
842157a6cc Merge pull request #187 from ekini/xep_0138
added xep-0138 support (compression)
2015-04-11 20:58:45 -04:00
Mike Taylor
a63cc01482 Merge pull request #316 from rakoo/develop
Extend AtomEntry capabilities
2015-04-11 20:53:44 -04:00
bear (Mike Taylor)
1bbb6f3ff9 Merge branch 'hildjj-develop' into develop 2015-04-11 20:43:56 -04:00
bear (Mike Taylor)
93894247a4 Merge branch 'develop' of https://github.com/hildjj/SleekXMPP into hildjj-develop 2015-04-11 20:42:33 -04:00
Mike Taylor
16bb5e2537 bump to version v1.4 2015-04-11 20:38:11 -04:00
Mike Taylor
d19a6e05b2 remove python v3.1 - v3.3 from tox.ini 2015-04-11 20:37:05 -04:00
Mike Taylor
86e85f9835 Merge pull request #313 from mayflower/develop
Proposing #310 again in fixed version
2015-04-11 20:12:19 -04:00
Mike Taylor
cc145d20b0 Merge pull request #297 from keith-gray-powereng/develop
Fixed a unicode error in xep_0065 on Python 3
2015-04-11 19:49:43 -04:00
Mike Taylor
881d9040c4 Merge pull request #329 from FlySnake/send_queue_overflow
In queues added option to remove first element on addind new if queue is full
2015-04-11 19:46:26 -04:00
Mike Taylor
1e77ea0944 Merge pull request #328 from FlySnake/develop
On initial connect use delay if connection failed
2015-04-11 19:20:39 -04:00
Mike Taylor
140f0885b2 Merge pull request #331 from mathieui/develop
Fix the element name for retrieving certs in XEP-0257
2015-04-11 19:15:26 -04:00
Mike Taylor
83f71a6610 Merge pull request #348 from gribouille-dev/tor_fixes
Makes XEP-0009 compatible with Python 2 & 3.
2015-04-11 18:32:42 -04:00
Mike Taylor
271343a32d Merge pull request #349 from mulog1990/ssl-version-fix
ssl-version not passed to wrap_socket, fixed
2015-04-11 18:26:05 -04:00
Mike Taylor
48857b0030 Merge pull request #354 from erigones/develop
Fixed bug #353 Python3 XEP-0084 error
2015-04-11 18:12:40 -04:00
Mike Taylor
1fe7f5f4e6 Create .travis.yml 2015-04-11 17:45:23 -04:00
Richard Kellner
81b7b2c190 Fixed bug #353 Python3 XEP-0084 error 2015-03-25 14:04:46 +01:00
mulog1990
460de7d301 ssl-version not passed to wrap_socket, fixed 2015-03-10 18:13:53 +08:00
Cédric Souchon
69022c6db7 Makes XEP-0009 compatible with Python 3 while maintaining compatibility with Python 2.6 and up. 2015-03-09 12:33:18 +01:00
Sangeeth Saravanaraj
9044807121 Added help for running example.. 2015-02-05 18:11:41 +05:30
Sangeeth Saravanaraj
24264d3a07 Updated Example.. 2015-02-05 18:10:10 +05:30
Sangeeth Saravanaraj
8bc70264ef misc updates.. 2015-02-05 17:35:04 +05:30
Sangeeth Saravanaraj
c16b862200 Raise http_request and http_response events. 2015-02-03 12:33:25 +05:30
Sangeeth Saravanaraj
a96f608469 Composing request and response. 2015-01-29 08:33:40 +05:30
Sangeeth Saravanaraj
e1f25604ec Added callbacks, registered stanzas, added features, etc. 2015-01-28 14:52:15 +05:30
Sangeeth Saravanaraj
0fe057b5c3 Boilerplate for Stanzas - request and response 2015-01-27 15:13:57 +05:30
Sangeeth Saravanaraj
be76dda21d Added xep_0332 to setup 2015-01-23 10:29:21 +05:30
Sangeeth Saravanaraj
ecd124dd06 Boilerplate for xep_0332 2015-01-22 16:40:03 +05:30
Sangeeth Saravanaraj
4a8951c4ee added xep_0332 to plugins 2015-01-22 16:39:27 +05:30
Sangeeth Saravanaraj
8afba7de85 renamed example for convenience. 2015-01-22 16:38:16 +05:30
Sangeeth Saravanaraj
1ce42d3a2f Boilerplate example. 2015-01-22 11:30:38 +05:30
Sangeeth Saravanaraj
2f4d811db4 Fixed a typo in docs/guide_xep_0030.rst 2015-01-22 11:13:03 +05:30
Sangeeth Saravanaraj
61127f521d Added PyCharm's .idea folder to .gitignore 2015-01-22 11:09:47 +05:30
mathieui
063e73c0d2
Fix the element name for retrieving certs in XEP-0257
And s/258/257/ in the XEP description
2014-12-11 18:32:50 +01:00
Oleg Antonyan
d261318e1a In queues added option to remove first element on addind new if queue is
full
2014-11-27 07:11:06 +02:00
Oleg Antonyan
d33cc00fe9 On initial connect use delay if connection failed 2014-11-23 16:46:01 +02:00
Lance Stout
27582f6fd2 Merge pull request #326 from s-m-b/patch-1
Typo fix of parameter name 'data' it is now 'iq'
2014-11-10 09:07:32 -08:00
s-m-b
e328ff4833 Typo fix of parameter name 'data' it is now 'iq'
Code was broken during refactoring
2014-11-09 04:36:38 +03:00
Lance Stout
403462fdb8 Merge branch 'develop' of github.com:fritzy/SleekXMPP into develop 2014-09-09 08:50:24 -07:00
Lance Stout
f22d8e67b4 Preserve ID for error responses
Fixes #319
2014-09-09 08:49:37 -07:00
Matthieu Rakotojaona
35f33f1614 Extend AtomEntry capabilities 2014-08-30 17:23:27 +02:00
Lance Stout
c9f8ddff65 Merge pull request #315 from louiz/develop
Fix saslprep on the username
2014-08-24 16:19:15 -07:00
Florent Le Coz
f5ae98aaf1 Fix saslprep on the username
Two issues fixed here:

- ints are not comparable with bytes, so char was never == to b',', which
  renders the whole function pointless
- The bytes were converted back to “characters” by using chr(), which
  doesn’t make sense if the username contains characters that fit on more
  than one bytes. This would trigger an “invalid username” error from the
  server when using a non-ascii JID.
2014-08-25 01:08:13 +02:00
Robin Gloster
073e85381a fix args, kwargs which were broken with #310. this is essentially the same but working 2014-08-23 14:25:35 +02:00
Robin Gloster
afc939708f cleanup semicolons, whitespace and mutable default arguments 2014-08-23 12:47:29 +02:00
Lance Stout
aabec8b993 Fix some more Unicode in **kwargs issues in Py2.6 2014-08-21 10:05:42 -07:00
Lance Stout
e5e2fbb16b Merge pull request #311 from Mayflower/develop
Revert "cleanup semicolons, whitespace and mutable default arguments"
2014-08-18 13:34:15 -07:00
Robin Gloster
3dd379cdf1 Revert "cleanup semicolons, whitespace and mutable default arguments"
This reverts commit 7265682a4d.
2014-08-18 15:15:14 +02:00
Lance Stout
a20582aba4 Merge pull request #309 from Mayflower/whitespace_keepalive
only schedule whitespace keepalive if enabled
2014-08-17 17:21:25 -07:00
Lance Stout
09cdbf1b76 Merge pull request #308 from Mayflower/develop
Serialize JID to allow json serializing
2014-08-17 17:20:45 -07:00
Lance Stout
ca306e7cec Merge pull request #310 from Mayflower/cleanup
Cleanup
2014-08-17 17:20:26 -07:00
Robin Gloster
1bf34f7fe6 fix mutable default arguments 💥 2014-08-18 00:55:10 +02:00
Robin Gloster
4144d60017 cleanup semicolons, whitespace and mutable default arguments 2014-08-18 00:55:10 +02:00
Robin Gloster
7265682a4d cleanup semicolons, whitespace and mutable default arguments 2014-08-18 00:52:24 +02:00
Robin Gloster
08c62a6bf1 fix mutable default arguments 💥 2014-08-18 00:18:10 +02:00
Robin Gloster
d61f1cd035 only schedule whitespace keepalive if enabled 2014-08-17 23:38:07 +02:00
Robin Gloster
1063feb33b only schedule whitespace keepalive if enabled 2014-08-17 23:37:19 +02:00
Robin Gloster
79f3c1ac8f serialize JID to allow json serializing 2014-08-17 23:13:56 +02:00
Lance Stout
a5c03b763a Merge pull request #305 from trinque/develop
Added wait param to XEP_0009 RemoteSession.close
2014-08-11 14:08:56 -07:00
Michael Trinque
3670d82f1c Added wait param to XEP_0009 RemoteSession.close
This parameter is False by default to preserve existing behavior.
2014-08-10 16:02:10 -07:00
Keith Gray
e94a73553d New version of the socks library socksipy from https://code.googlle.com/p/socksipy-branch/ 2014-06-15 19:01:19 -05:00
Keith Gray
577fd71472 Fixed a unicode error in xep_0065 on Python 3 2014-06-15 18:40:58 -05:00
Joe Hildebrand
ef1c4368d0 Merge branch 'master' of git://github.com/fritzy/SleekXMPP into develop
# By Joe Hildebrand (2) and Lance Stout (1)
# Via Lance Stout
* 'master' of git://github.com/fritzy/SleekXMPP:
  Relax timing issues in Iq timeout callback test.
  update JID_CACHE logic again.
  Allow IQ timeouts to be asynchronous, by passing a timeout_callback parameter to send().  An example modification of disco is included.  If this approach is approved, I'll go through and update the other plugins.

Conflicts:
	tests/test_stream_handlers.py
2012-10-31 14:44:51 -06:00
Joe Hildebrand
48def71d0c Merge branch 'master' of git://github.com/fritzy/SleekXMPP into develop
# By Lance Stout
# Via Lance Stout
* 'master' of git://github.com/fritzy/SleekXMPP:
  Turns out not all data is UTF-8, so don't try to decode it.
2012-10-31 12:49:33 -06:00
Joe Hildebrand
c8c20fff71 update JID_CACHE logic again. 2012-10-29 14:15:07 -06:00
Joe Hildebrand
75a18b5ffe Allow IQ timeouts to be asynchronous, by passing a timeout_callback parameter to send(). An example modification of disco is included. If this approach is approved, I'll go through and update the other plugins. 2012-10-29 10:03:32 -06:00
ekini
ea3d39b50e added xep-0138 support (compression) 2012-07-23 15:39:07 +07:00
60 changed files with 1788 additions and 357 deletions

1
.gitignore vendored
View File

@ -12,3 +12,4 @@ slixmpp.egg-info/
*~
.baboon/
.DS_STORE
.idea/

10
.travis.yml Normal file
View File

@ -0,0 +1,10 @@
language: python
python:
- "2.6"
- "2.7"
- "3.2"
- "3.3"
- "3.4"
install:
- "pip install ."
script: testall.py

View File

@ -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``.

View File

@ -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',

View File

@ -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)

View File

@ -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)

View 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()

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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
]

View 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)

View 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)

View 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)

View 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)

View File

@ -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

View File

@ -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)

View File

@ -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]

View File

@ -220,3 +220,4 @@ class XEP_0009(BasePlugin):
def _extract_method(self, stanza):
xml = ET.fromstring("%s" % stanza)
return xml.find("./methodCall/methodName").text

View File

@ -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):

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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)

View File

@ -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')

View 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

View 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)

View 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
View 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)

View File

@ -96,3 +96,4 @@ class XEP_0202(BasePlugin):
iq['from'] = ifrom
iq.enable('entity_time')
return iq.send(**iqargs)

View File

@ -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',

View File

@ -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']

View File

@ -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

View File

@ -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)

View 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)

View 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)
)

View 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

View 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)

View 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)

View 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)

View File

@ -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()

View File

@ -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)

View File

@ -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'

View File

@ -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.

View File

@ -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
View 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)

View File

@ -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)

View File

@ -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()

View File

@ -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")

View File

@ -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)

View 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)

View File

@ -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'

View File

@ -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'

View File

@ -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')

View File

@ -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)

View File

@ -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'

View File

@ -1,5 +1,5 @@
[tox]
envlist = py26,py27,py31,py32,py33
envlist = py34
[testenv]
deps = nose
commands = nosetests --where=tests --exclude=live -i slixtest.py